IanniX-0.9.20/000077500000000000000000000000001317340345000127705ustar00rootroot00000000000000IanniX-0.9.20/COPYING.txt000066400000000000000000000773271317340345000146610ustar00rootroot00000000000000 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 CONDITIONSIanniX-0.9.20/Examples/000077500000000000000000000000001317340345000145465ustar00rootroot00000000000000IanniX-0.9.20/Examples/Nomos Alpha.jpg000066400000000000000000015117641317340345000173700ustar00rootroot00000000000000JFIF:Photoshop 3.08BIM8BIM8BIM' 8BIMH/fflff/ff2Z5-8BIM8BIMPHUT5DPHUT48BIM'File written by Adobe Photoshop 4.0Adobed@       L !1AQa"q2B#Rb3$rC S4%cs&D5E£dt6'TUeF7 ?%81B1pMŏ*?_`TsqsQ_4R3TVLHz"J9@%Uk2рsP^?0 qz8``果>zş|w11PF.+0j^*:|`_3Tø fZ-z0 R1!TV`kXJ0<1/c15/'0*"a_09y1u_i_2]`s.x9xQ?}ᛊ8rdw1qPW`/j:^wTc]AKtZ WCZCӭS0?Qb?_6g5(:'Z,cG#_0}KZ0ZÊ>S0,'(KJZp_paRUC3_0E0)>{L|ӓRϰK*ǜ '/iAֱ/32`L)'-jLIj#`^qS3PG85',y0 ʔF= sPW`yjg0KLA JtL(i#*TTRS$Qu*S 2 _QkT,)%`}X%JPlԀTO)4V98$eDO "iFzF0203#9`I@<P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(PӜKS@HH8@4g(+,J 7jC5g/< H˨"aD 0A8d @t=`#CBaX@%RS#, $3$ x0TT s<3') p>%0`DIV)Ixy8)LidgI, ̧`R2LW<`%1.@ &GC9@)c%@#5R4$OprplT>0 P1J2L:!-'93u3"< Dd( u?@G=C!zHt($ YH玘&~L3D~X)S&A LDqG0 0 H| Kp8 DXF*I~p%z&U,HW:SIhV$d ;olu;oWT#KlSĆIśBUN8k..NhBēXRO(Y@,b%$X&zR02Op9{|NH* Fq& Np A DugH_@-R9`<$F `qWFҔedfY $$P "I"s2OLj2ǧEb5u"R"фX _#>ZRB^Y_l^PZΑ09YֽSUB%jY9Jq3? >J>0pbTG?W'(l?G8ux(.,&q-jVJ_ ?#I:NuIB~ҥ3,J'<X:j!Ng =]Kt@YڧT,` F Q=q]ŕKK`J gU9KS9@}g2$tp늘%i XWI@ (Ӭ-o{kTd2b{χO821yz0$d2l̆p$D'@)&s( i=XP@F0(1@I I8#QO"@ xdrZ@b` @a$M3uH@) idq's*{ _>]`FgejHe&R)P>0K&f}p5 g8 q|0JD)t>I2)8umZN yťL<D` WD)P$|:0Fgx@":X|@61Jg)er j1"r&Fq@x! fp0'Ϭ+⟔Aҡ)@0ry>Ie>ۑ9hq9o~QDI̳QL`ܖFجjcPS* ˼b}J$ 7KN]}X!Nfg3{p}qҊ c)v޼@$9tڦts;Gtzڤ}h+E<9iBD IH3:$f@rpOQ$W3(j O8GIȕ*R0I>Lϫ%X:<ǟHDOEx@1~PB2 %"}DZb )74̨$JN #LF%t$+LHJ 0pBEI$ҥ=3YV!Iz}ZS?a`IIW!e( D@IFMVe]eB@y83 N&#@kP2> zp qT`$YQR@p')K0cX&JӑA½RB$ %#e ;.P.HN@쀉Ay&/tNZ!V:A8IH[INr ?$(|!()}`&pj:ր@lz}0ì%8F'(0C`I A-sJ&P=IpL().hSMVtZLq+>IBz/ I3'PI9 &C d%> Ij0 HBɒI(`sN a$H@2g!H$'} .(L d# zz "SH"G8d"PJ1xe >$LI,&<BX@2s?/8 V2z@N ï$a.2f%)"Ic5GTHBR88ORpg8 1Gl4K+(?tI"C1"'!.<1N1Լ ,g@ RS#Y@HR2$iS<[keP $``0vzze#6ꇗT:>蒖 #8Hsp(SThq:֜@{i{ވi)Usl. VGΏ~aZj,_rrKn/N/?[X)ݸ t u5`8-ukiVx݃ i'$a8t!Rg>fx~nz|PY-66'YvύZ""R%%*V ` sQ $1> jT3I> *9V?d,5%+A BRTA"  `G%SmQZ[wI( QjW' Kk&8TO+ä] ?)@k/ZN04(jd&^'H#@ 2 g! $Jq20s8>"1XLHäp;v]*6zj2S :8?Αsa)@:NNBX@Hfy@#^$yx@xҠT5oYi )Z'y@ >#tM'pHQSzRÎj%/ `N %9'(JO zNhX@$LJ (@ Xa ᇌZ2Bty [wB FPQV}`##>RxK ʁ$?^q!*q@Ꮞۨy<h aZ8%AuLzP?]L&pj$8JY@bL0JȟIQF LYxJ3b}%bq "Yc/Q'1@ ,%()b~Ȗ fpU"$d = ?QT͠4`w)@S9J@c(!FeG(iR3"xq80!@kQ{rpQ߫U%މϘT䅬~Tݻv[e5U(\ez 2qN!j*euW,#SΨ)=Gy6Z^Қ 2@jq]oJk3W-"j N`@tm J*핖H5i *ˠwj%jJH-9ҙ2Wab/It8`I?|[Aںm/^2ug2ns+fCnQR7SX fO 3ZWB4)hVA>1)#<$'CU L"*vl5˺Ԕ׽V4 `IWZ{.n[m5i\ҖK,vXw* ƋRܯi[̀YӬ|f56tN*<~j8P D̑HQ)P(:JP̈JzE2ĉˤ@ DGHLaKX9}0aLf`OfzˤHz2Dem3V}h 15m㿺M6JV  ߇Xmo2JO!ʗ}Jޛ%Kd@qE %dq ~??j qu{OUTҁIY0p-n߶n [nU=ԍJV+D*bS{Cr>8*雬Kˋ3,2)=.A,)ofFX$bd08cyRqںo{m2f$yH@yW|͕o{6DL&JeQ3R0)#I:"N~0D*P!mlc|zZG&)_-,kOX}T*;*`aYĄi'HFy wKZZi&jrD!~$ϠF >JM(s[u]Mdhr7z=KN%pMy&ϳblϒIzFUN$&-7r %"ɟdIgDLQAl%A*f捧YnmۊV+b VD:_G[ኆ5:J:gRjc19wr7]}W]n/t$' 05*lBr8N%ӬhP,acbi!)YvAj2s`%? ,1 >* 1O m4_[UnzwkU©'R|Ro~wq-6i,i- fRuTCR]#2-3tLCNT0J:)ɔ<`%R u(E;kti)Ő j2d2ݳ7i۷v!/T6ߪ+XGy- ?J= ;>9vJ[UԊHy& T`F 2a:6Y|>,/>R)ddOA4w+E]S5H (Rq.$%$\8R"z{u3*襧mN䔉@y3휯[( ۭ\q*jfZ8 ![컞VܛS7JS]{% 8&Ca5z&]|"W=pVMoNUS߬i>Ff# svRlW;EE%js[N'CRMm:]Ⳣپ۸-֧_UhphiԪI,vI%*4kAm|!#P9)V.O6*BVj}Ĩb@ ka,WóvFhe%:Dw>"@%JQ g9N$t@3SJ^*ՇQEH`.Z|jH)DXJVxPs\ JLN$3)f%1IA2g8,jV^2pt2$㙗tx`"BV± $ 8NxG2@3P4/ )JJDΥI*2]rE!:H'y 5}5iepC2adҢFl EݹgQ}rBAr 97ŎoYlTUx:DI!j |`>ͻk6mi[6 JRqKV0 u-HJ?`{'__QW %n4StO w$7QQIp 5Bzw̏ ap W(v<8NaJTɜ#il{i<5ՒuS45I? X .Y@ 0%< $X6GH +(SP ko.(lyc+@) @ Pr'9 ҪwnF6ZV5n%*%W-nk݅meqԺjXԵ==qJاբ^znON'NHl*R0.v{YѴ ~x%qj)TOꖳw=HVm:jY3mŤIE$aa* oV$cV[ݯwPn:ZR&dt>Ͷz}MSE+ܛy+m낔^y"R P$@f{ :mQrRJۗL9/ַO^jmI mTܪ.8#nA2YGm;kt(St it5f`<{p}m;wr3ZQu" SRS$!cH _qr){jn *+dqm'Ԕ4D/h=yO|/hضWjW̼+S6А_^;ƪTa{NUHy¤IRƄK9=;o7y]]MM:^Cs"IJĘQ5tMn; ^} ֐dNN6>ݤiL$E]T+)Fd 9Y<[eeAڐۧe@YkpRlKum3\Jӵ2t̅T,|5Aiga=?u)X=#Ks *dt3 $"T42L# Np((NH52F  sPqzTN iI Ad|` )L(i$ IF}I&YH `r`(-¥ F")zNL̀$| @$g1% r!+(RBE*H@?nf]e9His pg$IJX/d{`V:YC80ďl`u0 OqCr20`PDBG,@Fp*LO0JPVGGR2$)} A zJ3K.hOpU T 3ZDiij2l{sW3FjEd]2b$a2r1 10DR˨N^@2>:q԰fR k*>0v)X..u7H<=Z1Ji۪Qf2> )it qL"Fd@:ePR(N$g rTA8<s&(D`Ay0RI Q3 9aj 爀dLO:V%9x 3 ` Ra~0:@683"LIJe ?(@%S/~3!$$)rLzb ORJ@aֱ)3RHFp%z ,b!+v^H $m :"05s@T>30Ǭ )Ӟ y՟Řd !$HH @QK2 D4&f<`a:?N$P:N@F=_( ɖ#)@%i9Gc< dFc8HF?dL$>P LAR: F9`VUpG0!!jJ~#"|?Ӭ8toˍmǐ)[:(X>TBR@w6 XD<<Q}-C adPJIN  GPt_XWFki-=R[nHm%O)蚄 tCg)zXAQ5( L2DZ}=œMseuhy qҰD"MvcguRVl| >&Zf0ԣ,9NȤݮ^Jvy]jCuA4%: m"Er3;ɱ$7:J/'1GOLW`0iݵͿeK6yն&>IpED 2Vu%EJ*teRbs@Y춵i.!3Wg}krX(Дch)ACOnf@IN-JFCl#Tґ u5zWlw5(*l$%V\yc$@Axiۅ6z**B})@8A}5VUril/,%,CoзiuuָpRBS H&Bn_ԍ4nŃJjtVޯ0&9 -J =aJ~Pzp0T%@HLD~ׁI}A `%?l TK $S9 LȜ%hBpq|`J'QQI?J?"ds& d]N#̕g&d`$Ӏ T9L@2BL3 'Jj2) $ԉ2:IQR ?7B|'^Z|`"mJ6LYiX=}@/Y%F4Js'J+Pty:Y m*@H<9N~?\;}2LH:_&@ǩ3Xi^y@K0q9T)q  -'* P -' qS1s@B+"` V@"88IYT29@HGE{#Re2DIGԐ|^Jdu?d x &%(H(e r{q@: NsIp!iS†'(!D(P>ΰG@fg<Y= O:* )+ Nzg꟔2H fX@ 4^P@40}3&%Z"N@@ K-ԗw߷!Sm 4H gS6+;y9 2 D` 8嘀,|0bIL^NCn]:\3MS["jQ dHd|`IgACȔ] $/`t@9-&r@H?] NQ1dR= N%,1|"fF8*I@ $+0H@7ɦXPPQ5 I"ei$bg:BQcyt4=jg@L/tH=I!#Y}L@HU~3L@j0 L@2y@@i'a$g#mcpu,(FC{ O$󟣠$12ru5 IX3p4,H &9cKW O' ?wVU@ \օ8ԀN.STݩکrԿL\HWm|+H8'Vj3 }IXI @*#@H%0',3:HuTuN~Y@D`Jb)y 0jp)ts &4؜<'(J0OH\|` B8@H3 :T x@69>pf%D3IVD bXINp#"=^ Ȝ3-)@a @,Ue$ 吀Ax@קJ% '@\8)LpV}9@G`~=}IL&Xe"~p.:R86I2|Ki@:pӒIVf`#9@bfA`GLLL.Gp &UxJ~ c' y( #18a`aLfD(NX `2JH@aND@ tm U{WRtLQyk%X'Ĝ%䏥?S n㸌۷4٣aKפ*$} =Ÿ qLeˢ^4w:QAP G@e>Ndz@6dt`1@J]CHn䭽W&GE?bǷ( #<33~$ N&R8+д \.p>)J220kk픮n 0ڜqdR&s8tS|i ]kνJNR(+̌}z@%,$)hLݔڛ m:+iZI)!s[mORQ\PM{V8x :=*"y@-^Stb`GXH`9m[l'- =\ >@c$K*L' F=`Xj>I0@)RepN#s@$HH:A ,0| z=ve:W$ąra 8?lEqs~s)>2"pKG8 scqiC>w ?$Z?(&dG{`&  8r&c1p .a@}  NDLS,N8 e 灀`:ĎG5c9k*R@JRI@HGH$̫"g$Tp Ļ?SzN8P L̨x@R yS=DS0pmSX#(p%S= &>0&Kt_z^0 h@6"G(?`:@(IJ.zAg8O@ ɖ>V5(3PwR BZ*=J(wLgO e^j2Z,1#} N~>0~0g$N9@NbgXJMkL#29-Bg99gnޣ0L0ITIQҢ.+'Ts:@`"H:qBJ"Y@YwF N:zBAӈ)@?i8fOA:ugAy ! %>3ЀU4GLB"|BkYJYKϬuӘ=` _45<`P 9>3s$pybf0Jsl)=LO ϥ8` Qlj~VF#?lKqSj )"$2$JBK#@1!u' DHj0a8c@de#@<"R"j=} i $}u3Sas@?oI%I'}S~ Bt C3d} 8Re8g:)SIȁ@|3u1H3\`#ւ9(#V?8LiP6OH@iOXQS[IECzj?ـw-xVqWeMmPi8)J $ so0ݗMnktWeb+M1:|m\o~\CH5( STܗIjjmfҰKK 9nUjҵ.*H2LQ@jPP5\mCS/,IԆL5 OAVTw6ޕ7ӏPit1qAP9m~H5;nEMP#[ζd`'ҫO{eݙS+]RC2Rka RntR̂S&Z,unQ22.8-~nYtʨArmmB]@n{w[nV͟)zZY))K/H|Uz޵!7AEnP\ 9=Hsd%-[j.Me( .-]}c iKu44S78~?`<{Q+߶Jƫm!i?/OHSFpDT{nV5IyčD ۜv5; ` :Rz*A>3շ!f;J6@HyNf.f)uh`9-ur]Yl7SV6JPʘl<{;i*+//)m2P l]MD]%)nYIg2`=,N'r9@C)P"',Gh7 [(~F\E5 ,BZ qoR4*~Tf) ;Gs= 16Js{-t4nhu#V #q/7[ݲvI+m}4+4 3 ꣖+^bnǿ\zl&V%U2.T ع7t} KaC BBrG4`0w6wZl5ttuja-&@|0KdJCirg%l! fRe=fLǔ,WT_wRPv$*^e9@ϧ JTҬeT#<L9a< +3%! L@JpJGT76,|`(L%*9[nUʄ0Ω4thQTA$̯RdpEJ fy@ RՀ$$YfT8@2JR3$4>ШXq$($R| $ 'i&)x`g3=N$U)@BOLk"`exR9o2xۗS%z+qFA)~ Re)X(L}0 OU`]3)>8$L"H8)JH3gkY}k6ҥ>9<`.vRJA`n{M}/)ۚCN!M6Z3aVQ8 4q&Y@Zz F@3 ,z@ R$I>PP+2KOS"9L!) ,ȜqGJĨ"S1QD)9$(4("GӏJu$!,1B2j#P3TZBe8 S' ^S=#,1:+JZ$|#jZG Ot``.$d-LF~mi||`(O>0k`  L7p(:ˢA8BH H\?p*9z>C2O]%D G@"e39Hđp 53ӑ V:eꐀS5L}IRӜ`"g-PRF8$z1FT8 ,i *N:@6%>8J)&dg᜽("!V@83cbCH28@:L0)(Ĝ9JxG `x cg){}9Lu=>&FRa@Y`gD8 G1L@+ :)>*CJ`'@Xa3DLH`HJ#.d((BJFz%"iPnmE1yTĖ^mEi1)>lCMRmV(Iy?y_OUK coNw] }4%G`;6=eMꮹv[ d9$3ɧ mʸU\/7ju4Jpsn[u}X߭Pө $Fi `/r޷˓\ 3 MIC)g!6׷m PviWRԥ)jQĨyٟmjPثx5n\h.TuKV bpoǶzەֱW? 46}ȗj[\)aflIJm'u# EeU㋦(K!Ҥ+ 7zMXҭ¥/ G)ݸ2Zӧ$L ~Dzm6ݍ=; XJs[8 \%|ۉۗj ?"dAL0[V*ֱ7/~R.М:@`xyqܜ]-bqhV3JH>KJL9@iOxt[}82[L;Eԡjm18peGuqŧwV3y]E-{M*ԅ8ʌj'\v|Ab ÄT񙀩v~]XX7Q\x!tH ۞G!Pr՝a+ZP33  NJc8 Zi\o4ۦT*4ܖE^ݦ_&QEJ*jq/ rYVmoWP<ң҂0)8 v;USLU\]62C EaX.;y\io)SdR(,%@eg|kwlKאA=8tnqՏh,YZYR}\X@ !yW{ɼx]D5(4^Du+^׽_-5MUJ[eC?|Odf6e1n5(m2ֆR2F`1{Gvʾ\ U=é )`;C '( `f?Oik8kZٌ đj r,h[.WP~ऀ@u0uc{B7 (RTsd`4VvJ8x~S QZX0 ;Iv])P)TqVܴ8ծPR%/8VDLpKm4>ݡ=@] TA9 PŰpio 2NS9OQhv[LӴUYR':q}ao+;e7mW:mb)e" %DsavۦZHBP2 @K:S!8JL0.z\Zf^p/ i2"$%)ґ!(g L,z@-Ĝ4(ADQQh@I?>^Ouu)zRV=$4Mz-f0սrrwLW -&m,^A 0BgOߐYyr\-; /BCKa5S F(z0ֆIը%#ȒsM- IROFbFC%“? &Ah[yURu+Չ` ˪e*Je :o 誷V6)}*I>, <ȼ(9Xm]mmCl~ypr( ; xYZʪ=?m!~҃hYպ*0,4+.)$$GܑYPZSLUt\AFRRg%z[NFxKlKzjhQ$N5d08mA a?8&G&rI"sW3S$~<@8 &H(i:t8~B$gפ("&"%&ULՠ஄u1sS~.~@#I%$g?tNg9HH2 ̈f H9@L e98L遀-m$,)j AF$x}Ks3. a %FDFPB^4JzGY@Z@@'W L4F )A^@@)%*3> R!J+x9uN0u>"'H`<,,g$GH@9Ip&` `N=`$ NPc+I8 $iy<%Z} g#(ȟB4Dɔ#8 @ zeT0F=#T&@I=g#.!)x+( s"r dRK$*FYa(R @p=LeO<< #>0  L` P8PJCJs0'"3JÞp C`ЬqP 0gzr#Pp Xx@:}_tD R\MC4L[T Ӵ>BJ~ʶ~p ˻[}VkS4SlAח }dNS:~uܝ̵v]WO|]UbKIR(_j*=`=A_:J-TIIM`e6eU:WM`*ix*i9g^leu)h֡2*E)rBnQ^|]E{ E:*.5DOIQY[n4jbe @d,]mV}vu+fտQ]nS2* ujt43I@e(M[Qbڗ6)ք»g@o^2#&dqiBu(O@x8ݽo[JݜM ),`66Ӎu[_*^RR('MFC @n{Cy޷Z mdHwo7Ey4TVصN)W-;U-2z@wչ/{bWܭҩ6;$x$#77`~44>&rKlӻESk0ǩUĕ6'ܝAc kat kB3>o\qٶPW}"RLM4̺-FS0]Vv)S^nZ)vZDXI$eS{}~֔S)j2Ây\w5tvU GC_**=f@˺T-Wv T=$%DYz`2#s)_u_&~7Z8G@..W-rܟSId!RI@n0*E-2"d'퀴5iJ0_rs (jn6@ Zg*fT- P׀JT[߹\r !=zPdB@~ݶiےTZdT⥒iWtPPGJH$`&;6ӷnW;kWr)"ĥ^7$YK8uU8PDk <4ܜe[u]Et(4}s8}>*i%ęKұ1232PkشRtXE53jy <<|Qi&kk~h=,sE"x@l^n0N[Dd8퀚սޫN>St7W@&UL/"kz ]fqjSFluQoQk&tTvrDTBLKYkۣ1VWRK!jwG56,& i~b\Rԯt[ew5L5(5g4tj9} 3>jԽ J2X%˪`^P'5JF0y?N19 D[ia  c/T% RorۮQXv]p֦)m! WSx Ed]fٵFfqһ{6TR# c|]ޯjj;8*Td:OƱFS+ҹG6*UM`yQPO-7Wv]NP9LӁ.b&Tqz HbJmWĝI^C`9I&H~?L2?y >nޭU$pǗlT9Mi[z$Ӿޖ]νuyUЬ0JR撈|T{njJ{IB21-A~po!Zhj;Kmqog$ mm[o$QS\aL.-2YBg,.~\ikз,tI hfj*Rӧ1{:rV[ÜEIAt٢t@@r=eZjתϚT72SNƐ6<Ħ|I{Gjn+nKMuaRҧ*+8XDpRTU"P 5d%<`*Ua%IC+8yjaX7BH[z%NjEƸ8}5C -~$ )P7tօvj[.P*7fT[8p_,(Je3y pOHx@nF߻)ޏwz.uK-*ޖʼ Ljsnzܷڥ*VimN2D5+( q".[j UVz8ӥmmll W-~7n6NӤ@g5(SUƪhC%\J)A=ŜʖI02)I˥*Q*JR22qZ!?CaSIPqK49`1}͚XlJ|6EEG`-ꆪc[SҒixSKUi4?q@TY.> p~(; s4Hyw ;Cՠ"q :|b:Ka VDSpjLz@y$%`| J"aY)zƭYJG8 2=0b}T|Dq frd G)*g Չ*BY@8fS8&C93 (j>VGq)@@+Bic$DORe9Lu~)qe 2Wl# %!%2(LH08g0W0%#`!(R䦀rGU,HrL/tP qfD@-@z} 1N~P3}BM^0WHTH!s:Hr9 kT\` (j~0L3`()!rU,Rd&3 %"OM] H"^B PS$K2`Nx@&zeFR}80z@$#t!VU+H!:IPǯX ՇS@2%Lt09,zXTbҝ"iI '9L9L:"g*DP 0%^8 0Wa(r'}gop.[yՖp~;)@q>*ڛʂ6w!Zؤ]*FsӉ>05^9nz}ALݮ\GkҨHe89ؖK&ZT<ظ0k.$L殃!g}>*[yUjQ4ԅPr*=Ǹ//{[tUHScQdeߴ466g<9/qwg$:n$S"m^j_'UTմilv,q|8΂vgi]cӥ,J <ԢڣUCimvcĜ`;ӧ%0]ggq*bj.%+ ECMch(CL4"^W.ںzB0.54)&#Iu0xolGk۩xR . m$PI>(h[h*6K AC"j)=8^PhomQ-VM2ms(IĉV-^*9'R _ٶ?l\~q 5[YTqLЖ)I@j?lUwz+:m5 AIp8 <*=,+z-+tڵI$␳qR-T4ԩt6'0FoNr'Cf[ ~{aLxJg3@Oas@VP:..h/[P *sZS? n Qk؎5OzmvVe .-#H 'gPl+дj48JuXJڤ OL G߮wqsX/K@-$Pe(׵xoݓ^/m?P0TXck܊͜2}jAt/L/qg`JRh:C @(*PUw,Xw ۲=o@WpRKV谬H]uVoV+ /88O܉Srh{kWͨgvWe-S9GM4 -i#@f f3$ W}wݧp}jGڝ[&JRa8m˝65majLvNS#cR+y u-MvM9|3 ;~juuUUk$"[tJA9b\#OnkfXwo^*_Su R=:nfWnϷjͣV'^MLdBq>4SX y)| F^3"cu~2d{NJD0H:(ru"'<2>P\20T3>oT` iN#8RH,`)S)#8է18  BSĘ$,ȎLNxFCM2GX ` DϤ%Xj C*RC# |Hdgp@| Dx2d̉  '=O(NpFpt}jH = #\ o=Ml;Rꛢ* GY tS*T6hm%(JGaH! k!g5i^[HMJLĭ@2,)Lt+Q), j͐"@R3h)yDq:@VH )ӊDrBPR@PVV0\GYf s,`!mS3RT!P)I~ ]HP =ړSL`hEBULd|(H iJS,!"NYea,B3!ȔxI'3%:9@Ng8 8IX28&G3FPy~ N^ Ӏ0P Ztz` 2<+:08V *Frlg0e<1EK匇@9 .I:(#I'̥J8KLƑJL,`pS9ZzIP@:|2է DX'j&`OLD'$1!!(G/T$FQ$%?>)HH# @2YpJJUx^Z )Y@4) g儾PP=F0:4 a&C,pm(JbŒL!jQ=@#3#%A@,`s 'jD9@VCũ u$.k \q NS8 <"|j0XT)TM#, .aY%8)V:cPR $09$*GdΜ$1>P IzPi % Q֤p9x@J'JGNJ T& R0 2Uic#n ((*G 1uaZƠ H ϟJAa!(XV $S(AprK99@$!2L> $0O1g .q> e)y~4Yt'x s9F &L+#L &sR Q,N?#YHd9r]rpMO˼ZһbiKӫpks!{rem4 m/RVR0?N&r3JcBT%jV Nby  u?)*+H$*EBXcG q$(!8Np剘xKS Bg&DH*$ @>)PN @2W|`bl>D 0 @9N/le88"q8DǧGp"4R(,(@1( L^c) )+8)kHH*&D!ԗ'p JW2I>0 01p5,}@5 Oe8a@y$+Ә$(I_‰P|C$ H3 $I3A c0lIČL ? GsJe d+OʒBRCi*x@1a J ` :`N29Js*X@%Lp$TΣ0 $"^dBRLzHz&$IeZd@HUb| $W bL r@1JI0T < + H#>NH3p28 pT _xp FgpQ&psp4j"c9u|D,` ]MKP?b H|'W %Hh0e-}zK2H϶ LpbBSO30t8)`+!A)IyY+ PDˉP:}ČcɐBTsӊf / 9h%qz?{S: Lj8C~n ra]P3`ԓq5(3TƑHmN ,qT:l1^ l%H)QJ pT2T\ uaqtzw1JDҡp2O7 &N 30r8SKT8g. zNsPf$Sff퀒iP Z"R|RH>$"dH A:\Z%' LX)_\00B=n|9KJNtH'3J. jRP'얓%3NH8td'.$LF2ّ(.Y@ †d  $@c"%@@%^8 ())3]y@Gb=P '}e*D(ak"x( JC R0 t g3Dx`$4? J~p q3HP %"Bs@1ԡ ```&!+p )"~#쀋X3cJ$y&"Dg2Ȉ2P)&R-d~,ap bPg=f@1֜`Efr9N`j:DydF?L<0?2 QF'V]zdJAIY2>Xgb$H@?u }$wҙi= 28gʫXI&r0*q cVR/F[ u|IT5U H$? ?B`<2A'\xJz}$I&YO:j'J>&z) TA`*,JIsJ@LT]))ARU3UʅP01 pJ~8=EEn*E)&rc$O![9c HVGpp$ LIcฐz: ts#, )<ܕ)@LVdTrvӯPH5(J}R$1]yA/(%`#H'A= Q]LUV'1H=r W9Z), JрJ/ cFAXͷHiNgՈNg @8}EBstQ3*OA: Q a!`($ @oWz\ $_PL&fG2X I>^8}g$$&x֓x0X @8@"<T9@28 S#8Jˤ`Hd RaBdK(R+PG9@<<|'Pjt$z$P OLtϤjGIMSrsQrJՎ08bx` Ju$<2xJfԡ Nd@XL%$( Rp@@$be$$x@>0< 1.dKӨq*+L$;N|Fp\I2),@'%bP8@G^p$}HAZ=*N˫lLj'8Ox(u*IV] &PZ!BD֣=i@W|Zg,z4%^D ?dwhLQjpDk} ZS&L)G'8Q, \@jNHX-%> E|!RTC8FZ0jJ]8 p"Dd$\e*JN)ga DI{rs%+Q @Fڤ)@AR QGX D@`ZVquvJ}YN} ZJ 5 :AJ*PJp"Pl+@Krm&S2MNR6&%8 Kih("IRH3!jNFg| 0@BSԙO= H"VVOX+PZeuu!HMĒ#qN4@Ԣ=H'{kqE@Y@^mHqHKZwҧ5 Fҗ y{ M T:`>,, (XD#Nmp L2+NR[SS*o/( xKy^_Wg] .|( $(^2s x$]A#BAxqFⴔ Cd,1?}!88At.L]m)n,$uEejZ$LMrY@JR2IF(NL>y{ " kՐ'8 %C)R`-H%IXRU20@J@&dH cg M$B: JR2'OA$+#25}äR$Jz<`%TIgI>Е@FbzJg^0 P S\%IjHP 8AD*}f`& r0JҜHJJf:dMD/P*%($GAX%% xV=Ũe~p}C0Bz}ŜV+De30뽔͸  (L1) c g8p } P B"FNYz@)>nےz凄tBG>I8#` r5@ XYHP~&H'T1QpN3=`H Gx8X4Ô!-)/(@f}1"$%&E+>p Rq@ ] @i@$(NCh$L (HX@F3S"DHx88`R30(00w +LA^08Z0=2I@$B~ I&ifg)Q D[I%c%i`@9"_ǧ4bb5 10 NPIӬe83IdR=r@@%%RI9 EBIV*# k ҕ}ҩy`G( Bl?( &!C tiPڰKqR^qH*&@@0R%46'!: 8􏁣g[-GǩqtVZkCk)CTeu2ʥ,IHQ+4t,%%d1$Z%TApJL DéaS/Q`XIJ9J$3KCINP 1dxg$(KI2[`~J |2KL  HϯXuuH C- : #Q0V$?|8 @!RO8ut6A)JBUJL$@R%<`(QOt![ e@:iĀ(cCԗ0H)$J\mztnȉe4)@ HBӘ,>. ( ˉ%^Ȧ{.㞮ƎD3> d^zYP%8􀕳1?,,&OX(HǦP 2X_WbJIt#JN!^>0ݒDd<`6&N$B' o&mEAEf@KR:I:RVJ'&DJȪ^^0LSbu.rˬ8#?lTq(Z30OQHi(HKNxg 0J5 g9 a T #se{ ?@8J #? BDRP!s% 9e!B@aIdai #  'JBC HDu`D$(u>'1 g8 0 Afffqұ5$'q`$t} 85D Z0T99d}0 -:ONI# &(BR=3ieX3FOW_Lz@9P0Kg30`$TgP&'#|D#8''W4螓JmqL>::kd6D @"c @1e59X?@Jli#ݤa0m2 i$eI!@ L @b^hTIr@} D'$=C//PJRfچ$ >yҙ 'S퟇#:R0J#( H}*51HjC zoI PN28 y~RFbSn$'!&Bp\Rd34})zL>퀗@D!K* +DȘ牜I$x R&}2M0'U2WͤHH "Sӫ{r0*i6 $8Tӎ:F/ J ' D9u@vL!I*HqF|}DyŠTe^Zg< 2P'@Hs $ HO8) iQ?dg:qh3y` Y3/:H=]=IJI$/lRUib L\s@ * N%X) %GRq 4$8 }j&z!,R!ƒ WeI3cX@He ESB8u2y@sdCY*ITR䃚09JuIJH o3R D}Lդi} V%鑜 i'gL9G{I3:jNp&%@p<|3tbR}G8Q>0F0` >T}Iz#<b NT~)c#9!2H 2JPBAX KgZd0 bs`#8$ a81$`b1%`2e0 KdKX$GRp@HuJR?d+dzM@@6F?d-z` I(J$%LH zrY8 cRPi H X|P"g@B]$y@Ho>,FI"a/ 3 qؙ  @0r!Jax@UWu"g8 Bxg4`[hISx<| )TV e[ f'(@ xJrHc<}&}5}=<`D8J=S,$z PF ήޙ9IBp%a-*s."by@GZ `@dXHR&t|S$UFi2-)_I@)9@'8RF` PT%!3KH=)VxWLYT X&X@0RUJbY($ u`4@O)p` RjKm"G IC#v:L@Q GpLy@APԤ ?8Nb}DO LQՉ`Iq0` "` H4bI >9s0e. N!Z+ $gdOUc0&+yVYgY@RN#?d#Pr~\ ə008I'8M9y@!)#L~0#VX@Op.j` jXϬ@$^P$YT$d@f`S2s'H3cJtzJ~0ZoNq" q R}Jd B|uj^Z,MbF_l$cR:JRdK zgU)N$sM8iV#5!,)@g,2} |(` X'F== RX)Z PI"g@ D"$HNh np2FP Ce PXRRq9U!AiSI lzS2e<J `D"ipP BG`0!8BBS`OOHJ`hH:sVۥA $ +锥4I$}89"Xg8>LciP`P |bp @I}JD LH3e2eLUhdq$#0%]1'8@ u J%Cp?tCQXW3H)SI@ y@'"WZ5KNX@ B@3,K^`r`N$TL&J9D($d`)ȜBBRL04( pQh %I&PڥPH19c:ft ƝtK6RW5D$8j:> GFMACR E&d@sS՞b/Lfff$XS Q!"JA8MPI$ ND$gA:ȑ>P~u 9K8O0b]`!B$Cٌd z@F&D@' F 2*pgF'Idzg0 ?I OBf@y,qpDY,  /iPIa+eR RHOB'~=`#I*D1i5*GOL!9@KYN%):FJX ȥWKȨ K~& d&%/8 @F4^PRN@!4eIN'"|zHr&j`%NtA'c(L0YDt[NJ PPӊƎsKLDHWAC   jXȓ=xHHHtf`̌%&DH2BfqOMjPIA:)lgeD(`e+$ ̈1$j:Or'8$?2gFRӨfgJ)SBX@DLiYR)PZYx@0 8pÉx@JRJ0%1#Nt(e*s g9@B Q Dz(J@ S3#HgPpc, 1,Ny@$8O^*4<^p j 8=fD< >B0x@J`>(AD8 ^0 CH9R I 8>Y2I@'0'89HJ109'(˦pQBRNc(TD'JHQ$y9@9HL^Nf0GXRf$0H X# IFP5DHBR#ӮEFCFII?V `$$LiE9c*a@Hj9 -q#(!"#PEYN&bD4b:1IkTsPFc(2' |(-90JU_iGADȀ $Ki# s-D )9y1J!DB$F$p^X@:ZuN/LƮ@F䢐I ;r),Ȟ *CM?81Qs ;h@}`ZH#+"2%Mc `K!LfA#`e&KKjGl<2Fc(EJHRI@a*Q%2 T+ VFr5 R{SAg}L˦0S$)I'!+n,R wVfJ0]\IX~ d{]`Z%FbSKH'Lq)æD@HX R,0M)xO<H$2AR@≚W $KD7u\% $@Z-$iZʈDE$-E)ä, H9 Tĺ io2>) zhH 8WR#`Nc<> VN ':d`)12xS#J-XX*;iRNEnhHJˆQ)I N+ȟ P~03+9=!b|Q$!ԜϲiďXGH͸HL`&RTtzzcR}j@0#c)Yj&bY~x@JpM*"UNR*8jeJDR@De8 O3žSFc2d1=>ң'1c$"$H N@F9a@ cd%cS2P<`RP#I@0 R}0de<@9bBLX H} I @LDy@)F%6*2(R?dK8_H8:@8RU1`brPe?(*蓌dONp @}>?H " 1=04SZuz51 'b3 ` b0r2}&3*HX*?@9pNH'XL+u C95jVHT2E!R dG R'<ω91)@4cpICI2H* K^] c=f%) Q@c,0r5ON&p <u`> :`I%$( JC8#FpT:|]`b`(RdOH!$eAr%#\$@c^HC*LP$' "Z`̀p֨w'Նr}©)G P9">eiҥPKN>Z]$+ DŽRD j f<`."jL֥.H +@?p+rXpQ )*ˬ"DS=`$S꒦exb$`( mhY)L:@-Bf^, $mG']0а׫Qq>rTJQ'jiCg尿$PBz:K 6IOP n Yc@r6A>p Ĥ8 )ya:Nd'h44i>srTƄ84ڈ҄30T2Cc`?) y0c$I冓2Z"ShcJq!PF(L‚ ҕFKj&kI@IP_o0!GĠ+J)H( =e,*xy6 2?: X:q{r̔12@d e_ffEX||RW%3 f| zI B 3Mg&T!#R9$$e3*2rVH@Q$Y@Sp')U"  H#<}"gR 8II"YJ%8;bN @M-`(lHRlq|EM[:t`g]hT//@I)b|JrOQ3yS+ Ȟ@N0%:$JJx8@AscTq]rS2< PfOtcNPL̈t% t LIO8 8b^0Le Րb>)ˤSD&`$eԭ22tpq#)pI` D>1 s$NBp 3`&`LH(!Y z BNP # b2= ^P*BRL bP %>0A(@Rs@q0#pb40 Ξ0)> 8BJşJ*Qfg۞X6(, %H9tZF9{`(JpL0`zH"rZ9H4fpX0L߄c` %3@ .-čIҠHxWJp` 8I##(QLO0>0 AFdg19tipt9J` (LN0"%!KT&=8B`8 x@]`K3(O@ .sNP 2UPP I%KtHX%$@4PL "'ONԀF|@I`$jOYcfBg1j*5i)Nrb-@/@FzԠ@ =@})g(|L)RQaĦI+XXKih(NjP**!SjZ t @j_/leJJIJ' rIWRʼ%XP Hj\ !rN@PЍG( VaPXJ+ZT H 0 f^pB`~e$Rs0KkfPYԡ4()")a癀"MFsv4̺z$-Dh*k"$6I@ tHi֒t"1>\VOPlu/<,ⶀ 5 &j$Fs8@9nc8 S$0Hly@ƀHǬ~Yˬ[GA3hapS0i "@ :9;4kBB@iK|:D@(a`0T$N^0HGX̄3/(^bN0$dH-I:Fr4$ ȫ i d0u@I0ܤ}0ꠐ?TJS%39NP%8dN3ZDɜjX)G e0A N3tL (3+ԐBp= Źi*s@JD?tx'P  @3` '##D@FTr kY:@:%:#8(@> eF\`/d)CN]``~%$@ 5zFGIs 8XtE%CI@<5Hu0l7Ky/w_@ όI g8d H\'ҒfI8ƬB-J ޥw!?yLDDu$@d|pJA9x)sR=?fD)`)a=`pW퀑`@%AIJY{|d"A8̌s#sZ"qe#_}`$#8g(AIP9I@ O|Hu=:ǯ u (D@O)ӏ)Ƹ Z4>ΰ!ϤRfHQH "sNr \'*K Bd|بlIYnT&q'4IuC9.l%I"cԙLg 8X@I |"Q)_ܒuy)zT "q[|C,<0'8 ȸdt Z:9>pdN2>"3,pƩX"?ÇXAI)8(:@9Z0D4z&R$ 3bY`IJH. #)jJdR$2Vdb:<|Y7O L(%fa3  fAN#@lJh00BS3%PNpj H'c4m3R=`$| ,d:y@"nK5J~GI@2(+'T1-2_|$H6d>RRL\3*,: Pў1b`% ATdpHrO lj 92)I%88 , '. ɀ)Z:RgҟÂz @ՇHd88dA= `31$`eTH<e"qe80!'03 ^dD!r^a9mAs@F[QK!@a*d:)*G( @5{%O LD*N)%$ZqVpu4  ?32 D LpPfX' $@1+8G9y)38STGŜp%X@2fɞ0Jd %Xc^ QQ)HKI%uJVS *_F^3Q0I` EDHӘ<%8QTB'MsWfCe+)*)ҩ>鐀9*ZFp84VRA8QI @FJN0a@$)`d3 ,@\*YO<| 6)BM HȌ JD``$^R/I} +?s^_Р4[Ug=BۡK 0%*u)g:f$'3& M9 y S6~L !Kysp=X?Jy8QI#> 1UBqϧOS D.H#>D8Z$K^>}` FS0è'V j U34@)K/XJ! %9[F >:ӱ@&|`#qgA\Pm3µSb4X&OP=}J $D(dX2=RH󀋵5j jK( fqB ,!iz֙u "c  }Le<H15%FJH`+Nbx(j2GXVF3:)L2TgjN4+ % МA:@A 0A' L@"}29ee)JHx!e*g)x&% *) 3KD (^j뇌$ 灀I09@:t3$c( JBpPQ2 H!<1IqI6q2*z)N9ϤćYHy7pvPHsT4X COAILX rˬ'ӈˤY@ ΰ&OV]%3IH#`T4C??| |X8F`eG! I( O,) 8:`ri?t ʉQ(B30 ',` :L `^K"Fx >#)Ny@92l 181H8 O3z> tĤ44TĆGxH8 D ~P D`c?Bp0%]GIa@#JJJUH 0fA>i1"|ALs?P-^0 H V9} Hy ? K'JOLB%xNp̘@K!iQ@YXeZ_R03 "BVR&С9I+QojBA"d@&Ҡ%8*'0IJrr_JBT$16 24%H@ac @$EwX$DL J$@[H8 "d@F5@c^lJX̘ DNp'WO(a0B3LORADLKf5JS$p IN3BI@(hL41 JD(`}uh)m20,h #V!w wx->DgR:VRe}B׀@5J*>0!9{ BT*ZUqL@d3%@  6B + Ip?(Icr2A=< LTS<)G#4BN8@IFbgT0X H/<$Jpf 3fbJ#,Dҟ,di> PZ%JNH3IQr$击*(>d'#T zz'ęz@"gH2= BH'iXϦP-:bBstMp R\rFtIZe,3 ?(OV@#1϶BP!2{ !u!BeEM LH\rmqL ,S)hJFfd2ퟌ6Z%NbB&6F_(TtH4j<<` >I) i3L xJ+"  e<` ^yTQ-JVX:JTSD} d0 @fg/3J0  $LJN<}9 &&L析I9KJHd ' 9KO`z"pfpNc@Fۅi3srI2IIN$j4j|= cI GTr&^ T= "}=)VS9d$IP J 2dDՀG}&*3Pk3 (s6#3E:e*NgFÜ7Ե$ 2ARs2ĈJ 0%,9Ϥ Y0 gIZqЙ3n~B 22D8LA8S'QJa!Tș$ NұNd{ $.JJ}'8PP2p:x8Q +%Xegޓ9@ @RaRH̒NX@YFd1̌&#OX)I9"i IT%pNtS K3$|39 f,18` L3Rd"XB `$ G $e!$ș ߩCQP@Ya+P:$*X@Nu"IT9(?0" lf9@M/u"K>8r=JI Ls"@0P& kv6Uf Kkt$IV2dVOrD[81g Yt4V0F]5s1RͮE Qh:gcjmNDӷN8dQs'e0?(_JnTPTPռQնH$1umoW*íG|$ 9%/,+/bXU_gEGa 2Z#0pZ/ͿP*vpe"je>d'I;hr6T6%ԵV*]t8Qo7շ\-Z5V JkTBB&woYIUDI0#R&1B@`;S4/l9Nxa)a8鐀@c0`xTg?'tPdFFI ESG8%G4F@Y{`e# >2N8@1HQ8$L$2e<H$B _kn+ȼ&V[j 34ւRL[5TNm&ӿ9?l? ~ ľ[c?L~O`ޑTplL}z1J3;fmN))vM5&r\t{bÔU%W)!B`oQ$AtZkrM2!*Yj= %ćRT $aB@"9 XBe:@4@3i =gcI| $NFP"3<180%> z (92äO`"Ruz|N /8l(HH$H>gpӔ$pgdfe`/T'l [^L I? KJ@B]R1$JZtH`%  s8(O9C3=$q <(!x@F!+f$<:td/ݴ 1ɶJ3/T0QJ'pvVX /JP`$mDpRR[J^ @ Y%cN30X%jԢr x\J0rq$c93< #RD0'@ *FIb>fq0+2c#GI3'쀈~_tS,zLȑGN=G0 64+p.g$d` ,}yi1G($%#  "]A0YsTD, ()l;r)XISHOH tPjX!m: u%B`:5I| B K FH&]e> zFLO;ƞH)詛S B>bWswЗZZeHPP>2$$tDId`@`&s2L@-z9k Y #]`$ IH>@S:547 9@8("a9f@CAyu"DtrP dR@P>@$_TIOS,>JJY9>>P< 2ĵWmkޖ_IL_ZrR$O"n׻bi3^Rզcz mٷ*j U+ oQ{`(Seʷhqh,ky cݵozҩ˪IHA?[Vۯ Mii*}5'[UԷ07e"P7H0⦵Jj Ml)-[Hm LEqpU[BWDj^@=h.պ*w=ibۚBeSJP Ty@8e@鳳vcj U!kn PJ>"|> H?""D8=`J)>x81#38e`Jx?S4H='0PNP ?)T'8N>pS?$I3 fcp)O.GޖvAb,$Ss)8W~mnrn.Һ;d ȶ9fݡPZSm:yu 7f᫳٭p[I~G6$bLJ -5Ӈ4]m%ņeT6X@yɖ4[֩%Zfڎ+^iw ^_qдj﷫8+qjJ=B9CO!7[y y $Rf:0FpXPhgԌbHHϙ$@"IC(s2PN3ieiY2H |̑%@I9 R9cbs8@ :Ql)rNy-Z %f`9(J􀑀 `ԣPg ^A ] U QADHU.s8@)0p L'p!|P%~Ntg(פˤiy9. gYb:1 ]:$I@(&@ '@( ;̼ `3eĬ 0?NC3AiLql+OS[H)XPsabx@2#3x85NPII`#J-&}LNA*ؘ!s0 *e3.Z4Pu% AXTO*OItXNa:y@1:p*8JI8L5SI9`D㘀Z!0NxAR?tHFru #9C9L'_ԟ*V'4Cԩ`}S)"AՐ:aJ M(*]iijiiBݔz g{Q[w6/ɷ pCnWKbIl#ӗ[v%vKƚ1MCG=4%H62Pgblq;{7-Bpڭ G[W洪`>5| X ; n>^NT&54H'UI>=`8;陼YQRjuT)[s|41R?3޵R/7}]om-BrT_:Omǖ aPknթ jR?bR}i~.w+R%/+}Dt;,WPxHpp$'<=Xy@S8)l)=P=+j z?Ҕ#97t$ɴ&g)QQ ́ Rqҝ)n -3զg|| 螥2} `b`J 1w[K򖄺is\HnNOmN5oGnIaBLNpDn~5=%E'Е!o/$Hif[xuAҨL5!0̥8@( mM~U.CT}>(2-z68vI-%PGR0 `$ qF&^@B930{zkv@uw n߭R1l}iE,6KQ% L[c]#7*KO5SO:R\?ݐNgLfsn]xi$wQP%+aҞ=2^L{ 09J]"a >z`I#3V@`:=iUuņBKϦ0|^ͦHN|KTfc \@}G$dzFq2Dy&-Ρpy jZEg)K@d8?{^wڻ..$R[W% 8'e.@ ]pY>X &NՂKjB^eaL:Rz D'j p0n7+Briyn8BRfpRe4D)3}ə0u Ur8k.oK%=[M& A.@l?qwkhn;4 )-A gulEZW.Vq┙t VHԘ Lj 9HZtWNډ8 r(ր1u0XZ}/2A?(%"JS A.6 ` Eƥ$h;f1`q.)UK X2RT<$5ӏ ~B]80U](>o#ͥ0'Tbū:(3WNP`20=p;{n B$sO{t۴?P|jWQm`*Gqtg-u[5?5}Ksr9*>8i^顙Ā|tUq2-E% nRq[3׺(?_jA5 &IPJ@Vt8BCc<`& Z}Z9歛7Ջu[d5')wC?:NJN%D{)vzjt$[@Z3Bǁp% J~l^lem?95_k%U'0seJe{id[ݐ#ĽtniM 65۷]t[T\iZ`:+IԜddrd̒H ۄc>URu/2:\ϻ :{Z$xd}s=v]uZrU*sg?APCqW(f"<\Tr'?d!R$t=Ҁ@R@^p A> [¾KmLu PSLB  '""i=`$ԍ:IrP 5s<N|P&.Vd%:i,7j`N$5gPn녓oٷ%ݯi]6 @a!%u\fm_H>ǂ:I f ZT I&'9g>)vڡۛ= Zt)JpI+nFv?'+ Y"~Oy} E޲m)ӀP۩ր3>\zHjRi =ɉov/=KIV5I$.[蓚F{6Օw*Pn4{`govܦp(kpJDO@Jnt:_MǸ 5m׾6ٳW޷ލs4V]IxϥShhujehXN d =/vM IxDž@ 97/rw WJ 5a@4|-qM}BY5tD`~vϻ߶mMU2u GtA@_zA_-tF) +lO'h4uJU7l}Bn~z kR@3X("pLɡ0Ӱ~(巷: R)z.UG wμiYN?(+)d 8W=¿l%i[(!ytkԙR$H9u*s%- "zgv~fP`[ltPs<+)ASq V(AIҒP|W4-۳h T0$S[֑^u"@`0ۓ޺L&J$}B]~CQ_[NSjJH$`jiud5>smmƮoE-6!22"S,K2V%q.w6g?p=:u2>;/wC)um' &`;:~v w W_|UwZ7]&X'`9g%Zk[t!Q-2Tyrv_E)3HN'RSu[)I Ļߤ>ڶ{9ASk%_ ?|ui8$HVbT/*[6%|.۟pbdehu%AX %oUSSiiNu\GqZB@mJU?:VG>J^)b> SK{{wunum KjZ4)&@yN٫iĮK8S 5MpZjY+rK F1oBV Tel*n7EE[V# ៤~"kԦyLC'JfD/|[oooJDzlз_F$ !H!i>Sz?2KhBa@ArZ1PX9*S=vm9B[ \Fp84:Z&AYgO!Prpܧڷ˂aoS'BT}* XLPE⽂A۶J\c!Nm STsxJqRj4's>Pn8V۬46jJРH:q;׻Z.WUC6(H#/FR[WVuT?r\hXEeImjy΂-stZjfZRJ14'&t+&&PٍnMtt,RW8NJm P2QOP< >|lMS@t}Tΐ Ra)ꗔp}Y`*-m;tLMԛVܱg[ws5Ҿl ! S%6"L9{=,i'Bzړ20;*jua44BVgAZqolUp|`jicW,Jg03iR>۪ff egI>a1^@jt))6]q55lѡ Jz2gatKa5)fI;]ږEXbjnKXl)(JDT#*ÂZP`(YH`@ m_ ;5;Wj%:Hvnl$*B #^P-ܓԪMRB)o$SFl}RTP:|3ck r)^xOTnEo\O%n7šefU9V9qvթ9 y"H])ud`5kѯ8lzG7yQR5%i6SdX}W2{az_e%Ԁx4즦mz>~wfRUXޠJdA-_լ~Zmn-@`@vN o˸#kM5 ƥeP $`=ֆ^'( gp2С,Э=CIRg>iZd+PJa /ç4/wܗMayžV)}n\GpG2۷Ҏӛ]MN N-V$pgF4(Ofvt[.54m-FC >njN(a$#Rʌ ?dۅi kI) )[ gmnM{7 COkE#2~'A_8 U[۔eS[6.[,@i*9+Datnb=i #)sJ\mA^:Lд!*)8q=+Y 5+._﷽CMoTJ}:YnH2Lt>BVg2p<$ zNd@Ne3@.wp,00JxNV۵7[*75+rukd|HWYlpujvjӶo %䔲BOp/8 3_@ N&EMC9)<1vE3֧;mT5i0\#iY73Rq=].c(>p4=|BmŚ$w5L3ᳬah->24iWPg0`2&v}d2*vK.S4bq Tےx@/}-{ g{E|^Iҕ22 #{*m6utͽuIeCHE?=إ]i[KZMBDpc Z FA5wɆ%qJm50ro[l N?|-56'4iKg.A[Pٳ)JP I@j<}WݝaVJ.ZK$RY@m{\XۤyM%+ 﫥ɛh*3\2OH]XY/OU1lZiitL#1CIhZh)Ԛ:d=]VB=T(zz>p5֞fMjZz=A,R |g(q.?07R! q<D[$PB)8d)ʤe@BhNiK %)y *;-UVn7S4o:JqjLY m[HrGsܒ.q'N]@ vr4[#5,aU д&Y!Oi GTZe?< 1[knj6UV$NX_jR̦s6e3pqG-ߩiR61}Rfe='y@dʾdvIrR$#\5Im*!g'_WxE3 Z3Iy^o}ҶJZ @:`(}s uE^0@f|5Zu򅡮͓|-K[!j>C2z oJknSj}JijtxaAԤ `2[[yuKNऺ˕PӎHeB@rr%ai6m{ijku}fSD_dX[V+զbt =mrl6%w&'5G6N]i-WnYr}:dRS} {IWSuPRq$av{{f9^Q\j,R22LNFqm@7mgS( =[yډaUwPJR1:`<śn4nao􆟫e RZklJzYNǗ |pL%7U ;u6F'jVʟiL4f}oi[NPSӌgfqqYI&HvJTkҰlnP3hRvڥ#yg-ZFII75J^ dm% r2a,10a E^UҞSn)"b} 7k!ycSw6s7f7:kjk@PRE]NmV%͝W1c( U[ZBu#AT(`8nwњVs@'UnK >"Y^wo\jHSzN\_L#Z^=_7.ߺiiKu J)PUN׵.ڪW3 6BeBzT}՗zom { ^MZYaGl\ ^v Y V.}6S$%8@sV*6E>MSR3*!I)@d8)QHM2n@sNY?;mwS$ӥuN)S29@+w?o х-8EoJe$KOtֻ;jS U,ċ{nvZʵqәHhFp@* -}N09@sWU?[$|ó#Tn/ki[?~U:B z{_SkpJҁ,U 7=|nݎšt!8 :&)T[[/3| )m:s? h]|F}uZuuڙS8҉za筁l@Ylz+S DDPY]mH{ZvcلYZM,@韞Pcnv~NW!~v2KtϷ@vwK4 gZRL.,7L? bg3mP $]^r˶7ߖQоO웍6Q^meq.,:Kuw1E} (Ru* I?&}IRh\h讛vm6Qw\jJZi$Ρ{OۮkE&6k*qoWye6)@2'n[J}fZSj@='|pv])JjWf-t,TRzp5y}Jh+:ufyVKvKTv(jyqdPO 4HؖbG lA!]>soAK-o~ZRnn[ +E3IZDnh٬\\e R]xVv֣Y'}fe1ϲ%*8ϟ WwR!NjO >_U;/smj;٫Rx}tiRTdux +*lFvm).v~l1kk?6Rʒ*WI" {*ohn$%mduIfRH]]};?pթᖙO? KtKg_mj+ݿt?[/%#u#)z0qyvrnm=ƆQ NCJޗǷ5([M*;!< ~Nb(PnU'M;{(%].rK}߸^frնӋ$TEW `>4Qkj)%{T?d@AKJBKNȀT8@djv@2fG\? # rEw fiXl:]ѩq!J_q?n}q۩ !}Nۅ; *vN( ٮHeMpqNym䁬̒T P oB/MuBJ"G*ܗ|i7;NbnӥL\fR mDBSʗ4Lp*6RnJV7 "AL0Ǜ+v>ǻnE֛zS]ojJV ;54%^P7 U)#jvjͫaUZ3Hڊ-hRS$eĕ5XͿ}"B/7l*-R^J%~l|x-dWB4LiHTT*PBt2MU#쵼7 S(h%ei szƗjƁiI%#VRq̓_[ǻoq>e *@y@`x)˟7e[EE[Dj 8 ;c6⒦@`A>]ar?unJVGl ZqNޔRu6"Ndeݕi!wԑ`,7ä ʍKUz*xkU)YVڷ@;w{n]Ia[.u{ƭn=bZԮSJ#BJRGX3!]E1Ouru5.3DKO[o*lKkXjE|aSZJVRBJet;KM#ioԄJJ'3tUsq5/m-Nd@J^ 1L]q75}im5 /4%/ ~~U^}nq}n-d %6OI;x-Zj[5 C,8YA z{tsq?j}.,![qԝ8h޶>iz=N}ubZRu**6<{Sjz,^/Ԣ;,*IWO1 ړF.a5TuT3N0>}@r=o}x]x~1D5E3UEKHpu$z*㵷^ܽru/{SWU597`=ZdrAn7=QHYcSJJK D,`3;|׿.wNM@&Q0҂+nJ^:Dxy-@2(T )p@j{4K_^µ(6׬!6ܙ@x"ϵ8u ;JkSVך{ܪtvN~+@b|YH|iX}Y5+N)UR p$0b+Xj6W.)hl7Zq\TS!S 2D齶ֽٔvMS[Hk[ :zDQ`))dD t󀝡)@H*x Rg)9)@Gït,7%}/=k}4a?RB}[o50}ıIN"C$} KWh$=[PJ 2!0mES-.ĴR zSltW}{LHSM/%_ B} 0W|tW6e+7+STEO9D̺ Pᬔ6EҕE^⿙R>퀮vDV֠j$5>`"Cgy| *9d%vCQV3F̹kQI2zz]J)11\Ap5*F#ӧ^ &nخU5 Ru吓,( ۫bkxm)tlε}F*W^U>)\2q^>_;cWJw$&iH P wuʛ%ٔ5ZZؑWŌPEEK޹UTn[*qimA36GhlZj*ީInhB*S ]ņz@piJ5` 9^׷rxmkb4-:RQKT!r㖝CǍƒ#dO5 9"D!\fg[uLT2%Ab#/XNnWga^8V[) NʨP/)hVVuXRG-fүj@OU* \}TSVEuogSAQfED}{k{k>[P\V;F:eT4<~([ڮKK[FR@Fr#h jVͨ)Bp*\jv}B%kV0o@IJg%NZ vuRZ0zx9n JZ@Lh2[^T&@' BڃlPV@?\‥[Vkfؼ*G44SebJ 3# =O]|qR˕$0q)p$\߹vػRmjԱoCRqDH8z,J[otm2P)K)*Xt\^٦wU8R+@hS;2Ĥٯ8OpCV8F$`>e>ߊRlj #y*^l_2/ qĭ ÷3uժ]wn6nsN 9a+WMCrp=PivH-R':ؼag{mUn/ DƩ (O`Z]jɹT ?^ڡS?H-{n I}D`;ϱ.{m}b\j#VBIٰ(\m$KL!q{{[{8T̺R:ebx#,{ܗ֍UBتe J KiH#)O8F}:\SCWc}M̛,nJ}WV*~"`;Em{wj[U=:&╚gR`1ovmEnuu^7#Dd>ۻ_m3mnBPN/R+:N'c1_l]a,N~w[.ʊ-OijSt[KjL 5.V=`bF]FBJj&Ju@tQn4mDA^?ۛTANmOvXhRLYdfK}ym͗V a#l\m:}A[PѪ[h,NrƛGf;kmi,UAS?⁙8mTs܉+Bа5,)eGt+R 13Ckݵ;w]7ҽUJ eJm>~&_ku%5̡~n[QԷKk~¨ >kZ*wEu;pJ-LJx_1D/Ϫ}**n{j[Com;Yە[ƞq[QZ&eKVgQ3DBf S$ _XCkBo U92$zGpi,ۚzn~yUA`)L~ f,*w-[vz(i*u&Bq?tSI7{1JTo@X 3~Ju*owd6s06-=U_m]1 LH3$9cm?VvZ V$g"X_ʚj6FC-])BRA˒bU"8thE5JңLLL}n> 5$JtB}D! G(讷zmWڬCkd(L2T W:Wn$,%@DR= -=VFCi)Y C*.!/g~\R52R۩N "xYN6TtR[9$/(yI83)xf &]MgȜ; Mnv^u%ORQī5їQJ-YJY9gk*JA. A OS&<&dB>[Q]iVKj~irq䔑KWuPSPr.WMnree(!LR@ӸB7 LשV挧VH#iiY~XBt6 s+f;coF~P#Hr&fBxZ {s`<KxK%U75ӰE"uɍ9=j6cZ ijvKm!-ကr=N#osJ`=>GFcCr]ei|YABH2RfP\[.1Z(ص}:Ouo*-jk5 6%: ?.D@IcXQ/: YiBVͼX7}B*n;k_;u0˴n~o r4 Tڸ˵ޥ޶~sq^i~QlME@-vP $%tچB56y6cʍ' 7xorJ.ֈ$-TK0d8.tۛS}Ԣv^_Ө 9Ǘ+&֭whfMNl%5jVRēyHOt'Jp}{o֍߽.7Jԅ%EσHRTErx]ٳwܥUutD%& S2/vnRAFPGV6]vwM]j׸Tv`}Tm)ФI\ԓɔ0-l}y:ӠoGaRS8fAU*V÷S*S)B6f m\tnU X FLJs4\ОMqAJNbNSh 4<(ZCWȷFKՕh]z.sx@t @e7ېc| #{|].LwR4mO8 oq iK(ԳMsdө6P҇B 8?p.ۍ^{v|'M]ʪяi% =e_w AU]KtӼ 9R1nt,;S=Non, H LvJ9zYB&Ų+m7%HKn>@{t5Oյ:CaN3厑9znU&kVm,+o6X1)PѾ+l٬{=.SmHҐì);қuv5S6ST-TBISdV1Hp۷6j߰ۢQ\Su6ZRB v=Ů,R.7velki*d)*2&rh9HT-(xM|}S ;nnRGYy[2ٿݻTj[hM+Jy8%I8zor>a|\T㴨eJm|*+KZ% Imw6u{lvNSn%S].LR۩㭤$iI'2PMm9L.q( 闍Wrꭢ- XuSø}Cs#tirNZ_OatI=Zg g?$_TOg`$ *t7{X%BCfrHIÆ<;FϤ^.eDȸz 51LR^=}[Gm$Wxr:N1uWuTLb'<:Emp-&pҠ==tˬ-CQѺRSu8pV_lePPOU >qM VytӺ?*PݕxL +.uWܰ$ TT}TmlO\tقz88\p\`Wg +.;B\ikj4#WӰ7{*+SHN2@/Հ0cl^.qۣKZ6k*HW9&xeF;}s6]EJjКJ$=9@{0{ݗKNUocu\?[vHH'9/}7~:^[OG?07Z؜wu]EؖSsxCwnU3mS0ꆝdc4&`lGhW}=rhR'#,:/|}ko;}U0&-8-]T`<˼7`WܪBk"a'@Q1NBڶmzu˝0vH#~v/QlSsR٤Ci SJEb8Gf͖7:REi J=`0ۿ7Nvs] jn!-(s@l[}2nWʪʶ_f Qґ Ե"|;w-ti,2,/X R=򂹛⧦M%sFRZU'"N)xSR7iP8k 8 @zѼe7Y A2~\sU6_lmu/<:dS cy-kN)(Yzfji1_|gлFӃߩy{:yqrT6iڇ+fJ#FqG$r(fTR|CfZ(*oE R@ixft@]-$\3oӏ;|7e.u[~Xk1 < =,s\vӺC&дe0|_w=m4>TO߮@g9t/>u~{XzŝmQo^%P0jF+iF'HĢc}M-`0=>}Bq>X@y+bNv~};XnS  f%$O8O'ݻfwuMM "X}[IR083nJڷZ SKP}Җ1Nj2{ UQnZFܩiJ%Klwձ--v2{Π'RN˶2[͚eaOPSk)3JR P 9|D.=5ildbfSOH7}n*,)@%3n%ɶ/L3Gn6ERtS$S)#iw!GsJ\ 3Z2 .Pr{[7 j8z:@h܃òU]wͽ朧LAq0w^ڴfht3]T=.$( ϩѺ9QZW(yrBIRQ)KLct}e1?gs(Xkujzu)4Ǥ`z@zx8dXMߐ. ѥ-6BRQ9z&}D]oo,Ky1SWOOD*^}]UBTS6e"c(O?)3*ir[~nZ jJTf"b"[w4n:AD∖ADe>3xcy5Zc]?t*aJ8 ؼ%}S&>ӌ>9.;Wowh֖~y(Qzlqm3 o=MGN2\rpӧR|`<-3hwR꜡b8)Yj0u$̉G =_w_36eFŚqӹUWGnm5 i'J?+}VooEa3eraFd.J&Y@zr=kwrn[)UEeMCII銱Q b`ʲoUn05P#3M)HKVʅ?gq.!l ".P~*_"#o}26qJ%^R0w1hԻSV)*oF(<$$L:U"1;6l]x+iECK)L̐)jQH0N|\[N޴;uMUS%vR{nsT ~̟Ϸ(nw3l;Q@(5jЄRUZJKMѶt0%J&re(.s"s64oC}uMk;IYڧm."Kҵ"}Čd[gX*ٶWS;ʲ-n4P :CEuw oއm\5zp"xHnm;{;FݰjЁۡflJ9Ѥ$ g{ot/oESdmTjn6:u->W|i~m׹Yz{VhI&S0LJ/*oMSMXۮ0U0yLRvJZݐrk%Wa/T,R:_A3 OoxqvݳcQ&7 WTUSU-R P8p]iꑀMڷ>5J 9^J)"BMRİrڹJ³o LHRA'?|TÃVm|HqodZRPN^N9d>ޥ4APP 8m~x^yWP`tPKn;keU] yT΅:3`>۫fAMuolm3UM @u:V`gߎM׸T\6J[`k1ycjm*ZTz hc]tH3J#$~k y͙B*P*@ o{JϷjV)8id*F(Z[\zLYZ.J? nZ^\19 $|`, R!Y .z/>NRݻI;[-QW\Ck-R> d=*i>{I]vr ֆSv0q70Ű~,Xe I2P5ۊջi@Q( -7).ut?r7g&G_h* ~^j*@ J>I&`t  bC(Jp)uP(iH78Q\wEm[Vۖ@р&5@rͳʏ>*4%چUT@' 6BR520 E RXtbQs2'3#GZ8-#N] 2?d)19Dy#ݻco5vjnZzz|:l *:_{ Q`Ss(  X*&!Nr23k]Ǚd u8}~SYua*Ӏժyk S]JXeS' 1_ UYvo ?e4 JQ,V󑀋Ճum}&@u~ IeMPsjqiR&vA+LbRC\{#6K(Pj$]Y0Uض l%#vӼ8d 8 gw}IʮP)D-ۻ/3PӾ*S8dgS2`9cYP.YVٱ%z"j@{/aoJ[H|@GDLɀDbgsoW']a–J R0f`=%~^5gi(u;HZNFf}qV|,XMIOAmI+yeCJS9O_kt4/U WWeVGCnٕ |QJk}kOSy޶|qߺ(u|mjJiJǬ|d[gtMkm}(QQdS]m$%ƨ*HkSus%-ӴvrE-3RH}? ٻIմeT)R7 JZhWai@6~ @PnZ Uw{(uY֫.flsIP[Wl8{nnwh]G 02ڒշcN[k #H 41r\u{j(JiL@mo;6֣EvQ0}Q{Mn[-;Kŧm>@fhlv9Iܗ*UN{fnJ@)mrQAyL\u6KbI3zJ*g֤;IVP!*@>dF2+8ƔJ&uVSS m[n常KU{S@%ʥ_R ^6ʕ^-׭[JReJd>eFܔ-Y.7&NImRTLΥL@wMv[t Jp ROB&'JսmX=*+(\Dz#8vӥJ-kW+zI$cP[WkP]jo 6u/)VDˡRܰP $H+$RJHJ0QWizN6 LHӊxg&VK59PJfC*G ۭm][M-K(B@m.,珌{gknk{{Mʒ%+JFjS=윙(l*LjB$3Dکڶ[)ۦa ClR $ .e@c` Hd2^^RDD̠4 W^[P6m5ԧ'z5G{BjRRCr>p:[uR0M2R L}UDű(%䦝Lksf?mi_--SJ'( ohJmfQ)8 u8>ޣXʝw$`5M;/4.ը?o|̡qL- RR0)X%)ҙL8 Nյ6&Zr408Ydsew=}k*~`&?(h\`R)㏺q5c&6ݹ&/Hdg:u%KwvEHX $0h)@RrK-Ꞑ bͷ.Ve"*hK4K4!I!t?J7%պqSdP MS3c9O>[HMC*Ja2SP$I@yC)Y*Sp$6JЄ$8b,6~l\%6֜xԵ.,=&^P}Ovڝv@c梥ŭN,H~9״DZ5 6j1P[}֎+Ixe^v\qeŭ%RJp}=RZZSXSP\_HVZ[EL캍mڄT>He)&-,[P|XBe$pxyG7ܷݯIBi Z4p28ť"A"I% daMBf[ZLf'Y KF-ҶYi! 6 B$nMd{mWw(S|2׶R0gx׵/VFWv!L]3SvXNTLJv= MNv*Ҕ+Y@fv.m ո|yg6ʍvAtjJ-ijL8@pncw&oF]Z*51_ؤm5,0BՄ({cm۶l{w ]4+4Gqi):=So[~=5CR-CnP$oŲ75.Ѹ>m˃v,aZC5@8`l-hPRCeAԅxlrIFޓB%ӿ̝C8 mjWT.l[&Ym 5 jd'+wUyQ&+MCVzȉO( ( |C"3I,5WP0Dr~0 )/OH g c6nͽp[n$ЄQXU(P+RPwy;h۸rKXj5՝)S!9~7 p竾9bn<mSQeUTQ5SPK H*wr{#٭6䶕RT*d[S )2z&R0|RF7o$PPZ+-ht45 RDۛ~ꭵ\*坧4N1TH|`߿]A}]ʪSF:JUd@}9tIfFiLLJo[Kd..:%Ҏ6!N,s)}D\1EJ٤^mJqh'I$gpwU#Sǀ!`j ԩ9ԍoߜ6%N/j >j(B 1e!,Qq;vT3% IYзR@"5LFD%R "z«knMה!3MG)X VvN59OIK؟3 0RpQ  ~0ߩRs@KΑx@LtIp f)Cw/)1Ǭ>1)pjA-uҙ-NēL$珜RT&Ϥbp@<2 rDc@)K(ID"RA>u򀈌d>(iдH Acm 9٩MMKm&C[R|ɀI@>9ˬP QT yL3ĕ =| e9@F/fr!FDDmkKIID%*z`DnW6ں㪯nI%hQݶ:[+Ζ쯂ZP5vɣqt9VRRbd@$K8 Q y$8}ew-]TdS6WRO]J~@P6;dL@H۫kfF?+@Do@hԜ)ɐm9h 6}-VC |IS+<殇AJDzB~rtRpd~ UJTى:j32g))촉>$OgYvZ_*OɵILǥfRi?pҀ 9<(SGȀݰ[ײ[íYKheʉ!ǤQ='6~U.mYv#lY]OQSTUUx+Py@Dr w[˥aU$(R$иs<^b-mꭓo WVЮWs'S `8 ]M ڷ+XÛmOKt͐i-P"o STKbm{Msj6*nu(4UℑD$lw>mtTQӴw}o[k ?0X(x@Ko;Ol;uU=Ω5嬶?)!mwHCWf\`6چj}ܜ Omk}mݛw]07ns?uL/>0n kMWSYI c59tjw,mԫ(jY@}3 eC,p ;Qa(>Ґ0q-Zm*e%h3jV#{ͯ~*(Pa*mA&c#qFް<U[ 5hH$@e77*6ⴰ+VjD(D(x(P7ME%^~r (R+'v iR~DJ.S4RU>@wN*[;Lj]..[JkeLe,<H*8vXw٦b]i_d T|%1־shյ]M qt$`;WWn MZm$H*avVEfT+)SKTjYye8ksŋhnQ`m!v*ARldd:@o3bwmU㘨??` m52;T} I:F@iתǷ-t:1Z%C( xWen4nT=L(&p/tJ&SR!$) RF'Uwݱe]O{}(Qև-&dH&NˮWߔ;w I~JZsӶvݗqMiBv a-2g,}VUSVҷҽ}@PR=DV+?'=kR6==oԖ DS!>[JeN( hǵ #-b[3@% AI !N%1?l $~P^3凴@?,FX C|l~/˨j|nfc"L5)4*}) Ov˲lvjӫ+USUQܨ}iȩJ9!.)‡\_muTrsQVO4iU-ޛu ]?"}mHKhQd{7pFN>[X ߭aX ||Pɛ9ոU{ހ#W5NS?r{)A1] ˿7Sv}`+ыjBd!RRq vϨg&/#w .VumJp'G(br2GX P 8TL9Nִ*'H BuaL= RS(1"g5+TiӤ?y$ y-84/)L6~ H)p!f`%l8$ `H' ` x C @0@?0%23yS^}(VBBC,8oGaM/Pӹ~\Pg$ @hoMs[ثۍխ$pI)Jg ,:O~[Me#jKNT]9o?laiiM;-#2$`,ԯRtx$*d@9x@L'HdBDCP%% @>9@ p ` H  JFg$DJVDeO# @8y@sUjWV ͬ0@ɧ$^)7|;A. TQZiTr}~)i]\j57PKx́\.u^;#IGof : ' e``=A|coQ}q`'V+x;XܥCxm[M]`dyo)Ex+ {#j(yPv嵐 ;X F/v/kNS!Oo"p3Q2R )i:2^ّ3u IPM u& j)omxpxٜiնhh5ZYVP$UA- IKmu&d2q0p Ǭ4˱7em ]ºJ>S쭭?4r`&bܖGBWe+IA{J-<ޱ4ܬR?{?Z7 X(S.i>snstbi% SB]9 nعGS7r/WS6N_g~d *Ia p=.urmꍪ$z( b髒i#ֻ)Es Pray>&s]By:XKfm߬2;OUZ`Ivվ+ܥL[UMlS£( mOnKZ&F> -7nGR7+N Q~"f =4SRbrVϘq?L7$/4n$>w#PT6۪#"ArR@dd2ǀ'*cuŭz= #h}Y*sLaC@BEb5IB<~/-V]H\ >+iS?*yޗmۨBsnL|&0Mɖi+?6$ O#5ZU/@So/uI#*mlll.=) .9i%ݱGS$K۫ (;GЉ4S"~]LR7`j'Cyg Gnwa#/8xۉR 3<r~V؊@P@e;#dʌu3,d]oglNCSDAi -]t)"4Q~a=e這Cje[_h: OfQ6 A nF604V;=]sB{;gl^Z{p|JIĊ{r˽_e;sA#:q^9WPREB]>`+ ۻs4H,w'd| /x"6Į/e$E涕.oZZjGz:jmw߶˼j^{jN.ٛu'jG P8I̬7 "hnU=*6d "Zq}T`;nzNC0xTl@e<1%88R 24t} ͝J2ä#<&D9@%$l+Ic-P -4='ڨRקHNs] OHRd1 c)kQ#LxvjtWM]M3{/gQ;B*ËU\*4۟}nBR/JMص D[:KȗCxNICfUf[[`]{\e.|D &}QԵI ҋz/N~mn\v] Ct. qiӷ-BqmJKA22t8Ӊ{Utfg+llU7ۯnL))R07Ʃ5{kl8IkUmTT?lJ%] $ Z9)FP-|Um=0!H>얊 IyٴPZz~R"BPt6m{ecrCf~zbt Z TQp v[o6suVlUBECI'6¯ fmKSMjR:zDaXJy IJ?gSzdۃJAé6J$*g'`b@燌:ӢJ@ 01xsem` 9'@Вt*Fa)` Ci4,N] '8NdXQzqҜ'"P z@$$< Me5`f3  #<0LBT( 1+]%ُ4*iJIR ?a@5E[(v(S,Z$>@_u}rBY< R2>0M.O( M,I 2JCZ2Y4rr퀌` ^p *3G ' Ze@IQ8@G03P /(QNgԤRI#_8JVRf&'$LNb>}0eXTe5.SG(`1"gX-GQQX̓DJD ?lI93i&s?lB0ΰ-Z[]2-ֶOF֭ $TfOL%$֟8 Z 'CQ5 Oq9@cT) ,g} N+ ڧ GP'2Q#"3wZ.'I2t'*)!LC0"AG Kɚ3PR5=?S5 b]Q4#PZJcX"Z$t(i,`",#SN30"mzFDtIF^ O`JRΔsȘA鞣{dL'`(<Ydf^~$u8CY`GQ1NۜIJBT4~2B) |Ԕ`  ш0)9)c0`03eoIx%)2r\!bC, 0JF=S}23oX'Ix@$}FB5b4v5-L#eC-? m8$JcJԉix xzz HHؙL) j#A($`S'Ab)^e)O [̙1i`hiV 0sqY>KT)KNR43|1s$BuH(cJHF= NJWJ"^ OjDNx@D%,sfP"] (( 'Zt!%l)$ I*T“@8m姹 Bz@N .gAe/d2RL̀Ori,p'$3I^! HgS =O`$dRsH8@)pL8){"SI2H @I=`t)'VFDF8Vd@,3&^P~$XeĂ x32SL`y( O se,V~P%0ZJP nxLZI9@2<@20Als>bc%3P HJud&DkJ1Q8@8!Xtҩ{`,Fi$?|iTί L8HHT0*c T|> H!DIPFFs^8> P Dԃ5JLB)GO&i*H9?ͨJqM 3XHyBs(RBQ_%Sgc5!0I0 Vԓ_|ea!# @BzW%^0 c ]RtgJAҠ|3`I3tt=K:bM#INi+Fr\Xk-P !剨H PFag F(A]PмŖ-00:nBc#f+DlIPӽRD<-Jxxm8BWJ%x Fs QQ@@aX^O !040 G JgT9 L+3 _'+!`b25i$2k='a*79A@MJ'NN O! ,r@+1?)>&@ta? cqg,wZ2(g+bCyc$@9| 2S 3&Ru(9K >P)°BHYOK8 `%JqIĜ@ RJ+`D)]aq ҢECRs)Y@XJ4ȁKV$e!rϤ9(X2Q%5eR1Gč <2&+%,eIt&S^I&g@2q 9HTvU`2D)c) Tf:c x8$M${eC@ A2PJf%6 !8D#3)ua' +'棑fYFەf`̎I: 5)K\.֗H $@mRL̟5YCRviRҟpL(% (H3^pZBLbPU`MC*JL֔`&J6FJVDJbp!пiӉ As="s< %pPṳ`-J}1pU,1'@Cr.t$FFmd0 @"`3!Di$@I1'(`Ds#3 2rf@djȉ KH#Jj'S#ԜDQHJr2. =VG38KA M5j KEIRT5,`(L@9Pe &Y@N3pd.:4)TT@DAR 6'Bè'6\Ƕ.%e>f֠X&YDkSw zұ@p V>w$F$%)Xqe}fG6"dD( lN%#8){#'INӨ~@ F8tI) Oˠ~!"{socny X `h)?@ Ji;.4R@J|KvY~U YB (m !)&!@ Ҕ  %8 8I8eLt@88@%*8Ly@8pLOsHSiy>= %LR' 1H' J<j V d%T H:R`s楟R3 J[!fDu3BD@) q0 変NPS{`:0 b yAi\X S$)9+ *(L%R=)8)s$O*L$,1 \Pd8?PNa+RY=GmzG c=?B@$T!OH $8L`>!k tV&`RU$@̧lw\Y Oe-NԌFP R% ?NHLJuOkNO^!:gӯZM.˄Mh՞}`,|Á!]1n$KWhZ̮CL&BTTXsIAȃ8, sCzJp:ą'S !HQTS&fjԌdU&#y}sgX B)$p2cOQ^1' B'z" Y(XE3JF{K (t3‰Hp ZLtNg)3G9Nf (8W)T1Q $a,YHU#8uI Re N)e !L>&P GO"BA ĻϨ('z|P&~A)z#,`"SS8x@Y7x{!@j}`IQ |`-Js})$}2K UiRDbʨNiuIII& Sʤ!!$UXgPsЙt=`T$*I4 Pj)G-1JI}drlb34g= >L>jS}f.;^rmS "cPK9JJp3>>B T#ŀd,ӄ±@2 L%9d󀑚ꐝ ȔhO+)% Q#Lf >\S&h R RTBZ /f4̤'!=Ĉ iH$,"/uL^|µ!HX y$B\q`FpIZcMg(JgTF{)%81E#iR@),`RVarF H$rPD+I|<H l rX GՉt NB~0^#g(JԔU3p2< N- @8u%S>zD%CVe>D J!'~ $)YfDHQ-ZFUL#D eJGy=I*I0`%)(@7˭_3P)]Cҹ)Jg a?.)Y9H mL(R3Vp C`k*NoH' X=& ,  Lx$s:U DBIH@BC2PUIT8%1 Ǭ11 mSPe, 8eG4 g8 Й,p0hX2%X-(`)Y T cJ#P@ҕ) { O@|L"ZdJ@8`{ 12p <> ᐂ 45wf|'!JUvSĒD'N%~s*PLLϧj(J^^;uDtA!CKTtIC(KgA|gSRER)֘R; 8&g}AK'qVD~Qkgxr&|6j=m4!7R^Rf 2pvg Agi?+d$ {+qAi-&s=4>Z~ )N"Y }h>ޏ띪ۙɺU 1<;;[S. @/??+ ܀=uL04[HJz@¥S,uÙF=wK8)( ))@b8콕3ޫ4Au$Bڞ,W<P&RL@8X[R#.kEֽhQoRjJ-'dLv5|(VqwHd̦_ @TCRnpIZd$,ԾiBBPTOWmSMM*6ko]U*QQRZR(o#?I:㎆ՊX ,/ZF'q`@3k33OT%Fg*QOWOX%e+D`XVNloj)8}4JpHs򀁔.rXԂ3`z? @:P NfRK)*QV ʁ!jp bGI ?t)Z\%~~@3PN V'XJ۩_ {0O ? %sS6D*3@]ZA R) DU:Tt +RH3@UuŊOQRU0:ծrF2!"i\ & q^}`mNPbHf2z0*r@@T湏 ҴzS0:BBr -0 ɒ1  $BAP 0UXIy du6)^),HaCII3Wd$V(2f`S2&CR'8R$ K  7i'H'WHFSr= <`Hb`JHV0@poH9BGHOfRI$rI#N!Z[I6d0C}I ($('?QQXQ# :0#Oo(<熏Hg3ъP0Oԭ@J%M#  @( A$P2j^ Z@ gceڵ%)"rb #9I&D@))c10N@} BJde9@&Rf@k >$K$$<>~[~䪛uwJie% I**d?42-rM#/8 hpfܗ{٢jW\Ӫ]!AdH #-SܝpP&)t9LWw)9>r @@@C/%D {$ϨU'閑H?Qɽmr]TGd߹irM6eS?R댌YCC?4)A*  s>@@J)8@CFK)94C)ԬJT#dt '"JV?2s=`%(j$ &CB('IJtAC`Ԡ %Tdci%jKgJL5l N$1Re3tB5SX&rP$xb*Ts8 E^6%!u6uK]e81 # XIHD3@Z *`vdI(HH)AT9m@ ? +2Je/tBʌЄ$-(OœA:A)[vVX̛@o ֦,zPp0&F6q /Ai)Chew[Hb ϑEU{B$=ZHeu* &`jufV*&f҅'Y"rLB$YHkYD9uJɻwU_h[vU9Y_P)vXegOL7Kz.176&ܢrKnTM"xki aY.|*o} v3, XdVD}Gp(uOvkwڿX/լ6QC,T\B?E[ϺdU7YgU)YqMvkۮmx۩rzN:iC.Zz/ҖMJ{TU{/m6a}iøMNLS!J)OpF`;ZwVjwWIJrLj?< 0owN-]󶭰"SROqD.~8OjN۠jK.U1~immحcr-ßyz6ͣvi5YvpK~fnK)X^oۚUA0֘$zX/eNt%):8ӑHґP1 a>S5sp G#崒f` }$'T@Tl5%9@X k/2H@Bx/disQ!='#`fFd*2Ҧq&x)`_QR'F F*R*Hdִ` 4x0!/d$&e(JR 39 $Nqdl1)8 XJ[F V@:SR}#P hK!(^"\ iC(mZTT<0㼁Yj^ꈵR>tmzP3F:Uˑ~Ky*1Ƌ=2e &xav4Lm6yRڌ000]H)X@2t!3O!N6@Oy( %2ӔhVV]زTT/Qy tCHAJLSH^~p?$ j*Ŕ0TpDH@1dh$ % S9 b~u#;&rL+:J?iFbIX&?1"fC@́4RT3r v]fH9xsQ֕geLD`eIZDxSGw9SGoK,5P\ Ո`)d/JY*dwR C'9g.S0*Q \ 2*l3.XJGrItw R9 :@% 0 uRe: "xpHL*E( 8J"P$y@3Jg(N> PYȄqto8}%$$Db`$) J&R:F0ݵj^vSJڵ/O0aLd(Ga(!%&g}8`)(RA\L$Jp ]CzP5*DN 4Rv+LnjSs\|v*۩IWpT/j`&gM"Km4 H3?{Vzݜgi&궯[n$2I :bȷ٘KtR(I> mD$pvBZZ4%30HSyPm[$lkȞ Ne@%ҥb@ P 5iwEp\J+ϓF>ؚ VOR%"A"ddHH X*N3QiTo]JGAZTҕT&pNb] &JU DŽ%(Xp 0$J I$RW,PXԣ0JV #i4 I[r%pRHsk@J:@LmN/r8z+DL|e]1 吩Ni',`pQǧZeH}<"XEX:)*ݔ*I*"p 6d1L!tS9@o<ɜ"jT̥!i4 ee:f'ˬ*c4$C9WK]f޲SFu*kԅ!Gĩ $)S SʋWZ]PѰ϶d$HIQ&J@0Gi/7ڨ5meRL|HSW)\nR^FݦiJT.NrAhԠT0Wivtw:jj^[ł=/LLɜJu")Is(@$z9'/dl]5SOO ٚp:u($vӏ\cnv1p5H[ jdfsy5}i5V=G.҆$@NIHh̑ 947WnJ ۝fWۓs TӼƱ{)*mζԬSY驨\tkM*fF,^rCͷɶS5DͩQij5'5 4zӨkPA^7w/S{tͥTջ*%2Lg*{X*/ S*4aä2v͵#pi#m]Ҥ t~8v mMvwC~U;<3MFP*J ~2Uywves8۶Ÿ?NBj.'KI(F+.ikU~E dUU%:MZkK`(>#( 㭡zߦj^/SͲJ/AunaM35$iD6a"ޔ&zf WkRPڄ/)XXZe2 RFG/ @]Q2 "ctd pXVz9s;@MYh8ԗ/X>r;y[xu55bҶEMJyhIҷ%5mqѱǜjdQV(0zi C1AhP*3>u:FS0{d!29p;kw zSҞa@LdD~ +!fAdIrUX:`A&:@ B"3퀝:qZ|`#KB2H'|,%@ @r8L@D!JXﯷT0Hԡ2DR g`N@N=LIZx@.(QN2N@cbds/PRJ8qNU4<`0:@i "\7k#;Ƕm:+?!YCh/%MۭTϩvV sGQɾ,-]RKm+J{=g 3QW-o ]E;u k 9N?ʖtb]dݴ0 q:&e e(  nzW*+YrICm`Rg8F"h,X9CT#(+SaPApzxߒکaCgEZ\#e;MO *E=pM;S*Xf{5;VՍ)]ۄ JIs_u2VݛM%' -FM;a9Lju$|1@f7pBXO@ir~iv^ePN<Sſ4w}t]pR`L OC閍o*}{/z}TҏE 8 )zv9HN?|]ާo0dS9_UuR3)S3x+$4 qT+?WۧII:Qwa`>L glVT y#Ho* yڋptOUz {: !y S.JDq8 Swj O!8:Hc{njP6umN> Siy~zTΖ*S62P遀jX&Jp=US y>ZJN)&x0FjF}PQV\NqwDJu#H=\|V+hU&e#F/jU{ wkTnw!/dC[HEC{B\ Lz\c{n',k[l|+ IaIZ6` IPS;EA0Qm(IK@oRѵ\Dm A O,-Pz 5=$OAŢuaׂq(8K#-@-)}@@FY~ vMS+Ne*5l-%&~@ <ЮIDsFDC*]4Ci\I^^1@AAYn"fS(9y)eJ:N`0 ڮ}]jc '۷z@!Ւ=EaJ1y߻)ko  WvUe.и*>qHbc@m{kw {=RmS%+@6<`2ޛNljLcdm+;\Q&Xaw7#]Z o=`gTMLQ ZLPZ5Qo7[}<k}1lo2W CmCnݖ.kJRT (Y9sF/V?J;o'8 RPzJhD^m/pJC|'F\/Sz (K96 p*miz"OuڦƫKa@ZL$(x@zlokvAl`0RdJZJ$0sMRKs4eSh8 9!}mQwWr*RX\~iV

mМH%t&@H|R l& jP?w7Bݱ+ "^2M֭C_%s>[qͿFmY)Sxa*@@>X )#jne$f(Ng} 9)sZI+h^R SE*}D4Bv[fsX$'1'aܚQV g?(^KӻLj1Jjz))oP!$+Q/WKhp!_$D"v򝛽qTfN6  ڔsbJ~v[7R5Kr-mT\vr\`2J5$ ب]jP'O^e1ԃ KcP:XyZgDHp UJ#^0ׯV?ppxMKD©ΤӨ*iq3"x 6J͟sl6*Chq *-?﷊ݓjPRxCo8)AhR^!}mnW6r(Lf=%Xw/ֽجagz%.%߄<4`)lv*njYTRR,N:G'kNcP k)x `.7R6U!~XW[qW.h6WOQQwHČPۛ)۩UUnK];:+J PoNۅ^ǩR!Ϛ TE۴M_SHt8P/Ἷgj.۲ʂiEKi-ѼHhLh}3#6J2MyFVSj q*=Q%4Q*>n\pڶ˕]ulX̐2Mk۷ mS R:ǡd`:3LmIur!={}Ң}9(w@H{uZ34b޽-xml}mJ;ۆSFpސY% %m›N7| )KԿ|+uaQtǕ/f60v,m|EXH:V3rIH'!ޛfldKge_s# }qKe[Z A 韜^ػRg s\] V>HhROZ][n"Eh[$T ˤCߜXP䛑NR}ƁrU)KIeA-RP Č1yPw)r݀r' C&bBU m@TwI+owY%@4yÎ*,&(>vtBQ@Kf݂ݮFźNjlSH@[s6 YǠ@bϻ1*]7JRGiOeqUQ"[]yx)G(/gj~[Dd=]d}6R"zF3@SGLCjbXt@s ")*Uv>wpJԠf JV4|RZ5t`r)zR?0@Lo[?w]*,6Sӊ#VRsܹn vj]/ZEBR۪TN?4n Ǜ5e~^jn6S MKd~O9*wG-lIC [|v $uݮ<7 [9j}iiV6B5ȅ U/9I:9? ?&5!כR쀵lP+I( @p;U&K PҚR1 0 {{ȤsR3+hs2ѝN3I BHHC2.oIOrGr}A4ہfv~:EO*n{ۡ))ss^ w[;ڭ/Ba$459 U_ZM* .ˊ Lʐ,?Nlxr`[9LpKRJ$:M}SNՊA Jp 5(D^M(ja|!_X@NK|6emfjk{I4mL4-ݸjZ8[9ٞ%9)]'p;k5jP&_j@f弭` 3L&܏PIhIZ4bQtt朡Vzm26KAP"jO \TF!/oxIݴӑ$)^. oZZ9@]MNp;Sx֪peJUztL(m]YWj/DX.xS E(Wd;[INɀӺQcHڔd$~ QzKaԁH8jꔣm*3o쀄*N^"sҦ{z@LN&P L,\CMфXQUR*ӠN*H. =%2Xթ@Z3 ֨Fo,="pqK4ٍ]RDq(d~IXI`<>rvꪊuZZy*eJjY2Br;2ok6XG0{/4H\m[[hmKO!n*z:Z% 3Vf^0Lb]JI<85{>Uvv{5IrN8&I+8.A>0'h1z] uw}צn5ma}-Z) 6MwZ&QXZqhQ*I[8jz-⒖w՛bo'{Ŗ5+@u4j iT-Xt@z"`^?x7%-iz{ :?H2\ʹGIaZ-96;m(KŦY$$Ze N10n&mE[ֻ#ozĦD)R ^ µ;78&]UԛZږp JVz@zdWR~YM2X}ZۂE*D>~2Uu7=ohv*w+4΍MԞ3U;2d >ݒxfl fP,|C#8 VZKrCn$Qd0kldu$W+֝,dxP3mB*QdA6>IR`5ͅ{Nfbps%R7UER2)ҽjJZפ#$5 +WXK?QwIi>@vl4w \J=rO[clW'}/y 0 Yq$4Jc\n{*N}"KU*RL`3tm$jJ@ KR@N^y[vw7Rkw6ʜP u`<役*׶7"^6޳[[VW+֯P L4k}2yvAi, *<y^t{n/]*&k[TN(zicӗCٴc,%m(PWS#ܻ!琿s!- 2t*&ܛ%&_1QT(ݷ*\7KiqD4~ 퀮ժ7?78o/͵UPrCP&T'jr/&UQ\iEWj&$p-JJHՖ\@櫚OBd V0xk]nta=ݥ HO@KxXx?wMoҽ.)S9˹Ҳ~r-K(P Y {u Wio 4I @v׾mm\;jzSR^d޼T|ļurvu`ژh-a)//ήytHIcv;,INx:ɔEY>mNC->`=vݫvG/9{y)9CLN `:FaL~_5BNjB:|ZtFJ|?0[lmN}]j+,?KK*H:.@}yMaީ/+iVUhR$TD%+J^PEFc !@ # 8LR, {:rP<1t{Lte8yC1(CH!i((t)u7,6mnޛvޫݵ4@:z C7͒k_<`=~̩固9) lPn+2jGpS GcvT+ Q)n{e&7>NE ]"jAY}\V^eGxթN~~g>`2t{ˏ[nCiRt^#K~5즲پl= ,8S9O{ݻs䄺@kunBkQ\iT/( aGoWKRW4`+ 額tN@0k(߷-3 :Tf=^m!JB[T{MA Y} {)ҍ^Ver ܍6By*Uރr:JTJq4 8\JJӆdCs^s -n){!s HX ܵwt&l"RF} 8'񝧗vm&; 0#(iHAy[z`9 Kwjxi׬Se5S ǾqN=@ :mkVIVJ 55:OYyn\_|+;45O!dZҷTt-ksbYvڛ/)$$a" -!ڤ0WqxI\F*%0UB.^R8#M};؞hit̃\W-r+RY}6"r^3ZG8 5'ўˬhn^KJ$%]ՂNG쿣vfe:ظ:%Sq2֢3RpKo3 V[܌llv. SCoTC-n[;~q*\ؙR' feѷWWw թ.ޝJ3FܫslӇ(|)$aMrRz*-J[@:0N0UC]ol,JHDݹ>bl%h'A*`7%p]^PhS6*ŹH[6M+5OSS)tM:ܷۨ^e4hB)uf@.mX]Qhm޹"T$%T>G8uUZ;_b]ICWHXm먵TmKxM[!h -L@u}}=+߷jeIB e8/6†X۸]+֔)m`Q:gt{=o;QLa)_PL@n %NvҗթGոZ6960orG\Z&VGmK-nk{~Z}iW̄"$t߶Ulڶ2I)P\Ndmv68jSq[+y( Wg!3GeIMJH @Hp6]MU,*Ҋ z R1im5جSB!1%[b~EP۪Ԁ@{hԪ=WJP {Bm$iHщ񀲋~nHvm}8GQz׸]2Ems$3k Ciя7g6+vP80oҷ퐱^} OqV9 ٸXZQVB O?^7 +j0)J)22SN }eŲֹkn %i)1R}kQSjxsqoo=mRݹj'0$ 1{w*xߩ*]T֍Xެb6+Ej[:$E F؝cLU6t IEV!]H;jw;TDUJ LS,gw!m^ C~ =wkr껕Z3QP"RCO֥I{WN@ZfC @Lo;ن\,]( WR@V0 x#O!D@ե|9rް IP BTTe3nǾVϵ[{DI39Np%ӾmLxlwf2@UM NIt6u$j ;-P6kKs$%@y闍w do!q~C:Z{O2XᾸc xMh5)82 "'< 3G=}eڛꞛo֯qxi&^Fޭٝ;xywFFoB*$=Gd`dRF6-4+2IpJU ds\jî%{i!4@3WCHP?@p>\߹fٗ)+tW6M+Fj%Z10:6˛W.#NmB[tʭl(Ap'ixoSV5Ek0[s[%K) Xl3ܻt Ѿ [zD*m*H @j=v([ e)W!9(~o}Q@!^Snn3ۊw;R*V{T*a3 M֠Uն;۲``X3TT?Q%)@ݻ).iD9 1Ȃ+e,ۢXPQ 9wlmTR-{ʡy:RNI~$bY}!?%^ְ(@P*Oqnַ'5`6ۯ+6 ˷iW)ӥaT΢:IwrRe4m~Fj@L}&b3F>'LcwR.W:Ѣ`b`*\Y;uح5F8tJD$emFm.WkΚԻL,-cЙ~7]dBT(+8'#}xozN/ܪm(6L0KR`=z发 le4Q!TH^PAii ߶ SbfXF߼9gq4vK Mւt{zG9zZ߻ULN%KCi%JɽdlivBK(sp54HA##-Y@j[/&[Qj.ŶVB[mDS6)+P%DX@{)ʄR+s1Ȼlr^;=wQ)g}HSge[cSֵrW˹q\6=nٯ>te1!CCe<ҷPw'&[?1ݹFjܛzt֡GJì4P* 0x7Z\OzlwUVV0٨}5<Z%r*Zѽv2jF>DG$:7)  ( (PبO ^Xc]y1ݻ RZa@z ʧsl .{UɷnWMI G=`.*z6 d:8 g{l[n㱷bTnL 08+8@QO\뒖뮷{u!Il*rJS=`;[՜P]݆"Z‰=t@cC'C#NRCL`i$/ >)|*$?0HqExuU$+N]lw9.Ux%Z(xˬ/ڭKChaX*m< #,o8B8vR.˷Y&N$a(d𠻦;lK6Ҥ-$=,BIv0@xN"R:qA2i0}k aGJ qt'ea ( 8'.O8)FINg@8B%/BI yYRg(SMi%-60QYM9V~v1tQSӲS<xgY^qZWqH/P4DS1sQy՛_KmΦZie/H2 <]% "P:㖖~4 FIF7ۿXش!ui7N(iP9}R)HRӉ̟h\ݾYSKiiRf!!%- 7hqbc dg ~JgӴ m@oR''FFI#Gԁ?@DvJQNPزZ'vY+M  ڶ2.NѰGfȀt; F]iSkE *^Բ4?gHuIzB(^=GѴ mB*8semhV* [ ] u|A 4n!Mקnz;u躕$(ǭdfTpOmT -2!m2JE Vg@3k36J2}A߇g)XV1t'ӗ Tm秮iەKg^RTW'IDU=FӾea<7M3ڀ xOPRgJ0xjRR0f$fwjAHaHw&kJM3^n/!!-IwH3?|$lgA#g =)H@xok4y,=vV=yK*S$2z ]om OTXh4T!?w^qWh[^~=ڨ_]:=(S'^Ǵ$ ߚL m;bpQe{H@r~7mڹl1`6^ӸUp!Vo =`\K, /L m&cZ|D?Jvmlܩ^ue("s`;oq%ٴ6c~Bk4>qp %2rܿ ޶ZQtGScZ8Xm%l+=zyRsL"ŽoukvkhmxeI`Ծ?- S0o;j/m98lT`F؋R9 Xā8 7 j[{+m*EES)Ԡ$PĄuq)xsmZ 7胯7W\.5DR'BU/ m"[uRi)o׺v ښVJw*HH/@20BQ{N٢km[="% Yu:xca2cnNHTH=mz3CjHw8Ka=%;(VSYŹvg9a7<  lD>VB\ll'=:=39@yg=n٨w'i®3RdN%iGfp dɥUzzJi,T4 Kn2PqB;閥JjO娕X)^*np6pIRq3Pxkf*J H' @_GlFʝnN s:y G=FVFAQ^Qug8sS-D!JԤIğ{TZʢ^ӕ!Ai^3I>uIY8jqJYZA%SÏ"v,&`8F2joJϤUN8Rd_ڷ $qӉ칶cTF#J"oTءV;[tZ1sp#)7B%?5Imni[u/impbu;'$Y.ٴ@MSLU## dq6IqN3>~`/=|ne)Ғ2`!"xMMݳo2T( T< M|\{'GqK%;Zdlε#jQI ( q[D.84p>m?ܽ4)+X>={CWifڪSJY.izˤ7%#:JJ$I` N*>&RpNR`?r^3G9@:p'L0)&z $bi'TIHc O20 uP*I + f`5 t/p11;NѧJUW Gp }Z=yM]:HWjai{Hp 'V(yI*z1|Eͯ ]R"1\s{rnKULfSCJ4L. gI"Q8 tk iI8$d|#TӀX%DISe#qZ*fU5Zh,jZPdzKy5a\b,uiONsjܹAwʵ9Rmчea 2)JV){vPmKR֖VkJ| 3#7Ϲ^ꩯ{fmҕ$4>6]L%Ꮜýu-ww۷,픔Jyŧ]J0MimK9A"dT%"x)@A D`!= cWL  $$a=pKDfAY@y5~w{uL5-NM }Y5YIpmX (4˧AR320/ BdL30eǠj=`M9x9s0"P JzrpujI Ђ} '( n* eu@O w4Bte0?_va\mjf,l;TBʦHJ􉴒>0=`3ϷN2Y-9kZ~r cOUUն[ufSJ-$8)la5%GCn̅$ >( lp(@pNBC@8RTrp` *]GAA 5–*qk> L2|R [:B,@#o[^W|ADq$#&_6̭ڏ]/jzԩJnAwK 6۶neNLծvi_O s1}Hr fn2IB垅{˴u D $f+@!* "Pz8(Q*]g9MU^*_q R߭Hv%bتem,2mϲ[ rJ*_Ĵ Haiw*ֳQHˬ6}%.f sjتDT9N8"s؄Վ3dqzTEUZܴ(Zș٤"It&S($&@P 2E*~`McTOX)(c@:9 =N⧌C,G ӡ%[KmI)BBR +m!Z&Kr3 XR `0M^NQ4&TOTϬm(N=_lr @qWs3$aE9Jd'2B*D qZB$ s96ui~uȥ_.x CSm;Fm?ȺF&@6OG{mwFX;!%_Ɔg`qb"x<`L P̜hQs"S.S4'K)3INr8SU[ ySpٶhM ˅:PEMbVa6L"<Pj(&f` @ P!1gy(R tztJ #JR3g$[vO:oxf@unlHSJV1I^sBǠE[(R $@mIR|'~Ko VջX6 [B*ۦEK B`=E \)@z,;ggwqbwU= -% iА<y[[mT9OC{JA)"DN[Jm$b'P ]$[L{~6G@26MNVDZ P킮m;NdQcOPKm<&ɏlko75~dk@>,+RL?gTX q[wrj '"e.C[/}ݸ;4.%R:֓ky6ϏJu&Õ |`3Ve;שB+v4H::~4nŽ\_oZFzR uָKOD.z[236g^^*7YJju?JX iߩ&Q:PBk5-v~{8 ҩX9,lf9}(w E 0x䍡]faqr=7 qcknfvZ&A#U@t= tV--Vb 1)|UECC{"gjgS,)jQ`>P /!8Jg$9iB@FbdP)-Ԣq v%RI4k&YK]J '5?@ +@-j=$@ 9tRI N@cJd=S`4ڎ05+5ZLNpiAvߤbOK k᭣,iL?-,'<*DҦYQnc ժ_m&ǢTJFC퀍{;l$nO,L^jG"d~ۨҕL@D'/t!HkL=d| PM4#541򀨞C\P*$ LG.y z2NH$6*q2=<2;}5V:N5&O8@y/|}1n[եݿX~䪪VPۇS @n*#9b\VҡT[()j $Dv}aKmsUڭ RJFI x 0((vNܿW@V4?1ߵP 󭗋XZkj)#_ʝ2є[Scr 8vRbS(Rsm@t9VmIRۼN8j$xj_}0Zl Pa##P<;n޶Ro%U  ^05rg/"^.@S_14yOML?K̀$Mr 3v؋E* 3ݳʱK10<ߵUI9&pg>tO\Jif`nkl sU,W^ȗ5s5:v 1!`!96˧d}sf?{Io^蚮}Pdj!Zda=Mբ׶6QmJKYLM89gQʕ!{l% w/^pT:Oci\ өM^_#_S$3)@S<֢@p4#kiPRYo9iZW;TNEd fa~tdMM=d#Zg1>TZ= $5U_J O2_t&]BZ?Jk'`$wnSRYҡ:Wݐ$࢖qZ۳1s>ގ)]IGLzW_nAjO)uVu)oʵ%#W_AqY2H_⊊fٕZMSN2g0'y@t.cVew߿PSjmCgv9m;}]7gSm2NVNiqQs3GzwZz-]L+ %B"g(.bg򻾩.te/<`;'i_qG@9b*lRp_lTb_dZ3JS2e=jI 1EazBGW~ & Ǭ!%S*2H)ĶQ=(H!ĄgJN%> J$1`F`:EX@'.`0Hgi\pK'QZ㏄4w-h{ wAl2mnԚ&4%`8}Ks;ͨS2e>! xm(wH[nFhyLJ*7=!ܛ"M#N6qm}20^d"@%*=gL)}JX1{` >dBj 185OTtoSeYJ^JdJra9OgN8 #wh6z[ǃy&mdAefrĦe{QVr*jzR  j̦֫\AJ *@?}ČǠ Fx_3V$mSR ?pJ=p3@!XI%d?_0Ru@]{VeH8@a&[V5]*4/2ヶj14iܜհ5oSPhI]ʆ +lUjbThp:iE m` #I!#<ҥ\zSOT8Fc%5.q`t ECbe!A'L8;UMA`Qi7@2U/8[kQLr#P1*PD>Ĉ IJ1L05D#U(!:f&d kn-TFdkeOu}] #TD @=I@R?h0 ] 0|0 &8b`Hzv=3Z8sp WqsNy$MMd`\]zrXa{E#KZ}ο@Zoj&JOeٌ %¤t( ⭜ 84Zל> v6Bmo轼[iͰtlY$ d;HQd#Qu@JպO ;#&Y#@Ue%@:JҀ?dJwgq^ێ"]XLo8P3\sozM--j>@`6=dz{S~_*` kSe _4(;nnoݴ9ph%26)ĥ$j'[oi j;}[Aj2Txܦ T6,mI'83|, ?_~ȏ^d:G駋ւm}}k0xl% $MXO j/`%Ol%IE ]"pz(%pNp:HZ?lpiSiu =J?V5詫H^`( GZ.UK <&`+# { N --d>t@2%IF鹍Fstqeޟݷ)Bm/*xqoǻcc]_jͅƱ >y@{'{܆yfY ĂwJSm܉T*Bg $gmrAK(e?'\TR`]6^T Hr@K 6~S Vf&O9A)G'%f~*4O Z_Z(DGhP\`#~@fi)9knR-# `9A*XrmSc)ux#qrzg퀴mlA+WOiߨ(ݺ ) )BGLˮp_1K+`UҶ LIQkbت"-6\LƬ`;(nдMS+O4K@UveKq򘀑[yHUXi(ݷmdz^d9s|~-#@L}Bĕ7T2*_gUNHs_8 xCc,3ڀSNkAj HjZ0j}1bL( Riq/3omh,0PLqvU.a.u,qA2ʴL@wӨ⑀@-X -7k-k_nYsRd{jg;Cl"{3FB5LTtIҲJDDPg~O0q'> h KQ:81"@p'"HPi&pKrI$ XRf0dpy{`$T$`L"LN tC/HĈ{D#$ c+T!#` 4MSe%8Mg T3R9`< >ө @Wjjxi)һɟAe߸|Fx'(LҀ-jF ӷ&HJ@@Ueb@Ě4OjQ"``. GHpd_ F^0!8Z'=RrIbq&F'5@dH %I "/k*Pd@0!!3AϬȨ/>H$DiJe,2AIF^ ȨrjHডmO<6 JR *ٮtkݍϙi/Ӽ)q"2ȆQԄS?HsK5S8pBUY'9(;uۃkQh =P S2!N?7ѽo۔ή}Ơj_R? F (Rhbclv)H89N˟lWC̽_K\ݺKN&$e9X%#mMT*jhV}2ӊR]IOl`=.^2VJRF_|s%!Rbé3Kk'_% msԤ*y OЕ23yDX f0_)lH$`1iKuY@H%PHA@-(gȀGDIL )^P0)Md}p#)L8Tp4S2tz!`6NfS0p=}SRpS Ȉ$ qGXxJ iR<% %9d( Ղ$J_Y0 t ?/H8&f&J@F҃6 U8ӞL^g# @: R RAI p @%21@A8F3zp>#R82 I8Й IyOI)\8] $s@ jLe'%0w\#O1Tb iEI0Im _ Lv'<`$L8䓇  a8)$a()'!e8~}VӬJcGoXۖMJ8ATlr@*􉎾0=0 RI% ,p-H3$-K&_ș83Ӕ^S謺@2NX ')r L'䗩*>$% >$ JDg1PT|șx@# I @:*H()#:@p S  H|@`d XP rQn>@==: O)Hdӄ)S +T2P;KIj*ĥ- ,!HUP @HI02&<d4SA2W^<@O&/dPBH9QLĤ )2qiZC {`I= c#3@$OqrjN PgX@J$B~Jr>0 ˬja} #) Vp23 Jcb0nwE`]#]J|<<`< U`ͻIvUn;hkKn~Y:TH~#N<W~Q}}t{k=EIU7RV%fRQ?*R[S*%gڦo[IJ z÷N" AxSjҔ̒קKj]CiR) h'z`>m;Sy-|=Qܔ&^a׷FJR%y vkߙf[gjH8D<^0u{[EF↤V'5d,ՙVnj T1' #xe͚ҷ䓣gu5Ay|P@NaaNsmY}oFBRRS\ mƨ)EcKqoo;w7e϶CjHI>RԵXȋNHE:zPTYX)CwGkY3?,O@U22oj-|_|3ŐWޥ[ Pp2&% ,we(oYxi `ިC4i=Rg5P{I `,RW,&K2$$0= KzP 0g POP^P XFc< R1pZcZFOy 8}Z&u2@X2&BJI3h#PHV! t<4IH>TS( ԝY0L0b ! Jy BFSLe(ie>RDR@*OVpf}P6)% 0[Oc% R9(q&@L D2O9+K꣄@\'8CjJH>RW HҤLz @QVhu&C7L d( +ȯ,@U( '/pptF(YQRd%N # F39tHe) @ 6ҵӡ-XԌ&ٞ$@ @?} #Dҩj9KMߗ˭܊[uEڗx]=8L Quۆ@*V2byEmX)<1}]^f-AK!-!:Zy +LԠds#\ j%A>'t:@X{.2PzuK8`8''*=Y[qؿ#H=EXMRӠJs~>Krr5B(Sڵ4տV*Uw_֗PW7xi Lpܼyq}tln()MDH\TLZ gNөwlr6ݻU;47Wq zRS@y-ӍjS{N:FqvVl6dtVPݿE7ɨeNRU^@k L@f{Z('vJآinԭrJT?0 kA'L19u2o%FH$x@h }iZIȪBf&uf`%5M T )( 'q^I88PT u GUI.s퀴ɦAjuhф7pT^>yI%u%V(zJUQ)qJzԙ#}O"%0ndF6 ${sW0SNTtdR|0;K(x`$J F= &R:@<`#vВ^C EmMN @xIDRfS V('Mw29O@D6H:"u3ܘJR ((3b V>a,mJL&!`-j:"q xcJ)4JS'1p +`(KKA k vxd8%AvjdrCS@Sf~=_ql5Nݖ%kZMEz &2$} ,$ (z@! ҅NR H| $ZtLKa JrO @)b @`D'JpR&Og*&ZHL$ xPFXTVY!'2v' ́AzDS!!Q/ Cg( &Zs((&S>BB$3,19{`Q>LI@|Y#!3 L `| "_l̙efR"1")d) "~0 b%R)x@:#3(&Hr )Ң$I#5, D )gT,9y@T΢%@YQF* @ORe)OZPH$@`132`8@I0az̤=Rf x@8RtBJJ^Pȍ=|`CV 's@NLļz2p9B"9 fAP Nzz@2ue,sBKc>̠NPi )pIǬIX3iX$u*#0 e,qO )% + g F u0 .NR<N5iI #1?d IL甠+W18f JS+R9ڽi,DDzpqD pq@bqHqiDj8B'O9PPR*)*HV< ,%3HX /-"QX Rr[iT<:T'T33IJ% 'Ĝ ( V0=i$88IC$]g`%[Nؘ]&due)HN4 H$JҒ #[ez`$ZJ p!ҀkdH@&7RQa!>ܠ).4ϧ( .h/IPMA8)2XLbL޲4bhb996']`!pYDiZeO%N'H(sЕi mH>.hV'<`%Sđ4u&Dm]..%Jf~q{azFE?/,OW }J:S2%}bMʪCtvnސRR GzI<~l^ȸ:W6*Pʦ/T+Zhm< :$k*:4M#ُ$9>`8D9@1D8OˬhH2VJs)ND. Sc8n bq8KIHӆy @S $/HO/RL![d&`HUh `#a)+)Pp&q!)TaA)z@EQof٤m$+C LӖ \ S _0BW#9' @MJׂz@H$$dz KRJP$N@x`!.],@ c*i (8 0F0d!2X<20'q%dx@1Bǫ9al13JOb'$M#PH3 % MSN?~#3t Hl0'3P #9tYs9@ '#dJ`q0 @ 'pQF(H 8y@-'`=QBsc!,i'=9Jp8@:@{`ceRB| BS#t h$k@@R/HR$up*B@DSAd%!g#BIXIJ(Ne@`{ #  Rua`8&R0 @#fbԡ)ei @2T~#z@ 0)LdOh*"dx@X3$d $Ì 掕ޢ#G/WRc/tY( HQ CWFpIRס0*xH>'N(Q*k .I8lR 8 fjS0-xf2 BtBH BHB\\" ҝiR3D+jsI9*Y2aԅ64 $l@ k$6TSbX|" PYXcl5&(DuaSkP2\Xt-PgT '3-L/B @W m-D:{J$c$ + AhDXV3>=M`Rg.',2Cc׶V=` KrXB E$Nfe,s4zAJPI'hKT憁 Kc8q>8C{o+vii%m tDœ!)đM״Pݨf*+u#/dܜ$cwstTZ:{m-=\;jBd|'Lٚ)3Kyp쀼$NS<2@'L2CIq=e:'^ O$sp Ww22=IP x8LJ<A:@H  8R#=`Za~2:xUh&X2205L''JS!.$ X(@~N'-FuH *Ry6HYkm= PsNߧ.9"q( NԱi>\fA8pP킴)}BL@-R @G10'5 8}>-'"q%'@29yF1#@6D H̅aԜT'*29Lh( 1@/Te)c#9@ L@OaI8O$&xgDf2 gSgDa( &pϧ)e b D98Q:|#J`R<} #PJA<` SˤxqJU0 *:)U,Lw+Cqryi*B:3#e2Ruu b} Չg0O0Zdf3iʥIId$ed(O@%GFZH9:NH S$]!8ZQ2z@$0Lc(2j?d) \O1ՆLE]@@) 0p(zr@85JXq>sa0qZ ` +QFH&@0Q\`$P +S9)tTr`(LY xFY* d|3S )f*-0:l=D2r "`&a0u``ga*!$](AL0GHdl9oA$G|fALv9`15 Ns&iN퀩UO2@OaARViètH@F =8 Lz062RDJBR呀y&^pٛD '):YH)!?(pK(KH*@@F)bc J&&H6qJJy!@Q%9iJ#!?(aZg<M@:&iPF*<0 OI'J%>pTAS02$RD]#<b @F@8F I$K((0rI&X@:k,%$P 8($6uBJ )}%ZA FQ?(ɒ瑗X ug6|AKt<`)K |\-/$ j{"C|tTL7n,3KW[/[> 9r*꒝jc0:z?N^z@ZeН'Q}` J .^Cr|tjt3XJBAHCFI^"}c!01P:9H$zp3yN# դLkЩt8F<3`zUR\0q0iԑSd$` g3!ZCZ: LE sXH&DFZ* I HПTH ?,iRǤg2Z3(e(Tˆ @LHt') HdD(it$cXDzRri )X z}8iO8Lр8 e?ˑp -$9)(P*J@G*8Lxy<a19H<FHuG< zg($xr'1B^3P)a9 #\c =% N<0B&d3Z53 "sftea(eg}3lda,DԡsA"}:R LxLxZQu)`)թ%]@#霒3r, Il`t@rJJNr1j %XK` 1BD/(LM9 F X2R0 )F^3I %3L)' >p Ǩ e!`++gP Q2Xd$O@1Ts#)@2ɖr0$fb@a! $F"&<%)!*L P$Rq NA30֝k7Z)y4[H./8]TڞmWڧJV `_ѷebԔS ⥊~%iݥ)"^ӧbf0򓈀I22"P A3 H@)OPIJU.H'V)@FLVV!(*dj3^fbfy@JIT}@:a2*Lʀ>qQ,$uԹ$'(/hbD*aϯX-DH1?` %`%ɘ<` I_qIPH'L˅"y]3Jr۟ Lp RB-H(!IP3, Z`ԗ,5*Yp3ç-5=}[^"r>&4ӠM fL@He2 ۔%ǤYI < 4 Bzy@%5A`RFK'jJ20t@:gb^~0L*V$``P)$(x@20@H8P$Lx1y,@':@0()%'0PtȬJT@ieb = g1 h  gN`N+Lʼ`($xX!A9$x'(.x?^A )3OH'ԒO"1y@"OIxxx@@2q)RH\>d'A 2(LHHH@ FJJά'1#楒RS  O\S$~bIC$r|ϲr=g( /LH@H@ g#Zd$ @`GiH3J@7Y}d#<(K K  H ӦC80H#y@IIq`:@A KGW,4)<">x+8$OLdXc󘘀 IcϤ<x lR'Zm&`-@L&g)HIN&D̼~!94RTJ@O> 4exOD@1Q($g)8ᕹ{T;#j(J= OO^B3>*yc e3(aT9 F Rs)J ^3  }@F0pu!.&R\I>1!)C3( ƥ At-C's= @ե0 fDh52 ը,  FD',rJA8@TI!9@ PQ(9(P( êuu䜻7u|e/?t6!$}%o`]* uU,0T ."JY`2n0FX4-GbAHQT+ԲeMBED(МI38h¥%g0LD dL&&3H9@k5T,)ZS9PCeie%h#q􄒩_|$I&C"r_&1Q#'qJtRJgS%Gp_$H)Hp8 ̱::/KHx84# ̟S>=`@qFdjoIVjL SXĘ9L|D_(#C f=L LB%Q'P@2ig:^(eTW\`R MJ>pm6U%Om`Q=dtLi^$*y`r@H$$K.cJ֩Ȓpfґ-Y8URH 1#U!GJqpRfCi !,Lb4^"*H8f$F'kym(aD( XD,p- e#d:8J" $\`EDr Qg%Ia>Dɞ-%~JT 2#Sy@A)Dϔ!(|`T\0zdH<3ED>pR&32KRNV ^Iq0 sT?AH 1!zXND=mHT:2r@"V %gDդa }z'{?$@@^ >>  !C`GnD`2AYr >"Fx@"e8'9au GBy@DP$8JJTI3'P``UX X@&1K)NYJf'Np RL`SbS TӜ '&^`asjx@2GL*֭WիK !Na"gVnͳ=ItkRiiLŏTq-^޴Zu_Dlx$pJznWvz{cQ]4TKY@m82Q<D|0@70OI&j$] &La Ġ#* ,ۼOrݷuu:k̢N> Z8<0Y קol6ʥUЧH8#($̜8>Y>8Hdg?@$$JJ8H@ju:m2} :գQ:@"FPx=X8x ')/?8a$-= " HIJ Ψ!Y:jUQ.шRzDSt>*x qԐ4 AFG)u0NJ8ޒP?pfLD:#g R0`$JWuJt}ZHIRYgI*ĤsA%>'!8l$tw ]P b   TSIL%Ԝ %A(&F% !]yh[]\}.$`&}^Z`v[u:dhs$d̐=` JBHRv@= $8L$pVr@8y}XaqL` dpt] sǠѯRjJ 8u+P+•Nr0c,OH 9@H"~$8 Cy>|@~0j)WHG2HϬNcZ[eO0="@P %:rtH< `qW*z% n&^"Z29?JTp]` JPV1tzJII9dz@< S$1)e"aeLee2?`d* ҟx?Yx@4Dre,ìL&p9{ e28@HfFIs jH' dTsg 8KSyFRN9TYD)DOIy@4 0e_8Kz PGRAV HTrV^P30Q(9?(o>pkP8aJLHqIXReIAPp$ *nIm'߈0 JB3!$mjB,`#0B9H%x Re `#6,tG_8 7PA`_Pg>H =|f  3P8yBG)@:A(9<L`#8h~8+QRg𙎦I`AI2k218`$$pP )M@(<@éiP2e+fttd`#Izt^֝I[/!M'$wĮ<^h۴S+]UK͡G< O\.v/Ա{ÕOJR\^86:CjJC*UBi7^\"`=T@ VuIC`f:} $ @M.P \*0h.aʣN}5xm-SYW:)=:KmR-Bc2oJ(wܻR5J(4qBb15 VZir:)[^'3co];LM)٧oSPAsWmAi"!Ĝ>p !/tG^0*@< @E@ķ]T@>``c0 'Q9JӬ A3e 1&ITe$#yEʖ}VR]CKuA( Rd ' @p$XٔlQ+ Lș}[s{P[DxhOQQTsAJ °:rKK'*hOZT LzyW9/WL'O` zeHW} R&dPU (q#O2@H TDR,R&0DzaW'}Ҽ_T‧: +m3Ss"`=]s4t_!my) T DxA `0p`OȐ>̠4#Xe=JjyA%!H"]Lv(YX)/,Km n[e")HQ8 ̟t@:=2S i3ӐL` (')a/+`$@d=Ytl􀘐p p 0W 4U"L HI X 䢔OFE`Np$QSJ )8( 40 H kY)Jc'JD}`{t.'y@IQ!j H2"zRp ʀ:r $s,bAOH Nj $0)msJy#^pN*Qt8>~0-&D@Bڥ#)իĂB} DH@`] d4i:&R>PLqIJ@[nS&F^ #H=3"P54OJ8%Xe"d Gb,@1'Wf'ī>@ pe#LPsՂH:!Jq'ԉޙb2$3ԜHJ# 6糿w{gSװ+z.m/Z130uO$aC@rƚ~e.--`-I@ .g)2Ԑ'p2N$ D'57J!I3O1"`(X` R I RJ<<%oBHp2<#ר"I_@TdI&xJ):Y@FmHH HT@GX^*x~3.e2 F?dg ^ 1RN0Ui VA]DO"Ć0Oa82e&%!2 *9S3"10 @Ĥ ZgtZȐ$H~IV%]:,4Nx@8+(S@F}L(H%S'1A?BIe8D\9k[MҮhlSU<=RJP 7EEd&Ҫr;$9rAX+VUdg4I(9|9!X "}%$= }}e%M©İ,:HLLz|MUMQUQZ\/'RSVN빺[mBz_PCS@&g@T  [etj!tjy"yK6=q\\y&ۧl$O #Soh7Mzڻ:@ $)HOz'#`H\*:P1A2q0 U:% |$'Hmȫ` D8A}&p r̘ ( |jVP >!NBYu p!zL"HeL:e#ZNP i}RQ1UsC#:AW}.)U)zFKw[O)ȂIB&fTL|h Lɘ0}9~ Wunvѧe,9[pVjV+#2#0/+wG.[wzi$Ke ')${0Cm6= N :@NgG`A&X@L1(81&ffRLp1gC!!8gy8e8 ħY Z3GДz/Dd<|\ǔ$Kes@I`JI Vc$O ?|ilK#Tt<`G`ǧ!ȐgʘzSJ=Ks)x)0F=p 9^BTFc@2@@ GU8'?d*I2&ij8 sQ )X2WAD @AR2 )P 3)TQ>P39~"b}$% C` K8 K(@| 8{F9}Ӏ`^D98I>x@G&@OD%^OJ^>U_Q[l=pZn!K#њr3s(B/GSxU3InJKm)Ĩ%Yg{Ow`)]PT8ceGwMVܷ[pS 4yHY 3T =rXN(XP]TozRrX}- x+Šhy!=)e_QVޭjza5V n <é0w~9j]U>%GihSIV2_K;jl6YuU]3/Zm*Fp U#{mefK%\[`0HH@VrY2ԟ@ZDrJ( JL ,u |,#0  *JC*<<}.=F"@ $`INp gҩZP$2"YY Qң_8֙vD>S0 Pu>i( 0@VK`.鐖}`K>c"9.4U(g4󀌪j~&[MZRBeH#ZP Fx@"u8qj2̆XJN$)@&Fy"te>`%̫8+ZpYǫ3%]0LO#:1<[wѹ~x+P#[u P O$`5$Q[oV+Jz6F xe8s\H-TӤĎg0t̄Dj3R#@:VN$#LJq0{펃sѮ|lDIq~)d0}K}:r5 NV,J!M0Le,s8 QڊqP'J\Pm +QG%ą9< ȐRpeSj5=aӬ=+.z*أV>IKJxR⽱Z7͛CQLД `5z :M\MU2҆Wvar?M|yjAm%m(i}MHANpƶZɡ6XHҠxr*~~-/.H%ibn )STC`:I=+b}#|[mul޿RooR퇕R7Й}o=X]:.K-IJ!C?֕OҲG@AJG:He:@pJ`@>@ *$qX J瘀f '8LiLF ( IpAˤ>}` )ПLJfB%K՜>p?(Zӄ2=)"JQ-͎zxPubH?*?1j@r.<ޔ|.t:vEMMڍe%%ۥMj(Xp=_M7˯к$NĤ v.?uֵEe2 "PJ{*V O 와TۄEL0U)Z B$$Lrr"nESSՔ] @/ {o6;i-YNJPsHq a,*'(xiY&S`@<2He!@ ~P<0:-إE!ۧi[:d} }֖\C(ӨF]:(  siJ! R#3D#~11VzFp!Є4Y0񀔔MJ$,a8 Ŝ-F zg9[Ȗ`9&Ww;ǘi iU*Q}]Kj(jg `FT4_4xu4J-H J)#WQ,~/u@sA0I<1XI)Hހ: Lp P?>P *J39P)4Cܗ I{gk)dV@P9^5Tg @9.: ̰#O ^'lVl^MՌF`;-֯r7*{5`a_Q┒AmN.$@0jw3U:ꥢP i Ё!:by \(;j80ѫmWApr]K)w@/.a u8  CZjqUlTCz@eQ"tmWjIZOWfmNۂgj0% &p:f=,' ?&< շH)iP\ޠEMwEӜ8r~Ũ")nn6ْR 3hn4[ MJϪp279yItK=p,&BФj@oOÎvv7IXW+ӍǜZ&d$ 0hحKo%ѿQtE"ʻ}Hq8r7TwڼZTSKpcr0\fDֻeܩ$W_|IJ.ATj0ze5}򓐩ntwKg]:*i)K3?* Eޮx]hYS6 tu/nt\9$L%s.:-',g$Tz 7g+hk!M:/6raW8uZ5JS/38_(m;Q&| wry*naJ槉ֹ 6MjV 軃˻UEQWNEK)d*>O3Weڢ &cvHCRg'85[qo.Ub+˔3qTҧ9$3;Lt\vjW^y5=8kFܜժPw5eA)̣Y@z:l jRJ %(' a _SSA<;%/DO!͛uG쀙<ٲ\%)`OkQ%#9kvKJEȞvo^پ&jYW)ZPG!`7A̛0 4 GzT[A{E]ś L<,l5թf .R@*go3iyGi-N p*J J׊mz` nN|a>+l,4:A! R*bN'V@ͨDڻR=}<` peg%(>+$[ }ڔQSH@&Cy7j[ޢѦ'J%@ @di!D $`0;]^h =$Ŧݸ%Cv5KVҺP*!$ 3yn AebP:)eIqRH ,;ku>ޠ zFǻG&,~a {( #m$M*HU!?9,[6岖a k ijN;"yz Mje;H%5Dl: [oQ|KL_+l7 >*'3үT%P1#WͶ߮[/6j@,UIY H4)m5wr\q) 1XKmn+bd*Rٙ)l` |~P)dVnq[=ܥbF{!im G e:]lm̤) `XيARh_ d8N)ED%~a-?I{-[%lpNg.[! (;#drx(rZQă)@XI6:t[dIV崂UZe-=;EZpڛ3UZ} rd4jр`1dؖ]_-mR~i( &&)lki{DG\A23[@5ݨv'~i5{,j)B<30Ϙgm )2:]g)쪤S+֐ O-G(f]N7-FK9@|0\ģg0mG-m&c<-RE%5 J}'3”kQQ8V=ɻ(-+Vඓ#N>Θ@c'-RrǫR+jɚD&&3@|\V@`jR2 Ǚ!ۮ鲲Tc`rSrZVEJL( hkH'_3 Cj6&U/ rmiSCZ@:{b6JWX>m=U*7E"j6!8 _ h@*ܤ}Tk, 1Xܤ} Vn(n;Q}ī.4dT.j[Z$L2ǔDm$i(NdUaj~eؕkJիOm"gSi^gs FYXنE;π5H!)nK<͏%i`3`)\ب'Z><`Ysf V`-ŗ)nKBCƈT$s/lU pA)Π :bDYخFk)ИPZM;"p{=3PƜgk3h~XZVUAВR =zX@Ȉ}RZhHDf3PvT,F_( puF9@-`g1!eJ*%9@ kISv_;mUuN6!P,VJ/n K,E&jiҙO.d0Q#n76^#99-ښpСՑOLa~WS,L-۵řtmHu !s۸a/nU7VS'X }#Wh[[2tJ~!ۻ @nBȒڱ0ںBJUpZTj9;|ԀSQY)mGOrY =veDhP'a_`[J`]wdաS"nmɻnB2p7[B/dX] n @j':o ҝ|M'՘ {ՉT|+%}0+plۗ ٸo@S<U7nE7pw;jPu 7ӹ6E;e~iJ*⯶VF%@.K=ulѼ Kr O˓9Z!w*'s.*ׄh~pR.R8r 9&ޓO`zsu-?J iy&]m!xuŠSY@u *Xn۩pSNAnܤ576@)*V=L*Rֆws3Uu]hZA4ZITu϶UPZJ+u-: 4HZNSsս@`;*Qӿ8| yuiqS#Otw6Z܆**A"2X'r[{Ӷ/{.X)i}N.A Y8'Pro7ێ㧸b0JX'8 fc;nVi/bI%Ԅ+m;Gq#2' 6R%-z)ozVRտ}"tЄ J] 8W%]-sZ'wMBm'(Wv }Mh kj zJD?]M{ڻsp[kǜydK:ۙwcm+VmmBjX/DH,(~1Zݙ%]!wks; >7ۥKWJ_-w*:ѶE]e[e6jʗUR'RԠ0&zD܍P-'t+H~&xlZgb\! *M$3̸*~٩YkWvܒNUBRȌirLC 8DO$Qߕzu9kV'ʑ/ zINټ_xUА\hR(m*k,͸V$X eyUq7-  l 5`M-;,i!nFᚈ`0su =TpԙM@J[]BjOn,[6R(TrQRxEmbvlHRg 2WsF:i= 8:omi_WNKaAK 5:M_;n|퍽GCrGv@q((f 9@A5.Km)q4mTOSCF ;jj~sZ7R\M54!2JIAFpjFѲHj2HյIyݱbm 'Q/8 ^in޼g !!Y =Jv@T,:Y5(`g]c*d'$oPpE¥܀xNe#ESE om4!]sPC]P>H[jH!La16nܯبm&zJC.*ă ۻ|D 1xW-V+TR PmXV]~;R0` ÖZUkSqCqpWXm5hPiJ@ql<9[e h-_K|zzLϠ߮]׭T)e)Q e_񠤦[J\2u$%]rR|TB#lfvaB#Mn$zlIJIwk^jk[AR>V]V߳Zhk w[iׂ ՙPgm[¢ oki^&U˼S+%%{,mB*d?d+kxۛ㴩nu_*5 m낛U^ѣjjN?5A"SM[vyJ6erR8Zz2Wm?TR?Z^/__nN{/ԙ+Δ(vԴ hi+#8J(bwS,<8m/1.V}ƗhrrUD:U7VIpHz7k+FҴY/&dxKpzEEn9:̏H+SN~}fűmVSINk\Xm,R5KP# ;^Q)wH,<]Ub[{uKΤjRЩ 2]USXvg"Jqo!iִclv* "ٰ\&evT{SfjHruvҼ-O>@ˊ @ZQ#0 277ȸV>r\%KB3=;蕁4@_PP*,[`P\k(uj*Hp?^ a74a D(\욣㢙u)0ntS4xA D3Wu{*q83M.ޔ(8Hq`2fR;¤6,m] hE H W!8.:lE8KGcwX CujT|51$( Fۭun6ݴ MUhJeÖs⵶КRdpJGcvխUki*\'U[ܡevJCs6!3?;1}DZ]o5*x|#{C/>3Ovi@h{Ygㅾ[ գSh @m}Ӎx#RBf~NJt,qd"|`'~IJl\~3l`~)@WM*tbfn-%%#.!?*D)$ 8x@A/)&[OaT)-\IȚ0#^U3 ol&֕ -צye@i+GJ:rJ%j/ӊG )(}:I,۫)6-ux ۅö́ң^ oLi*wv+V[/Kf{HR'*O*IiҀJqI ` ZJ=AMuPP Re%PS!P$B1e E&XOVFbIt ` 5HU:L6 T}3AJ]9.&sHRwH3>D霼,ĩm{R"vZ#MyѐHt;-n$&>uk747hM[ǩ흕6Me5jQ1Q8fM;kݖSy$ @#(Ms)q{޲FY>^+|@ q&epi7J@o v3xֹj_Ι jI4ޘ .)ܖ"gdcs-:?`#]&On[JV9X XVCjC[S! Keo'V赸fTPbMu$$-JbDv jg+Ym0"w(.gY (k>SCGW)[k>jۼ#R$X C߭]hygt۶e7[EHg(krO;a's;s)ٙuWFҿjKOa$) C{̐̕Cme[{-E[ДlpYB,~GL=A"b>Jfd{tXvx%.z0~OyELnD/nJ~rU, X t'6㘒U$`?uڷҜ*mݶ,& qU-mvsekfIe&n8$'[KQ[._\Ta=,i㙀Wmf-u,TtgZnۿ!Dzy_귐9+vozmv&*} xBt~ w{߆ǷW{z-za'Z2Iy@{9J^DA)S,ط@- $)9t= <|qv}Ad~IT RҴ peG=1-VEV Z Jʔ I0o7Z[VOKUJյJ[^JZ}Szf4V*Z)pb j˻/ZꂰpLxt>D7 cYotV[k%,7X2@t)a˝^YMkYVBSطBj=j1n%=ʧ];ESSټzV/kiR]aP2&z@pxk_a}M6E,> e?S3Yo 㭼֊+%M*jOI^] 5gn ٽڙX{ݶ[u関>ahM=>a)N*Js;ww;sndIRpc@^V܅Xm Ąp|CݔUmlma6R{nm[ldr>@r Mw)z*J*nog0Ҍ5um)Ԛf}tw 0ݓs!%<!Z $rǺʶY1IZPҳ%O/[KږmZ3 a%-/mKC.-132ͳ~,ӳ-O$3^VƚcqA"MZ|Ǩ-[mD,%̣l)Ц-h i <e;=ʐ6> $cסm])zgQ:2'9g]KC6=)MB&1ITӱCP$>U6SJ}G n/%l LZBI5 Cߛi֭.7UB3dz4e%Oiw= j{`Qn ,UZZ˙(:H20qՑTm)}ć$>%Ne"$X x P^̨]:D\p*]q,õ9LiWu.eSV@@r=mܗ~f|m](RXUS򓎩Zc$t 6js_C)35.c.;ywRYGĥGh,"V¨- ` T:pD9)zBؕ !XRϟDmʋlH_2e@ڭA6 NbO;1 NìJew/:d!^b~i,Xi␑x v5LkcڒU D@a6S;J]E'~<#lPXiǜ'!㭿X㊩ⶖTs3]8ClWI qm'PjPG 96Y*g6뛎$JxK] ٹIFYvٗ6H5Š$I 7+fߥ.Cn_'gM{ ;2mPd?>89srյXy;FX:qEJ>vV޽Ym[lW^C-hSL?/EV+.{`~P]**naHRd&3un?Jmh'MH#YPm=GfQ2)"D01><:{+p bz3ʴ벬i9Y$%6ʽ)S)Nt?/ U RF*k~,_ 5ԂB&AIj^Pߎ;1gj*qIG0@t1o`KQMpǻ]|QhUf'iH?0H97nsm5c3JIjlJ = &Pݜ{yܴUtw>-"(Km XV2$ f0vMچZ )L?iW[ZCW~ NI2' qjqq.gOWک Dm`8K-SvqόMϸ_In(rhBS2JQ!?ɰv͇dq=.h*S-N3S28㜠7?ʖ8n+W#in'6U$%u!)C.{$V^VYK\B d>30eѺmL5z[4Si|c5RIq#ؕ{DȑHdFû{ m;Sȧa c.MI]ߗ8&ɉϨ[mE^ڼt wj0_d-zB`remz:۴۞ *i/-2RS<@ըxxg}{ӻNWyJ+`S%¤$A8o;n57Z)픍k+x=f9@l(wruc^b8Ȗ4fz v0TomnU6#5\%rʛFu r,(2 "f{i7P; ^ƥGh *V#h\[cJ +$rn_TPТ@HG+KazW]N6 hF㖷]xT}J[Rш֦ Og%uOV<%jM*GҨ/-dņ ٤U>3ggŷ1oҿثa*P[$`LĠ77]6El:!n!v Ҽ)a3JRep-{tWm(Jj]C7XDԉ'@oU<9i~8T6UU_4o]*8j۫|1$-2!p mmoj:d3JAu4CZ@ٌJ9:p9|/I I dty'w۷9Z;5p!ڶ\5kjv*t@uM*S>6 S!@(EE*2 @ZҡAԵfOB3ŴMY ?"YoMTuGw 6"mR).TvHA$O DdRR}R8X 3QJLq=쏄@&g/}蟟OoH,G` J$r&G0$Xf ^X z$S@yÊk,&t4O+=ÌR4AR\Wl%J@Uk6zHmO5_eWz写wU kfCȶ4U` ٓ?r3^l.sU<%'Iፙm`vMRK8u|Ehv{zNWRax][ګpy Lһ@ǡdW rC^_lC8` ٩J6RW\1Wl:@uMMl56.iEKCO+yp9û9D I.FY +MjS*5< 5|ۗr;GRR  5]<{CjFYZ9)04fnf*]C0ji)rBxh_koz~Z)F%4УriP%nj-ù/t=ۨWPuD6u$-X``4oNۛtn*W_ҕ[Yy(-Ԗ<=&א~Gi_2]U2/?-Jk|"/,ǬSewnӨ~UjkMVIq9,J9?ӣU7vMmsEia- Rz{x#eSk˦ֶR΁B*q3}xa[׍xC{n>è^=ʎjqƁ%)2V6?ysHuȓmySd5Qu*+)\*[:L"8gg}TymۜQ!*HN:'ZP8玶#mnPu&iP.ejٖ+m=^e\S qdO5g>A@@9 F8g+}0%jRe'Ϭpإu.ILJ\l|+UVKĜMm%Թ_i*UH)FxLYRٯ-. mԯ[_>~ VW0 E*fi8`-RńT!WQ)qXOcdZ7P^Vz}ҀkZT~p:!_ږ+#-g쀝\]m QE½' z@TWR}7 $l c0X:6Uj8Dq5‹+Q %{w@AGH #$$UmuUI\Fj'&{(].s9)g (/i]PuW@F 3WSzn;ImjCߜ3JsZSY0Tj(7TMID8iK{2 &֎.k2WwLJes+R8@j\¿ԻN鶫wMʖ C }@a٦&A.yD@% I08q7RM>(tm{Iw"y*Vlj쀻֪e]ǻJ˓`6D%C׹gR S[3T+%uB@GHknw\'0e#"8얔w]82,<m!H^DH(8n+? ;Tƕ1?ѭt3WR|LRF%@ @2 5U ۞qvڤSkJJRD8+J%PJ&_nRT^k\,W8zωs龗@dݟklInf۶^hٖTj3H^}?O 1OϹpKimm^ٸ^8} RXNdcޞkn]&H=`5m]۹onbM8>rT7n\/VMŸҪJ` UE42ѮN忼;J$()@M^bugTeCxtgN(@Q*vRnݛ(( -G5+[lCT*$ϬMeU1}n*$j NVNT8f2ӃgYo7SR0IcKu[s~DD ] R+<{7U%<vQ{@ȕfI@]kLwwvRlq5zq$϶FI t>P ^ n@+zZ]ۑJ?&}e͹/n-/mR Vqq$0XJUw,HQ z—J`7t>B2Uz_ w'p52ZX3Rf ⦶wI']I {­45=z)R~w.)S{q)wS0_RHH$X»N%:t.&D8o>$$wR5#?(gh;p@F(Ѿ"Q)g?o7Tr3PU@:%vϧ Ax}^jTY:!mO vՂP2mPX6t4KmSPYL=`+> Z߾@F: `BHK86Yoo-V;BV fLl+?VgEzۧS.'798bIJ0 (P "O]O n}%a@0 4J۝ Z  X R{t99)9w*e Tf`:OέanJh~dR+~nweS= ZA>P@pd>9Jl[z]ܪJtޮ y(ZtԉwZ|`9q"L>j)hG#<`;/q>Y)Au:A9[ꛩ: *8!t|A!G^9s,'| `\, Qg(#5$(ӳ8)x)1m[=-UoWԳZ]Sk}HtƵLd2)j5 PFSǬAQR`itw)(cRp28{`R4LҔ(Lu!j{rg{ߵ-u;p8)h*=QJœS_mNLypsglSUީu_B2#8*!v ??usf /GFt~Z@7|gsydʮd˿0!Uc G7t_˸ {w:Aù`= (;@zQ 4TQ?Pvs4:+X'?w/ 9g)g~7S(b դ橬?cq[Ž5[JҔpt}lF? P׬4wuR3b*K)C(k⻕Ƨf䪪ǨYdDb]ZTpRx@z-RJpEIV$:@I2 hF} eEFd-m(mr'p' R*1%hiR 5I&{U ;aF@8-#8֌r#Thqb5`J fP%y4Ҭ %m&R=1rmSEn.Gp%ۜxdYIT+T4hڻ~]N%ZS6XBB&d@nrWn{2 b%]) <8 $JQN;Zuh/lZ-v}֚JvH4 2AVP VJR 30 )ߔ7J {v^M k#WOJц 87邻6׊SW>KgU)ciKIJd BGD =dSJXlNswFږ6N)QVe8 Jf``&DcOЄ|}ٶ摀~b%3>' +^;5ntVGT[a^ucBPg*wUgSoj wT$@M ǜ8 <5HJ[qx%$M$|vWo~VTR)ږzdtXxr?n˟(A)x?ӽ-ޅ׹)jԫg'e/9Rۄi 2I RD# Պ@ R2@,-:gٷl2m,6ª50:sQ&R"G:CTFaIќ*Tj`0BH0iN8azd R Pj .bWB׀"Å+ RTPT2KcdF"|`5ĺ[U&z PS'5i7Q^Mn[0$ ~ ѻ,eC %XF=( U5kP3-:- i:"e6pJr@NB BVz@Hmr9H @!@NPV|T)4&JɀaL`Ҕf I*^Jd-4+#iHCp1BIs6V|`-%, mZM:RIG`yi~f0ĵR ;|$ku%+ xJTȴd|>PTtrR[`;K+X ](m0ZNB$G&*s77>v; hAf]-BKcZ"}=r8-ֻwRTU J'Heտ Yo6y2mk`$t{4G*xʼ82D(Uߍ$xV% \hA#e!ƂDˡb mŷꉒZ$U?Wzʯ@ ?\'#X }VqkJ]~5Y."~'%?UzTu|%Fpq#nu`MzG Vq <}V?yf~8и|獺 k)6i>h2@ SfIwrir'u3nnzljH~PQtS1>F>2} >8ʥ nZb$ ?$ 8mU#:B2Ҁ'р7%}oR]/ǫةwWlqgfx %Ƈkmmҷ.C4루Jd R'`=gzj]Vfae#@q:J:[(wjBICe}i_RH(R@6=B/ͺ߬ TTFg`4 *6C>iYwxY~ Z0|μYQ4Ă=*hȀ._ԥWe_0n+T3NR1$!a* uU_ֻEڇPڐ8H`:{2M \mD HPt Zg2'N15xs;#i^jw6a_VS԰&uu= 80Ӣ)kK$-=Rp> _aln=/nZZWZSaA) LhJ@Sy[aR1#%#W(k)q3)ZtSu$*Rp2m!RTq8>}I][ [}@6!.7TDL{ =$PH@)ttRq p.QlE3eѶ=}`rQhmMf[JA)R*ZU(le59 R#T~ e3Yҡ"8(ڂ{O  N) 3)Nn))hpHɜ@ ҩ8F2A)Q t` ?5j19x@JJ2l=:U<<`?+ #2"@) TL8!D8G$3UL{ji.Ӹ$& 4j+ٯ6aZoĜ_k}Un[8DTcv8͒= [qEӀVΗkr m()W锥C#gnײ5M=&bikR[LD\sP-/.'7RC@;7(gUS2bz -Q/MM邲le i4/h‚Rm=`'] *lD@ijt)jMC)-:Ӕ2ͣŚCLmBS1翧 ?4Sۓm4ኋA jZ1L熒s>&|(޷5QR-5GN@3X) .G)UPT&`-(3PW!Կ[(npR3+eϖX'9Skw4[T9S{ n`-ҘyJi> ] .2-Xl0@u+'1qVYܸʂKC`Xe/)S{VCXz[9+Vcͩ5TX \.j*Ǥhׁ"*j@}aDGsf? 3hMJH{|8 o\0m)IYH4 w}ښ]**]rSTʛuo)XD:@nWXŅچ%WLJ :sJ8hw'+*T>J4!?﹑X\UWͪj ?]}jRmSӉz 0Epo*1 0*qJ?lI$8u)EG(OJ P3" KDBU J $@bjPQ SpvҔD@YKMr~T=ԇmX( hgBJA -iꙀDduJ oI-3Nr @ њ>JԲ&L k )gTR JIHD>< TeOGEKrEIdTq!N8R|OM,NUXl065Ibvp|W*N)j%:tB!ځJF NgiJ栔 cI :CHWR: tHc\'.ᒒb`'lH:0 GNI^ Ӛ4> 2䄈+?y"n3 9e8uzyfH&eKVpRpPYu%_ 0 .!N2pdžP*=ˌMBRi(}$aLl JH>Vx@Ғf,B凃ԥ`Ns~^Mi^1~:4m$bZL }I)V4 H `:C)kRJ&Jp@pzI;ݓG蔵HMq֧:A5F9ktn)II{OӶĔ,t02uBs@ %.L00 Hi 8N^;ϲ|ޗm ee<$3@fEk-S%jak8jB) y 4)<VۚI`! !ա-A}:/t( !hJp&* T1ȗ叾(R %F~ U A)P!I_$(H<u7ŦE;akn\lCڵ˴^@z,JRP@HHt)@%k5Ph ) YF}Y*t#dgޔQ '?%JpAMA@-9_RZA T4]Ģl@?D'$YngH ZD@qݶF JdwE=i+ rP'pl;뵽5pUTS vIڶ+MRإm UugmJkWCKDAz$B1Q@l|}n3m]AIL 2.4R=SP>^r݊f뵚C)ׄ[+h-SQLJqc8 ]6BVj(ҵT-rj%#ѴH5l=N ,l6BېX:@l6N<;eƪ͊o~%ܦmH($piq\vݮ@P]^E2$G6Ϫ_=%vjm.خvu5kN8a%x"p@lT)%r"_쀐2ơ8LJ)*KRշf6zݹ]] Xq&ٷU>mj*L{kUU('U^ IfE&D9p:=[=vj_qnYԠjQ!!rBc EpjD9"'8uVms0rT%Г5ܧMe%`/3|Hr7u2zK>- yq^{m]mv޷ p#.)m:d0d̈ Y▪]m^/RTAl/U=)@B'=uNO^ڦ> ypQ%lK )JFBl1R^a)Q_($:`+;$w1YJe9xYد ѢL2:lJe- Jp '/lwu ISu."@Scv`_-HNH8ZXRp8P:$PH-!%"d0 jX uFI$g8m&HR'HO7CXȘнY/JM> !#"R =`iLN} Aǯd I0kRԭ?i#ۤp..}rS5R(+NedD:䭪w.*RS)J-Q?) jk;0T#%JtjNr=}ܴ)P@Ҩ%+ߖK-lk()[yHihu @~ 6V"K2;0FdiOt 'O덲(&JUTm?[N7Jo)y؊sjaor֩5rq{*1jH2?eܹѓ.TYAMʐ/GL[)Eƌ/,ꜮTr02Mʐb~a>S&I?`[~Gf>aZ5?P^+=Vh\:&Lq RS4ȖZQ2 ӄ;m0! |0)B4? @a75;zTv%F,$p.$ռ7nqU=KH8Oag)Ha. 'YpD J&Fc/KNgڴ}-8K+7ǒ92U6յ>ŰIJQ@z@6)m н ! 鉀=[nmUnh ' [,6SCfef$e€QzH$ 2PX魊zUkJZ2iJf[+TLfqz2RҕxˬvVTuX:TfI; pNJJPE4RTU0:@B g/Lz@KZ*80gLg #nd*rAP IڌX >T=d:3#@ L$c@* '")t(`p>p2>*5]BdvǷn }4N]Q[dq@WD_۫g.;-[k6T$Ն9Xk6Ez,W7[y R1 IP9 nG?8` 0 I  ҹ@^#F``a 9 ,PV|` +-ǔβ%i@WK aaje2$Bɤ'Զa$!  QRݭX}RJd)e)W*%=mD MJguӍ%}#)vҬB @L)@|TZrEA='>xm>xT}o/"fr-.L*@Bpߛ橦Mؐb,t)p\8n aʗ/۵j+H :RBPg4H5H 3 $eV 0jv5 i9Xjnkԇ(i0N]z@-KBT#z @pzkבB.%Ϛ&ZH 9}*[AM%X 敠WT J|fV0*57Ps>Fl&uX2dhQn!ľv,+;rM]i3.drl^ $UfH281Ner{kC28 |R(2s0dRQ'4Pc7DJ?)L '"$)v2wwLJ%95ܡZ\Wf){U HVKwZO'EK\rz=5A9@i cz $P>] 6ѳl[[;sjQEog&e-GGِJHWSaK$)(!:L~PKP ~9( =/81X pӔ ,OX@3$zR u閡FsE&*2 &X.jbzJT¥<%g=(t{շ^mM346q2J0gvhqS.`8!: *Yk7CCL7V &  R;jKdO#%5i|tV) 0).ƭjIfm,#e#32O+yëh>lun+֔y+499 8;M;PRBy@T[VRա2%8-,!g( !!%'ufL$Y퉌9m'q3kt+5ќmONH>Եޜ5/1In [/5 T)C:0N6(l[ٸkEΕ9RqiHţ ~vlWvSŴ̅> vzguD}RRr)aA-,_ChXꭔhW&BQNj {%GbTTh(>a-t'oŶ|vTj_ș= "dXݛJ}L̐XwV۷ZVԴN INt0%9 cmբwv>}K 8\^dLNٖ.RÎ"IRx) nC|UTsAS0&RTLTMrZҔCO!L9 ѷPR0T iq$`IG>܍5U8*Qڤ:(-z2a>Ӕ/6FJ{j*I3>2|sjD)K,2Xmyح3RRSbu* pRHT#{ݛ}r}q' % ]mi_;Li(Fٞf.**ڥfZGȓ2`*jjm*S@Q(Lvs#aÊyVnHګ8XE[^ɑ0LkS5lrڤBZBKHBp JCd2I#7o{r=-ΝԩE]FDb5yi =;ZNhe 0,Ф`1Hg.s-Ӹ' 1t2g.S*Hnd%QIWR{j쮩 (5=!ykzgK*QJ1wim̷fYfPUImmure QH{ {ն{C ZT1S =qڮy[$r$(uYK-$&0-,Kl]Z)Z4U| ;%Sih5Z8KT:H!ٔjK)etӂ[P~Hm҅婱̎4JX9ͣ9kkjMnrE-uQ?1WMo4 e%LIuҼ14٢ L ѥks3M&%3X ZRT2T(Qbg @*K34\yj |fd> HԨ&|+ OX S̍6䔣32ʯ^ UIIl*sP$IG vr x9~4%r8*4TTH&s17ꬶWY̮QRW2t s9CDs̵"7xmyhm3I):0 V |ڀ_SdshV5 #n8u9ͪVjOBսH+G5ze=JfCjJ X_ĥ:h5i#>ܤ:@V['7<[T';CRUR*oeu)Q Дxc@q cI}JS!)FU(q n!JLbhl[Fz 5r.J se7mCBtQ`'g֐KNZBr=W{p*KUN؜E%&Yh30([|܇tHzANMQwtjm9RВW)8?4WODRz "j6*y R j?.Sw 3!?- T6&H]5#Kb+0RgmBT%5Si[s#LZ{;Ånն[q(9%Hdx!m p&%Eee?X(KX?|§8CI 3)Yce,DX<H$Ȉ -ӼІ]RAs;M)fݽ~~m$\^S%-[jegnϺ,P-Ih.O / ]hzӻPe(>}D=IjQrPЃP&Yx@r;wP?^YB(^A'ÌyngWt7mqˋeSNGf~cŭ^50[/w s #)) .# }䒤۽:PfgRS۹zҥ"M;4/npZBPwp餲뀓CdԸwaZ}$v]i$+wSp5,on{7 RXs 'X*R[Es5e76nʦ@3agT "m2@@ aL4{KGnP^'_Unhhn$6.:u]vPptR1mR7FqW.Ftnݺҵ}ax}a^W„vWx D‰`̏*ZPy p1y`]gTnO\י)S),8>w?qQjVZQyv/P"V4|` 1IZ}$%R W)N] +:*II^PnsTax3>RBHFGyc.y.Byx12\J@ZL2 񀲐N> R2U0 3A2B3RLj*$JFOi8(MXz@@L| J%#AHLT3rb<R湂 X zdp9%R GW7䓀èr$J$)D TuOHȎ%&L@"71` $1sCVPPr4(%I+:K*` ' *< ,%"A!Rb@Dɞe%='sDz7@|)$̘J8yo6K>KT֘sO~2Ym-5i.!)g \(u҆"WTNNd<< 6ƂTs%LC`JiDd!JY/H9jïK8 RrpM=D(Li+QP)H@]R#'P:fdd` ~}pfv.-).m< מ){n*Zkn+n K JVD a~[hn؋8)mI.`Ub`߶fe?S4͆uĀO]N2R+8`&rՔWZJvxi6F.Qte%{bB]&avg( s+s(m}ϼ fR$VI~PǼڳfˠRklke e1On m^*-Eh:R'knpukW[2ZԴj+Fr <9][vٶ7QG@{Tm$J0C`c[vs.k}׷v5}]S S7ҰH~&Z0W)ɻ7u`^˕5(4ED) \ -Y',5]Mu`$5RjyRKb ĵLm*ʕ&BCffG<`6{? ڛCQx]ƨ׫Yl7\Yɶ :lV^-Ɖ ziy82klbU&ST<]S_pHi) 5MinBRҡ{xּڊ$)5 VH Bጠ=v&Ҥ(QwuhXL6[[{?YRJGeO9@yCX jm)*E*R2+mT3|[wZ{յ[YMJWouK--(3P#w;/\ ju퀊ɾ!Kv9'J,:Ȇ#U~%ԡyA wp@v%EzcVYܷMvٚRfu$ V56;J@ɸ rG-cR)-HC<0}O&.n0V%ŵzf,& = vI 㭌 >a80*ŽYt" o"VGmUq((&9;_t<]d I@F/*,tw#Ԅ2T[&(`%50S+B\Je bs8G:mҖ#@uhlN2zjw[0xbZ@&zHbϹHCrg0>Sskv[iԒ.l}-gJ7!Hr6R&RӗVϏjD{ hIu)eRB_,r (I2|eMͥCl)$xs( OUG;ET!8ܛR$̠;(٬;:ٵk˽m}HB%B hH$g_l(8$d%( * >$U^0 jp hHtYu5e,   $̑Q$=P`"J p 7;znt5VJ>i+,Htp4}*#Cmv g6=R-Sƞ4?*O` {T]5,+ևE*IR7}hC(%ߦh*XN0fqWjŷK3qME4cfJ|.*q[aM+r?t (ދ /ʷ 'o@ko A ㉥nVV2F:H?ߪp> #O5&GC2:-&R:h 6l&s*f~] +RGZ5J] @Ywhr2P&D6pـɊOA-99L6w#uܴ@(SccZ}q6`/1-ҵL(@UkecslTh\lOJS-i;{i*?,0ڼҤj,J4?`$ȷQe<3X 毨1w髥kWIzj-0B`.I g7cvVeM=3A%H5g Nж']_L`23DNpFSsP@5d>'EG#00:Gw:%u)Re % OƐ|'}2&S<i-1s` q!PNu; 2;NR0.K:V&ޠpm0@ ` <@>8W1tpV2Zg0$f1}*9@L sL8 1DQ$AOLj)8' * SPjPknHXL24 '1e3T@G8 )q3' FkYN %xNUdtԏgNlx$( {$~b}2@HfC%9rÕBmqmⒹKPI0۵v`PE#j ) -^@n=tvrQHCj P$4Ns)t)KO0ZƵ1_*Q%)eZDoJ<%RTNtI A&b}`JPPa3)$3^f$$%9`#I*g!\e_g-Yot{o=| "RGFwT @A܄݉7e=t]n5%"oQaTmʂظjSH*cX6V˭W #jx?Xwz]֔dJЄSNd̜Lf2{L$[yysKuJ])(Jq:Ttz7lt iIix[w徊=WD {࢚2ْҮbiTx3#< iM٫\i48Yq `n]d^LZ Yyx6sR@smhۣmw_M-y~ShRbWY秽?Jcm[eT⒄4 ;Ū. 6*u4ޢ @l5|kGvUӧC/=ol2ˆ~ 1iJ[mGRmh$-S݈R%pmNOi1v<ƎJ"H>6Bm0 k'leeBV^ K,.hnG)FlP44HJH+ZUKc.{BkjvMI!D+Ag{VCGC`ທ*ZîR4Sf+~8jW~k. vRl )$KNNCا{k. JDNޒPĘ olݮ_kbSL7`8ɛqBI)Da7H/g  )L$|&]@26i<JiWX{Z; &ԳX:OIjt0 ͙dp%2Ź uD:\Yӡ!|q@QNSVD;6PNFԲ/ ^2@r/d*_ U1b!NK^^0uvKe"*2a+R6V`5LRH7^MH=ٶ[tѤrDmDWSu*BHIKs)hju{I"u~objXBbL5O ZLFD)*[x_ר4M>~P;R=:> rf- ?7M)T/p%b5'H n\H -A;Z S*B)BF8%3v&k;tjYM"D6بJJ(L| #6pIFKNݷ)Bԗ)BNY9?v0KIdBT}ϾӜ_J>4QPXpI;uBW2th_ 9G3pحv<ښz/ueӒ*7PT C7]~}ߧPTdMXGN#|s`ZTԠ@PDg3{F!)g_u3%.ѝ&]F=ҀLfuOW6P7{g(/6 vOu-"K"P\j&eϧ3=a :I}v.}D};"BiZ(<piTӽY tjC"pasT Z=4*`+1"3⹒FӊC# doiѶe_BΕrzP+ꝕ[r{MEbZ[ QIR@#!SOPv+%DgҦ} S~Z3`,A,0?Tig@)WX BeBrf _L`$*R9~P8 P&Y49g,`j sPOX W+{gmu"i4'@qfxwh+T%+[i'9j9@NQT:u` n+B}oSme &@!  HgRkLu)AXg $q"d ڲO\On$ȶ>ZWͬhL 3* Pe8e( $b`i阙u9"@F ,.EH8%)X8@ J &COH) Pmat9(xlI)ϏF+IK'B&S@6 9 PV4eI"T}Dc(C)LR%-)n8s^<@ PK$Hy@U p$퀲Hҽ3.= KqD*:t,*X29{S<̠< B)`#KRpî1 _zrt?*yt p"RIZR ԓN:!ɑL*)WX-NFg•=D:ԜלhY(p⑖0  _ƒ|>p YxLs(8֤@;nJ] $+QHD-FP@48fqjK 'H**#@ue8<`ZP@`Pď HID:2[\BijlbǗE@e{[oBWmyYHKGZjbL)f*)_fBWR@ 2QRJЯD$ⓜM'VPg<Iԅg[2!2$epdTZB` &)23B'hoN A uwR9 I hR'||z求pH0 kxePuozf&F0Y Rp'T! "@0T5(D=}8 '_oYc)|W7e˵h;zLRj\d N~ws^wru5 p׹t)TZsT RRG^ gf+鉀׈I%<~ [cJHe0R_VXiR }@G^\w"F~g^,5Z&>0AQ0qq',D.s `R֧XqF+5=o+J\ԅ'Hd" Ҳ!Ҕ!(:Rt{#) 9N^/(JXV28@̒e~ q^@  5u *q `&-xG'vj=`*eMMD/6FYebp稘5dzz0ĴaQtqEeg?Q+E:#KkXZbp>pZDڻN0Bea@8ywMPQPTdgGP :JVҽ46RU2d$, ЬN'@DSi*LgC$̀F%a 8z򒐮QzHJ =20$ʵW_(JƜ@s>0͵eQ"T)j 3^guk"J*QS$q'$XQ:`mZKk$q@RI Md P% (P *e8)P^2gJ+WNGFP?L]* * NIR1$f`JH2Q 뉀@'A>'9@Bp`-ݒRHBe FP)Ȝq NJ02WؐVV2F"S H3@RLR`$oJfT'3tI r dZ߬r#` z:gH LҐ1``pH., *g$IDҸ@X/} &D.FcRW)@L!yGh RLLRUVL%D#B$?AL.'8HlAFiR@ZJ$< BL ZAAd@%js`VBPW_(t"E?Bڒs#(*l (A>GYNuI^p .sI0Ò@2OKI)O>5 D#JROO(Wᚼ`k)epA"s!e1iHjD&P%G֝J# D$,G01 ؐ&+T.fܠH p  =I2+ZN8YHR6KBGgE/Jg;HX K %xJ ?0pZ4Pi/H2X iS'ר@R81Pr0TJ 5JB> $ $u+OIӊh8 !R֔Y2OJ@JSP>N ,%WP -3JAe+2@0 +ပ*' &eK@&t<;'@_8| JI_HʒV(̬ `A Rʌ I8O( 3Q0(u|`#+G)$@ajyr QN%7HΒL] +DSsSA:CDye*iXXtXd:$@WSH>Fqܻ`/ JVJ1 )ӆ9H]u K> ;:ْTXuIJ5P.be$(3 A&pq!8͸Өe<2(UMԀ0 L-ILDg!l5HxO/N4 u'g.V5IGVp:Lď_Tuw'9 ")=IՇˀh2Ooi+@ KP<'N5b AvaiyI$=h)Q rt%J}*Ya3@3^2b&R,ah  `737l%9( TW,Nt->:t3T (Qr i(\ `?8A LII V2axZR'3 )O 񀐂8NTI2xQ!K)DK)[9퀼D~P[PJ`XIiI$TtJ$TKJp\519@NsZ]*i % i8aY@IcY{`?36$`a(RL`j$Ltq%($ 9<-. @Ut|`dHR)} hX, ) H9 $'u> fg@WRI$9@S}L$4*8=0,H&@F'iWDz%Ĩ#LIA:*96<* 0QV0V9@ZϤ&P:GiZ)V="@3 {$Ttk3GBҷ 2 a4\'eiQ$R"+OXDSbaC8 J V r:sҬ1J(ޞT/T4E=gCJV *IZRAm`L fzfJI2 "BNzN6u )J!&G%EL uK/%3ZPϤ(IP}P@ AāPZ{saG3/(R–> PdR[-*  X=>'( R}JN>(/ )^G@ Ak P@28`%J3:@m.([+U!ⴭq/)%*R@!a(s'0 g/-8T:uCHC( vʈr`k+(S+A++$xy ak)gɦR JyZRp,HKaE,g17ˬVD(Zde&hKSi k8A'>+Jܗ_8j)gB<j5+9:L4R$NF2U)8AbO|`!2Fff $&sKu2Y$' x 6NG<@0^Kj-$~-XH@[f‰rd5' $&q82XpIGHi'&0A22)Ľ$r`a^Y@Se ґ"eDƩX~23/eA$fee0?0д$$@~M3 s0 JTP&sfVq8:x@B$eNIHDs>P )LGmA!IHUN [8N~@7e$'Q5i@&PgԀ12ar31 Hge B 38xN@_?8zt#JJNIzgJt( 3(ZR<<,'&e )pYH>i N^PtZJ[42H m$LJ>sCi/,H@W[Nj@X} Ia!8'Ԣ u;%L!LO;%krܵ(ilm`J3 @Hh : "IA>0ڊF$a^^p35@M qD)FBtj_|>8x @tmA"fFH/t$e<`H2$PJ 8sHP#\֗% gO_|%0YXQĨ l`G?0RL`eCL :1_"-KթX! 'I@LY9@BEi!K"Y@ 4lq4̨1J!GT|RR~&'Z@8}8&r8 ~X [&Sf:JUnh/3!`0 ӌJH8 @.C)`  L Cu65 %,5H'ZJ6MJ9`2I:Ue!-3T>0$ IOQ$a sp S(#01m%LIAO@HR$#-$`=l`P%<ٌ,!~L | L 0$fgB&R8@YL@DH%8(Wl+SdgBAR0 T5鑖^0NFg #pI@H$8 2,() GH:%2) PH %@= -p &cPC *s󀯠wgLx ~]%IZ"D(Q$aB(+^b<%eDf NeG(E$32J4P&gZdD̕+`)H?}5FR# NIx~i!jYVBej@W>( ȀdPq908)$x Z$J~'ڔffg( :HjI8y,1J8P $ tg, ,Rx{>*9Ge.`jP `$)'#" "`I限"tCtiFi3ZAJDxf' 6Je xP)N`N_i9htfH2YJC2LjWVg!c%D#3(kGS]p7֩e WEf#,%cԣ9!d2ͱsČ #HZq #hiFϬj| ()<`$H ~PiI#(ץ%j!(gD!z}j=2t)LF3իpl1HLIFr2(|AѩXO?l!Z}'` 2%ABD}'5N IoS2"( O& P%IZ&eTX6=*K<`(8[{[I2'VV],A@Y*'Q*'O(:}?@8}0e8Q)O 2Q@]/gdT0SRJH `x !~0Z!P5+Yz@@GFt(LwX8 ]`GJ .$6F@ZO1p L2fs@cX +k" %f` /HH&%.$U4= *T0l+Xp3L@#H y K.(i3**$S, #H@]<ꀝ Ԗx)H!hRI , P O%@Mx fU$^p4 -aF@82 IIg!2Z.~, HTT%2Vp S2RH@%t$u%Uj HP$0t@) r@ffH@Ҍ0 S(` 9NFi O#Q%,i20pIQ ` AV8 u*ReaSʂAF2#`zP[{`Y3HD0 BT K(UCl) >p( &3= F~r>% `,%r^Au( 24I!Y (S-` E娑xsT 8K 58B29@DΗ5GY ĥ/(, iKHek>(h|4RBG]&!JZH򀝇R1|Lӡ}ŸN^Y@2T)T t-)JTL~^p^0z@:3**ĺy@%+QL@)&sYZHS`(Qs88d0dD퀝)2 #*R\Bx@OXT@`?|FjvU0dt 0Y{ JBrvqjp) iE-z}Z=|Ygesa:dd`R#BsLH))3#XartJgԨFJ"`!y@)x uO,`*"Df8T 5Xry(>U*TQ>M魲S%VAGezfʮףOsX:sj뷮UQ\q֦>*oNbmcXԀ>[30'g?8&FD3@F"fMiLI22$!1=`O A&jWI@;mL0% uL@% :Ip)u /BıH )B3)@H=Ffpu' DH:9ϤX9B٘@LAPqF2@ȉJ109#B\,H( RB&XGĠiXmHKiHdA0k0ѲZJUn$#ϤP V@0 3gda` IaBj:4O= SMR44)P=Ĥ:o-}0 Q1czS)&`s0[LmE eȠi;}^f+H`.eDNGpb'q L %G@g(_|E'Rq@ƥg93/Bgf( 1$ӮX2 QJPDP4%rLrPF@elDah  3Y׃j퓎 & jȑ@Ld@\IBӈT :F:HLb  uVp*c`- cQ #qX0wSR}X I&RtG}#T%(p 7$}CbI08R$ !Aԅ JL#Qd 0,2% c1CI%Z?d;5$IZ4JJs 5y{ -AZ]R@ 85IpCT&D}PҘ |f$gmh-:U Zp(%} ,H r0$c9}?R*RS?8PRI(dRԘ9}S:bI:)`p }\ ϧi9' @@aTee2) 9eH9L˒%@ iHLK! y/   SVr% ab`j+tH0L1+"p1d3&Sm `U>rE}&Ke/z:{m~9iXP)3JPRQ$X @e,LcPD8qܐ@`埶&J*yԋN!> Q$'='AAVd@)L :@G)HNYơB&AL@pU2&x sL@Ꞑ *sP 2Tg (M):IOL.!e!GِgB"dp夒* `)(Bc#J 28:@@ @'"GO3R=܄R >Ni`N}Hj$|Xt2<0"`ڈK< R̈HD*EX0rJ$5@H` |0a!%{ ,Yg(!/ sتջ^bʙKfHIN9Lŵ6Z6/KWjSjbaE0n+=e''wk*@:s"̝u30mO Po[jiyPCT R3'X w ܀_~Ya3+:[G4*V(PJa4̨!29;!C pLʬd0e"J)fZٹs2AMwk`m.* PJơ< m\_Ы 9 !寨21X$0æp j~ž9mUZ  Bc1 `j眠E_XzjV Y& =Tӄ){Let0 LER\R;HfPk-8Q>&):U>=ꞥDp8=Dz~ wSDeS; 0}$q@HӉ#qJq+ *@s.=%Bw0A:M&D ;)HN0 %@SȟH ,I)&S^&^uLT㎥\2JR"O@cvܫ.Us]RSx6zH1%P A X"fp BPމSB0-(gHIQ29A&4װʥKN$<0xmGRT¥a,458 g.IQ#w*RRV8`z ᇔI@Be<|+R$D U`dA@J)p$?ͥ*RfD$(' I)3"bV@3n"a^0gEH:JBII2T<`,0jJpN>Dw] u*qd ,֐V< #]FqܓVN-rE.Z &IRD(`:MCB$@W+SJR*eLPF7BmY}+ S 2@'f|Y]_]U%u~f ;rq)B')@B*q2"?d4'j)De)t!2{redxz C퀀T:=! yJH #q%)$pjNrSt7eGId-&.@Iq@ 8RI,6MjL*udH( Tħ*tt) &dQZdWR"dYNW48F>@dqBg3N_@aSeE8$@ Jjd /fp ZK#̃=SQFXO^0$'Q3%*2qbitiBL~eC)gDH0` =@ϮP4̩} 2a R]()8!B8$M2eJDG?`O2e"2ʖfi7KQZD3?|IQ2y@BIyO@ʤR$a3/zԕH2`#Ppi8@:?|`!Dg4̼ AK tJJ20)dI UF p'9p3-)Brt>% ODi`SmJ(V:p jR wAm(L:G?ܰJdRzfԥuH6:VWZH$hp H!Kz @H\R8 )lD:d@L<'q$j!R $$9b?bBDx\FXJ]?[HOh&@H@9jRVb^ iQFuDa< &rä+2VL` &^%t}T1?VRIӞvZ! HV~~ESZA`@m)e3ף {?p*9LD`r`#&J TIJLds0&QRHy@1X )=-aj38@G U)Z@ i*֒>p >_Xvk)}M5WV;J]WPjE7q,͵,O.km}vr CiF^" Qw+#nAzQPYZ֡N⒵4;H&G*Yg6=/3yU?sICT BDDQ$7lWϸf[)gT*T <OaƟi SK@Z'%!B`#?Q۶MVnWvH>`9m!0=YʍvuS<*n"%?Pڛ6lU ]s)$n@:}s-@I@FZN3'0 K3@p&}!Br)T MI0”T#&rBbqT #GTky5SQ0¹LeVGXkYӵ_B4 -NFj)@)3p@H?S }5I Ϥ)H)XN-HV&R$IxH@8L30R%Byu$;R (]+ٵT\\Kbj /ڗ}eFe)ql)KSDlpܻnK咚jUԶ[&X w~m;iHU)i4>MIp|SػT 5zp(ifN/uk*qH%*}lAT;Ţ]PnaL6$@fZt̏di%>pb[@+I&piED?)oIt z )̦+FRL['JRJzLpی "Vz!:8!$I8;ih0M)HI\RVBLaD ^0)TBtd&}P 'y#PXNεgu傔hDY+T@]u2V2<}wp₦te?:W0P jFCTjvӂRsQ@yOkNcmZk}/$kv]`.ZUm_ٱm=hE޶uR(CJWlV8A0k@o𚻥Ca H-+lJ*Rfs3(A8@zA*'>^,jB]H}NTWTAKj"s 8":H%iPx`$KjN3p ~ B1xY:` Z&>V5 =p)"S'Q}U-,%8('Tv"_-iP8e?P{c%A*`eDrBjN &>ƣWctZk?4:L'HS[WRxхiP ?.R`!gwJjZq*9U#@MM?*4ˬK%r4"`t3KmƫJ`h}LQ_SJi>23Rx&n6@)_LF&Zo;u:( GqP$5HWWԧtzUYJrӗ/OE.L4NFNqS/tѢsXqvR쵩BgJd2/s:SSOd'@I=%5_Q2T $>Pqh!] 'ZNSR(3FFs2XO1 :8HJK JdjWMSn$d/?R<{bfStԼ֖RNG 6+_5lCV;Ka|&DМ AJ)&` )J*\^׶FTjdS򭳁lcoBU٪N9NP_}Rm#+E pWA˛po6XAHJ? v{j-r3*Pr&pk}Wl qrMnS6(m%jKzcm}..r7)i ʨZ}df`:3[*mTR*|-+j+N6l.tv~ou* Ο|:@nM$6)ْ҄p䜞+n:c/)X(JNۅO? N99WQq5͝3IX\Xv#0ǽ%i[npv*ڱ l#^J&/XIRh/^c8´DJKXsz+knm4;pi0=l;ܷUڙ R.GZ $BGNme+}ܨRnpBJkko1ezThFI'fd鐀!I^L,1(@s~HUDdj' JT0T&%L*g< %YTfYˀjW-== P(l(9 efq8qGR@Wy%N45:L9ղDV)Z#-o`}W% &z?lom쪊}ub,J)29SJ>"IAI2JH8+IBjwkja sNHO^wۻln}zݼ}Xm紫됚,Ё3L^VPPiu,JH3 _lܐH3,Ok\@$' \(I2>@HLJ',`%RJ} {`Ii 'lꞁI٢~YV@ TN M^]ԔSs'+HJtR*ZGnb*MO˓sH_Pܤ! I)( TR?9 IA:8Α48 ӔIQZ ji>pzxL>< &BTReιFuݶm*٤ܮ@) &Jm߰ niIu'Ljeh[Zeb ifDM͵{/̥5 iOH)@[謴tvM 8e _Nkl6 nHq/ VdeB6ꖐ=s((WlO:@&j4zP @I\=gQ!̰k&n1<) Zt8P@; @!~緫⒧ PI3p1Y eS ?lRJ?( IJN8@J$㗲R-_fPX$tdH*L t H@@9{({zI%X h":IA~C@ِ[$Z2Ƕgg%$3 `!- Ne6>&P0S:aͶob+,T8RqJ (쩼-4H䶞a96,< lMzTm˽E[ڊn\w>YkmꭋV׵\BGaGBC9JO &XHb-{eNR7ySdc<m{l[NV6TR=[rC+`$MS65ϸh|+wT6itm~ nxMD5-`c},5mNDT=s^h%C4'҄L2OUcw[>M֟q* +m? j^fu)KbfBGf]vR]mm:Si3beYh,pVy^`5KqӘ3st*r Q?e0ʊfŭ:flųEu3W&4=T!ѽkAe:Yh7S?(.=gh2⤠JWGεsݥD ^ș _3B>w{Y5;^UBDTz0R%g9|)d}#RtJzABp*%f=3i@tt)*=$XGٔINOSSՔ { (Z*KE^l@aiJB߲ԠLV*8@5>iqjm#Ҷ'9=>ٰ!KfJJT>U~c8 ۥrnH4&ު@Rq OtjjjK[zުV3=ڵiJ*,6HϤ5q6QA8~Q( Ӽ* X*^K@'g #H8Y)#nܛjq!_&ȒYAd4 6xڤSZC8 ?ˬc-PZyX[.J20tێwe2fuuM2rNBW^CMLu8Ւi S13ɶN+&k8[n)" oǬ]G3җT JNH`5M>dړ^uԴȃ!ϱ{A:k @Ci2i&`.{IS,ד, w`&9636\8{˻ ,TSuѨ~@iWEp-B#Oؑ[No.)t 9@vFc-et-2_`$_0l/6c[TO ӓtrү{ML׍U:Nz@Fm/MZBMj[_zdSp/lFV/`m²IT =kG{4vnhL=E$qtu;:s9voUxq@vܑJR?X^ٍvܙـmei](jt9ii}S#yh?`-WćyjJrS`E=&e=,:^~hFbiFٳ[ YH%Ũl>km ~ߵQҦpJIt)zaKg⃷Hp⽼HӪi(PTdU2% 1/_Q kn~iR-g7A=gRwt/@hӗu4[Ok_V NI|JO [S.]OnT(jR |n&HpI9aدm[stߚUۨdt 7QZHӂ?dțYNvꟸp@n2 SO,r %c^)"c7z:~,fz꘨39eT]m[P3::T @ <)m*7VE#3*o(Aƥk-rRwJb tKu/7ְ +~Bln=UOV]}m6YR]`6n%Ng%?8 z[خQ[Z6WYҢ:)u71=%n%]锩@J75IV*7Zn ]FFܺntn8&z@x\ٳpڞSLaԔzE$y@hL6=ccq+*/ &%`, =W[EmP3gOHfZMΘC3`4=KQn;]_ө()jt:Enc 7U W:y?!i%B#ĺul}Ֆ :C*CE`,MY3o\H[ly9F0ۯ8 ]Nx` k[ZcH8+~ &ڇ$zw`8赛1 S׶} |d$pܻvݾOq:DN 354`'<8[m i K`$]VN$M]-uKS Q"ehߑ㶪BJ>mji 8Ule%ͭKhS A"S&xe9ϺGu/e#úcL''YdL.b=`iKJ_0jiJkILlT2wZHb'`/ S Zj}=i0hak:\ee5/{qn+^eU)N˶)L m?KG04Ԥ )6SN_l0 A3ğZV_?Ro4$N?Uu3S,_LfY:"='O3]N}%%~`VӬ!愌4 BP}i*_g%-,@ kV@'NԴ+ i3@r8 5+RiT>0F㣼T\m˝U' "|ZlU4vYqECu eO$,>@Ww傓s8P  W+yNTgRݼ8̜RТDPJ - =+gUu["@e%i3wmmp3Tu6[BKf J^$ALF]UUWWl\mv.6G)cJu -RHJHԣ5Lz<Ģ7U iz`TL~jJJ[J)`7L@\O_r=ܥYxlmԥDbA0Sm(%m=@U^DVޞ.hܨZ[)IlL% GIs"]lIB?`6$j>0-M) ) bꐊ10ZH8x8PV)#y&L5fs3STKu.!HqA ,%hXZϔ@8:LDr3)2 )*L֟N^ SRdIg?h/V 這Ae-cܷ">N+ Nf_[ nVk)}R |2[8pRsB_gѫ,"XFLYkiܬjeW-ӊiڣl8}w5UŠڻtj xHm@j;qgnq4$zBFeS0cyazjC&56PJ@R[cAOI)sPeM6y$sRngݭdRYqK2? CAdHdFt ס VNCbzF1+qJ~( jq=f[8ËJU9%hjZ։3.JbbzĞa jZtP4!BHp ROYHX1]bP\F kNV$=@[ZHT0'5 lh.$OB%T!%*BHi퀘U\)%)L3P Lеc9|pP&c( HHs?l S`*i/,i I3 ?!ardLN99>PX^}' QZzn0*p >Pg(F;˦Z9zhmJksiXeUC@#s^KBWlpzVڧ$t9@z g֗%ɬ HRMNu5I׷ IVzt(חy~lY-uB:efZĐrt qk T#Tӄ2G&dn+B9Ë #PtAKt[ҕJ")l@mVِƍuv~mw^˕BE% $a6S)֠hS?5&?Nx${ʞSv4HϬ4]Ϳٶ=Q[l쩚d %?WH Sxs-7k{ urMsTT_J}`ʸ {eva>:T_/}1z||`9E`jTiNr>۾{hFg,`94ۻoҮqIM:'$B}F"ӏޯISe  &dyϪۆ*4Z+kvQJS#Lj 7v7(o;=R R ۩;jwY.2uR[I$O@gTH}۾SXm\҅bFxNq %C-**E:ƴ2Gʕ7MzJeIxFN^jXhޡķZJ*)@)`=HU[UsZ3|Pꖷ{JH-8+cwVֳ0++jH}D#V@gø)6ݱm q~:]$v(#w pѹ-ӵ z"ZV3D w7ӻwJx€(aUԂMuR՗Hq6-$(AXC$*?XIP8n)L񌓉??i2Rr 3Lf)[2X1 =C+*Ǵ՜չ{Ԗ]- $f=ymT 5$:';p!)y,+PqѶoP} ykTs5s?{#bZo;-9PÀQNHa6ӵYMfW:֪ v[uAC;3l2$y Ya mJmnJFiXR9v~E8$|PۍVҰ^)i[渵Z)MR4 `:',%)gfZJDPem/eZe|r^ {plzM}!ؖɻNS:hI%v5F[~`Y- QjB3'PyTzRΆ[{!NaA@W]l٭GکNh% Z8 Dݵַ@$V5G8q]~P6v̪S=C\B~ ~( vץV6.,jnL^0S(wU|?6i[jiU%]ՠ+_D:l:ۻi;s;u/VSVL -r\'e|եV φ0mjvŝ>Z+:jI@0ȫERj]AZd{5h2p3dSIg\i"bx=liwiֲ>Z3&g9cikEb6ju"sɀ۠%lZ[xX lSUr>msIeUl ND1δhܒR"*QK!cm;~DuX6QJ*RGpa{l\]dZ>K,>Y'ԴK%x@swK(oM^-z(8e)j+7^y6ajO5 ULYVCwTI~ a[^vŸLtȘ7r olEv 4gfOL 3O`6+8~|ch\*TULJGu!I zS_YJT Bt3Ni\;͢k:TȘIOn\\ٗIFܰ- i^8)/^fltOp;VdBTLpƒV* 9ߛc4v$T>Tl< .+H38@uz}jnq'ᚄ񀬫u7!X}]YIOj˸PWx}@WQ[B0!e l؝%w2^]EųqTM=_Ř2oR,nNN'*%ZN HtbO\24hԍBۺ4"bjtt@TS6V[J&FpǦPIc;2]޽NP @݅!樷[AK#m}!+7GBK[Z{XNTBS-)8O^x¯6N:[*YՊ׈j(&P,wvZ pL D<Nۢ@QR\]> q UYWٸ$:3@f)m҅(j\qRqz#y-Cj*kHhhuhpB=MKc8_#>'+*&.>TߦzTjnv5E-Ը5J[Ir%JK}N3:.?ߧ6n%4hn" z8ݵ,[w6fSOqxG4),@썸͋Ԅ%8^ܰ6R(56Aΐ]oMX52**RjiJ¦v*ŶiKQI}A2}x=gGcz4PKTN2J"|vmB>UEcqA6]v"vMmԯP!HV<5Vʕܣ~~iCJTuMRiz>OV~V{f_NE܅mVTRTTY$D8KrzRRT+&d'/2%>oӿ-m4IR~+[IK$$3^ʱVϿ6"s&e?3)8 p@;3ݼR[U^,2\"Da~wm{V]{nfꥆ :ʊYNKCHڜ/#Zyr{!sW#tIj~@P;no:*Ht%”P*䝧MM#\bVTunF!*\^w[+-gR5S-gϫgS=iTUu-Qq9R ғ,8`m+]7,Z QLW) ~=,N {ʊYoSzdI֬IR`` 4 n<`߬eP\]i=4@K 5-nzsfT(r]źk)P 62*(kj_͗MTε])D)zNHۏ5mtv\,Un8;;Щ삖0q%9'&_~:5Aڌ0ƥJ@zK r - 3ٻm} h }*7^RD )J@t('wnm*:SK+_V;w|RGr+.U5(Ol 8L'5ve|l[EkԷ |JNeЈ>Y+vRmOK7 T:*Ht$`ޕ@zj؏Vd]SJΖ]>Qa?WZuz4 |IJƨ(_Z¤eHPP)`=M8ƍC𸥼\C.fz"X$c5AEy:^>ZY+lr3JFGO2ǚ^0uV6%w euJZ֕ghrzGJzi.a/8 qή )j* 7,nƺ/~PmJHC՞ag(GV6&W= =u2cfrBe5?V ̻Wp{#&ڴUC!0@S7aЩu(l4nI(JVu8愌5-S*W00D$` K01Q K<HcBB@^PwgT)Np$%G}'88K⟶0}P bp'yiR($gP1>n-(Ws5OILK퐤zA$-yt.EQyYEu}]2M+eɲEm[qoZR0 3HH? R5[zz5H#{Ïv^Nrlm--8<|6!~*R)_ۅIPJglKK sqwГhiQ( M]iN(X ɯst{iBi' 5Mz;]l޻hZ pܭ&Up۵`CmD9Lx[wFiCn.aĠ2mr%~wpftSRtZ6Pd1 öݤ8O;qmA,Zۙ?H'\ hLM^U5ݰi)hˤ(QDr9+BOc1c5ky)Ĵg<pPުQ)IR>( ̥.ǵ&J_o4s;/K[.U-pJgs+)smmЗ s[TLYN -m;oo;n4kJ͔.vqOZ[z[c/}ѥv5d֊A9 *M>G텍_c^]R{M]Ŧ<ٻ UT,Ȫ uvsa:g> 3=PUx_7kxUHֺ$.y@yv++n@[+J cBӵn6= i{sm*XJ}erkm֪tK{=Z* ʲ6™`PұJzk)vjJ~P+3V2eM52Rce>29@r ˛ aivua2b/Bkqۭț`ZuQZm7PuHM6͛o`U9$,1Tk8 m*ڲ82jE W]BfkCl ColjiBj=MB'|Ԉ}`9]g[Zٕ%Mhd|ĔYV)7#ﱮ ҥHd*%KPJ`gt UC>| *Zͼ֤$<)Pӱ-T%l1k8@g*6"bL~K6ʚWf;wfQ&Z:@aq\6u/)BDĉq5Rxx"\(jfJpL 9i||UglS_EJA:8N-W>U79r+_U~Z__mRܙQ+=BN"e<ְ2-{?{F[O)Z%8?}0]m}-kejPE$̼Pm:T6K^p@Ȥ^[&SMVK9"p\-! u BRmiRqeٍi-eiPil8&r: ](tb^qn&u&i*KY@\;ki `r`@յ4;)RP^x볯lfrEJXq *%;/NrmelMMPVnpPzpE;TKi VϺ_ 7BoXpzS=:lF М5S%O }0˲6Ύ^RS4GFʼ6'!Y7Onjk}Bijکe eHӄ;رl@uj*M R^ NA0 w3jn+kH8THzxiV-N$4à: 0=ÖgTC5 ԆANǠ5qhOѽ3)L`4^=΅]yXtYUsӧu-Ur.q'*H9Ka.Qi-ݓ2@ϔ0{T7=eU596*Dd(cQa[h- geTUfsƟmUvM'iM\ \y n-µjUd>cn݇jN҂h۬m j8 ԌmJʨq`+IMfkvv_-2eN[ʍ!{pd6[_F*KnD@0fe-?HKe[W|UUηɊ$@nYǨ>['U%٩ԀOz27 fqzOUTbeF9= |Q\6%1]-¿ n#P~= %~-]5nT[QSR^:&L'npb_ 0qԷ[WէuqI߹GʕGD`+xqM3}5mVR,)OG3*Yݜ+)Vl:A=%]e$&a9t>6jk! zj  xOq`):uP+BEDb= 7+DG4άy+hj,5EBULBj &G&" 8]6m-dB\iou'>~m9w;jꚥ~tH jiJP o HߒB,e-5vrι*kZ$%NY@Ax-gGaBj-RA p$L6mMID2[hJar=yZɿwR So RU- N` ⋛<{tdR-*ZJV$Xaߌ6ꭽe;]MUEiqKj>;JJe$R:4h͑Q}#内CN) :ROH ޏ6+ RZBtO- }{d#i\[oK-jwI &둀ScS]G&r TN&iCgRxm*tw܍VwTA?P{M[!rV3N 2DWf&٧[M44kQN8 GtI{U^}VP\lJA'0> ֓V5, '%={q1oRZ^ZAriV8m߻2.Sm/oǵ^RQ@zQZNS#Le< :kзPI*Q{G+Ӭ#v ĿHH8Rk!MQn~rR͵SɶD83TA.3Io1!JSqQhqe9UU ܎TpXQlFF B'r +E. @Bh!ENt.NC} )u[MĆ' 1?E#7)PO$|4c? 5Ν5k\XmFvË_Rf(b G)IKZХ_ de8 c$B-ojmk(4gӒilM,TG~b%rX } ڊMu9\ibhq£t>rR~byi'%6,'Y%ED;rՄe|e_ LRda*@sKNK!"SBAX@b7uZ6J]-+IG *>$?쭱OvvZhT劄^k~mϹ6vU;JI8I@vl5ZѡhQ$?(O5VʰU]MKBr-Mg94 l(Q9F's\N,E9xjYhe]OLJlt_ցy|qwάOm 3H bսl;O1i*+e !($;/H8 >+:+^ml!{evRH,e'׍xRmݽJJEPT7ʎ;,٨д%Wl2l4E3BP9I厇 $^hl7id JׄRҟt~;Njw:SUYRԵ1NP "yxmO[׻vyMJ-vQ=3g83[dmKe-%ݚjex)@z<5Н,XDa)$`0&em=8BNh@f<ۖr%14좂(Eppҕ H(G(I.Ƥ4eg6 )%?jp7D (6 d( v`C 8/\*J@t珧tܣJz4ev} mrzԵev ,u0Gl)^TO}?쪄vCH/dT}:}InƤ \ud:Rd?n-[HOrqk /T)w*qiDKIvZ틍I]eԐ=AC3[k&m؛9U6ZR}j*5H~5(1q̵.jt8[gp |gθG=%V ?]jۢzJB$ڥz̓6~ЫkgnaM>An=L~kø7 ]\co]XiF*Q\5!^mmʭw];\ ``=->iu\ ᴖܹ̩r7ˢkT'@Qj|lxO@GhPI]T&WZKW@|_t WI=EroOp_H>+: P?<~9izF7Jnإ:+ ˁFZL' P/meu:H{=Em7 %E4ZnSxv :m0ER}n@JS9x@f݊Dq[|xU٩.ThqUT),%֮6r6C;ąU0jl L)9*56{&_misZ.5% )n );cԝ! 8 e"_ME/9bDU;ݫqו(\-R7XjbBJ8iMɶ:RJ38ofйn5+2O [;R=7o o;E߸k3Z >&;whvhx( y8FT KJO0n9z{F^`8WvY7g?>x'f`:[oBTť`-(ogd #a9`ފJg9Lz:7&Р0PhrZ\R*hR 9Ҹt%hj_r~ W~mU&^O뷷i]kyʖD |Ҷ0e5 ԏlK0jU~x|SpudsM~PZ,ֆShuIUM,i =il [lL4#Ul n=*( A,`9kS+fEZizo< ӚemC5z9BC o6K7`0Y /S%^R7W]cJz~l S3?+&aښmy?,٣ե ժSr jwrgR|h6n= f綾.ϥ6}Ei)ZyZ&fz@g oN){G@;WlL K8Nr(F>bu[$1IP )rucMu<;ȮM7)W!DnY_& EliTduKX@NrsNO'ҫKXB-3rP 2( xZu+Mo"S ͯԐ:bgi5䕓Nz?@q̓ǜp;Kb;n%Ia$I#;)R\&A%Vz|r_X\Vx[y!2ZU +Ļ}{ ^T.vRա &yL m*.Dt(/?Qiͺ"u9'>3`2WضƗr qAP:JA%*Bq'-8y1z>jhH1%{&.97Ҥr8! mhď_X |. %SbH2mo7^˛];dHB Om <ݽzT+{GrEۣtS<  KJۋs!FuO)x }Uuc]smeU lIЭD\G_0M~cR{[C"ة1[lj9CvY_"ʝt7lCJ-(/ҩd`H [Nה(Q EzT% m)%)I"^ ě{׆w3Im@. X}@R m hZL9) K%G@yNڵ#>! %G_?׸Sx|׻j7*L|M0Vi%S.$YԲsM {=p r IA_&a#4Xck8ӓk߷ SԲ;rԙhq%*eؔ|ҜT֔@Wx lƗܵȘ>.-5{:g?N^_C7oɷz]2gvdՄD5/1')-)65I$ړ0 }Ln4FP+,G c~'s,!Emu)a3@BDLb e9-X!sH@y_ֽzU{H/3v+c ;xeՅ^~b*ssP':mNdkҒV׈& :ڶW: 6?dJR@9+~ݣL.r?1<* z'j\&ҟ %$*nڤ<ׄAy*x-+BڏOg( NlgPBQh2҉?2\H{-J@hNkasBR;v lz[{EO"P!cEԟgP\r{bJr\+LoIBЀ~y@F:~gmDiSր}|ʚ?tPdYO9@R<}Hay&ںJB되,OLI&R(@[K %L $))1( T'?d%g`?e %"S%I>iQIFf Z4$S/1IKQIa '$JJWҵݫvqMeQF" 3sѨ)gn+$pJ~HuJp | 3(VWu*S1t{2}Tζs!ꀪ&bD(ʣUtr/T4tlJRҩ離T ͵rX]KR(d3 ?am*KԌ!, @64~#].-̗T)HI߼9|[﫧]#4|Mw*ȁoݩrftڕhj :u%M/GY 6iC-$bs8b{n׹7**Hy*.Wrn%`d0 ۧmSZ7YO)@ig wmAnQ@ ? R'RtiʖV #`' PP"351Is% jŘ [BCR%( >]TK ?[l}Z3R}霠<~BNV kt][Qr[ iQ@BJJ-.ԖiuT ܒRHAvȶ(ߙmmr230p03T[yQNYXRXR M##I֥oO9:)')HǤKJ}Yf@N3 [R^اhVd1fVa4?( 28(9eM@sVCC@JPF @ 1@qe$$z H:4D@8AOY t֚:7aߩP]B.WqT^.J/JʞwJD8&Y Ku**vn<&.^pwݥ{֑6XS.~e2CKkTD8 t ?dr&Z1F/.0:q* A,+ =ڎJW]F.`/Rrt eY 5g6E[EXY7Dm%SBZ*d:zmԑ$|)/: _m* wA+;(34KJmPjVjmҀ淯~2֕&t*l c(]abi`BD}AqM4t%T "GOK4^RLng ?6m*~N׈0 ...M\LIh֣ڴ]JN=0XUBU$q)R0hZnpH| =*֐j)ybC^ԭmZe*iH(yԐupg>5u UFoI r%! /:Ǡ7ȵحw{*wcHRҹH z$K^ #ʖzurfIz FhJ N2%3眠GZs@Hp#BL픒'g$̤@p $JGFR":@L|< M)<sümԴgl^S IS@mIWR1^T+lnwUm%b=qVHzZP1M6-ֺs_*)-kSiKe PI*PH`:Bԙ:߬yv_,IA1D5j$tƉ"~2vT$!ELӬP$2{`H V* ' >`NPx@ Pq`XldI#3 <%: e`HNL5g@c, !3:F |v $P $g8LL&%?vSٙ9Rr"G`$$1"c1|݆N';jm^T:[ L1/ik"R8)7ArIc$Be)@J:|<`" pE@t$Pʺ^* :@d{iH($F06Ǭ))RRgsy%0dEE2N`Li 8  r $C r"Rf_ Y"JNP1?/(IϤiDI *NO('P&A4:ANpՔJ  x( 5  Dc8Iғ% +L9uuyT>IjXD{#QR,`<-_mkH6)PP =`6gv ;kI70ˉ9zS$Q' d!.QlU\P6$']rKid((f55T20 @Lh)@4 SeIȐF< L +L1eye CrdLp^l*0$=*rO)) ɀly$>Ly"FiϤa Q򀐤8J$KN'(C 3@5T1@WCu4 J*HY k6kx:׿TmFfeީqzK@Hd{cRFj fX K  ï ̞UAQ漗{fJŶ?퍅]Dz5wLQ#(GmOf5 M0FYBD@m3@6 :S()p>'9N*bRpYL@-)$@FC9%r }DJR q0k8 @3`NH2H"BRh %+OC0 i+% -Yds]s~JBmn,S;CiNR?tڱp|>pOWN\ՆxUP:9uQ_Pw62^Jz)f{̖I<"p]:acͤ^ײTtJ'Dd:`UdpO}xe/a@Ca9{ O Qo LM "SsDɅT4:AK2H^*ZIcQl(]pb.JUM])@)j*ov-iLz6:$bSGwGë^XnY{y{BPr8oe/rM6{ҾZuر!TAѥ. e$:^/Wnn1k46c)nYPԵNpX'`J 䕏FBN8y t >@%k{ $b|`>S~[!GV#uPAYd|0Q0D5dgoXn~@T*ґ]}SްGpx<@XJ#&Jtg1!@SX9ı} 3y Z@F`3i` 3}35)?V <A9^N] $e3#VxITӎW4JDO8 @FGT>-$N d1񀘣I$dI3d-!#JTqIVۖ"(p#IP HՑ25'#ih@ 3SsHgStxp?œ@s L&^ #@"@<%ʔ8%0}H!,~9Տj@$$z GF>8,IK@/HVy-:r#IC8LS:H2JJ}iJL2$i L 0?)g)"aG @ $%ħT]FW"Rr#%J)IRHXf== $i"sϗ儠3N}`,0 D˙(c3Hq0 'R2:`RnJvGz)[%&bD:`1{Khvhm:TY ӣē2Nd`60@}g3!)̟d'@7eq>@X~ 9@CzC( @Fa@piRq &F@L BA2Q9ec)( $H,z 0qlH:=`Ie霱`4D.e(J`ˠ T ]J^JJ+iY9Q&C? d28@E0fTA Np )i3JR>0 0OpL刀d yd0\ tMZg$G *}2jT MY@DqI #CH%bHxR@3> $"Iө#Lu2` t(DJ ?<JxO?(S~Z*^P RDe(%]$|fPPQ  D^3KiSRA"^%(uId700 O uI+)PZq#8sS9a=|$3I15y$RRX8&&IXe"s=!a( |P$A̓RHp]J2Hđ!YN H 58 $2\1t9#9 3 AdC ;-$uN~0$ |pi"#@R}8>)B +ٌ90̩9AZ1Ip!. "LP gHL #'L&PM*=`IጰdӥTTWQ@$RDI8pWPF ֖&njb=@88bs)INX@FVBd:O # %tfQQePNxF0wu%fD@JƢH$̡GC #Ul JH*<0\Ľ0 kdIJ3't0~(a*yեIZֳ$#IΛ όy+rO]Ca$2(^D c"1ìj"R~P a39#R^}jP$e6HHITe#JJD%z@\""i$a,`k3QHp IգND' <  Dd Ҡ}% NHkP*LX ԟ`bpQ@%%yO^k HK+ eR#")!Bi:;c &e,I9@ (`S1"ADCQZ}*3'/(JNfgX Leؠfgf hNp9Dȧ THFs2ecxZuL J**GvK"y@F%Z%:&B2"JOH!4Cx*%:N q-4H>!ԼXf1:\ @rsQD~%!x@DZX u&dAO}LG<0$ 0IDp5"hksZ !d7IC IYӫ,@BJSV/0hLH*S$?XMKi4sC+I =  Z0$ubp_Etf:y@GؙĈ 2p- >Wy},D}Vr=^:idP :ZԳ)j!74}8Ē۔3OZ|`sO $Gq5|SJTɐ_|iR0̠P Jl0H%*S5P$ (ze68 Z~RVj= u TH`5 uacNi>@1J硽2X !FIxO ^"D. @HF%95 9@RI&08@>+bz@H!#P1)^p 3)HN8QYLHk' Ac>&A'0X 1g+#D9Ϭ~%d ?9HS9a25"z@8358$ydj"$b #`r H3*LTQ40 @8wtkm$ u5v,0:iz/]{+el vXmR<>mt,qACPKeoTZJTL{˺$$H8Jt= a| #Pd2r}^%+(H,>Q D-O @y8y\H# H +ѨȓP"6uW^ԵEi+nZ1n]ް9RIIWRűV8iKS,̧*jEm8e, -<}Y M`ޥ u'z:&s22ʆX柄g)N%<A"jE㓚T(S+ a? ÚIPvV0<'"ZY+Y@Y#N@%R04#%fUbОH`GdȂ0= &IϤF"3_QILF3ex@ 2*@ `*0Res} 2 PIA2@LRA$(IHY0GIw) j Nf%/|H8-xJ0 R=FG,aX$(Bs@Q:@6%Z~YJP(d%k{mRa0\8 $UҐqӶ+TL'u>O 3H*ē -[٫RYTMd0sQ:8[$L@n$%GH*l>MtFf0A n{"’0K,\ta<`3ZFh xxHV(HZgHW@-= _QD!^WIT+͵z@%6d&< !֓#1e"VOd`$N8bXa8$ :@F}8$D :@"LWQg? Q@al;ӹSKge[3wӜ#nw e=;9ot4Tvbz:[o)>bjp"_ ւaa`OPU._qqd̺R|,.Ht;jENN$#ؚdrOMV%5yB*XmH֙>bP0s0F L(8 349KIFIcLP7!lJ-kMᥩyui24 b':xiܩ+ZǾw/m>Stm%TURke仅 vwQ38@wMVRm3Q]ZeS, bJ0N筯r/r/|S%IABGv!Yw@飡ulT|喜@uuaɛdMn'uL'ԵȄ'5@mV-敛ԿHuL2:ӌ0fe$gd̎vߜ;AUJS6 TR:i uHl=^ٸ~Xc7F͢]?^;Ωũm_8{`7unU;̟mDdL%2`;m?&ȧ8JMehG)C`1rͷ(iJ˭5%iX nw66P)) : Ldu$yczL2aSJpA$ 0 `$8 .+E_ɾ3 K8',_l#lZZD"J~Hzzzd?uJ"OpSNxomݰ)/dCHJ*(.5n!MXkpk:eW1T_q 閴nԯ#թU-;T8^q҅8G>f^i9LM}FQ%@ H@N]`@!'0 >Jen;).ܟ*NiH`3KOUgwS2}`1wթ W6B$9V!?f|)#>^ݩBuGGww!=Cޘ@2-ϱnn, wvS LŌ0JS@U)3WH ⩅4UMceR?Ϩ@FD_ S!9XVwv^%iYEjep1< `AW,줤!lԔ$L@i.#m/m{|EK D|7m*jSO[5Wtg(ONX@}->~_]ISne!z(UIx@9Gr"L,& %)sa8g"del=ntE 0 yllU0;jC) BJLe%FbXg$DPFL3L}R$xՆbS% N,RRJ%)@89 #PLpbGO$ #@2iHA$eP zTژ*Z,綤ËTP}V|:. RhgR\lMm2)lHp )IDy`.-h)'"0hJ'9N4(l5)M\-@P4(LyOmԡh!fj|2QԤQLI*sdiT1@2& e2##үHZ2G I&g@+JSYXRfx0NB!˨RJ$tj -')A 8K*pJIH!C 0 mUNR| 2r@t@FmI#2d0ǡ9:sY%FBS,rR8u RS`Z4>=-yB'?PdP!3`n~k4UNR&P|.gP?ҩ™KH7O{iV~m@$xltp3{i 2jIT=LuZU;n#Z%7گ墜JeY<[JjcW/M,TСPhN-e ʾJXU{ZILI/cHЛewmYAae!A),`5(ٕk.eJ){%U?AM'I[22EӸ P82LϤU?d!W iUGZ9R7\+FPJ2@B I^i?ʵ @GJ)I.?P6F黮R(+wҳ*Cc7hi1P0+j.!lmƒ7T1gE|[o}T^ĄÌeR\ˆymKf Ag5m [y~&L@1P8@̙$ /`rLi8#@~9J*Y'IwBJ὏ŗst[i?Mn n 鶶<[%پA( ,'UKjҿbV7iHNT |Eg >h}e>iYx-K-6T*0_+.ݛXQj"6b$6jyvf۰w=xt)-8Hz@=`>ުntMK y IϠte1|#(jBP gurB$s?(g̕jut̺McKthECBOOI8j<]kV?bn9juVΩ$uZ ORW^+h=S#v7NoTe*q!gKC[Ď+\Վ𩫣e:uA:t)?j#g\[{g[k[h@<L0oLԛC_yU-ʩu!E-P=Kb^ nvT &M$֍Jxmca[HfUt)5XE\J]P9w %+:@DNS.?ݿXk#lS[ RVڧi3T)pM#vQRS)G<*^q{Uylqy*Ҕ~0N8{.ն6:pkݡen:{H0 LfD0]KӶ)]r۵%,:rBsc}HEEyDOJJ$dbX|`ZS]pMG` 0 %' 4 jsS%0D?9~ۛzS]~FH\n8)@GO͵~TSm븾]UKmJkm[툭~5TÊj.D#k/mm媟pgn"@N[͏pBHP"X,:_tblP`7 @{OHmשm8m)fH> q5;ܗcICeoQ[Εx+fHY=kn@9T̺Sok;j,2"@ ĝ )JI"`)i{+r˸xrK"ƒ5-CLjbXup"O-7ʴۉ(u'K8sgܕ*Vd6JeMm=͞k4=Eť<ҕFp`w*\m$ֵ'9 O˩KaCL>Bf2#QdK f:J>@q][82Mu҆6+~m q49$Nӗ⧅4n-3A@^&Gҧ~)%=`P#%0![[wRp7YԦm7AnNPKp;~-|jXmՕV KE>JgBBʂ󀎡 X`(eDwT} #J{hpI9@2,c<`-t7%rMKZj}015K9 [zu6>#6]BԵ" 3P0)f`lK yw'6{m !V[PJSsV}"nU;KX@/$JA@XJ싎N~e2j[-kIڦWkAa?8 0'`|$R@J!$rs8(eJp$>c>oy$W*JKkpL@)i;Wno ]5q0S3RaNi t I2;ja#N$=p) J`5!$I9GpzQMbXb }'tDA*[`C3mD*acJJP#0H< Sc,?ē#.%"cfd< )3 @oH%&D}5x@)P( <*I4, uD)HKQcQN8JAN$SYfxd3J @}}Զ kJT4>eD%R(s7 ;bQ|J8I@32WvjlՊZ5$'v:'Iv$$8} e0L3盟͸7{9T 2Qm3?oH6O,X9ݷ㴭꒕zgH>#tRtKHkBggnq.8PgC1Iq%$ rrRܗ+q,&`19"ͺ.&[ZHb :$]0i0g>0[>_rصv٪vEcI/2t`3uXT'JVS&E5jJ+iA6iw>-7,JHsrͰ/^õmPmtRB@t8c!P$ T3Dr%vx 3 Q\l z ' \4nT%hWi9_ )R[}ơ]Pvi)3 br֓< 5.RyJ/[X]#?AO@m-.ٳlӭ[TliJR!3s:P($ τ?6ͭ}"MHLLA>0o;rl;&`9VFrH@us@12(:TJq % C{Qn 췆u(-=3_jw+mm u=BJ{G y#k ru֚D$%I[I$HO c`i2S`g(#QD@yjTp-MmKEA)f+tb2Po]v-ZS4EJ#ZDi,Lq+ :FC(FPeJcxkaT@x9crM*U Tʏ׏$)-$d(Xң@D%EhaI=Op>w,n4jGaM;ƚQTż8UܜmslJ&]틯Z٧@"3ˑvh޶TQܓAP碡%CRLͨN}"&OAjaTm*ܐ- %#H-XyjҽvU+7z5հ LvNfjGYH i? 4;~P3NUJHn+e%wZf24Wb,[p}dw<U_Kn/2{E@iGqBv̘ Rim=#jk)"~P`}JڶmhWR6j(tu|#9.ndfKOR6뮸ۺj#1sv7y?L@hj3J 2$z`hL&/y T! )X8%__]UzU,[6BAXԐf㏨glUWTjHIABT9]%i.۷zٸV4[tػ;n۷8WL>'ܠ`69EZ];(u'SWoڼ}~}ߐw+jOq%:BAQ;f%gqqo q%K4w%!V'),\mtaUz꒓״H2:)wWp_,>()uÜp*ӣv*+VSң8 wlכ]]%>Ϫ-Rջ*VtpiA)7 {y:SkW*sR#7NBi ~&@uqj]Źa @uC 'y'*_r@u%CʰzNΏtr]¦zSKs/OvBiu %E GG8Wez&grwK [jeL:\mE3r^ :7%]vli)4'!Xer0/;vok6 <{ӲL֖Rp_޼urVMmi]j*-W:H*~_ 9@t_KVv'6~ڵ[*lpQ/e t @v*}QeoPq:,OA8\C6Ճu])-"[R QTJN㿨7̼6.ޫeA5M7aR8>y77}_iY]ŖukOU⒯B]Hg8s:+!< "  ૩beUc襨rǦ%!Mp8j;gjv aiW7{PP#$;{g)gol}_Pދm\k S>̳6͖Ǹ.tR_[q%0Q)#d&kP #+d %aXRΩS3 )0 H $!hujϴ[T8 MB}Dy `>86]瑶UnV eU-]%SO6iVà(@(+esy_w?"]7FֻѲ AKtE;>r$JZ ~y[:CS1vJSFb𺄇+'Ҝmh<';˲mmpiƷbr.^>E;'BX۟ԣפ'9@j7O~Q0EU~1oe)>&߫+ETۯ?HضBI$eꍋmv+UQqPhp9 Jp>⺫U]uX_zWR>iDi!8@r]Uso\Ԭ{[ʒ'R|}z=Nձ_[uMEkkTi\Ҏ,U;R6e뭞lԩJyTIQ fU;T= |6q$%xdH&rNLzG:f1S֯BF=@ 2O.Lx UBbXO:;>}Q4:i^Rĕ  \` P8$HfGr@@39x Q..eI])U b(ȕ&9ul i$[Ŷ_iRH+W eȖJ%kW+j]{s)p`Ia{pPwmHr”Z>HoKɼO(ElR\{KnZ}gI #K{VZ|YpH "om4jKEI[aN2?R\ȼ3miRiT晅3|q|ūp_%_JUL$)C CǬ1~Gf청M$ N8I&ûozr^RmK5JU.2ݥd' )6Kuvە4jZ"j#!,s/4T7!-LZOd; ֊[nj#KN(jRA) t {SIR.!Ĕ" \a/Lf 6ԥ]N'[qBݨSQ8S#@L09gl3Gfpᤚ #Eǜ$6Y4nڐuJ2FʈUڞnJڦWATZL'2 ?nRD 36nk5"ǘmFR EߘIS6{BY0,Ys#ffh-.!,: *ϯ1|UMGs-YlN&kP(k߻v.2*o9@tͩ[6]{c~βENH> 3tgĴjʀa>ۏ ,-Vf/%JdA#ЎuݵoP#ԯ 5o{=Wp5i 7& `%v{5ҍm۪yqDCY >D6:v4=n*&JXB',=;Fj^ 7w%#.N gR^$ lI 2@ye}_7m[uo;'/+L)K-5-JmN{+7Kb̶u&%DrBcM{THx?2@Umڴ!ݪqIO\2oB_nGN0t9TrߛVlhn+c BQ9a`0 6vzl{g^]E7JŸY2V.w|}.Z5•vqImH_rӶ 6VK/m6[43+P̸dIXu1vڂTۥILr>rJKu^p=3/!IJ][!skLoJjPKʧ_JFH7]s^ʶe"(=J 5.-sz٬jl)m Pn)DρHN!kETIY@x'*]./o"?w2]YlIz9e{lաJ5q HOS]Pnta+f 9#ܫziҩIzdYfgb˷S&zj>PmYw6nKwUDa2e$%FS̞>Sy›ZUt5i]ڑ*taCuuͭAR};MS!J{Hr$fdJMq`2 r.% w2U=Y}n}s~Wέ\C&zP$ 4,mpޖJ{TEaT-\O!Lr.H\\Sfm_R: 0܎:慫=.!T$w"]߷mT8+iVP,Neԟ_}@>&Sus@ IKȖ]k񣍦ϼH; Jf1|P-4VoR`xJq ILgqJi^{d,%BFPyqm[{j.nmU:u.iDy9UVMu]MpqBZRI3 r.F7-ʹ.JPѭyMzWd H ro{Ǽnfj5;A!?x+.y@\꘨NU+=SU<|df˶l7ی׷.jKԥJ*8Ko9͖mqgQFʣIURJR58TS ғp.~޵$&NuL`3.N7S쿾J{l+P:RCUrVڵo5 wܤr0Y8H 1L:Q=PexALa _e)r/ XJRf 8ʊuIAWLK6PԤds_NRnPl0\FJUSHY]PFJ$}3O4Q.pO|-Ago\kiu8 Q%38 _YZm(y[(؛KITQXL攁*kzgMͷpWZ)SB|t~᭯mSgKz--Ƃ@zA?}AFqa٭?QTl\nR^Y`Rqe iWon=[Za,QTRQKcIņ>p}Cl!0=cu^=$ڛuװK!ڊQ?ObCL=I>mJ˟.jt mdHL;_lvF篤gU'^R >mO}Ī}& jڛ+}G)R\V۴'w]Dnbٛ'U_RtKַvni@*ߑRܹMi퍽wj?eӎ$g)-rٗnjڷmuD,K=]u:MKDM`JR%38tKҪjkf*0Y, {cinƂdfqH])Q y$mm؀ījxA]!hQNݎ!dڼFb׶7J~v.TJХ9Chl{Wv2,ȟ/8MCd_d]0yS߷6}pPćrT[Uh!sax͎m[TWRZHeok $)'֩a!AnvRvo_]kצt#ʙ(I!8zLjqUcn+#k-:KcKn'6{v տVKpEqHދ5.m@ݤql;c]M> ޴Kp*,\cT/-q)b5ئq  ۬\LG񵋉mT~´x-'Fco[,pn喡PW t#x@n }T쉮4婔YxCyzws]6޼o-UM@j}֝P mu@rCw:jxom)5WUTd?CPS/O$$TT65QKP!V=ɀ1YR$fZjeˏİ*k`|Kkd?IFP[u.MH &2 2NmM}RVBŪ ~o  [T| /JT@OQnصWF蓴CWLɪ(%Z@p_վ̹ܶYqW)Y턍D-ZT)3H?Ew.QJӽ43"[Z4KI@}gE읫fh;vUA H*@CMc ne%"+Wp*-A' G%E("P7٬gmU{Jv*U-B̬k_lw-q l-v}Ƚ}(T8*UQ$<:ۿX2i^g$jrNֿ/EXٮ.WPhqv R'ϩ]`=d;};e0Z><5)J$ }Z2BL5Sbk>vkEUi ֒Tn2wJ ?Jmh>Z"PJ| g&۶U3h[=T'9@bI-7@*6zL> W/]V,8)BS#$Iw_T!P!8,+z ZTIuu `V[HI`"IQV+I/ Xl3N^zN &Q 82N2m8qRnڔu0)97㛓9ص߇Q < n+ٴAHSnKoF &yūr4ջ4xk]k*7_rZ呀֝T>w 7h-k EkT0l]Xgi[Jn,8'`7[ָq.-i(^?(%]h-zEBT<}]`:.kEH<^Z8,`|HKMTzۥ >iܻct(Sk, RTԟ3$~nKt*RdG$GI@C[vƪPmq⥤$"I8@m4{9騪MVJ^@smg/nj)i4Hb/)O!qYgoӿueSӭԇ[s9(T,1Yd4ɠڷH[n ^ 0}n܆WpAY%DT漁ǻrmn:F5 RP}:VB\F)ei! (NX`7nրw!4sˬ;s:hQlF~U{:,d RH<'nvuvSߪ 2\q&tU8uPS,xi7&7}hƠdgN}V+uITQ!>;֦vyE R.`6밹Qjm[5JR  (;}Vypnk )-E+)޾vn~8ƛUKI"b}zk*Ǹa(}V]% +F~PrѹǴ7XPEH WL5M+wn5 X:pH2o6͏]uJm rڗ#Ԩ||GoloKR!?2{m)t1i;ewV}wfYm̡۬T.&R *:u5W*) Bt| 2w1յ[m|P\KU0&0P_5Om⓲7]*)BTy1<MmzmȻPfwRRx@d+o.MQM_K`/W䒖ddKnfp ۋNTA=1OH .,]ew&L#zF\ϔt`e' 凜ԥ]JP]u 7k]B>M0*A ` qC`m~io`R]I7V-NPYjЁN-X.7ZD@HcBwn˻[\m]O Ӽn̛Pqh S< lOvݡUA]bWOtl_uIB p*Uc-W>ykޗӾq( R$qH}exq}͖y&]pvHH`0edw$Gr2w 6i$ڶR\ǎR3}tC? FSX)aqE֒j%LǶP[OhϠK2 $c|Msy-6?fswFG.ئV 7, #vxOZmd$` G!f뼽I{#3 zǜ 'YR7S JXۃ.Q1 +'##,`:[tymH΂@WV.{j$,H Uk7^k2zЖbJZl{կ٨v@NhGN>V-DzO9(i7MSZc?Z "@@t^ hxߊ_i)V^[Fjqj5/Usx DEN cWDg5ٿ WJk*f.:ʾ x]?1m-%R Wd'vBP~FHFJܽu \'RuﶉzV 4rT97f)f |<%뀼u Ҟ_sE>'ި^*IP  ԣAK0IaSm)T}0&Y@eYJ *:a/3v_Xe REJ yK8 ,\Jܩ\t$>N3YJ CkfPҔ)` w~0ڜMMR r*s[uavN_ZҋTAԫ38;r+oDn]ſ"jB)6qIy88N?ڋݭɻ**[ls'['O 8?n>9~);֝ں˪iiPyʕI?Q0g|q݂dmIٴ[e2)hM 8Ҕ938l,*wiLI` /]9DSN'*jR'BjSeI& 19U+ydSe*"fSvp׌OdUcUUUUL * 7^flSVG5hVrIe2ûdᯨ.T݋[w+l0h 3+DՌ@$ MSӴRm'\uyu,pIO);3iݠRKjSJ7d#pŅ7cj|Uە5V(Ow֕aM=M>ڔKL0R $g8 < ߛRN+%{Sv9bӷ3<7`-?zBOfVBR<2yi;z<fe4͕%.~?1. K|IFe)DF*!gv; )YT\܀goPU*ISl&s~n8zKme];ն=V$f>*GOKF^ D ,"d)("r3$|%C:8@?T^'9P? Xz,$`zp +DHD33Unmں<믶)T$ykجMT]s|ԡJǺ|qNvV0;G9,JjZg)1bCu29,T8݄U*pRE+ LdJPԥ'on5$SWzøҲfA yo/h_|+yi3 G'}Ί*v?wRigN#8 5V4EY:t*c/tܶ _wJ^egI /UVŒke[0/nӚ&2)Nh~}HS 3XQ_T)y:;S[N)ɩ`ـ_ٶaN_]mҴ\Ȁo zn= hȫ@Ey_d-Ln9Nsnl縮]ah:fڦ` s2/7*Y@5B6(F^P7 :X q).#өIp6뺷 R! )9d k`vJJ+ `3Ąk{RH`g30˾ۈ?Xvۯ$)%iA(nR3ja2I- Ϊ\h/Vw<Ft;f c퀻GG[⺃lnz}Zi%jpЯ 9%kH"tD'#UH)Eai2c_׵HS|NgX# =FjJtGNb 9 ߤTDx0 %ݚА ȓ0ׂy9^9̹͠I:{ |}q6b]JU@ rz* /}XuJcKX o`ڍf QNpWӾΣSѦi$K/5Oݙ*JoEI.Iqeq&zOH~ l[J[o{YI%+z`"Z?l\ 'wwQ+BPGOmhgĕR`Nd6N;/`V 3_hU ЈDVn&tM!>~ܥr^N/ 03}ɸt4xvҔ z`8_.z*:Vh~]*! H# YaM hѻͿ`n:k]cvڴ g#6}6%kmjʄ=QTdЭ҄7)R@H@2& q)WW*h#@ion2~Ӵ\TN?"5-Wt߿TO?"uH$a2V/buRHgwmT<ӎ'Zu,pF/()+6 u=Su m(:{j"RPc99{dMڕ lI.`a(GVmAÁ 7W mRpRAI${&/$m?HJ'. %r|zi6K~~l-ĴJPj֦VvSPt*JR.b W>k;jBn`!xzƇӔv>WOX>}1])/Qyrʕ%i_Rg 0hUmU2EEԺ`3hC۸]v͆pmqJ@H ^ N~pw],#K!A2~^]DzkSm;Q{xࡴI*QVZ{J?ke"-zAIjIzGf8YP퀶uN8C FtϬp kVhw&ƕQXa |I=VEn҂WZ`6t Bճ-U[tQGlBy!e | 4m JkYu{JmjPRp)yu3H $7-zȏ+a; HAknGGSҦ.%i::0rxSeE$:lu+U0- zatWʤPĶҶRӬ=`#n+JʳLIiY oŴ*L%Eue]cMN0`>cnN57&oڷzI[k dԯ0I{iݪlvZie5)Z?7Hc"V_YFB &\sU%66DxMm˵S}HmԦej 8zlnnפzV$"}SqRZVwX ;!ɴ VOx@jʎ\Ell);[.T걦zό.A6+ڒ( tY Bk6~ȟP}J]@#iLzr m\jv~ݧmwm횝$H_O|s6~ٛ4lfb E%ZOK.fiB|GblqUU(>*I@ڶYma4戒Fc}K_-~bh{FP5?Y[u֔[O4U?a̝iOك 2^}[ݐl岯Ne.@_hƓ$ +)yK쀬!|9$ Q%HqaiJxR/SLNXR/ D5,H/L.~E[ؘW*kMK%@@g2f&oSݪnϼAg Ւ@sB (mrsB*g mͻG"WaB=v4o-s KKM8 e<؛36ƙfқSN>HPRT] cf&|:OЏ]K\}9@[p͎#}&'.ޏ7إGPCe v*逍v[K?dQJ rzTen9t)J?İTu kFkrmu [Ue5 0`V}j;aU t̜0+Ӯ6/l %jﱁ@Ep^Ҵp%* ~@&о BF4ďät HR8NRHp>eI5!.T(rj_7NLrȮ kqQ;)Nc)JKdTSƩ7:i`%3lU2&ʦ|'vu\ouiY kFk( yT}ATvE88geV]eP>όm4(\#ZCcT0Os>Pʱ vB{#J @J25%=3n횖#V U0<wA}_ U<`8t\ ? V&ZP:Tj}Kl%FbUh2$W[|"$_4Wqrw>Wn'KS1kA~jILDOqmH 2IqMj׮V;-~G K*;ő˗|iM&ϥ+@GӾõYvܷZEnVU+[)(Q@>YcO.vgZ7W3:Jy)*zti i+KIIV(epZGHS@Vڔ@N^2u)5طj6ܥ}:Pr_X Emֻ-]qv4CE*=2NJ#5jY8j+昶Ur>g Oe}:QqVޏ pq%(mg z{ǰ*ZG.(uB%3J@'Wsɻ-] %5T$ <}r;(J)8 堨Rd .5a%<Z>JNn|UuÊѻ]HVCI-j'(_b+!<u"jK)LH5RVTӸ=rSt_C jS:0KjE}׃j%fQP!ʀ&)jv۔uvӊpxKmnVem|8d =r䴸d:Z4ruEXi/6dwVI*}$R#9`q?F̜ `:p&s@EJxNˉ=oo*ŸM;YM59L=A2u?!ʟ_@BHB S)q?p |> ͗)iD%" !e88b*m-:vR1(oF=J "6* O҂@D@,( П:Q4џ-?*,Gh*ah_m6'@2Va'@:#̶҆o'@U 2$Ki IJZd 6M;%YO} ?HÌ T6;M, mJ@id@J)2̆' Ӊ4 b6Cv]MhSĶVߴo)8ܲөK1+Y۾FINikGo)ѶFm"R0`#{gZrF|Fm 이Pсᣬ'b=sTRZ?,AIz퀾6^linF ;Koi*e?FpUH/emm(ze'dܴ1%2{N^ =-bV]p$IVϧ͝Ȗ_[ocPmZ3y8'g6=aiMRRKd)Lfmݛo6}ݽKLVV’u4\Lsxh,?Ee~$Z?RJOŊN`Ulzt~D@HP^Wo6$`U<c@!!2 8xT!CJM$ed]O~HBxP q;ة?5SY"O B^ S}[9dcJ1RYM$O8ۋ-Hfݯn[G*d|7&͇]6{)׭|EVI$X[)VL"J^${Uhm;yn%:6}Ɛ5ܛKI2qQNP/9o] BWjMkNv plU#ĞؚA)Tܜ怠xcd6s*_@3Vԅ~5​ 3]jLNyPK;5騊V9?-+ C:RTZD( )˿0GAJFK#{vKk[JդY[W (E3#Y|]-ѹvCTFqE@8c;kkCv:jzX-Tѕ:tpRg0W|=D m$$7DI_{񀎧v}So"T*ϬS~e!EY(I.pL l/ Pp/ `"W푭M )~Ȧyu&iLAg?+vqO!L퀦ޯ~,687kJBDyWqu5U3cEm/\ mZϟR#˕1KĸN(-)'ґQt-: ڢX淚m\ GO_L~%h T`O9kcm(;TGo\\ZJpHbm-=hnS,̰ݴ*'WwҷQ9( :o+) .'hCwJ2p/>iIfqn"% =%e?M؆K%]ǤIdi:?PdM*I1W{^InQu ~Ͳvm~nAouk׫N}D![vhq$*eYԲO%D/9/g^ĴޫUmYIs^>2v2W2+serd,TTw }/>ܤjE;tM7HLd5!BDux#o&ɹ[A Dtx|I86Қ~܋qRNRq0 (9+OqZXJ|;;bYNBź$&^yʹ+ݕsw=Zv}i`W5 :v'-T{/3OCn]ʲszDyboZ   jRԙ+#퀝\ iRTn=A M xc }J7皿$21[&x]_{D7>lh 8>C؇[u%: '|}%Mn] gnq׷,[F.ܪpuJS vfm%5Y'J[ i`=}HGO"nJ^YKͰ?PQGъ7@E-}!r>BRn(}PQM;:IRA(sFSpAxw+TuT.r^" JgsWJŹ3&ѷ6#̻gRECWE!3BPzㇾ8u?6:̷VӆfxQP>)LxgCUo[7nigYyƴHx U[D ?TV2.iv7-nV\n̻yrTԮJp TpH@cVQS\-y[)}Rfc) 5(rCOKvqD{-rZݗwxĤ9eQ^0HU@{%W;S[$I&S#@ `p3Xے! /xP9|VI8,o`_7EKRPY[M:>ڲj]SpSIҪ}u0Pd2dPLF(1=%+tWAH"ghp5zHp9"5 L8P(Itf>\Bԙ-BD8} s9V~u`$ԥJZǯPaZ0  6dJ!K..bK0ʿ!pAO(p2WV0W/8؜˒)dT|`2VB,2%_@)#9JH֒IST%#`iiRBM$(J8"I2d4 ,|`$'>I8JL1ɶP˸JnJ@iOR}T%+hX`"Z20^f )#/9)La$8T )*0(I&iаpgS<5mӾ-+nU[}h/9N, 0[M} vT*սⴜ7!{7]퉶k^wp-R0+v-om.rPr0Vӎ~B:{5ZRGBJj2BӂqKi&p ':LQ#XPlS0pm@R0=?t&EItIZTLp%r]3d4:O@IONa, iBR<9ݷ׺4#e[)TG?\>0#}EY-[g+"Rt7 3HkRqnl\VBJI d=QjH(C :Ʃg $KkP\T F8ci`<$qkLKQ`oPBY4U+5ܻWnPҩ>v%n^/|꓾M=%‘Gi3ara1eiGx0FI*RIoPҡ@Z g2 +!+Lҕ 26OA3GBd%6P|P 4Bg>#_a@D!-p>"mBBR%= ԙeDd>em3A38,y@LW+3e J8` U=< -jĶOQ8ndB^ S%@HzJ.0Jgā=s @ f`&qTTD!%OSHTuO&Y{0L)N Hȟ#Ni%,` ] zE3A+k2K $<RBJ?~&+)&YFIH8<43'nvjv=-E VPŒ(b%'Vݑ5rŷ\jBjV?>$P?[\Vٷճ9!=EUUk3y]\[cvݴ8(\c[2'2J>|~vAHnCrvrz6Ρ/E @Sg~e-qȧ ̧ OSs7& Un3j~B)i*j|CSŵI%LRR Smz|QŻ5B [S925&iaRQy*7}tDBV*X8͉a UDgkם ;'\1-IzFn[B&fP3H uGڌ,6:RީUn_^6j|r%li9bAM÷8n{ks8UاhĈ ?ϸѥX9IH 7Ƹ֮JvŽ2gxl`:ػCbn))Y]%:)^[G8[UTU 4:PWNjHȬ6Mt*=YUt4L]x7nnj)K[j9g}:ط+nkƞ\ڸ f1! ˹<'%@:C@ȩrLI3R0 La Vif@ *N 0ǬqUA >R3= - e2KJ`@؛E7ס^(PY`8sH {`7fزm=m rpS:˝5T6> FvURk-'Uj?R\]M?TNh3ьՏj_5~wr)qҐAjAPΗڶ.;ܕ ɜXqHY@[tm-@}f 1{ɤRnF6BmJXjʴ]J`-R~k 6d !}I@C y!q5Me53q&-BFmd`7Q彭wst{R)p+!$ Az>.kZ[Ү{pvT.,MN<QaELuC |6׽X Ǫ_PKhO')@xȜ}w*E cJhb'{eJ^N8 \l g@bKmMcj%⥑Nf24J  A)&y$z'GL3(6U5LRZ')a/+/p'IJDq>pLNd-@M*-)#ݢP#WSaJ()$ LL,`` S2P10 RS D&  8$`] HҜ@>f!K [~D t@ddRǮC8TC( \ M &G(\L!BZ쀅DLx@ F%`Jʵ$c%&@% uR%*~ %>#A:a8g)%#0  zN 32p? :P'B?*Pe%$ I?%8$ ǹA)K}`&V?|mQ>P = v=dp rFp;s P0S1N뭩 pf-CgqƦ:, ~o.8K'Fz<!$e:uH m@&sZS!SbP}X`OX:9 @@$fiReI Y >EWa&Si*[DͣȻU[nab}iZ.E©PfnV_.ڻvJEx)I0Р\ۍZعvdVҳm̓JZQp:D!B]`#qXdgZ$C^P+A: %+5VӶzb !]W/ȧBn4wHJm&iI`liH =g*4)#2OX RP6@p NHH} 2dI2 ̧JA+LDڈ`'!yHNU3 F2OjM<*FpHV i.8fNzTu%RR  5-qZIR4tLOJQ-20 e&C F%ƧX8yx@%:!`b^גuY/ u bj֐$Tue Oxz+J CRTiJZJ9@"R S> 6Zyk\.6Ʈi 8sip^mξyWm׷zh5J8r"J)廾?TZ=pqsNyJm7}ki:jJU&HHFߎЭLvŜ:fkr\w2P-I5D?E!Ri`>p8Ǒw0e2IFX@_=ݥHw%WĚJt( mQ|_]3PK`"_ r2@ & >5OvH_;! ۷}棉]qPdR=}}=$ݪС _M-!l]֠w#뀜}42Rk2uGY+OVSU>yszE}ŸTۍ)Q6G'J@^zRѴ'Ong i“M,fS'<`2WTvJ Aȵ iB>^ V*6LnH fIL)i/@Xm. SH@:HKiD`> mY ޷54+\jܤRUY:~]VkS )s[8pʦi*M"%%@H[xL38 X'(җOO!iuMxJt$$p2RJ@@n"^t}N2Iir\"P^e28r\r[)M t jֿV> 9rm(7 2/CJ0x4̻ԅ4֡4$a)jn5-RjuzUR `2F R4G~܇R7'ӝE#Vb7i"5S̕@n}+v҆lX=ZiTu4; zz LkLYaoT7SzRJh)RX qtIVN[?'y{桶h)M>}W|Áoʲ JB~BLrǛR TAEAO04T$VgVc :e7g*Om|X VE{@x{k]w &Eʭd^”ziXė%I= =b67A{b]MF.9R%9 @uARJr3@pJro|5jw6u7۽BBb;I3 yӆ8!8t{o+Yzd2ka7LަR &ZJQ>М=AO%,ȥDK8@B2IT| * )+Y|#IBA2 2 ,A- קX(&_Y@:B$`pQQf&2 sRQ!=)cjs"W!D@ujH"ޕ$iRVMdRTi^8Ұ$?d!6) K>/uGg!_PT&s"C!:FX)'HC))8}D@%6(, :(-/IZ e]ht+N~9]KM;̏!tT;z]_.f'`ӊ:q gN:ב\`pJ:)|wa;'wjlu:i@ve0YQ9` 0̈.€:Kh$TALQxdR 9 D1RI"FR񀾚}`#)2|D TeBI$xci `B1"|G2uP$W5)HDN֙#)du$L$g) Դ(8Kj84u2`* )c!#5=!EN(b|<敒4N3VʀJ+aBPBg8Q %zҁ`$ԅz1xIi@%BhXb s8JcmSDg( IGN-(`,(ҟlSV #RDcIItc(*МO0YN$̜F>f~$凾dR 2q@ B@f| 8c":ϔU'RrH?H@O:#&fd+(J%$I1ZFe Jt?DIG"0S @Li2`* N #%"xȉLzdOH JWH JL 1"2Q !? gAҡIJҡ`I ^&Gp;byOAHT&^  su6 DPiLg.D})k 6<] &Hlr+Dm*$K)yJ瀑=1_.\%iVR]K?vPcTxX2ҬAt$&DuMJH iHL(`ZN, 3JеI8f )2H8(@% 8fg @R!hQ*tH9` Hq@"BPR0B.W4 )a>@"K^Q@AbLIsUeT1N$NE$QT 5O` 'J123P$&=0Y2Oь<23D'Jr 4` 08JJS 0THUm,zZ|l嘀(M_ \!3P @)$L'#H<CP O-:RBTLqxpa?CT`K, 5Jr $30 Bx*DfBABAU2g^SxO$UdJS6L@,s2 3 '&q$0ɶB}')1X@ <&Slp10f1Rîs?-j$OVFJ/(yZPYNGA&yDQre"r=f W#RHTS<z^4:]y8?y88d 6ue@a!>"m3yt@RBҒ>E:$$(}U~0((Nc>ԨrBCOLaU*IHL;) 2 LU?a8闶R=="@m3yhuWq# IR"2*BZ dK#E5)QJu-/'H 4jRy  ~tTȇ$ -U'wJӤ m2H )x@)q2'JpҢx"QQa g0yg=G3)RO\}) Rq>>4O~Hp%,`'d1\r)p əZN8Ϭ$q8Km)Q%("`*2``,'Ϭf@9~ 0)!2S C(Q#/a `Р- ϯP3$tL_?bjD[) XLN>pV0@ z.JBW)b@x$S$a?JRN3= qIǩ@Hpڂ# Rm8`ݒ0%-C^BYKDŽ &N#"qG3=I ^>dBSꗤ f`!uX2 xTu2X>( ҩ^pQP#RQ%hNpj ZA)r2f^ g`+YH3P@ؑ9f "OJ1 "# >P94䠒<5P-+ć$~GN$HOTִ i=`$N)pzNPNIYX+=HJV}X|krHhE8+[8 2l+Y/8 ԤX]* i8@E9@Lx@HL'.g?&D@ >s0fF`^tRd A$z9zFщ9FH:Hj R0 P#2 IF>Ay@cODbN(&D%OXìRfBRH|C` ^:NR@ P%#ӗs#$JB"R~| A2q2?*S<)'զFY@9:V=#(|  ? FI0T+O)?dh,jLNCf|e_9A;eIP BGW3'pЇP›)E?PAxP(ោ%'0=) @ 1^0Ȁp(J4 ̜2I$b'Z|sLfR , (x aRP${33 B2dz@RZD:THd48N0#l<`:cU%$iՄu pGf p!%"k@< ˠHbLL#` g/ R'R# .<0q"% e^f|@2L2O2Ij R28QysJPq@Y*dTR8:pfXԷS",(*> \-$LlRN0):HNroM*Wr5'?z@GT, ?% 9{`Bx ޤqT]3&t2EB % ,!NRRD ,sW A:I3 yN'JDYX!ӑ  N&[SNrz($0(|2SH18*$s)Хv8Q"?/(Pѩi"fR PF&p q L=(t093p&sSP=#Q f q2P$s89rgHX׉*I$ +9 `Posbz@< ̟>` ROdNg§13H!$e8 CqT*r0THf + ALle-]<`388.35*J&D=pLI f` s( f=L|IC!D.R ds%PPu0'BqrL(N= < KI| ފ΄?u}8YB?SR%]pF|$?JY IZq(5td)(SO>0kwr]:CLZJ n|hSV{}i_RJHKs2 30DnJ]>stBJ,M'0FX@RɽZyYOrE:ogRL-# #[Dzo+[v4 fgKEkZEuꪕDuL^R]"0:~@1Z*piR $(%S?tqL&N8Jj\IѩJd)*Q$,|xK>#)@Fږ e@ @*&Ai錱"J$ >9&|r0R)2ScRV%bi*msH14NG#( H=?9 `%)lQ@:ÔJ泈8c0LU"C>?< IT$ e IRTq8Pj/-RM't9O G :t@ 5dS9O>Lxڦ&>dr G#8)g#)8@!# u $gT#8R# *2@ q)Jr"uHK~fH?4be?Fr9@8H rLcuBB&N I=  5} }@@\rJӎ~p 0Yc!YY@:,2Qc388%#((I? id+)J `Mb`! !w0Z[ڤEEUˬx *Il:#KYIiUcKL4 +GH C, F@#)8ԓ:@ 0vj]]H!w6iOҲBs#TK5MJcR˗:ɧKҔdA ]M}±uԧ*]!@8J(lID$O<6g`/| 87uV]֫.tMe8ۙ>~bK.,Md]+E Ӝec-;-uqU<46Ia!o8RO͕mcuY޺[/7iekyJYf`:&wn6[6V %)Iyt猂M/6ZzvntTݤUXBJS;fmJܤJIJ̼̔Dd`@`t2 W􉌧_Z0$KHq9@1VPIKΡLH#k+@1,:7Kbۉx}%oJ*I'\&e8ԅwH IIHg #(L 'm r>4e0ґb\›RJ &i{` ,`BBW .Zpż$e1bUp[!9 @Q[KZD́z@Di hNx)O8ወ>̠t}&:B2NT$}@Nc#jeD0`&S`iy K2°<2^ .&d JJF0 ܄=eș.$0v) $mwOn;)₂0>0#㯧;ՃeߡܴLS-]ƨmBQ'BPnv/6!-ujUW4k8K>Dθ{WۗVzB\m*iYL %3'[*qMC*.[ɳZ-9Sݧ@Ǖ>"&Ĕ0_nqK{֭s3GON8O!,.aI)jIWW MJ ( })3 D$ fZ)AKˬJfP$`gژ9JB8׎pf= JY $̏"JhJp a0"`S @Q960j%]D"y@@!3-q&} &B,HPIp5Ȩ!"fs@GB]B_yQ p>JJJ& J& g@K@Whzp1쀟 8 _KhBTC'04Q<2@9猠3HIՌd*ҍ.f5@cs$H dД'*]lz7Zr @2ԕR9LCHd)H@[HALNi@0 <&dsIJɀ'M' a2JڰpFf_d)I8`f<jP'WJ]<%B`f`$ 99˥ 4E[ Hp+/O_N &*R!%c @uJIx4ʤYLY_tLeSPT<$H@8P0@DTF@`$GXdTqLZ ['ӑ@(KaRo86K# DԙT:Lg T34 @ cT9$:=#`4 Gm'Bfd!JPfz@KL3@3s`Q'Aj3&JD2qI K)Q043)N2T.Թ*rT+Ys !eD'ԁZZ'jT( շJ9T6ַLO.l{onwp9GTU;Kjl-(u},]6. EbJRq| =.L:8V4c$BYO&gH@8<(_o}ͶNl "'<@ϠQ`?"GBG *CE-V5)쀙(6*R,e{mMuz1霫jݬؚe8=qWQmmw&0D̺>/H*2]7Զ.<֨ڶ,PTv.A+P`=A`eTo*VW Ppaz׀L8!pտvyy Z-STU*;Z >3pn(K[oBӈZT&PFF^81zVo45VjiLNg#OFvv()K-2!S5APj(*lDPs\%RK`8KnO:[ H-UO1N(H j$>+FNj>i2=bP:@zx@ ]JN)C# p z퀉T8%#Zp]IP+%)u.ӯJ JF+V&&H`(&iN= 9e Drrsg@Omx(0URID($AbC8Ӥ: b[hN !r$d +O!p&EE>fF}<@J#8$$ga8`Q8@%#&'ڒɘY*%:-^Y@H\0<@28I)>HZU2 `|` OA)* XTp(F 39 Ӂ2HrDAXP5p'  HQ#P Su) )  h) R#4iIzJ*R^C Ws$'] ,6TZ&ӬzĀ8Ha>O R!"^20__ '#XmYB= ,A9e @Fi֞%4gRӚt9@DXx#8gL|Lv̤{MU|AS4?98W -5TJW,0KF^8 v_{8H>!HNzN|; %_.ꄂO.L XwN: Sf Ӛ.(W?._dwS :D*~SNNL=E %@mBU"à< i4>9@mBt*E%~ V[Fym)hI 2 Ĉۚx@ L>2A up]ѷuV0NɞPi\jwqo3L >RDYtVjۖpfR4ZKI#(OvFjE]D(ih(&pr6:㋳5FvާR\H`ĜuK6UUu}VR&Q 3&~OO>#|]HS8ynț~Y5"%*} I yfvrv,ճLS_IB\a[zm1fe[fzYt8@g얫}|Cjo;n'4-@' )WH R橒DZR4|Q-LH OplHXd0 ,N= $M*J" :r\djjBAFF to֥*tۯ%\p$)=:@|ٟT-'uVRU /SVQmIZ9)-fQkR*5lGԤ, 2w* 2ʦhUEKmgȜU)yGvbfyKUSEk5$&n D4n{?9o~ˀ֢[e'`\xUOyV>پ]Х-f6fԛ䊊{i,Q K*q`e_`s?YR4N2u4ӷ"JD̠ 'RR0^-C{g miRBe<^!rZE)|MDpҷ՟RLr7Wm-ۅPYB[[Ls!LV˗}I|uvFxkpTV,SUjjC P)VBg0}Y7m.?5;yV?z1\Zy&[8׶}1SkbYSiNԢ`<ϸ{f7-z}˵Mm֭&oz&zU)O( %^97cuKu\o0 JˆSP8x@z׆6~'mJ&~Jw-$K#ț{z~)++ieIm/Ժ% Jd8 })mPߕH}^nM*tsLӑ}męt|aotn7vGD^p $dJQ `8g4-ikߖbHTպ]u߁&PNYw;{Z{ʡ 5'NeII)@vD$Ġ$&EDL+HoO_,Z+NSFOҴksI#)(@{8^ƻ%b U_o۞ӦwMM ò+=3Id IJ|)xbO%_ x@SSe0ɀ]ڢt#uGjLg't kIGydRR54Pf4-`9jpdH1$ s'퀔Y* $0%asT)x wq́ze:?$s=`;Ew l]pWn{vppkuj^I'Ҟ֢'W~bX IQ.:2N9._VqlݴǝyGT|(RۦDʂtOmM[zzTTRJ]jN FrH2#hG~QuƧ%cegH0JY( 522WLz632='.RM!1Y>u N9@ԐZ38Ҵ D'#^s` ^/cl/[s9S??Ӏ 3)2$ό%>X@=`;&VHIT.Y`3hw * 9k3qT[(RI?^l;e4ɺY5ВB@-毮X+wc[lWLKT%8@m/DI 8BH[ @z`"5TzmJwzLzE*R׼}^;?fҴhB0fـ5R!dP3S攭lRvRq7$q=<'Y xJPyYcqnRTw?yo5WTS!. 5VUyT%(4HᆯNSa=QhýJe su'ȈO|ms*wRU"|: زҩO{zJ "^o˵,bEuUM |/OLF)k*@*_nI:zۗVv 쮤^*YC Ȍ0tV?Hn%q>? ]kwkrfL`9_2[b/nyA#J%mv=_CMkwUm;[)qhzS Q>Y@u$\\jPaىkJTP@TgL mHܻe5Rwg;Rv S+>mutW^KZr)%Ҥi-OT>87ozo)Jr"a(eY74[+MOq%,t*PݵMO[q-Sͫ Lczގ_ λ+RG2'7n䌁h{?{ CoUeBz-ryŲ^djg5@N(6$TPQhmܱ@MgC H |9ɻk W9@[TQo-$roOTQoh kz҅ӺN̠|PlEU3mVT5xt&҅5%f@&sHci zk$7Zݣ NSl}S}nߢJAsrV۴Ssx]IZR{x (\yZ)zkB+PHt^-pSTA-V\lH=e?̽m=DW7?l6*I۔Oj` Lީ%?`4Cfݔ[x*{̷( ~*r >Uǜ.T- H374͟_Au+eĠ 3wybȻlPMR-Z DǺ; l7ۙα6>I܍+]6k{`&dVm+z:{%niA =' oytInSOm5 I*r<nkw9,[;&]P_SiS\Ҟ$tJ$AU|׻'!qݹ^ߤp*o}(5 JLL{7ҥfnLSXܖܐ=8XVݯo|]ͽOTb'Wm))HY l}o%ZRT)ZNA !0;x91dUJB 3{jjBn$R1щp#n;3.vXwq) uJqA(~9,{`5 ѵOlP:ɻ%n-BB@IT&`=}|{s^Y۷۹W7D] 'JUTegyvuXR.JZѤ-)B%>-p=wݼ)wUu3_{/S4*}2e N`9 }3N:Bkb.5\]E &3 $)2B.S2r B2hB˩Y P|ǢoOڛ˰[:ۺV.Rf 2Rʊ:Smwvp\Nr`ѥ[bL;g,]ڙ.rjmm^ 3k2ォCQF˧ѶvI2a@ySw$TSqvj--rJ^Rq>H`;>|{ ml*N߶~ܨS S*sPPgR5[g opۭiU:ՌF H@m{7_o^)/bIW.R OrBL/B u4f#vʣ2}4 j3Cj~'rBRGT8$J*ڨvO np jH-rcp6Ee)kݩPU2 D2@mxr+gYTL>UuaiDH8 =RiV4ԑ?BNzgmr͒mV K5J} 9]z"&kZ@j)B:HZN)9rnyb-mE~n<ٙm}6"xɕ]Wpjښz[=e骆(u`WHnۿfv6 PѩPn4YQfp*17u-JgvGWO8e&KJsҕx\t3̼IW^JL~9@s1nS]2:.+vJd;NI9KM30 u s7cjk-T*U1i CjPCJm!on[9f˵][vdQA Nc w[nTNᦸV8{KVl4n+ea>65ܳ-h *[zՋ%2p0nG mtfmd>3ymC{h9Nڹ[!/R=g瞧|aO?S|DL#|D)UfP<{gxNX>ZsSkQ{`@9[u|_XO'\+R$5ŕkpujN>-˕@u 6 iO2%j2<`6WyG/Y3ޘlye jTW2sHT~Wn=&_YhRY3 (<˨Jq%I2H$ϹL/MGo"lʋUʪ^S} ݗ*Wzim?loAnK5+%M݄xu]U55mk5L&V_#w^2~ƚYGU!*{:wMN޷+sP75(;Ťޗdfgo^_@pý/,rE%.bܵUoZu+>O ` ?On߹&t\T.JZ}BbD@wjJx5_7[49<*S> UZK Zmpy31*gp?QlݴRI"a>Eu 2 e&iԪJq6yo̹IRM9MR}# [hnFڡX%6R@* 0 sY2RqjP╃15ڶu6*ޥfa5)XxGvNKFroӆ_j䴖LBJtO'w)TuF)Rt.]oqdNGCme.RTq8 tɬ4c? ;`ϓYIBC\w[U&4:T*)Oa73> ' /nm^@Z[M$*&Bpzwu¬):33^`-3/a#N$QU?y%a6ui:'@NrjHJ%?tGU{0)j_$_rRK9J VH7MWα4,͸Zz9ZT72xFww0.-e%5vQq΂@ g@y4\MfbV"Ԇ• ~qU2ٯċdzq攸)Id$c+[ȩiƝGphqkZj^,MS0,0MkU.˦m- ϧ?l-B*OÌQ]U:nvug/,u)iZT MSFJge{z+VPv,*wL~afL( X/ &CAfခmh[sjCOn%V0@Ow6N[2R%Է0|Y {Z҂dT9 K no6>)S*wYL-[g0RW&(,S8\J&yvM;TEp}#R'Rx–g7)yz`.|NzJpT5(Ӊ #jnKJqM<'((Dh@TmN73P$J`|43soRwVy!apEpvE@F)@6УaKW%jPym gd\HTWVlU7@gXf`!vm6l[ N̑r椳W5PjXu'gW/76wSn;Hit$ r5pȹwkweU )S*2|<;)Tn}Ѕꐰ4sSCocW˥:PjjˍNp.7GKh]Ցn=HSE!Bfd%PU<;/Kv{mնQR 2`;F}iߜ%W #K]\,s ݷvn&+T%S03hmͿhere?8]ڝ2(#xd\ʊW5mJSgHH6wݱktΡV"eP۶ 7%+#KLLP@ݟt)T7F~ Cv]\N${m"_@/a8 V齸ݰ:A vc3 ɶ -lm}5yM֩H p8=öSwٴkmvKߧdžH Lp9Q៧w5p)ں2K QpRlN4UG'p?]>:[?8n oj{{uA "YHO(Eʼ3yqZ;fe@/T= 5 Mn[2ɺ.wur8l] UjnFXKmoj\pxg]]{o`HR)=?G0m&M i[iFxVt&qHwk]ҧ{YjP҅͟x5DC6 UaIQ?30|*9IS&K2nO\^B+%5">n[EuZnK uj Ҵ&bPku].O|igZio wDͬd(*[ka]v}ɢU\[Ltd9NcX| Ѷi)ISv]om2aB}#LQWM)d,bEa%*gH ڏ7J9! ː w-)3Ͱ`֧R_ s+@쪲'>h]v͹*t7̮JOܔA&svxxr6mVzƕzXiίV%j[@H*Vr\q@ cj-=5Bˆ ~&fcRA)r礟9%Nn}Z[ N뒖b ݻC_{F',>$+33Qnts$IB ^l"}g׍SO+(*O,')hN论9/k @y{sXF[ffکUR=J[ᴜB5rv.ԫe.*WL}2+kWm10M~ʡB](KJWUz !r[snkNW^L#@c>kvKY]B:EOى0xC?+( K9x?)8G, Wy.2> t^ ܤw>nT*8)v) O^S ;C[ޥ^-N{!8~fp.WJ-mNiJP3 g$8 MP׶6MJv :}ÿoӶo#NTҔ»zSYjUN!\)!R)hx&uȭ$ ԓ l]_Mh&jP 'rT75%Q"Вu\9Ơ:|RĻsm;U}pP!5ښi zRBO &$TXA}2NQ@HPS ^pBR8>eBp< JIЍ> ( F0=%)/lHgI#`1wޭܖ۬u-P֒Z9û $'v9F&~1Ļwk:zQa-,H|3oJLѣxi擸љ)M$UTMZ{M{"_rqw[WHDl k|֟,Z70<}'``l%w *dll>JZEʲ2l gN8$R76(&]9y@2xOrfH#?o8 Rڬ$ nr9Ĥ8+,BMH~ff)['zݫá TuI 4.mobN'Il*  ݇ p)2) J"܊w}ג}3l@F 6Y;x؜QOO7=y$:M %%N؜]% CH&gyX(F$.R긫TWeovmN4a%'HRte9!H]*3(PiIR==ݫm9 3@@E4Ulb){`)'bﴬZs$)#%>ގRt!;kfdDaUƥJ@Vwgnm̠֚ tݛ6@"kJxʥ \g^BV LIǖθ< -ƻn/ǖ-+Υ+9l:$㭇n6)/rxd`:oF6/$S^P9ӁℿQ֍nfsLQ .Qme JӪJIsh) h%ɒ1uIЖV@D\_Iyx)!.S|q7)5 Ju_:nŠ~U:G( qӸN>6)7-nslYpRmS 8@bDwڪ+j}z\4xy |OniҏrnHSV:M;^u/n״nZۣTL2 IFvݽݦ)P)L> ٛ'۰n[Bgi9^'m:͙IIܷMӬizvv~ҶZ]!)L). )qi$)ޭoBT"PvUƨI'?l×)TtTVۚk(_ ȿc5 Ҫr5-+|2 s BR/66'/sN[w%pn ]]KIqjEX^ ϷKniH cn󻐉T> +e;*m%wҖmR@nZG`7S{!5ݝfʨ{_Ե݉3IV~VۛdXBjPw]-kq) TLϲwS5Q79Z!4gI^0vV-ֹDX*DxDN04[FH|63er%Žn5[YŴΔL(@lܔ΢%)ϖ2"RHCG܆MMEw-%+сQP>eN;^ya,P"DGܛlmQE5(u'pD#VPm߹a.8T/LK,'7\նv*.GJ ).ۄ lmRuT;4{rGOjL6=?i  )̣idr7!aA?ޘIF"Ϳ(.0wyqP\G.nġ&ZVYьr +wzҦvI> ,1 Ԗ$}Ͳ3%dmku,s.ROrP]_nzmL耕0nmaG闁PBKd8JW@u*)H/iN<.߿JU] ze5P4W0 )e%cӣ ܾ)Ӝ|uM%Jg yԎe:HQnz@is_VG.].ouEiɣBBi_8 NSJ|pK~p-ݔ!jգku<\7+W} L] i c{*$$'ф]P .inn~Z'IЦ. V]Rh<+ HI:9% ;Wg=r cRCS{8NqjnCUy̟ )OYR טZ}).wPi yѭ\9o~:IP+oktI`D54R-H FX{*o,5"V` 9gWMP.[E3#+mF:U mh#Ơy&:@}(vŝ]ҶkӦ(L)U:@oHh65g ='#kC/?d:Pu29 iS,$Ԏީ9ԥ$儧3dtp H!~<`%QIX,2Td%I&bg4(yN0 J$JARTa{݌h^H8 (ҟeg)@8H>p@BBE%$y#m-AmDӎ:2 ԡ와֜L#)L"`2@1H9()@4y L}9*X@ r4GOO8L&yg8̼byLI@uf 3"f1R>"}^@;k!IQ9(O8 t]Fe[BG $x,Ip"` {`8J@{t [e PBT5'nR- B*?1`%D `7o+uſ7*ְV$fH%Vb٧4̕lGg`yb`<\^`8-_Kzd` fK(SRP $q`(^p>OÎ`u%|}REGy@9uH`@rJwm5emhOU :Xe kH_+L3;(viS53LI$28@i >|X(oGK)М(hF=F $'M֟F4Ku4VPSt@I (S,ae)z@Z !te4ô_nSBkRBq933,OsNd!L,>> *M4COv)$d(OY mSM; : ɴ@Lh+ܧ@s/eo4[%p:NE| :Xa$Yn]m2[v] -˯u%.L=HZomZTTͪaq= 3Kࣔr*sfkA2Ke4vYbC:lO v2ϥU㯩 GjngR՛haRB[3A$@wY%dRP=~ϸ*>ZoeU/dәÛ+;9671xM%rkhJVI[@>0J9gvmdkI?l>W< -+iu*B@3wOmҤ2M3`0U_9za'Fy$E|(#͟0}ݵ/;/kT\j5viT(SBS*P {>mg}\1~D9Rdg#"=CNp)PPҒH #aeRI@E&XHlIN8d 96n=˳v+}^᫨M 3uﮝO5Md XX-A)Fe p?PHSTjZŒfZGk+7^M#سS;JH!պ<J+ @5 e}Yvvu_(M[!@2qfړ{rŹ|ql ҋ LR!ZV\RYRL-rSc^6w l +ԧ.v֐$ A\ﵶMl1GP+WP\SIaUZKDJ9!JH V pQTɛ%ڳ^q԰Ƨ/W5%d@@z0NhLt HJt@q:!0w ~I'U*NhD@?i!F' 1@8a))ه` }FQ<YbBT@,0 g瀀5R~2L̔g(4MKWm&(X3&F> )im6fPS!Tl+ͨ{;j@hBD$}*J@LHҁ2A'#1l046! ,F @?ˠL 4IN8 l$bmY{JD- LdS$)JD 0ҝ'72JU,p t z@ )\N="S0Kh'Nȧ, 'CI0 :3S JJD' nۜL"&b&IAz5R(&=}ܷMENRGNk9$ ;ShO\&04B O 8 8)&J3 995V>KG(d8=`tN0 @"d@:xp:Ӝ0J@<8=W#>eeoґX"Dq@I349L1 1 #F) 3Ռ^i 9@!1JGp PsR$03" WN$rH^)*2P$%?PNtd@1?&&0HO 0[5 ^[ȐA0P"cL5bGX3&RۻfX% 4`AWt@K kv%妅%\nfGR ;g gu,`Xty I@ 'FiUl1I͞b$t噀!"0bR0(Ӥ&Duy5#( *q9NR)*Tf%N$xv8}7,JCtJpRJ 3Tm,toөTu3 #8 ZFRPp4 ZutP=FF"0u @xq+NHm=]yjyʆ$9qKuuIZqڡQpMPD9l= =q׻p}rA(OP$A#$\\[_r.˪aN~ |gt[BO^z{1槫v[ADuGqY8np$Yb擻hygsRͫEƌz;AӐN> J@Ր缱T-}.X[ گ{HYqcfQIjRӄmxnl~!cW]zu3jŮ-Sq{`5MѴ*(knjE/TI8/`MzT&N@'Bf!"5kҫ3Du6Z i%|ݲOr,=Lˊm XG8@lڶpIN^J[r9jp~ v$m@ڗҾ%ZoCJB:@}C$P+AQJ[+m/S \mą%` G[ kJԲ핕":t4B~ۊJ}$c#M8d>4x^`/ʱ.])l%#"?SI#c[( ۂU>³ᖦ`9?+Mjl==Άʚwd%WvpXQ>q3)@fD>kEZƒQ\+U! :ly؛u]hڮZet)9˟  N=r#JASXr&M=ln[jD6-N459TI9 `,po[^obqRZz׳-MHDŽU3>ߍ.[)wtuYJ}%kI utߦm -BvT5/ި@C8\Yz@iCa3}{۶k"ಇ44d0vN 6+[]ĥZJ=)Q Rp珨[Vju-y@]C<2K@ߜskdFФnry#4B :ˆGS$>3TnDE@!S(dhR=N@HV 29@>>D F|3d\qC&r>(:f` >0F`3N@q{c\U2fKUeZU^J &K2qP xvB _(@ 1m"ZH&R9*d2u|n $< R9$$.4N@NPU/Vx@X*L)3 $MY@SblR(a=H R4?]dRG2l憞 n.dC%(j'ҁ,}]`! C@?tJ)DaӁIIg8 aḎ)zb`CJfO@G!c@1 = Y)0 =@)@G9ʊPS0p tDy31ᨌ0Z5'9)J}`FPdr9@8'9 ~:Jq)]| ȉHN'#(LOӀ i23>0  Q0NPe9} Fu`~/,#Lq24p DfFA#!FeZ}g8 FR*pn\7%aT?"z@-DTL't#B!ι'fx|U02*k;J .*\uJp[ +mNAoݔV\.AjA)m$JGrEW)X?T%jӍ$6N^#e> =0I:g,3$p|BY6)zvnuuev ~M(Ԁ1[:PK-yUNSܶuꙷ霹ݘˉwP*q)SBu))&S]Wgq{Sϻ:pXaI-_K%eF YbWʩhyh<`= ^sn`ݗ͗j.e i(iPZNXN;wƊF͚T%]æ2pmm HYDs-6͗|{!r~*YRASm58^ -[*YYTr$b5)*Z <ᠾTg-KPCƉ-zisWA J]JvCFaST:܏^[1Yeioµ 3'@z`Xொ?WK.m$J`-)3&4mh4iG#-#"ձS-TH  j\!kѨ 4-OIg{=3 j])SM6@yu@@2dNcNq~Q[}8nH8e@ Ng#j)ZA 9OZn,q^&FR'`,qi-SboĪ^W?0fqTL jZz.# >^q~Ue&FvΦfA+u;([/ <ʼ{ogSj}aCz+wӤgk-j5.PL)̀ZYϤM"nq~ZSe4.:0@v&9}@jʝɷ%Дq_H}6ɷ?X?YFL#y@c>>h>6 Ny-|PQp~X&eR]+ 7--+uHvA^:ǫN0MN\ˍѺMBc4]n[DRNk} 3oN1P^Ie͵?`VkPOWT(PE sfN8@90u0H9I:U4a<=U8` M'Zz=ȈrPT˸D b}QO&]Ӵ6&\/ 'Lۄ- Xb_1@P"qFH)\2fCL*s`)y@$3q?wHWO{*{Zڷ˴_ZFGQ :R[–D)S: JJN@@yߟ/lQo};Hai[k RKi{GptcVUAXj'Č:l&jX 4/t >0HH&X@q}s~\O4 mcЂ^hQ$H(R^GtzqWQ!3IXp*S_|$yJ'f| +pnjK%׋CT4+va 6JT(n:v.4.:u$)+I)*]H,z@r]c]j[Rn8-ӀTdiI7^Rs&Y~wcQԴnuHpw{n(rdqRJ] .:IH GX&Ѩs>0jT lvLq2 g$9(XАW ˖qP#vR ̂`m$`@z~CcV@KQ eAIVCp,+BBL".zua9~ D ]  J"POL|` C#8ʥ%JsĥP2&g( juWjM\j^ݦB@Yu0`5m߼i6u.[Ͼf7t䔏/uyZ[Fh]-@Фt-*3_^JiX'NreQ)&e(Xm!.A ( ̠1 ݾԶT8J./ 3` @ϻGlm qסWc RwݨY20N(QpRintTfJH)06ͯo{pn*7VI';X5{Rk@2X"Pqnn7sZRq(D<q.6+mAIP@49 Tp I'voWn6JgL.I_6K֖,VRf``^dP$ %E@@ 33"PR=`S`0Ue2*&Q- nN7mbBzE<œ$ 3me&uL=sbļMPVS*XLҢROW!v;dFpfr\H{c̐go鲩5tlUWJEK yWz&#ոIZI'/(ksصK`4~Paڷzqi,8HBr'.EgvU%ւӬ7!)8~hܕ4tUl{=JTI@75 ]Ŷh/.P_Z^^S~u_s|u}DžrjWSܿ k+u'Յs͙ڴ:j[ g;9TMR4G#WX [{*tT/}DHӵu2YIqJA*9tq*.;B^GqAYj~)q65ŷ=( d @SSwS"oٗXWIRLJϯֆ7XOfg}D4Tz OA@O N5Q g?*}2Bܼd&A`SlV)?H]4du/l᝻D v[z[hsSV\IȻeOn[:6Xv8|rmӰ6on6h좝=I}S EMSLS0_ò=znkmqM;v#ֿǯX ߫$*7+s2,@dR7=24(D&e0Û{vCN8҇4^00ℕdL-eM;hֱ"uȎ vepw:i(/5i[KtRR9+~~onú]_JmK7DQ =PVó햎\[%w!N2zF@cN{gC5;ۨ1#,< <͜e[Fb7uQ!JY"ˈssN\{ۻ=5ʖbW)̳2+2r=Z-fV42)ԯݖ R{/+g/sP$IuEA *2?\W]7ݻ8FT̔G~8vm7雬l--?.Nm2v߬OWQ-.X)~fjJקCJ UֿT IPmU-8oREd`6SqJз)ҵI\3,>7ϫ'>"I[vmF:I+Pøqӈe8IimڇJS1YɀFW*noPmKTZRnG`eyzU|uڕR駦4`iP Yl㭉TܝɬϷQAILի(A?(t70Z`_T"w>FM7W-XZ=J% JTz`;U}0qŻA]Jjyr2HiN%@w'n@ ?< ˈ*}Hݴ)^/vU۪F+1TN%uJS#) ?TRa;6_X}[Sm)z }Uߩ$eL%BH*TL9VwWnsE۵3%J3M@ծ^'շhҰI~@ZGe5+@QGGf0d@YOJcw(ry@L~6]VL픧( l}Uq%J5oL^'쀕N)rIEF@( }Xq#nOG20wΡN#wP. V;P[6PQ>#Z߫~!fuZI$8= +L' x^sN{7wݽ--Jl{S49\DVV1GL3LRN)JRra7©EYjLJH%_ˌT?M6|ߛQQPڭBI. שG)>xJKOAiSQYq tR}j8+^ZE#D#Z\:}X$)JL8~E7JĦN88y 0$Og( }jr=`!USW׫`1K%\m$aN)fL7[r[TmA!R }pc+qzJNQӌ듋}_ѯQ 0s~pqܖxuK T!Z*FRHI+Ҷ дi 2P=`'m2\Cŵ "jPJD9@H48*yAQ􀃼~]e,`?ƒCAON`@Oæ ҭTwb[G) $y ^囋(j~y5 ;V"`zpM҆Bjm䃟 q@$b3: \o~)KKe  38xm;lR*IA[zR{ujXjb[jUV=ZBDnmW.PLBHv]jsx³wn.Ci.3T|( S46BJZ4#1<o|u7%= qғQe@$Rx`mVmA`DZR5rɽo{j;5պ^ZBtNN8a ăcI8H5kh&W=`ȅb`:7}!~GIs[[ u6V5mLGzZݝ+\?-|{;VH~p)+R?=zUmlqr4IT=G@'8 U(7Z^m%kP)`0uΙe9Bʂ ^Tӂ7vp4w]8*jûwNolbi`κ:ZK`fVFq6qkRJ9k{+٪nkIM KLRsqfPo;Q>ʖBQ)*u vf\ &ZGS"_@s%|ܛaT 0(j) nӺvTMg㛓ګiIJ+ڤm |~9ҟӽӌ(7ߦ)ЕV>`ⓂAǬwJ5/1%!|G&{%vzm$?R_P 6{(}}ݖJhS*. 8)`e8o惄.շwe&5i>0{M\أMGFB)+i9v%H#wWx& "IvԿrvƪVX~uRб#2WݑkOa z)ܠuJQ̸ORqPVā]ܽ*S@l$IJmOW{؏!U~\eJKϏ%Bؐ+NPx@sjܕ;N.st -mלsҭ*.iFup.+m]vO%:~+=JԢJe1ޟټPj8ْ @ޫ!+Qꘗ8erj'.{JKgԠ qVqСط6nYn $IӇs nD͙)ҜSE*wfK a( 彵U\jS!*R2@,zCb(*-׺^[f8z֥23Qggra^#Jmj3WLi_#Bkr87kYX# lIiO3jCLͭ`Jx}NŶ"]HyT[T]* jRZYyKr^T[RMOx a)s@>v+ߴLwWKo *`u8 Mv^6~Sh*=*V=8p> ȝuk$!EIR8 \MG6Y(stNcJ[G-JpYXkZS t?(g )39ۭ5&ٵH0nV9HdJONKT+\\BͱRFѴ! <]ߒI?"IBS(ڜY[m3ʼn\Pq0 -0Zn.}bmZu9sl=ݺ:TP)B$T&gӷ =Rūu2Џ) &V8ɵ)?݊)3%phlKռd-&t9+R8R& >r*{-1!NkEǍQM e.cQ (܂QlL3rpbj*TZf'M{(t)*ҒOII|5 mQUTn1uR-OZkO\ Cs WMUŻrn.YפuyVPNΣ7,L#jr9~l>E:n'-4Ir>PBMh9+u@*U{( ~i廔xnKl  %4ImPJINhGY{"u[卆 IJeXQEQq-iPR-%*Rj rd[Hޙ]J6""LD{Ӏ6y{a$l#;իH Z4 qV H_C|DH6 ~v }+sJUGÊ]i ~Fa?Gy;sΩBݩx9@`iR RZ*$Qrט)L45fro;P3Al5%U2I%)$@}nw&.zr?Zmm4|HH|:@m၀S2Oi$sì, O vZ厬ș$A${ %J2r2T 0iGJz@`w+i,8AD6&B,!I!nwj&IkkX& `͵ϬZ J6v-My  $0+<5cR\@PVee3kH qˬkT+ '6dSZB2 rҦPHPT"UԲU~eRיm@gT5SW0i\qbjmg*Ez+5/ѯNM+z@YT* /6@AB\u!J(>)K k@9Ny@G8CɕVث>oLQ!.] :¦VFgp a@#nRˡt'̥.`"VHS8)>`"d@jLu++ı@G42 5TzʪPR5n]UZkpe(Se$/RY S.6k-(3vE"кv꓆N%O 8*TVD2 !*sV#"ڄyΆٿ{h)~HC]%= OF0y)cE3 {*II4rA>0݂DɅt89'B(M3iJRs-)"weAQIQ >>Srr?_o-:QMFoVa9G8 WgԊn60Bƥ$fZjJKM>ڎ5ML1vK[i!jHhB;f:؜9 7{R/*gk;fVg:@Tm@OS۴{V9qم?(Άmlʢ܄F?l[m-*hg`)m'mR"K/蛁I[vq? NmWiQӑ[G?wLhi]jKMVL/( gne(FZ%M^@G{ERKXxAϻ.ݙSW-;^HOwS`Ϭqi5W~ԫ}vռp4.`>psFl4iqw)^R; i8LB=ÿ*[m*o>.ؿS6X@0*`-SmK[5}hd!!>Pl[mv(Q[N[gI``%m]o9oqŸIwZer8Ѷtڨ:()*uohԣ3/)S;mT;eJeIJѮdknGpzUܧ;} bko dLas[:Ļ:y4ϬO7(m AA)`8'o&kSomJjzJD7W'y6U=9BtvU,Pߧ{=nVZ@KO8K* \}І6 +֕8ܥe݃TxΤHKjn=Ajl:Rqud㫹Q/qBJ'(mm>ژV}%H8 0(-Jv@@S#HnN-N4Σ/W`xOqh=PcweR|ysa҆ې&eǔSǵD(#P|$wFC-i8' A8 Wt㝎K{WRN 3:aW;N?E|~r`(XUZG*#R ̀a,f c eW _]QS3\2D|8N5pj 7{%H?>u'`!oo ¦ W#x&-pI*L|~=++wu*#|Gyf袲٦X-UKO:'JZ?0 0Kj4ٕθZTYB@m fxK%tr KUg ̍m)>xH )B٦SQcy_?7oq޷*WN,Ej]#ϥOCҸLIy#)\J*Ro#}8ws-twvHT䰜t]w{>:n;۷#MFM5J*SLZ2 &rgRc]ovZU3%Rtҗ}DKP 麮uEl jԕ4"@fKc&P7 6(:hl&0T|G&GU{+QNwPOJbP/4'gW9KKWUڻY^"5?u8(Xlݖ*ٲ3n;gKy)Z̞ 醮Y[}U5m6dކ(~)g?Ӎ޿g\[{l?X)qUͳVk[BBk>?oշ7]uVm:)w!R>6^Ht.MmnUۻܶ[i_koZ&henSOi'. ա)J жe ,')x=7juKv\RRڈGH!뺿0&zdNPM]LmbU9OKkSM8r-Wwm=8+l=0 >+G ^.I+=l5"0֪a3bA: ?pG0m]4߭.X6Lt韨xu0䏢}wm}q=8U䧨.:HN>+苒.[ȻόB-vtcە_$kUP'#CYBԣv֣ sL\1^4؞I9tR<cCR]R=5•4VS0H聏H Ymڎ k)>s@^k}|ҙW϶A gYveR"wD%%C,%eRvv3&Ꙧyτ*ePd@^GĖK`RPH&삒dό-.@XjMZ976ӎTFk"^ĉuղCOp%л!IU[Z*n[[U-8 kt E͹0eD;%ϧ1X?dJ\J:.^̽ =iN}R#AM1gLu* (O-'1W⫐ Е.2s^XtC,V(S-i ?Wp/!e^';bǩ*JS0O{2;YOaCxviempiF[ ]ƻOs׫ J`ϥ}Voyu*580[R m x GlOs)7vxu[!@*ORFdXcuRU ULOO 44ΩOLGQƛ'֤Rk?/D~mx[a:ڕ@hs85qmH-pÚNp#/}q\yVUMڈnV2S䄔{$JWͷ2zݡ]8ӏRiR3 !kl]Vk$V@F7 *[HH.Hk`mV)N ;Wժm$?m%NiQqwoQ"0+lZ*7Nch7HJ_)XJ| $*> _sZ@RDp]bͻo @-Ǫ\T )34c.8qam"ǠJss!{rx 0w]5 ( q '2/˥pctSku(  @{Nb3`` "SOK(38oW/TҭR J0ZOah &j+850, +ی39șH񺎕)0U)c,'g< 2W)tq-a(SƵKGz0JU2KsUOUg<0^؛pY-TR+$:S$iP[nVĻ]KLN3R}G`3i-5 <~̠+;ǯ=P2 yJF?O4-fܣhqd) $M T N|%|Ҥg6x--*{< "t[SUZ1ַ/q6ťnsf_p4TupInd!N<(_l}w-ibkڗN9a5um}/=÷չޝi.\(UXK)IRZO!uоҥTʑFqi3JSX>QJ)pO6 1*3=Gꗳ5jrB^0W6k/Z4 ՂL gRXn)׬q0~6 O0[t-I]zA_WӨӎsJWpORs Q۾b'\]Z.:_[lV^tSv0!h. |JPӦ&iޒ\ %?O6ڛfyBjo)2!Jgm;x&y[2>h!H^j>- ;U ȏ ~sljr=/mv5OQԟyUJ&Gͭ!I ^PFFK>as2p@C[&~e} $DT/J%lX[jdn;R#WH~aR-/8 ^Yܗe_CM?J>qQQTVZIPH;9҂ZEfOLmnJ%Wu'F0  n 2TH> ?['VZ tūǡM˻ ndD~lԩɅ#ڈ I\MZTN$!{RPVBWDR^0g$tJ戕7nf5U2d=T}.վқO!oH I +r6\B4-bQ'F(ּˬQ. mic]k[qCdߨOWqTyߛlݞjÂY{djl2A K^G8\sw߹i^,W7['Bf  :2Cz9$ܛ~:B zpUc8xb[mS3{*$.7\ o{xb=mZEl*K ~)֤rfofKt@Y>%quҧNq$n)TT7^Po'bR!Ti~6Nm[wsfkB)>1R[N.*x]\qwLu#nκkMI,Yz܈RK|.[4)38K OU iy/qrE?M4K2z~0rfQTl 0Eϧ[qSI+#4-?lWj͙8"|0I Ҵ*+E0>( FYW[B*ouHi L2Xg{)c7fDN nw;h¦%t*I n)e<5("y ; |SQ2O|neZ~Z9Zӡ)*U ?l7%W2TT3t6wycp %>JǨ >Q)H3X /pu+&_5LLKxbmOqSV~9x@_ P$fEO\~jÈ)iDXkb^+_#n2H.$jPv3J24}wByv@'U84Lkhmܓ):s H=Rܧ8Mw-$;-%@.%@}6^Cwv!~0 M%VHm#;xuț(J44 ?=PU}8]*#(@/F> M}/>}5܉^ AHKn%}+hjIJ* -P:$Ah/kyUo:*K{J *ƽ#*-:Йarl _R%z׼&;s#<ўӮ-WlA$O@HnЪp;Q$'',dD)i $y0/ӷRt;rPC^ke%^:@ROS!I]u>?)x #s{Pjw"2O?ީEnIeuCS">Z^[꺆nDqRTpۣHNF3t[[*R)Yn 943( 32PdueF Q= uH$&IV@Dt$Ƞ(ِd` AII:Y $$2SB0R 2(:P' JS~'HH2D+ph;w܀Bn[ݶӭ5sFv+Sn ֺsRHi91[|n=m^^T-եӭ4Xp@w[m]jU_THr%:g ǡ2$T &De8${ !k @EKH@H0Wk+RVEKRQ RY@I$dY@ SJsHJˋDB |8t9ϤT>ԢVvt4LBe OzsPI4W)$DIS¥P@HJcya y"J #֢@2p ”Wz{ JF*'~fX@I dV|Ҝ pyeROK*~)(@`ܤqӌIIIb ;= Z{eXe e!\ , S%큀 @2DX'.$L`5M-)8 iH>80y8ښw9mR\-_tM} X!)RA[T(lԶ46ձvQF8I;ANKeh30RPj 9`*D+( j']e/, 3siYj.ZufOȥ!Z׫# N[VSR%߫^vN\`>p71n~[ze=Uj:*YJ8Gr}Dcކi4˷Nihz{. JPT8a)p.D'T@m0R)󀮷 д"yyTJmJ@^0̷x@es)JP>YH3A(P|E HWġcmHIHA`*9Pk # jZTN ,-I( (lHNr+P#( a}dP*IR@`,75KsI {W*HĿ3)qdOmϹ?l!HbD )JD2 )+R[R>dNеe*`c0} @(m. `|y##퀒I$p FcA'\[Y'T 5 Y+ V+ 1x:İjvS/lf>.58I&~0ң"|z#R@9Q0IJB=&Y@HRJ'r}L$V=^&󀛲9g$~ h}`$L/ut$V :@LϨ)$ f]e(;_8{fr6ڝ !.|ƒU#뻇eطxC{ifa8Ye3ȶ6b( JA@@ Y@Qm>5(iBQRr^eXj<} !iI8L ֟C!)H)r$i*I 1)Md'߯rQWr;P隊TOB|l5hmP- ̺RNBv\*Km%8E?z Sku; CT! 9cfmmټ;sgnS2kNCČ;=TOY6jQ%ź)X,0ғsH7DeP͸H !㌥mnXnLW@-)IP5#V)m-6%)HjFkYrNJmcRTЎ%ef5sԾ/0RrV{k`lLM^t}U!zԲ*9wom`^ݴ-Y 0r)=86v%;Ud}NQ.zKb N>ŕu *MB }S6̄$'Y@u%Sè mP+% |%Z.6[]q};r[tάKzH3|[@n\ͬ0.EJqÙ$ Eo!mjͯfu{y! mA@Q%m۝{oʶߩ[z:)iԐ%5DٿN%u}05mm4*\uj*`@I>uS7>5ӴBS%)C`1灨 v۷=򖷛b@yz@wbbLy$'(gI)p1 j3OJsc@F"DbdaI8Pr OÑ(BҜJ笙F'"g<瘔 'QmN5ۯz>S]PMj+[nNC%(q) rHX=H$Bm%ZW @J&D uqJK3)TmPX R[J8@ A3ZQQ@%v@CjL=` 'XhX L0 )AHL6ҁp)@0d4Sy@hT[)mq:EM4T4O“:i&d*YN99O( &B'{`ŶPI& |=+II!sROP2 0 >B@ =OA&I0 $S.RBAT3b1y!~ aN<۩P#D)Z$HDP϶V@)dXb - ~AX!`c IXI^J@J}II B(*iDā0 `0u 5 RQyHޞ)$c  kZ:DӥJVO*QRS<Ġ8e|9B{ %. P8y]I2 ?wHGsaYS>hjTՖ#f]Z2j%0 mI[(t,Wi!H BR#)t*V!" ץz0 $ܟX N?.捥Yw:ۣ Z)XZ"]H׽p⻵3k(Ѳ,}*H.OzIЪ[}=kJfH%ƔtuRd'S+KN(,!AG9HyKdK89H qIc(4)%Y# Ȗ3`#6iLNP"a)A 3Zp2{H PPV(;N,I1Nd R5TT%Ӑ1SNdžC+ X@B jFwF9Js)x1ZSN6NxLaiaÏ^ c/˺$ZPxg G /ӷ&1?OpiIZ#q!%|0Z Nc:J8( LgJRAmE@ӧ&'Di*2R gzN='8ue퀂(PR d& !ex?R5|'HTR |%ᩒV8@CLrL]e"NGQRnӫsʄ"ˤ<`4F($(2RO\_yK(T `#&_'|Q8oռKMʢD%%bmu>8⦖ͱTBUiq..x@z]-!MJ$H2>yG귐M6vU[|m⌱ WƛZGvwzu^Zp΂5g9vB-}FwߟS7q ǡLp9ݼyڒ}jzuHC }]r֋e_lVe$&Hmm MHՌI<Z^(2涡0ãPq;B± =[V*[ \#PF9s&LT)hV~Wy#-3.nݔx?Pؚ U,%8)G}5tPUS4M+nxB O"q0:@  *3Xcr:} $R| ]Lf1|0ᴔ딄&" e&58g ] :Fe-0Ri AX @XA9J(j H&ៜ#% Pr9LZR'$gJeA9 x@Lp}e/1a#-iB}'Ziœ%A l┑(Iaj*Jsb vu 8` 4:f=i\Ç&Ka=XO(uAW2BYFujVPYR{3>Jd1%Id s-OϬVXe ́)]GpLkp?Dʓ e,qݒܒL%RJ#%pCJ' &HԢ`dˤP@D@ ' i>0d3'#>B? L~~)<%`5 0$&`,&"A$㟔|FJԒH?JI0N*8i _hn]h&Rg֌0CM%Xc!H:HӔnǬ4#=_t|$zK( 3BtH`qZ~?HBFYI@H0J%9]K)Jd0 FA}Bf8i%#EʄeRD $(%#b"RďmSAkH@$2D:fI)I%BC <`IP$+Jb~T) j &r88SL(TܓD_1lanu $ĸw)YgjKoɛߗbQ3 'V)-C3 6[I%NiPā@@ѭ:OeR3t jd  Hq@BB`?%#0 } fXZ$bZqI>I$&DHTyB <:@VtURD $}IB]BH'1͸)Ppvh kլ`2!_kP,a2>ް aND6(-D/@DD< s=ZL2WQ`'ycա)2IȀg+?d@̌@$@^@| #1,)@I)KN)b::p&cP 2z ▬3PУ` T.rؚ^P0X (kIPtf%* O?8Q*! G0 @8H&]%K*rVQ!fe*+CL$q:u/Β eIG9] G&xb ;8ǨNEc90,D aӤ%d)L@? "C(<N֛_onk5e9JEO#w/MSOwF>6fgN@z65dҾIPqHJ&qF{v}J2aZ:N`g^ Nѻ5[|IE:*m%Xd0@K| mZeƦWhZOYF.vq-(ޮMSnT U:0D$`:p܃|w[ZnR, 5/߿O#nnMB.)dS:2 D 'QmTj6#e#HB:}N}E͛Cgn\UKĕ%.yP4c"RvH-*}`3{W6W]*wvϵ3mB%E)J&Bu_mSaSV4T#pؚy/4j[jfE]С$uՔ*rmH?IqMV,L,~fUi-5/!HUYiR:uHb1yaf;]-R.$pT1[7پaeQDJ HH IJRHgR篨MnxSWfM b=R͋sYeo;b71 eaY#ɺBMPd2:uP N/i.*vkST8JJ>+owcm; ;lnTe"QD駷EY\vϛ+'$@b.ݴ>fjrUŠkT@*^ywn/n q ܒ} rRxmAWڣi!NB͞o^,U P mҩ}x@^$1$`=X@ BdAp& @H}FG?_6ۻh uHV) c8t׻yc}BfU:+PK Lp̵itRQVӢ?i8k*;o;.&ܫ(iE:LS:N&c/L@:JHi'm|ܗmAKd$'R |P"iPTdGٹ헫~ڵTn6k}[ԁ</v Ţ=B:|%ն=(js%^Cd&A@P $Nr$ t0wUr+orڪmج..A3ycR҃p$L)$GH Fg&USNKqġiROEf=]/T*W.SP7-nBfp4.<ݻɏiB*TăSPd :oy*R*2@'%`|*5[Z+UeO&ISF{2VȜRe󀾥M:HJ̄KͫҕL`+ԭ 3p@ B5aehTļ wO RfTO@!33`k,`5˾m07-ƞu*(crZlcɻI{ϢRS)悈Huww")gG6Iպ>i?tBEcJB]i F S4#J*\N0mGJP_D0 @9t.-$(fr˽%A7w=m=n˵CPtvV05,`/4Z9b֚gsaV6[Ry88&D`,[@JFB~9J%~Wﱬ-zTTfuGE6 bQ&g:B,vܗCM*Bm-n($LՃs=xАjJg %+֒L),e P2':Z Kj #"qlj(%^ `)TsYO_}jl2Fp~i\nRU; M+^k)u-cL@mũCFx@1R)Qs @7Gᘘw=i|w6mJj\ + Td&zorMCyEΙTW"B}=9E]noEުGISCy"ZKOp`+2H9@zBf#?5F5N BfFI@8gS2L*6ҭoV.KVKA\H#,g-vܷm34665-:i%(BF$p2BRzs$\W }$h0^0'!/ RY@q+IRUs]6+-ť-J Wʓ'RVhH `#RE0US 0N-G"d`g{}msSoەeUnRܽ S^Py^7]oVFhUi d+Y 뷟oN.4.5vʋk;h'9_TBR'?@mԥ: Ie9{ $x֓@NRIB~ >t=ڎIӆI9 DfJzȀ2R@:ПWp f D8T =p5$̃)R?38@y?H3c RτS$ %HJ^)r3$fs L@0RpH@灔bI=^p@~@z,1)@I)IRJL$L eVZBfIgTfs}r6HHIsNW"ZJtTJpPZXNU'P _BrG4 qD$$H@k S,$p0R yJp3iZ D1> *I !@0 K^$e8pn բ÷{?;蜩!,!5|65nM4gwE pZ*@i$!+'Lpƻ]S5IIҲÉXI%$r]ɰZږ<Hq-閝%dL(BMxS46ݭMou YZD@I ;c5s:TqmX;WkTMNcɐà+~mɴy6jP鹤9@sJjhd;^SjпhlMILD /V.WR45 9BsX eYǜd6C{m;z)K(Rʇ$@cwl˽7ۭaa=)Dl`]3m/gm"XIԺDINECϤ7.:Z{]})HAJ?k|ݻ)<5|1,G)ZEďZ> NIuqToh44PЦe/qP5ywϩ^ܛnI[.U,5P"\-7zU+ʭuSN<`0<] [wncq-K,b=m:nnʛEM6Sj,5LFZs08ުgX(*MΜ6~d}8ػm7& )U6^"s,KuwkWkV΀fL3͇*oQܯoi5*R^lVn"oq6T@B>z͟66Z]ϹڶWWnkMKAqEDL!GЙ@vڿkO۸w\Tu4'Y_x?[mܹqmSX)UJˈ/i$JEIlwh»wwvֵQdQ p{|lm.{kyn4[aʘQxz8 Wp;囕`)ꪺ|ةu>p LMf^wS7{ZZZ_jH8`66 p۽v[y))T^[=]nҧqZw];a+&ࣩbpSwl{ګ>C&)7c83m޵_TOJ ia‰R<*VH,'%ty% #9BtXxo^RIASPf 8SsڽXOnMPj~fR-Om㜠=7V*;*E܆FEMꔼ8oٶEhKn>_e$9n۷&6>˷.j|d9: (p-?ޭ7QEەƂd)cB@vz| gXFʢefwO-j$2?O{²Tl ̧ 845 $ օnmojErT^RI@@jUIj{9}t;VUOc58]rGP @Ĩ 9, wgEJ+.l[Ӑrz *fRn9KX2RKf׸Ӝs[l_-7@ B|9ywc-YqZPi'T@Dt{8FɷyTC 0pq7Mn[wG~_`SA('#폦ĥK?l}ZV 6u@oixk]UUKl=KJX(gL燄fvW>uQol:qI@hz)fy INn*hyk} KMK~ "e' k&--FܕU+ Ӑ_Y.(*L#I,;~z^}[3q %2N$u1tJ}lVSRQR*oU^TOuf P3PV{avO ZQYTAZ {SU4%R- "38۷m|>:Q\ijd#ԕK(a%=n&kd5q]M3U )uD|HI>0jvfvmyuڢѹԉ(΀g2> lj9/W=>Δ%u()}`e$!2(b;fZȼfcyNY9z MEj6 JaFgkb_ 鷕+>. )ImE 6BIL E+ Qs@Gֹ"S@x//w]nkf$5Dz'R^XIHDeۛ-ط3Gn3icA9̈ݝl[έ.5E&PyrZ]׆vu+%u*)8${ 8xoݗ:Z:*6 mⓩ'Hœ0Y+w]=z{U(Rt+ 5'kv7sJԄ*ZNBF$!.QmmOl}&[x NGnxjs7SOBWcO3W"\,7-ЧҔ;)I>ừw%UqeVUͺ _EN%39`|:u|U=um目k)RBj0}^+ūkl.3M~n_R)gQ!ÂG.RN+r}E=N5EGoi[8PL23r+nUm޴mRo -QN8Z;ojw~кwINs>;o[jvWw-HZ[qRXNP>iTY).?|ր٩עiNe3޹zvNin\+nW$K m.5 ;KP˩[+HR*Iȃ^vqd13>䍩/_/4ͨ~9yo:ncE%fX.Wzzw}G1{ 6l<=~ܛ|&Hm riB̜Tq9ĵ}6K6] S %#g] 6NgڗݧoZ_iBe┹⑧\C 7dt[V UKJ1LfƏҝy[ϸ-kZ*qkQR|¡A'vnO#X$sImd` v潿jôE+P\QU#i'3A.*h}8{(yb뮻jUuvn2ö%6Lˡ=D\_[;Gm_N6ˮk}k` G]IS"rmKl"ٹgmU4o*Щ%52@E?FZʜuƵ|*_A()z5í8'\ּ1BL1h0կ9võ wZݾfm`-LĆ#d <緯|w-Fbuv Na6)PL6NT׏o@Ā1:GcSS\w.FuOR&eS?( <ٲ>PQ?YR+e*D%J@}3q:u8ndx@pQěQR7QHjq1)X@e8ǟ63kmmvI@KF@- +7[bp⎮M@H]K840ik믅նp7ܧ^HŊŀRӳhV3\w;ma[zl2Vr'<%gSbZ/;?@)MuRkpZcR\  -J)S{˽o=Bs4+%)Bq1yn V[fP.!)HS2JTUHղvMbOoF^sCQ8ʴ-.SҤOq)^a+wqћ>odA3W:;RD"m#*ܨZPS#5,6TDf.^:7Ξ۷vtU"ԣܩsH@cWtmkyۗ-\*c!6TTu_O v.{­^~ezuI@Sjglv~Cܧ7=Vۯ_>jHn 9$kq$)zg1PnbYhU-̈́&] plˆDg>h]]Wj&YW@髵l8H$D 7ͣcĻ:׹kp:Kbd%h#+?yqm*ŴګŖo7nإF=q<2j7]Uf;`}U%|SۚEOA'"sa؟L[B׋si7gѨ%z$l='MGȘ Xj9Ne3 t9@8JTuKeATԟ*Ki"} IR0&i *Ec012:G2$ 4BB)JLPa"%E@S)9@Q0 }}e8~V]:D4$g@zp% N$z:48@ IK7ά%1W% 525H(d -Tu+Jd 3y (`a j)=GH 3=2ֲy)hL08YCd$I (uJg,?%2 &a"PI)[`fZ2S ,Ce[Rud`,D34l SOWL`#J&f8 }t2W;)u YƵeva 0Y9m{S=Ei5 wZʉP~C*Ql;֋$ycW%B+fk_RT0DJqϷ.FS.o[5ϴ⇩Qr*)KsJT ;---]آam 6JZt 5ٳ;dbHս)nӥUPpv֚ ZjgAJm°@cl{3omGږK{: CIUO&}< }')eD RrtxD KzJOID%9u&fq(a/OHqJF2é3 -J3IwNx@V]PpNc@] h̏?|QO:2Vf< Xcp6*ﺰn-'\84\Gx@gCm8jT$`8kl#EukCơpJVN9yEr MYLó} x:s]ӅOuᚋ]j먩?}Aj[n䤹VH}h r^-JqC9@r]gqn}vEJwr*)ExPyK,k8xEjqJIҶV=5KI0ͲM-=졦R2 @ 2k $ `/}mCVaU/PUVSK )|AEP]ljTJm忄!. ?쏧ltuڻqSBmC&9h]]3KJu% @dƞ$قKG`iKH4~-*p޶j[SHSiqMZUOl[vߵ-m[FHOַ?mqb) z,!6 Uu0巂RڐHJ3a( Ƿ ó-ɣ(%$tPY8em+3 \Rbڗ@cٸ?h/޶eKqZUitc# qڸTJ^VMjĖ%?n0=vejm(hK)3r' 9>zz@OSFmĴƉvMj6@AWD 3Wu+7 mZ[Z韨QuSS2Yv]37D鯼wu ~ug/s3i{n7.7-sM@KJ8/n]]^e;ѶYC_L[IJXȑnOw%kv$6ڦP8wB~bcĜ0ry`1wΗ'/LdVYKHPjSWWWIj=*yoKՓ0*\ SZ njڻ5ګ-UR4<EՊwܿP~z4Ov]r쩷Дq498Kbm/m)YV)hAeI( 귐VkjSmO'v*uumk[xuJCNb^ʝydmv-V3T޷E.iטp{߸mE@-rSCxOiە6=Kr2\KO/dX[^Fġm;} DQDH} OOjqml8J[*"Ai@@hHjeCv} ܯmn%N}LOgN{wl/Q")8^Ԧv̵봶f[qjZ Tz 3϶jmzL$dzQai9Mjn %suS 60 @A})8. mo{t]h웑4g)lT a(|imC$gomYkmjݭMi(Zb&ôU )`p g컅e^]I!f^+B\f`;sKY $.׻͒@a=Y`=i+8v 6E2bUWTvY(u'Tښ2Re@yg})=w]oWɩUV_fުCa'%ȝ*8>HOw)-{s.lBmK*yԅ&~wh[i&\XQn]tmϪ}fOǙ8tQ7S{u}Z{cSvcTČ=U'R8 % A3t{dNsMB*[b4*aҚ[PA!du #Tiwn7볶R;RU41?y1:rPcOT⇎jZA\vM;yl =R`:^߰YnmFmTtHs0ԅ>V;jв 0;ΎOAD{J3)-gʷw8{߾U_/P.y'2]mZfMCjm-6}R*TuuR})HsՇ>v%ӵXbJj+m/r߹6ktrխn*C[Nx6& sxousW3VP3nMBB5Cnl2ҵfIǶ>o`[46imNRYTdK< 2{G7o^o9oN)-/jvڃd1>7lƺ#T[Uܩߙ=z$a, 5aqÅ7h^5 E i* Դ,FC |pMuq  vȊ"TRۢmiJkX38 X#nm}r[jq-NP4hHK8 5}:ݷ/)/բp.zSC '0G3?G[uL{k[*NL&K3KMHؗf oKTQTGyO` BCuFT #r=)3dHR%JJ:$u8S wMݿ^o/_"V;hLy3H̠,$DFid JA0=`+8J<%Qzd*rxXԐA~puAT0Nj!) *RI2&FgP=04(}k,Lqd1<1}Yh2@0 o&XԪAGtL@Y%(Y֔L`%5Hykb=g &_i@Hȁ })=]`9&[-ʃKq]cNt ȂrCSI(CQP8 ;BOOd!o<@\%$DuH?lk҂I8 6]kv+6)`2nR\Ju$L8;eYTlIo$ ej:> 7wass%R񩦤au&`7Zgu-T%"btku Te7,H8BQ9HgJɹ7W¤~*8@dL0#.NIu(+Vk:fOA|,yai%x@?̶1Yڄ'Q jZחK44i:LL$n"uh}Ď M:@# FJo@WB+N=`,J>hx]' O>6FTi$EC}I VJ*QP^$HhR) 9VK6)U(jfR0IH$g I=LUMI?t7 m*N `2Iԭ2ZL!| q_ e"va)N0u+ 'L8~S$G9anUo\ W-QP2f`3%uiR@qA$<$ԙڝ67m7[Ӓ5K _ c~gńE $|*"G `Jq"H% eZR .iME8ҲPb~ִS&A!!)H >: !q JVBx{OX k.FYtIK|`,y!jA3 VgRmkW+Zp>qED% @ 6`L&N+H$jQ\ÂRis }#39Jr6M [4MB$L`N 57mҧ_mD*V AL@)dHJ$ /((ˤx) Që Iy'QeJԭ@N1+=0񀊥RRuנ iIlmf;JwuejeVuPdI$ymjȫp4$<dz °J椂$^`AH "s{w֒4LԔ@FPlM |  >"ـE%%kF3RCR,䮲KiO`Y#zR kz{ZRѐeX#*> J[( ںvtƨT ]10z>*YF]vvͽJ][.OlkOih&L#Īf$n$Ҡ0HpS_xWvo(\(maLk2f`3M߸(M{' Jڸ9ݧSS..HcJPVD<` N@A]ل/L< P 䜵QGM*mJWUPVKhF]38PnܵR(.lۣK#!cAt/3@p P9&@JuzҵXȐ8nK(B֯Ƒmxk{VWڛQKHRt=L)K2Yz{즶zwۅu⽺\i~`yNX*&',gϭ\(jL# TS{#SJI c(S ;&P { F2@:RRVpdMX@ S*p(R@>atq qܴʀ̈́:蒂s ,AJZհ֪xNZпhBX@rmRQxRڛgFҚ۰PVZ mc\q`t b[it*{%D[qTo;9/._ۘ~R[^h.-~j(Mqf."GYUHݪ:ejUMIlI)gͣ62𥷹[Owb2uBnS#L3׋eqR?Pr Z' ,Nz[Uv|oWF-TM"EN<2??o )ZDnl*dr@ r3\mqJ`@JRI{~NەTy]WSW:K,pJcKy l:rz($D_ snerMv.f-ήUTYFփX_՝ﮪػWh~t׮HսHIJx4Hg8 'ӗԕuhg[+O\jfi\ٛj=!xPnUb]jv޽.T%i@RJg p&xwY*Sdi}~SuSPOŔpN׶}_Oh%-=*d2^}BMJXzmo=GʸuK.6}NW #R&7ɻm&*ޯ6WKINi>`=R'$d-^"jS%8'}wJrPf>@KLZz ?n!I$'xEOe/ c`-:@$:ʚ8Dx@NR>ѐ.{dAc"-Vi˯S:[Ma>❙#}=ip5]VT׉lx8= G?+\m'02>#EW2m'l1hZL Pounn˶}KYi$u&Ǽmfk]RTP[5]Jt҈ԒAf 6nvMxHR= 3ZY J Gj])wJy„ \Mk+mUUm5%Y@ng[1vOɾS ?ӍIJӘ3\}ڛvX8W;MrݷCmYjD(A6>@286:_8ll[W]yZ[RR 7vN=Mr jTvMV(}#ot+l-n*ֲk O ym}jnG)/ѭAyecP~HTU7D٪u 0+qՙ%)dTU; f&,'9pErE/1WjFb=~\7j>Zj}j.6dfFfjր% qsԳmW5nin.MvY>Q3Ul]nִT3oУO{{`tzKPTBSsXNE-r4jZN"eM Ī2($!>^09u}ECsȭ(:~k;j\Co yxqZ˔|Ӳ,H8_:}s.[ZhwҀUexKpzCNj*(:R&`7vװS]n}BP>>y<=`7RAeXt=*QXɹ6y:)[t,9/`7e\Y5f4F2\OqĎFd{ +Y^KH JtpN9@FJkتbT*JRBNꇤ##F? ro#sͼyl1u\GdzI5gx7vV;2A֫UE#W)we=$Jp**2$fI8:/;exp۟tv|˥V3Geݫw=ixzKKVT~6Gjn :ꨩ,T?8 ΪFYZdjum2Iqes骦tjC-OP HTK %ՉVI *1=`9xJv޵+(7$TWT(_pjU: T d&> y?Gv^ϘS|.oi4ɨKgN(PmN 7)տv&ms$}5)gOg!鷞ĮbbNzg56P ;ko50N~BYg4j 0[w=~mMϻ,+w'v} T&@t҈Y̳bѻWJo+7lӾJC<[i*QZԀ =0k}8K%sTP0 0GuJⲳ5Ltd4mf%TR^;CR'W edHMqn*yU8jyO&P'8@lxnosEam4Z.-FNHD?VN,+-qi ZiW8}KQ@PV[sWq?5[: M3Iu9wVjIWY^K'RH%%_|j)! +m;),A  BBNELlC $htg[sPZJJ`%y):uִjmII9J *qt Ԣ}i.e(S9Zݳv㋒ҊGX%B>y@IX(ґL}}^n[weh*^K $ @;fS>>jDl3G0 <9LVQUIC,XRלpݛKig<\n\zM4 I'Q#rVm6;eVjǎ2ⴭꎭ3lN9ۜk\ŋcP~Dv*]:\YK f30vl(3}f~(hboS%"F@6D|~BWokrU7HQ,!uR4(IsM 7*cqP*y)Zܗ p/q*[G4m-UUa5žx<>Y S闧?f]SGY_ݠ`6)%T%XԬ/P,<[l;2yrވ(jޓTVg2WI*#mjw\^͢խ*\nhI4l_N֫$PW}ԕ]JPN]49|lAsr.ەYq.STR^0flY[AzʑR2q=`-r'SkWX6zGsK͖oBbP m^ӌ}Үt[WqV~5L/ټW7=p5T͓qW^-4$UJ+%p8~_-[rr]ݷݫmzT:ꊰOi*8'3`7Awm}=gdiED)OG f I]ōiJe%+]A_ $ ۋi7ڻv6nExe/!V JH j]խWw^`Һa:0;GvV1YGSr䛨PMCR0!dHTW/R[HǩvQҩ@Xᒒ}^&WK?4O92>0 | -%sIJ|%8(8ZU5 `*CQ #( 9,{qoUk%ҙ:y l۷ J]]֘r$ڛWӠ+`DNձ[vThڥSV>%{SaB2)ZD&`7&n (٥YoM1w)i.%*+!ዠ"uU.wz{eꁀFd`>@zQ4jPB$S9bV*j=pW>@Z^Jd0 $kvGzu+ӽԐ )V$i@@d_Oa#n--)WP1Jyxz;VдOZhi*B4).1̤N[AY@x3[{kn^0Nݬ[wUdE")*PRe|ݴ7Yson7fS@8E5#$;7 :~r7-u )4 yl8x653`fKPI~m;WrkQ,bO)A=gvJEB},XeD%u2Nrm}(6ˌld|D'moC1\jtaL\jSS3+Q@s w~fwUozCaJ)J:esln;nn{_ +ItKHY"x,rӹ}WXMeKeOS4M8@a9/z-Ύ{~iӱJt)e_ԃzeU?j866蔲Hx4#冘ǹN3bYu\hihd[TsOA)Wڬi5[L MjN2WXKKosFºe͡)mԴjJ9 q\έ˵eʑ\4 ӄ`5;ý^y^T6̼s84S@Un=qlr)€28d 5[,\?XMP==S~yjZzCjf UƸ525_"@][N JOiFl1y &r.3 *m3svk-l|\kZ*AK[);^spR̳&GHӫ:TykR7aiKzYd>G 2MڣO":.\ؠ6)Kie3>YJD1I00bVD, N r㽣tvG+iMRSSRJd8gIrWحlU5[=T.e2I$xJ%1N%-[) I)+L  2B $a" LwlV:ܪvMC%Ƶ$RɐǑ7C{j:z}.<U2)o9^L-gT*}O?''p/l'kn ]rGw+F 퐒%0cMl}DdQ*)I 6Rf.(̤U;trVhnLŷJbFG@{Z*^8SbcP`5KW 4r\Hi)Xe;8>(ΩL@z֦Ru$פz`>W.]o5(TծD‹4l2@q2(e vy6*hh=Y\K$O6}:qmmj…%3#SZp޼;`nG\i֢ۨ犃%08G7eEg٭R?2@ ]NjINvjrTQ7}TP%ɕ8{hRJPzrVa曲mheKIL%ēdL@n<;zv۶Uvw˻#]-80X{UwEQ{UѩnңuW$1ns% 5'Y6x)@rԽYJ%dD%z}Ǘ=V{N/3O:kSV Z f}o4‘V r}%OXs{70{}ڇnS3dfULWZf0 a|%fڶM.򿷸.UE:!zYu@@vOe I8b`&(H%RBUdP>%iROlj%ĕKV HZTZt6U :$c, &J WH I֠8!EIcFu1 H `"B!.Ra>r'U\qHjs\%,N y&IOv(wTimp=]+ P )A};bic;{j MeFgfJRI9-?(wۻ,Jd,qJǥhP褨`Jd,'!NV͹^ٗQWnGjӮRR1ܶkuw E};j:DzV$lz,̫UW3NCCn9}+}"\[+j#/X_ hʳK㧡(zOL4`a8*vVӦ;hQ6HTʹd="PL_C;݃G %vnB띒΋Qf4=$X~j!ctmsTp < $g8uT<mHPg% >] FZ|t)mRDO/z9)L@Y T>FS`,(u%)ȏ(uFBi|V6}`\ YHG:s }ƪwW-@[.mh-?)Ӏt#珹or9[wB[qzv6@v [x5.MSN-Ӛ*>9@ta@j֑"28x@xoo _ckSU(SARztHѡ*-S*Jr\6+Vg7CM%E5MUL<M. 7g>w%NC{٣Wvp!F*ʦVE g%pMU4ԎH4%㍠I]qB1non5vdڵ(Qwr^ER-*z;J*JS/>w#Kܭ *bVښTbId}XU@d9[q^־dRnDK+IRS) ( i)H&f|h"YO_[! <% 5jF!jVs0rǛm?fj:m}) QhG7&޵Jܢܨ7z(e=Kl)'(N~燨2d7Ju K( "q  Pl)JIx@Y4|`jB@i$`# %tjVG i;8jwΗu])o*a G+r3\Cζ;uEya%֝J >PFÍ%:s^8 VN)xR$p!2P dH"ŸRJZedV6 rԵJzR? m-ޝʊ7y4ZHup6͂g趥/*&C,̙^ JHcFԷo &{UP&J[ ԀHm.onzTqtM(' T| ,Is=+I&H di)\ +B G98u5)֕Q zaQNNӉb]`2H\ĥH gIiR2.&D8 :#/&| ,=g( j|n}*da(l(~c?QUNB՜%ե 2 x 퐮"IQ"HtyT!"hT\y.rGmu@L۞^p}*ՎW C`b^{T26td\h+OI}Z[}BT#Q[)h C Cm$%2;ڿhZ-eܪҥ(8= [37J -{4R`:zV`geJ£2qXQҧ`+ iBV2%Y BJO@30x⎶ME^ّG]`&R,9L!1`,}%qu"S`}TAOQ\ `K"|HE2@% bTKH]RO6 BW/d\6WIsQ1SWC5R-%AP> ܈5Q`c#RdpܒN' 'AOiS[4t}djRLIӋ-E"mzZ iJ(#4   l;MmQ~e k_fRIeۼŝ{2jnu /O󓊽\xijmZWT`6[O < ӮFNnIC0P)Ru{:[f a+t@:NqJ:zjԅ4CJ  pOoX+M@ya%(B02.`{6'x -G*]s]:fqn l1,*:y+L)@[Н2g)WwD? {+wRR~"30 jC # %2PZuiB}@JeFBRPMHK(L8$r]ûgqn^R6n,{$NO@`5Ϧ}soTW-NmRʥ Q&9_29i]%UT!̢]2`K6Q+ZV*RVzn.Xh)صm מ#? q[nRCImeKmG!3, 6 mjuoC={)Vv}nsmUDAdAPm+- ծ50 fIcJ%)ZKW4hݼ[KS͸=*NBT22_)NV%Pn .Y( ^pTi@sKw(qO!3Tx8RjRV6'2@PYZ "x 'V T1`fB@`DSvVN.x%8 WDd~9#vmv"UMQrR"uTp 3|qMf PU?dIiL F3N,́?g@b H"\Kg֤㆒@'e ! # ):Gf  T[>- v5nZʓZÊHu S=Ptʾ MXN+C@mVZ:R)? wj$Vm-ӯo%Jg32K#klEO8U%*OA}}QCbX0ͱC7O|:s'GɜfXaHQ*B92l7̣Z%V4+hI xyƾ1K(M9\Eq*=W{;bjU7RuZC .a˶ kdSmaO<{TZ߻f@fUAj<5WxLV|tx}))>ްSS[ReAh(FIc# II$% *ZyjŻlKQYki%k*u*a"025=s5T.fK%6+ժ`d| 91ru:uBj?q-OڨOSe!e9RA*P$~yQ+SmjjZ}*S}B Ԡ:@x'oR76V&H8@@ *GGRvB \L9<u/@HgjmQLW3;&Ty&hiC爀ܹ۠㭷V&%_ʹɺ9 1Wnvv.V Ѓ~Ȼzcw}cF:&Ze D$kGYB{<%p9YSkp@j#8tޙt ? D2t'3)Ax3>P=K@!)ꜺNLU0{ދm[jZhXrƩ 2F]gVekem(Z^BS=wjdBjw2)uЁ97-!޶=%ďM-[a`Q8j4黶[zݲE2Yyj yJxr Isq5n+&mޚVI'dnN޿7mbYZ](OR) rtm[z !L0ˍlS )YH'v~[Jw\-R(:tP+'yUŨjm4`(*mTO^.k RS6]Y)Hܷw!nڻuzMNB$+#HBv6 7 ?re|r-ԧw_/vՎнBc8 =Vw,.Y{rpWNIiV`2unv4W rZRCSi0nѹw=y]h{EhV.ՊPLnK8I&rXmIm-`17WʫUvlsL8W Yn[rW~TS 'N?>HpSڗ7w>䧹o]s1qZZ):iTB>dۿhVJEw CN5HԊP )&sE8f9pq.ӕe=TtIP|7ym9SMluTVdo HI8m+7%nYL$k~_] K,!IU*S7s 4d;0r|YCJT~Ri)P%F=,Buw G)DBL8JgP9,JTW]I{.n+֒e an,d@n܅ʕxZ^֫HfȩdT7+;CZfL6sHPaeaMp4  P$a&]g9c)AZA2h` JRNeq)q!I>4̥Z9g@F=RA2'˗-{UAfƶˊR,)s8z0l+*-c,"կ?۳n1t,TDpOzޢ#.)֔vAT}U3myinlSj+B ZJ2> iI?8'o smӲW-c4zZUk򋒹Bhy;u-mvJiԷQP~㥾 +8.GmʁTP@_Ĉ !NqkdKH83lŹWUqi5R9'י卽;t^[uoibr'7U^.ح[jٖSQ=b!cU 5N$jH["_Q/j @TMczj}B-BnaL 1)j@FP'##(Iq(Rf )P :p I,ҐpPidcY/aJRA@Rm}Zg @m@J8maB"06\Te,t8TT'ua!@Ȏ 0ީ1Q9׺7+i=rJB-J=&e6Ѹn%(Eɒ;K)^'{ 5n@7n۝eʓL4Bjqr7k;/KN=֪u+7_t2G "pˈwn ^-h'P'ղt {4om߾&UJuKА&$Me`prW9P66Z-5&Rz%9Ӳ6u ]H%"+ %u"xiϜKeݾ[ ޫ4IxHǬs?2_NmM#U:t@^:0{nrwzTֿL?G){L;}%`ZܕhfAQvXXxwعG77-TZ(mtv֜&Ii2.L,N0uchU~ƤMW~ڵ3R|}<`:9Wo*zUpl J'@xǗxcgk5dָzS S!l$ @zjv^UWT`1N }Fs.F坷EvquZK$(sc)mR\*ԄAD3ʊ$@ysHSTq1y ))8OܕU'閗̳$e5- iINpǜAOnjfB()uhHm)),HN&ßS^}mnmC|. 4r>Ϩ@tYm47jVԊWn-)U(tQhrͱOrmRe1fNiSjV+@?``6.Jn$9k2<岎ښ$bFp?V߻bEgpT{Hm,w Re 8Q;[1_t;} wN54xL)JЄbF+d*9woK۶> t[%nT mR}DVJpJ}suUTjx|‚FR0I!' 5``0\mȸꧥ~S@#ye_4Xkێ{-Zҡ>I&]1O\pU &TM$3LϺ?5p/c^\v7/Tm;JTLY72qfg( %NpBTeZΞXDէJ38@ewer zt(%1PU0J5qByۊt3S~&Tqյ8+[܏n۳jGK{Tj2@{u<նAj]TO[DMlԲ;^W)>Sy9(*:[r<(hҾ]vުbn/ҭ)/jm]ƕ%O2wco>5/qEk|l2q?|f7K*[S.SU$PVOٶKջۆw&p*kԴ 8m}>Z۞gQhФ(Е&oP.NER<1Lshnz̴.(l٬t6 'ݗXI5u^ڛrlWHO`jSic9g~nm^ W>%C:)@rݫ.ڵ_]hfW^dNNI@q%:e"fp%QVqɥO[/uv;*dL.TB@'S噴KecR̊ Q8)mmQѽor*-]UVk+)hq_Y-d.nRUՆ#._NM6&‘ڟU{w=6Wڶ\iv- ?>#8W{l5<ݦti$_ @:I)_8=͢TtBRZh l[~Zm\Zw*P!~}!N p ~ej" !mǼIʕbwST[M 9g!Qpx[9~SB٪V Pj xygq׼Z5.c: 0%pT*Tf}j%EI`3;CupNZ~Wmu1PS?iTU8+R+fKd5-jzs>,KN@shSv]l)t[oU=M%ʱ%+idž[ `>5Wx󊶞R9k/>R4[ߘdYRсlZe8 OzgaAiO4Y%9 9N}3¤aJ{ *_XХ|$"fU0U)0ZD`Q:d<4K۔;WM|tTPBTΐ)VvKa}mlRr[uLMp8uoW|KR[u:\IcsmKuˎ׸Bou3UBD922w/l&ù[`]j*:4+8`./l\,}ʪ]eR+k.kW*f H wO+eU5TŽ5m `0;G9e/j+EZ!O)QI8Jjmwi;ov!K n-YL9qM!R҅-# L|4] 5ߧܶڭ|OrpiM><9uoӫIFz"'HL 0q8֡ MB魴JmIuH qp3ܼH-sm8$oFW*n,R*$s`],+ة_l%On%ēR\*\E(_PUvVλ}gltio ڝ 5HBR&wӉO8 {p;fٴ-eCkio<#,O;cr%x=vw6J[jJ`$˽$䓗iS-#yݣ߸)U'KQS&51!W|8q!}@21KPЯrP ==:@9eb@LRb0q2pf'#+N1ˤ*c*O/8 4Vӫ q:Sj3Zuz>B+DI8O )d2Kp VV 4L= !th3YQ|1J}?k;|m٭w*i(֭>qrqŭ;PRjn>8iJJ3;m{&iWPLU-Gʅtmj3T9K;vO^rR*XH [me-KM\ [u+.Ǽ^YX鬈8?7RO\q$Uk 6ʷfu#O(yt K`ki,\h+Xam!?Hn-lT9L 3A` ⵁ(M/7#4W{=k*H =@ʳ`rC~Т%,[ 1|\sEt-53k`iQ) u#Q9 -nKܺ MlHjquUUș!'\Yfs2v'TSmTVR۬}f(|{srvWw+w/Pڃ$-H% (H4.8 ܷ~㤥E3T7]FEq󀓚+Gr1,oR# 4!OF2m2ډ}5ૅZX-'8 ;ctQs5—l[E=GDTͽmwԯsL? |2W^Lɰ9v=|ӷh])5 \)n(z#N\״Tk l& d-۶yI ~ɕ4K )@tɲ7Y[qVvtI\Mo%Ci?㶻 S\mcAڥYWF8ȥJ`/ܜsɬkv-L9HZ JģyoU]j^6Mml{=PޗQTiFa[yYn*w-vspnʖD t JXەxomV>C9o`,GZ]o2>@yΜe\_oޡ2RCԗ)\Y*u-dw-[J-uv ]]T ]]z y y}ww}mbtJ]9 4?v4Bg:cepHV:ue:E]JZ~ҀL*~\JpL H1, 4켇h^t\Ҽ BÈ&Y@uii K`%HJP$@ySoo85q_'Om*`tFI-s*Ȼ ִO*`JڥhzAd  +k/92JUO_;+iV**$YVrsqr]ec $ w HVHVFAJl?{{ۯ**_^FM4Imcrצ-xZYMaZm܈J~483 `Pt'!;+}m+f)a2qWxaҸ SL8LƩ L`7Z+Ì+~Rj8X8soS1V)jRjJб%$(=l~+ߛ*Aecq+*uZDӏu+nfx zڛ{kivjybz%FP`}4nͮWQkܨ]ۨܐ$gIHMn_+ߵVnkuǵFlӸ5\kEIv}0۴nۏ3.hSrf/:*XMjHLHQPxkw%U{UUӵfL mVi GH-*x/r'$OȵjKJ['P N~]߾--;OIzqNj[ TI"g9~>-7pq1NLЩwԙ rnV>~rn;uhR[] IF@g˳q6޶)tQT,gKf9tq_nάV y[nAAt۩(yLէ|wnKwZlĢ߷gZ HCRJ| :.l\))NfsmکJvJx=)ȹ|-fVH"\* Luu"I8@o=^ƐN"puO^1iPOA!js?#9{$3&C. #(3P(ԩD@iSaK-DOڨIEMmA+4R> Snfrv*RU=, N9 wQv8A[N)0kokv%ѕV:ʙ$5_Ȥg@> PYNB d< *0sDi#J%&pA*뀀 zXa}$jF*@Jy@,II8 q!2GHi%C(-8 Sam%z"c1fkWqϋ Nx" g퀅5zFhRY ,81*3&_u ϐJ`$)&9RItBj0A' t(Y/H #Wp~8O([q.#Ħn4׽q}K{Bo}BJBȑPR>JA{ .S 3YcϮu阷.&S)|Uf`7VfT5 f`5X~d&iz5Z7;5*RTA ?dP-Z-V*R@JlM `2,XC .t הԼr.8eP&| 5 $UmO &.qYRrbA>p@Qs U(dB[pNC#@FTF|i$xX9P灀%T")~ %%@2DGNړL K`mE]5}eʺi>*J3e8`*YMP)_iY:\m6NZ3 ĵv)^2Iq.!aJNiMHiVEWwM .m*U *_VN<`'j ZjmЃe]D%H,H^oFާ% IԠJg_gokNqN0Pq9i8ۂTVe,#c_8 Y~qs7u=:9eD,Bf> M64(4fԩiD.9#p|f *Je>J Q=L̒4H9% deq)zG\+)!81+o:q^@YWpD8$ %ˆjru4iKZQ.4.E9pf$`#ZC.Ԅ93oZA)9M3 FV@tPRܭ yR 1mJղTL!-) ChNIH /Hk#D|'%I)br$XoU\oQjߗV^SGnA>roPRQ㧷>&B^3IZdUAJ K Z;ʞ(e&D xhC6w \{kdީ.K1Jn SQgVDI@`6jv:R?Rj8)M $)@b6&{xmfeTNWѢrKeXcxsmͶ |{vȶҢ<sWj 8gQL6!o=םt=}[As]PV/>;e.._/˝uw'JT@}06ZMKǺQn: J4Q$ܽ)8tyVJTbcP \`,EʟiW ;wk-KTaKҧ5Ġ=yn},ڬ̭ T)A$!~vԍC|7H[[QOnqInjR!O26fv͸p$4SJ hmK ԐNaRo((+JqQ6=&L ׽w6a~֫S:9;q=C9{  KWX@sO) `دTU;Ǩrk rV$ˬ%!G?PqP<$p5iONyd-Ĵ&M0yΠ48z'i$dFD T[:N)i+B }: _'[AvٙmA?ջqFLgݧBR Ipr}5oy;?vjj…D=xOAAqͻ/4ͤ][i!iu xi *?QP K1n An{-j39H 9/ sU?1WnU[Sk-b)iq%*q!:Oc[}M*XۭUU h[ȑT+)y =%X'8>77mrա*:“FFnt%߷śmWZ⋍SP058өJ$ڊHVp)NC(*Q @JLjPQ t0 )$ H/)bz@h}m]tQ ?s*Ҷ}c',ɶ߯ +U%J2=1g,+@@k3׶*+aTG9/R:6"d@3L@@!'p\,꫅Φ a }ģe)(K{Tŋش͔:$ Fi&喖Ƭ%]`@4J&rv! @H5 }d@K5 $g A*')-^(3KWS|yVmm+nS5uϫOR:n9qﻥB*dJ]R:i*xײ7O 9[Y|q2"j֙6@K`ku훢a;}PK Bu&)$IN '.Kq?URf,QJ;go˃u6iju14J <ĵ[wR5`TeJ(L^Dy @wϩv M_*[jjP!E9>^_TW[MPuut-HzqI KY@ZHg7e^o7o[2Wt>쎩H2$e(y*J0*IH0_zȋvMyk@ P? i*3I0`M"c%gf@ IYG&z`$隺0D%Yt$I30 =$jP~>P X2cލU%lٯu+)WLuBBLb6f JWl3)q, wa.Eր5UL^ۖqI[>ܶ&@-)ARfR㎮]3\qUTT˕ IvZ+VV 8ln"[7֟jd B:ⱜ:F/a6w7qm]3]qRnt*)S8IIbCJҙjp2f[h,{zgeJi J Svu Lmr_QwUz76nmvG4R = <_O8wqqVW&;xoDWݝjˁYK )KzTq8`}^lmMvkv% ~ܳZY]]Ң(eAP X> Ы̷kmqQ6{OL1R yEvܫvWV*jRHW<5wo٭TMde.Si?$@-2MUTMڏa@Ҝʔ@^LߟQ{V=u͵ey2”<-lRzd 2_NtnFlm7մlﮒf4EK!n˪V 2뱬WmEu[@ޭUu&N;2AQN"1DĆ80`z2|lFU%P%LKh 4HH > |/POHt7Sݲ׫ܩrIvVթKnPVIJ@2^eU>},hHT񒕂UW7=UV_+z_2&GƶԞӶXPԾE=$T"g-dg_OR;[OoTn SW[IS!Ji#ƛ5{m7SX;@Py¼D|`0;*|^]7T q pm)7.Wz]kMTZJSȃ, 8_QW ~l-u5vŸ۬I*Z=IBS&?YG\=>bק^ER*m."E(U =hvkI@s^IGۓ}ʇt4M]Vbm.=ݛ~󾘺|n7ֶUDsP Hu0ǴQx[,6{M5ťi.V(&dځ&p*eTtr ;Yo*r88-AK:Wr'0m7p02).*Z^TfU;>06ꐖj'ufR }D% T@zF-O:]i[Tu|9-2WnJ>o 6nN.)…~1NSwnWMrYrm*KN>䎙g.<ӵh{qQUnjkz:î;9+Ѥaw6ػquiW[Pltԭ$L|ã҅*^T`$^iMq-VһjuaL:SN%*B @tWTq\mT()HD <9A.U%OTUB˨ư)q[0IȜ`2{ǿw-/i}S|!&Ps16#V!=@ ɚ@]zVjǬW_o/sq]J\a)TO?QtKsPn:Uڿ\wUʲ;V7"Ae*V+%.bQP"d)*P(K @"zJVqZI_ =OHըK P)N#%̜0xJ 擟8b  9 su7}l)m1XB"G#,kihxoۃJ:t-:Za*NAjӆz "O,qJf [v !aӤUoXе.nwKjZĄ8q ' }1mt;h_7N[Z.H=yd;݊=R*-JY<6ipU#:[~pT>A)8M6mhU[=W':.84z6ײoMƎON4 Qٹo}AtrmGXuN`& ' RP8컿4n^v ݹ:KM=; 8 g]wbkn48zT0Om/Ӷo۔͞KPT֪T@N*"~˲ZgYqjxnЇdY\)t=WM۽w%{7f P+X@`-rFۣnlѴ(i*RTT`7sڷz˥u͔Ѷ\Lr ܽ]S;.2CJ%Q=%S歯Ao:-nn-jlS6&gZ4`6ځ7eۨPMŦu*IfTrP((r D7DnOg%0Nj?3#@zgs_t7vi+q]$3տRk.>2* t3IVrWvn%RCBk&^&۹F-et)ڿEBES͵ݛMRn=C iWtQ\{ŻPvٵ.Tzl~AV[mm\%&@ Ω*FۢJ)UI0ۿ!Z*o;ދm]=uEeeZJ<`6-_wPۛP5(dG&P5{bЗHsXE .q͹꭫GV&ސ>u`%;qno;e{snӿeljwBG<AX|senjuSu$jJswG$rͿqX6ѥzܪ#Lϧ_{J|^腲ڊeS%Z,|Ȁ3BYFJ "^Qi  MD Ay)8 UVMꡙ[yRfI6W8{͵uMw%:Cj3#(Ԗ-4ب4sR~(NkB*jR[-*8bǔCcwKѽZ4n:Nϥb:@gy R]]@jE<PZĐ`5>M߸ګmEmRԿ?Ϣ = 67歭tOv]J:QRé@t*D^e}AVMm//"*yIcPtYh٭?\X\`V?@qV{7lnSECiKmh%.0' ?鯇m;{m4ixe9IU,D rZ=kܗb3PHrJR:p+_(l] Zieud.r`:@zrKm7GQpK),dPgڟ0.WЪiO\θ3m gr7;lʫ\,;y[֭C#3Dum3VTYy:s 󑀰H zkVݶ*4D/8}I@tm{n hI-צA0m{Kb'xxpA R 8@v6jebaZrRU Rvnm FPS;Q/>@x{4 ;`MU>դ/NhݖPGB2E,ZUח:tWu2HB3qW'\@n(B 0єȮ]iM޲U7einzg`6\{|ڸmC⴬J&i-&rOinv HrWҊD$"NJkljjQ&i) MŻy}nwnr?V5HPJqG,r,Z9clusJn+7w3a$O$J&.JdA"PO(f $O_e H2(L'8 uVZЗ+ZR/?Ǖ+z8,Յ{ +R? uڞV_-i [Q %P e6 xU-uq*WK4-MIJ lU *EֹöULNFA w7~03}ZFLL;⩫襪]#ųTrK?l]RaoaT[[66K(sVeD`0-՟uژrSdBTU>@Oل>v1cp]no*'kjT$B $28q+6]Qƻ-we{ʭ.9[V Z¹J}K4Vi:"0ika>R0%V')V+g v4ݻkEzSRN8JGW*Zi;vk؛o6Bw*\*]e( S =qܻ <{v=ax"!)8 %\3 lI/ԏ& ZfrNy!.H)`jPܑNPJ 9?mvy9Rw%➉(MJ I{N8gl"7kV4HƵ s#2GSt! 0'KX J@ Ϭ e}un:YP0UC4u(eh#,:-ܛQRz<J8 ;mntT(6PRZCI:[WʼnR0kJR/`DJG巨MZY 9O%=]Um?AG_HΚ֩uNP%$>P'06?.]Yhca.֘kt, HEJdz̦eE N|罯{|Weqw 5nֹ )ꘀnʽ}W6nٶvW\wQy"3,'/O|L'`3佥I[ WPQz)h=:'e<m[`;{U7 K%C){cg@i<;qw [=;s5YMK}S쌃#<mC 7tn܋rrPUi/eH2Z 5uiG\2U]pQ=)B#02H ·:>w7-]CU-Tl=!ZVΤ+ XʱT:7 /WP6K(lJF*0Z5U՛g:k%5y|UVȐЂԽkh[\m=[Gvy!BUs򒟪*H 3}mM뽷c\,XY\[E’ZLIxb 5^}EsKj•q6)ʨ!_Z'j n]sW]}vuLEC]B%Q lZoc~ܨj7QAPh I H('0>בxWw*-GK Uo-6RdD7ϥ2,f5OȨ`utߤ+\o7-snZŻOeFӧek b\5 O^>j;E}Vȹ,Tm)|U:WZSƬ_sٷ6f_]υ'JĀJO| 7ŵ++.t}ElORC!io/5%umlmywxWkl۸Z]Qv3CsĸFjPG*wu0:PHrkL0k# ?tjOpՌ)p }`#JL,gu:te0 s4xI^smFz1_C8 mҥJWh5Lhk> q)RLʬR;[nlOHx0+Y$zts-JseL9{)NRu${/UTjDeЕlbekmYH2$T} b=l`HƠP+Vvt?4Z[hY0F NH3Pw+vw63OQw\S%> e>a{7&㚪l2*PrA8rxF.Ϯu˂8A&fP.]wmbjV  #[NȕBFeGRPVHQ_un\5}J~D1_m/ݫvM_.AZHvX*7nȸ=Wyqn Pg?KZR< 4`b]hU&t&DmSu.[6L(y8ɻroJk] j=5ʚ~SJRO vjNHڷtmjS=POA]<7Yde fs|nS^5V|Lw<VKpkuwLd(Iq'IPbL$E*XO 3arvFd\\]u) YQ0*mIAXEcgN &eNɦesh@ !&@/sFԩm~lƩOvVr0Ail}bmqzzE[#W7b\7jKUu4VچxE_~vV۬v֘QVBO 62ٵv2u4juj*ZoCvj֕THﴛݸ:)^J_ABP9J@qu$0)3N@b`BIM&%VgJ))w w&V-w*$)ג92qNbnڴmm4 jm"LQf]QhZ>NKK > 6ioW.gn2(Sht!U WH eGVkT%QpmĸZ[81g[Wh=uoLauNOmSŻ:m]M5sS6hao*}ŧUO:6ҹ]\] Rߎ=0}[×6۪]޲jgT}$\ mc웵`WSvw Hqe\|k{+i*, pZI lD>n#hv.vwxBҧWưz.\{5C`ؿ]J\R@ͤ.lX nbvM  PDS2>2I9Ny֝QEC*ۣX+Hu|3PqDIJ%%c @Rn.9iRT,:U`-ՊGR%P Ҭ Z)-:k-ƛi,$%9c<`2AƔ'n_]ֱ?& )}}o73a2i1ZWe$t pF#$`%IW,r$e2`x@N~P5k22J %%sԴ'ZR$3N-P*V6֥g/Жʻ2=l%֨򪕗*u=Ôz RIo:BdGCRP >׶9*:44R]QJKlٙpU/3!oۧ<(-[Joی\7=ʑk-3vNԪ\${NpV}IrfmlZkv3jVkrZtj)ST8o6wۓ۶Ωy Ї.hDNMNrcWgbh+KɮMFĻm !B~0a}R%N̻&۵)\Pݧ[ pcv_7FKv+ 3WKByL:>0ztR{NJJ1mC͍[m;y-7 SNSS78 tzvԯn^h+Z,V(H'3g隹ZYu!H}m'X2> !Ԣ=+JϾDe8JӀ W:t%tR`bd#<6-S٭[aK2R[#3 je%R逌bNDX8o-7ԗ;]W+h5DSK&ZrqMjo\J[$i0a[kk's3ipoD8. f)O |{QU|ʱm.(Y `U>Zp$xzYEE+u() "&>0. w5EV5MEha)(QCzu pi!xl~v%gr܋U[Ix2ÎM2oBJZ 9jPVuT D]Y6y_RZW˴$7=S9țceQ\7EږVy:yɄ%$ q@ljUˍC [lBIOj8Gѿye5S6&~HORYne8V0iW6SlQFU(рJP[Q"j  %UmҙWpSfP4~TIPQpaAvK > gY"@К䒯9hqoReqܯz*[ ~I \yGoSouuNpgPIQa߷;[m΂ѹmRWߣRR*JFJӒq2PM(*J9]D=@t9Ogsq-A`7~X4$XNmAr`9T[]|m$"ܘso:4nT{]~9rIf)rLsTVR󕼓qֺP<`-Pr6ٯ˫[`@\ 7 ZT4?t۷EڄZoi@I48\iG.֝4iO8ohjζ4eTqAG7+Nlp RHҒ1Q5 ږ-4dPteS\,{}jI[- Tpְ^aI_qn7Mb[,L%dLDJ)[@ȚTH.R!Nr d FxuWx39WA) XL$ L(/ӼKD%I`,6HH@q0w[.뀦RPP5 "I%G-' vn ]F]EMB1m.i`;`ҏZ[76+kpTN,LQDa?q6ߐm9/T4X^лrkArD&͙wS)QR5O]E-[n8WG^yA*TJx\̖n])uL*P+Jp Fvה4-2@cRDOzIp)9(ѨQgeZB%" HzV4剀Pfy9(*h7413%z`q(:H Т[)# 0GBq2w[b .ӷ:GiHSuN.{ani]=B#RT9g{o ǖpw\JzcQ6;AvfzjF5.V% $8 <3xWALݮwRBkԀ r1v6ib`6-.yg? < =6-0$}@F{)?lǷ-W4p\dX=s@Z{bY1]R HXx鍿N-Ԍ˺%EtX YQ9d`D#N"RraIqd}o[e~n7Cav"Hu&haiG\r r͛^ܶp3D†kө|0 :u-}-=uBBVPTڂRp)2 8_!Ht;>Cmo5k95mw*ۅP v[G Iy-_X+ kҜ =n>mVw܍;N-tt:Mm&>BeFmܗwzn=@Z}$ߨǼ-ۯyTڶ۵-q@wm( U0{獻9wCm` Fbn(@ ‚O3󵃈m7Pvٷj++MKk@SHI?0pEx`P^U{K۶e@ME{̬b/d;~N]TBP/4}UE"GvgYfQ[VTCJq"RR*Rpn欂]FLS/2v^~JV]XwJd=1dqX3)'9{(Nƣ` fm/6\&Jyφ|߷ۗjjٸ۝}MUSSe~$QOwMƪbUbP=e*)0ߖJT+VǛiL`\tU˕E[Uvkkzԙ[+'BГ/R[,u "5B e|1o/u"E[YJU VY`O[a'R%^k~%mns6윪 Ì9'f޾'j_aWEb~uV3l/A7--=N&؛=KnKS͔!8%~)@Rm6͗svS3SQS]s `O/A AqV\/ @Rٲ]iXs2}k_g9βL#iGm5K?3ՌUpoE~,7UrU=J=@L* %3<7N0nkfi[RuM(KL*Ld-7]*/ZJ[msKaxBpkn@jwMں2Y:$ d0Փvlo®t9~qe^BX`-8)@y]54s&շo*(HoVh]mRMD%+LJk#%iܜi*Ԅ4픶UP 9=GVYwl[aBnnz[y#)1?;3ļ[v͖JФoF+UUL˂iK*ļ!$rgmk=ڨ~SHU}V/ԨbVNQh-.rn6[]S>BGutT0_ {SkTSǻzCU{)KBBsJ|kypnWkNREQK*̰qv>6_Umc=xi,ҹu#BNR |=BNp9yE$C$]`>Nl}ټw"o[[k6R;)SLWK\FRͷm;em߱QZ+U]Y8d=}]W; Ͱ.ޢ+m./q di i;FSjMƫi+'Y:/Iӊu;-_Nk\M_CNS*Bkm8KHVND8v]6mO˪ֳYpMUE1rJ쨞DsfETѵۨUƮo!*ҊZ Ld >oD|rU]GKt+-n` >p~gil-جE[T,i}I@2(3}>KUp_Wh+ /2f~fZ$K*=X e?)x3`7UxwˢX4Z!!C<<>Qfol7b*OFUT48‰ߝ{;ڤ2U2dZ(DL\I}M˸@~r^uJOuR&rBH8cp'w[Ȗ[RSԺ-}B<ڸ+K#ڮ$7W Kqg@lqMm%S<[uR [HPǫԤ,nM  FX`@x}C\-͹ꬻilG*m|,wUv[Cθ[6QӪzgØ.@8f:ԅz/%OP06KW|Dŷp?]PF'B2@v䲧ᒥP~Y+NR9Kꨲ흱t܊kh]4 fJdD#z}8N*[_qgV& SVq9$IP+9$3!1V-PۜhRT~]8^:߮]5`(j*b֓$ FDGoTwЍieWkefTŒ=߲W[a푹v׏ %[q#Am p>~.~ܛs%-3F6RRI@{Mg׉=:`?x^ѸmƆ>B*Vi K {qEpkSsS+3!GH3hAwHAlMCxnƉJۣ3e- ga%G)* &fP7J㨘 u eQSR[HXBI0;[w[;*wvBZ'TS::uqnb+yvdj$eWNN.]|ܔλoa$%i]d*zC]YQ#퀯ʛl튺ە:+YM TkVPJPqztGZOݞQ!]bMdK@>ڸ$3 yD_:x*+n(p>nD QpS֝~ܖõ1֚]k^U!Py}͉]Zp s*iZ8$fD@{M*YT{0۪Wf\VĠRQ=$^^0 ~{I뱽mE[2Th.oMZ#ёIՔY=ȍ\kɦQT@.;Vk]w*Bn 8< ;ٻm+.з[^M *]%"̐ڔ9bq˻6Qj Y+^IJL2a : o R߮<KM%80p5 n*+li5(?ܶs2Rܻt3ezl7_Ap-U#kp)ZPo=ʼ{k]7|*\)mt4/UkCbF@ Q-]]BQ[y3+4^QR׹.NjAHJ Pd>n?y]bjfm7Dn;'e+$%J206[=(;a;Kl\-a4J$( b5j#@<$= Si8@2PL|I*@ CDBP%\` R9zrzvˉϓ,E/9cnvSGyn**_jݷm AD!nN+Rj"P7üw%^ P,&V%SlY]|qhڂ0 өjHuHhU.ߺ@w'j n iΠӴSU1:;8cKv2\#:_z9e݈q"x+ MVǝq+rջР2>?s;-In3TTi Rgg\/8ܻ7wMKvw[m0a/Rtض6ڶ[t KB'42m7FF.dI5yUR2* HU4g,!M^i-4({YV@$rۆ{mQĺj~Q|K݌;tm w8I<59l'nT='zeRݶ),5w[B49yqmr+gsk_Szjܚ֣3`5j*n:ҔTZ PTB`mlkR7QVnT?7V!'"򥶻f)1i+ITMXSptqEG@yŗK귝^ۦeԦKB֖B m$#\7Wn*-zWnE-R ycHTՀ}n vVʌީ*cI H@]A6;uXGn[t)QB@YA*kmSmMWS$QP,zpmJbem K]zʸYK%Ilegfյ}7x׉[WJmhqo[X6jV$ǻ*l6k$S[ [n]qSʖI0Il^D]עCTꊳSWu4Feř=qwr-ߙx̊ɩq5TQA:rP202Ĝw"q}P+WK"SiH) C0 =TN)QWn Vj2Y`ДF $iDS < RQ 1Id z{o+nbeCJ%%P=Joo8nk}}IU֎_wnPBlH2`§(Q\̛-n3ob PS |Np{&^俗/ujؖUn[l۩Xp`HJԛWknlm53;ֲЇ[ԈZ'< 8Gm[ Nl-FbWksAA):f ;̟S nMhT_UEflS 2ȯHwhlil 0`:@xWw,yjOÔ͵.]S%U.HNoeJ`:&]eR]_),t7Z**i)J)#|'t޴nS]]pm5IpPKԏ bE_t%n]54cgvkvKjXmp!R`=jZ,.,gȟzT.PmKʲ4kER=suM("*$7`2[lmL(CeN:5H8}#囚DlCfpnk mTTIy-4n@g~{㕻hnT]m-M9H: dyžm;o۪/ʥin4.IRAI:n?L{oGS6$]*.rҩDZ$(kZ%xg.nJK[zo\ڒ&;eɚ  d-{sr궒6ݦV[pS(DdIѻ~ipYķz ;ehT3CNfu8RԢ㓚֥z38,_LHƴIŤ<=ɲ~g*VSFyO N5CSAi0]yri =Z}jQBjC!oTZ:<|q/W*^M4w]y+CH$@$ @p=y6C(tT8eXWkt%# ۉ.ϐPXqR Ǭ.^#]w O_t}/f`Ix H@Xl^)m[)-m)o:U@c86=7,Ҷ.6$ %QMvlQNeUKZiP3:KH D g`fZ~^P:%eR5dolҐL gpg\*ԥ_S\)zPy]P}T ;QТ1#=z/N`V< 2@8"F_ d2$OEHiu8 NJ'P IPHa C->H8Llݳa:E_(3i3еzlmD-A^NA@Q=;I읶(rF@8uE"@S:6m{6$g>r $ZȐCvDN?t#mY[N픉IN t8x2Uk&Ri9xe*IX(wgmOZԥ|Da2Jm4`'e?5(wtZq<k*@E@FvjU)S1@D` -eD=+Ol"^*UC䶓59 eo`5E Tc8 6^߫HU"  v!iwxj-"23[;6NmƝGm@ zOImlMnLR$@e8>\B@2JS ÛjK1H#ὑXRM-8BCx|ْdWNQ Që0nÿЮЪ'i $Ϭ C]C;pbjRJd3Co} lwpۘMU>jm ``;R2$8 XtU?T*Pb[تfZg-U mЄVR!ѱ '-8Z{aUϺi#EB%k郏U螩ZiJ*Wb)]{|kc%Zn`:^6@XI%=ILl'Ic"PpW8 i:"`9k6i~@:f!KtL6:zW]G-w7F;jPRQ_҅fn?#._r6tT(I-K P$ZyݾUQݣYIm2y@s{/4T[Gp^i6VC4f$b{-אE[ȬّfS'eI G -j5Ǵ7}*h2O< 4 Z+-he dxW)Z7 g7iJŦ@!:Uq&dqϨl j*'V220Ӯ:oRSmũm0j[i9n[;hr4%"JJ3ck[~ZuSԺ- ['-'( am]˶Y~u^BhPltsPw m]pENW-*)[.$d,A?O|cȨanK(rRTr"m"鞸\ɦyʷO9@t;ͰmHvs YJJ z矾]> ʉV R-KUt޴RL ۳űm,LUS%BJ([Ǜf`s`[Fy:UJBR1ı X{]7mi6QtQVeC9Eƶ,Iˮ[+q0ߓ0}2r' UA:`$Q閡%)i) uDs3S1X iqCVh%na29_\,H `._ i_zTVeuL"% `::Zn+ڙ:\=A3 =e\k/MyMέ=jw䒣@nNkȌ+x@/N쀥{^32$% ; f~`$_ ^{ӌ NpnHP:jsv`$]6zUmkAR@liy' #3]o C_rN۞qJLhPXIi4ͥ`%> H ]:+d,<5--qfciV44qiV}hǏ]wZ򵼦 Lt-:Y#TT!E j>*9퀴us"S9G( vNeJDpg@@1^P⥮Yrut$?έ2I 2R ^T N3(A?8K5j%zy_w}*qs9[wWVjzw?YڴTR3QRڤ @LCns55X|UuMդ7;wCw)UWd?MC@A8R%()mq6rh66٭]EِCh}H6IpO诈5̻m񫸽Jjg2x4埥G= jiTI|۸k{sWۥXH[9$'@e3vۧ5sz|ڶj+=ǚ+8INPMr4Os1Q(mZE bAabJ 33P330Zca5J=5*Mkq:!JdOGs}7qvkнn,)Ғ0e43먶5G*Y@>X0$te7]qm=KZݣnL^+Iqm4 H.dd'霽S"Xi(ZbD 蔿HMon~n:. ۩RmIJtY8?nt۫nYRIMWAswt۶qi|- 4I?kkY6 jU;c/]RIW\N:h0 ;'=$΋]z-XmZœݞ%g`<;%Zݶ_r%+_ͱ5KQc2egqy[;fe+褦BԄON* ì #ϵ{Osmw80i_r n[ouaߙV K'e)GT`} qņq5TLp (ei2?l~:mhJhUv%+L愩I% ` wB&פ%7O!.mu6e:]jHiҤlXFr2I:i2O(8lȼi6nMŬUi,#搡u2̦nD5`=L͚v]۹.ܨHPR +I@=O]6(o]d6zەe];jԤ;^#*N#́9pϵNVmkV#%.ICi%qJ:P2?5fꩬ"2 V yRJlC.>+IԦM,L;wF V8dRQ[7f8Ijq82$[ɗibiЯq yR){">tQ7"ڨbˆF n;zxղo[*Ө}WK,Oer>imR[۫TmoUTHxIWy9T]w%pmJK3&-𮶠BGaҭo-qtݔmݷEBjHNE`=WzyiKu[ m!?)9^%PJԅ,O=9+@ѪS2?5)D@L@GV#\"pJp @Ne3. F8?c?1LΒ00f  3xl.>ES`yc) I#)): @zF&B8}A:$}L'\JQIl(!x "שd~$JHQ`?K tq 0zN9)9 //Wy:d0?R1:?`4t@d2P\Iab1@% Xf$̐`S0 @18K3%8e"K(X T5~- m4FT +Gx@s֮H`\b^ɦ k:qJZ$Du8@-$|GBf $P < c*g9px2$'Vemh7+6H'`65*8,e@Jj~0i9 LY{`AT19N#d0.# >Fi NxS^VHJPc(4Ip2Tܔp# @LרӏX Kia+L&cR X S=!(  d|" #9 dHeeB Hq|)1%-3L@v™j3> ˡ% R'Pr0L20&` H  #hI˯YK?'fLS=&i s'y'p2 -DyNB= } @PˬPDQ>1>pPPPR5yx .G?)3I29@TJY JfSP}3,spy,(,iB~(^I8<_zT[Gۢ!kAST" ?k9nۮ[.imFil-tVd=<Cz@c6g-ODVU0+eUBf]$'8 ۃns-mm^١jxCo.:ĵ.s֓%py7K"u/1L*)ܡs։ejx@ji܆ɦGʭ*V*BUT@R/S{v&Ͽ**ڶCuhhYXuGl}X00@Y='G2&{gSe5hjkh}Ā u$j7&R/ɱXn EH.ZhT %BKLD#[aTEwe0a.W`2I)ǭc.vl<ol1 IR@fT{p]װmnU{pS0'Ur}Я3u :U QuErmfNP?a L޶'7.Km?]nT>2IҠPNKХh8*Pb5~9Yj[u(]@Hk:rm;~ƫaQ~[ RNשa_?RT4ER=5$mMJ[nvYQ3Clwy*͂ TŤ-r$/@`wetZU{U_8݂%pQr .C# *ErvBٸ.wd\*eQs[QMR*32Krw8Ul[sZ w*$*N8xs~q;MYskRSI0T+Zm65*KU=R֭k,1EdRPRNVfsIo)[)5 .&K;Uo<ͅ^zynʽl_Ŷu6M[UIi}O)S*J4eS,>Z28JFpt/Yj7k [S+JV@8.F+?Y诶g/&.*}'Fthmq8  G.,"sL9Rqa#Rޔmƶ5AiiLRQs)c26`dzh ÿ,9(\&Zg%s7Ls^()謡 5EjJt%)*qj:RL9kTq'AMkڴ=IoJR}_ηnS-6<۲H KXño&Pm갃KXRtMJ%MCn.ۺku]5t:Vn2IL5nx nMPWejZ4@9}b'Zt{FDS EAKVtO~ޛr[n4D[E;Wi QBLtu_NGOVnl} gҩ[}A*|s@rF6oޭؚ*{>ʐT*i^gֵL N78R{7 تSHyy%*NI/Laoų~:UEնiOjb4$yxLZVC*oQ9Zub;כ_ԕv=-vnTL$U7pӲ;5j2 zӌ9a,΂LĜ%<P:P0m:*V#<F 8$矀uL`̀ԣ1E&``G9N^P#h-)!H2p(r&R=̤$ee&YeR0 D4,fP 9K8J@29`!J |J3@?,gN| f ҭSH( XupOX  %*TdH0g#T=P .%$i^0 2`'Lf}8~ 3)1"~0 CVX@"/(#H@uAHHOI&Ԕ2@$`39e0 L4L 88`"@0\`@":1r i zi38)D($2Hԡ *'PFp Q'*bPk^dP$ 5 IvLti0`@h)@ɜ$(|23!#gDL8XF[8% L@DsEZN9LiI rafD,S=|`MaDcN`e ?Y3lcR שSsyeop /âp t%u 'Q9􀄂%229u0A7r*^A>#`@FiE#IJ3>B;Nqvwu\.TmJRuMBA{ی,ʒN^߹_iC02_pٛ;-[-p=GUk|Rԙ<e*v( O zUmYR+E[?r&p؟MSfXl;wE֨v%5kߗ}mx,bڻ=‹uZA !τA8M;Gf1Nܷ[׮) x~޹m,LUOR˔ȩCU!JP  xlY-m.YD܎&!}/q'&q]M.\ nShS$4~ Ӓer yV6%zl54``K ~c/~f*j^ZXԶ%nFP ! dw#=Ţ^ݴwuڂM a4@3xR0[9jWVC[V*IqP Fgi^㼳ji6VnzҰ֔)F$oWM|oD_=keRku#M:2plo'ޯ+6Mm >͵l0)kR(^`@44³uU[gXJWN%wWݹb-۵~SUMZ/Pz O+=EZk^~kkqVֲZw#!pY4 }iԖWwS(h̴1_0V>s{ƣ]UTVpXmIJJDozkE鷝SŸd"c8[eUrӖj3 %"Ae#T"rŹƛwp}TrYJPO3q\G9^ZmLQ*߷(Sݪu$:q[{b %J*S+.:ԓ)$|1ѿd޷ڮL\f㮩A= .3xv^@}[ns"qɗMKͤEgMKybQźU JU:M52t) bA6(eۨ)UJ=nQSTܳ7EłǶ+4w./0?»RJT [HZ ~ZZZ#' *Js C}R[6n:e(R:A)I8 㟪-vmj~Afd]BJ_t* 3k?<1lɶmnww-*t/CQDPns;ǔ=~]eHGzR#Z\K"iKL!*sQ=7~nx-|{nBYzZyK?L=KszVvU{!@^(+Na*ཧp|;prHzGMNtn@I좙Ң RB qKefUMEmR %<<y>J}Nk6 ]¾`;NQDdj OX׳;m 34vb^ / o^<țeUVؐ_rԴoTe--n>kw%'y&_s6JnB )Z]^Z0ܽ_СYoW܍VoFJ žC =-X۲Hh.kS5tϩ34n:%p7T*?n) ijZ;!"c9SG4܃VEifq_PYx", *rXMwo-} #*JjPU0VCdR`:N}~ MV!&njjtYIKke;wVGo:RJuMOY2Gya+QGRiwд"'3- qy*gOPw }qܛ:Ҽ%ZBP N:D:Z詞um<¦ԐKg) @FžeZCH JĪ@fz(MAU/JP 2=serƙ3sx'!R_|%_ e"%8h H%N0H8@"e#(C'/!,D32Rd'"<#Z%1!$Np!:dXg(Y8x@G2@;@ c#NbPh>s@L0N82gHQ0$2 HH p LȖ0 ZF "Y ."l`@i0>@9 BS9Bq391ATG1BI`$fFp<^#@9`NWH M#"=frbsD*~H= %Be<`'Q0(0%!y*M$|0h$@ `NpkDŽe80r$DL= $ "S$``#p H5$i2;e2R& H3r@%$)^!)DGd0:L2"aB(&DH"`eL'0 Nd %>{z6_ Vt$`7i&FT>Op$wi`-}#8 ȁ.%*k'st9/S EGm[zk }ZJ"rkkW+]{SKUw5% A@Ty-;3d\׸,9VuFSѭ8flDev$1n#ٻڽQ\nlP^f \lw[{ :U0gX J(K  FoPKUM@udͼzN"pkZhEΉMM"\_m!ϖpIM4Ô"/ug'hv7_5?,Z&eLo,ZPW0m֨WB%jONSR|WJsj(jQJe)yl0- O~>q rk'0 AH!"`=|S=YOy@bVI$|`*0I+L JbpP e,LO#1a#$P4gbS1:f%)Lc<JfP|`(LjR4dzq0)p2Tz@ NYNr9@9z"+H)teHg bI'3dD Nr!CS 20 s3GTfd00=z@FO%)t ` a99 Rtc( `M0@N0<4AG%g@$s&# *:btӌL%R M')ՙ0R&INXOs 82=8KV.Q3Nf(L;8 dzfN ,g= 1fp/"80H c zc"@K0q/G*+T 6P G?PTV5H82 IBp0 (IS锠+:  Ӂ` T&pY VX:@P3 `=Ra$:JhfL V ,ip 0jR`fe xx@G]%8SIQ: pP% rJ1N3!IGR%`H fy0P'yad 2ffH@<Ҝ姠0 rQ @ JRs3"@ 03,&A<`='( `$J@% +T2Ǥt d L-x➰OԒ"gHL,S`*( hRRIg IQ$+ $'h_JիXLakT΄ Y@8:@JjLHyIi8ʒ1PH%`+js?ĒqB`:6*H tJTNb:( @LI$yt$^a$>F|}g,Dft)9M}&=*Qq'Xt ɒN"HqR `3"PFj $S8:ddBsMS0dtd$q򀌂e/*"4g$Jqr%2OSe Ң3ptpsďP,eJpP=&C\@18<`z#ZAì#3Da9@IV&x@F %DM#Ցũ&$#Lºei@%@*O1an8g,/N@0Q'GLauye*qC̠($)88Jdf^?t +f2g=IQP՗J.(ib|G$*ȓ) y4sD5~̌gil`S>mSX%=>si(ȉ`KWgvC31 psHHd "t@ZV2|8L#8TrpJ=@ҒQIpR*WHH]g&x$ VFPBx$| Z# &LΠ:*S~0z@@&d$TI8HJr8` ) ĉC!QT(K YHҬ%&U5+G2 xHF Vc?R3yϬj p iT2u0q I+R(:@ Vxg(+bU(00."$ >#JSzJQ2AEg@*AS&~0-321@I=W!J2IϤW" L=|`,HsZΔI yi$ 32<@`%_a0'R@H D`dfF9OVA#I Hm`KyJ{ҁIK LHԤU!p4q}I @F r0 ^@"JC?l4U33ndNj " > e"qt8 &' U%|(Oq( Z!ŨzCJKIjeCԄ=)D8 Ho20d O쀺V]Cj2Jzx@3VJeL(l,%(a:&S IH)'=^PDIKD1ʑOH@ V#1ՀDL xfp4O3L8iXG BN9"sN= hȉa I  JJ] $2#"IӁ9dF0z1Q zp92AtD#I)bYN^ X 5` r>Peq>r):b (%?gA2`zr%,3`@)c0`x #tX e Ȓ$Y:D xQ 20dʀW響0be4:LP)s̘ ^2%"LOIHX=Q=`2 u 0DȔ$:1 eBI`g<%3'`XJ8*LO@$|Y SH8 0 CRe`*+@@YHVR/@:X@E#OA MCC4@IP+H)9q8*!2IOipH&IjH"G)b`L $P( s$g< *}^PI)2dϧ V 6:=%c<Fp D`d H "8K( u @@ I8ztmrDMJ#@C+ z@Hd V*@@$2WP$ fs e:&;8YRD}Zd\:Lj*$O/5D)5ZTļ<`{`"`9@ "2(I&H&`<@ӔI:8xGz:f pj W#p8@$@1j=L2FIHeN$$f&:ULe~I@:S9)}j$H*[LN]ۻlqmF*6C%%䉂0~/kl^AnLi5{4FF -8qߵh߽:m/TOی? @ #2SJB5L@x{%'8 !Ls.ڔ5!bOÌ@8T`,OLN fG%HG(!$:* g1@#@YZdVN̏z>eH. @2%"9')ZB}Fz)#" @4S(0jtXeSP@$5@  Hi2j e$LG@Lۥ%NdF@F%8@&j~ 4J ,0'(SӜ@SjTϲ)A^9N@ ?BAK_89@ANYL9b=FOubB]`1b'HJ^X |s g?lI uASk#= 2pJ *' $'9> &rJ姠 $8WNN8$ H>G( t,zF#*?Q $R"3rd< Ny(/% EJ} %RD2I2S'@ x*9@xybf#(F(Ȑti9 R$%:ssԬ:N3Upꑖxx@1P@8eESiINi^( $t$IXJde)+)PBXJȜԤVrN?U2߿f_\W5B+BTjR-3&HJVdNG ml Umܭ?ښ&uK"SYQp}[._iʫcU抄9u)Ie'礨sI:ntn][,0fY.±k=Z> <ԍvnIcjj}M bEMrmjpìUۼRnIS/v) U+KєrN/M:TdEYj7+ Y,{uU}M9_L ZOLNbQ&ʹP^w ~=]߮>Y֊\w咙өG&q<%SOiFjh_UoP ho{~^٣mVZ;e:JR۬#?hX$1r% mf{vuݿ˭5žʏ >c3(w\S$!0?# i 8uJ @L2||- 醬L&d蜇D@} pҬ<iL”따 '?( Sĕ9c. L($hv 0&~xjԅ[z嶣$HH>Wc\ݔo~z۹Y-t4ݲ)YfӻVٴv;OR/\BGLq"Wږ.DjmPRQ`/0L\OTP7Ws\+mu*RJ@n]ڝvv!Xnrߟ[hlm3U|#e)[^!+EFwq߮ 3eb~!ďHO`=AUjXT:V)J)h'N[om=򉊔]*ڴKg0q oz;uP$\{YK}5 7@)K@s^7Vm4:t8N(OțƑ;=f={i*Ast狕mԚkK Crĉ^0|q׺[U]%=+&UL8N2 'mnͦ^aMyKN;?;_sge7?'%D:P{MsҺv29$fTNB\ʕ[=k+jF&I?" kez(u2X`y.ݼxϷjtl<+phKK:Stp-sZ[m9Q@( 1OgV7Yh-"ՁxURZUh^-:ԐZYD8 Ƴ>Fj[[TTQD=+S֊+5"UU[Z-&mhjU)Wja#&9^OJ4LpjhHxjO\rMM y~uM2ӆ=qGMC ösSFJp ZQk)^) 2DBɔc9gV]-mZpˡ߅)W#9qE撒V*m°PK'ΦB~u,ژd$F<ηj+mlr[;e{@m"RR&p担qldz)k+m]R-I$Dҵ 5ӓսhUUQܯp%*6%S$m2ۋ +S:IJgs6⩵ӻo[ I4 ұ~[fN"QT۪)w8R~ezTpD㏌oYzDU[lw:0 FPMzqjRR$At^5$r5M͚UQTJKNkAO0{1pfbYMkUDiRI8}6m^פMmUSS8$u˼qX[bm^nĻg) ЉM'3<}7mf\/U?BˮI7\F8`Jc#R'T^P >()xILu$$Y@>XP=P`#  ?deNIsN 0ɨX Ǯ T?Xa(N(/f~~Y+誋 քҩpoq+¢Rqd%N' *9rE~ey+ouN&p#kovrB滝@)F#7{homvuj~uM+R0kff2)̃0>ucUh=R@j㴶F[Tuu|-RG/wK ElvpU͖֠۷zĕ3W~R~$g+#o<\A=N+Ncw_7߶F(UrաJ='n ǹ]wJ}URGOpO0CPaW9Nsts@YHXҬX蒌s $+ātA>̠2I3Q>8 ',8ҟ`e+cq3Y Np"kB%Op'4?|<0e4$Ag&FS:@2g)O)> ?y=^a2 I tddӯX 2e)be,@0󀌕Hg8QQB`c(Qp*s)@Na&Cs` m.2ABZ c9I0fqrxR'##>)2LI@S I3$'>C3##%J ό :@C)2>eH!"N~@N (@a!KBӐ JF LT(5`KiD}LĬL6WC( TLX+d1SF$FP&3?%#8)L(I\d2Vs0eӂ&B`($r8ghYꚬ[=R:_x4ˈ+%S$"X*eT%9?9-*2H `O`!32`H ry@jT# 4kIas֩1 &i R OZiҕ('(u/0O `jC ry{`$DWpǤ2=T۪)p=OPٓifw5fv SX`:*thquU.ύ"M7wOT%'"0 }ZGj"[ݕj)S[nVvb ۝{3dIq7ěZ%n9z/[yNԨ@PVVרSS44}`@s@ksvn/V\w t?%=)i,pq3WvR캪X Ɲ%d0LewRݑB?S$,y07al656:kI}3 y@sۗqo[7#ZSd"H'R^s_W}rm[9LME9mK~( {yخ-RmmUOUtR&S2-a  p[9էmSmiЕ" +h.k&ōn8Á5iyX$@Mx:e-uSR+ 0lm]ے풽$[QD⁛Rd0)@>,EnTTԮP]V öqVntlޞK WL:)IP[Vemq^IRt CXj7w%elmNvA%=qbsӵQCzrMp(Q-:qeFRF/ZNT.nHIOUX#z}4嚖k-8ԅU8PW ?ȝx鷅mvڵv=e 9;6frاmr?*%)5.ͫ{UZm^x7GN’]jLVq~ۻtKNeحNMVz;L v ]EAq|UUS:q#xgwV[뾘U[.l8œigg_>4wG#l T m(UƆ6$>gPRa qUM8IMY"FBdg#~o5zLTCdgY9g>kMGKR"U>ꖞx;nѸk\W+Ki:}&p;d{uC6uZiߧmEOzHb<`:{;smj- )R4Ս4f')7]njS~z0T[Y$FH3<~b;FhmVhOR:fT@ 4Fws]( j4[eEj:>@zpm"o"׳PڋsBh (v;Cm7G) :ZS&K>z|`r)?#90$8SA@GuW@VÆM!`d3832e#Ъ}` Df`(PDY3 QKl*JV=Yym*gޛ6lal)n=$#ml,ۏs-FճRű'M-:S!#)|ww.rQmeehR\] O匠6ϧo!ZP-1Y"uŹNY d9#e+ mi۶tT""M$1[skwZiAug􀂔a22 9.xnN4[цa.$!Qvx[Yj*%u,wi͕qX(g..inV,+ee(3qIT9lqɴl*EpU.iLa#0:tj\Jm}ݽ{ kj4A4Bmxv[} -A(ɀ[ ӌ:3P$bZ) w}#y!](L]G[EIX8'PI@Ju (t`J:0iєEFR@2@Oj#, SRHNp>pAJX, %#ZH)<'G*3*,& Pd9ad#HBg)?āPLOL#R b12p:F3 g)q"e  dҮu0 B3<ZNʒ@ nI2QN!gTȔHIj`$KIr= ? s/HPp2K )a0sFBz\DN|3S(ŹHjI NFp ~%` "BIRd=8%8KdMDLOc1`Dp I F3Xg LQj2>P$ILϺd9Iɀ`$$%`|`QBsspeJ% |`5U)xx@m@F0& Y`Adz@D5i $9*AIZJ@VmsI Gv}#@0BF@}m#} B|G Hd(0 m>n} d]( dvv"-HA( G=( eD7~ ov@.yh vA@.>o a o ad7]> 7~ evA@.g4oD7]} vA ad7-(]@7e d-(n>oDvQ]dv[uHn e @ { #A!#]}oDv[Qi ZDv[a"p v[Q!#~?} d- ݴ( 5+nhBL0 1Y|'hL̐"q L2 "!R I @$d 'i$;i=\H8 GX@FL%u$'&|7 L' $ J] S3@FN}LGYLLV!@ۏ 8`I'p>R̳305P +|s33*>p4x$U9-@IeH*g(!9O1G"f*8@~"Pa1I:F%{j 8Wz0 R '$SQ"]zJ̺aՄ剀A@YLI$' #3H2WY@/H"dNcA?áǨKیVJ?$%rGp8 "= e)3K]IL퀝 ČSpA&x2qD$dt@8-@3`$#сf-E(J}ep 5f?S ?|3։ P *I%D H0022pP L>} !PI  em,F#N $fxJ d+3H$ӫ#z%O9Bjs*'{WO8+J&oOפfHYPJV {`(e2df& BbҞsZqI9OZdCGէQ^SP @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(0*km$ S40 @ {i>  $@̳9Fr(i@<P t"yxP @ Hd<!'} @7i>GhQ@>{-@ 4@@7e̠pH(#GhQ@ Id#Gݤ( iS aKH9} dGhQ@ mCJ"H??`~:?`n?} G> @ %Je!MoSAJf<#SoSA 7)#G i>-"~-"~-"~-"~HO afP]( eo ct? m>GM>} A# 'kП@eo d@- B^Gvі@7i>G6O Gݖ-)Ӗ/dv dv瀀 (?=;G4#Q"$Di8/DVg_[D Y϶D!?`nS 0 [D-@?e@P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(?P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(?P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(?P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(?P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(?P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(P @(?IanniX-0.9.20/Examples/Xenakis - Metastaseis.png000066400000000000000000011334051317340345000212450ustar00rootroot00000000000000PNG  IHDR0VtEXtSoftwareAdobe ImageReadyqe<"iTXtXML:com.adobe.xmp ĽyIDATxy5f&%D<)E44h0PQ42UB D2dBI=~s>ӧ8sg{b @ @ @ @ @ @ @ @ @ @ @ @ @ @ @(!? nD ^yU3< #Xn#<$꧟~Zd V&w>%yHsv o7zrZɭ|/Qhݺuj(Q_>ӷz+$Ou+V={6 _NQx` +WRʀ=z\z6cih&16m$B̟?jX`޽{c.-T ~W[FYz6 -[JQ譕Yx1~FcPU0:Ǫ%Gm۶ b^z"4j/zCBPVrSy.ޠ!LV/a,-z#1qol.rP@N={RC"Oꗡ^:* Mԩ~Ug2 hNNKoa a/u„ Ҥҿh_B> "[N@|'5|w^\xhy .$28 ;wnʢ 0 OӦM/%\4>S:|t5!+><3!(Q~E@#sœ{K\s]wago!Ƽu֭Eq`NzBOM[B؏jBk7oNbhb]w];TX|D8'^5~袋.`Bm0FzR\/" Q=i"D`ѢEQQtW<RwTҾ}{|:wW_Ʉiwb#eʔAZ(i"U"%Ns;~RX&?uT{mM`P9di׮:=.]L4(Fw:ỹVZN6׷o_#xCfld$ڥ<6<$+ٳxы%̪ q|]P.~G1Z4z%0sg9FTe.rpp^C+D,>4ix5R ;KqڵkQz.R{?W^ݻw\d|V\Zj-'s +N2eٲev!ҥKUmL!2qRיE0O}G*P;wNQjjݺu>[fM^¶r\vm~Wٲ/^k.UV22?YժUO9<-^xi|2+V\y'{j:l/V7~ח_~S~*$z"M<  .*n5B9iH@7͛7+CO_䡸E9 JV@*\g׾?V4Up@uCYnZ2Wik? a~N=Ty`&Mtb2[-NDlMar%/(رcСPm~sv@)?3[`A`L_x #GŽuJ#v@|jԨ嗫W-ʾ,FM`O՞{wq/~T|DIP շzK}f8R?m>:ϠTh|G.].R@Ԇ xnȽ:y/@_Mn(yfj'Z_bz!13gaZ7ow}؟cX)MSA=8@p\"OVyc 6쪫!PG+asϴi;C5DPSzwl FWVɞt죏>n: oDlu1 |@ e~2Ai6jB/_xp0v_!SUY߈,`B crA_z%Ϯ_׮8DLlr˴.&Ĉk=N)=!߿aUjUm߾'CV|Av}h‹_ejPV 'WR'SSΜ9qЏ>hHޱЗ 6lbDZ;J,EQ{ UMh*S O`dSRQ+BIZaׇj7ː{I5DԆ5)3A͒#>S$-Zs'lذgݬY!CʠApLx c W$ eJm~tE%@56O,Ȋ!KV'jihW` mz t!+\0Bmg=^n]2xA}ݘRJ=PRJlݺu֬Y:u1't-ZSO=0`@J! ʴZjMmOEZtTKCup͚5U-axW< 6ݺu[|L 4 BsjQ*g>}gWNuyRA%ȱ4NtoӦMp)-L͚]Mٳx≋/XlM) hZu2(Mp Pֹs.] <=K/i7oZ9r$㥡1c@8T$3gΜ1cƼy2[n!ٳZرcբ;!x0-tmkժ-+V"8X1 ^}ux9ZW{{ɓyԳn"E+&94AB)zb4ET|ҤzȨiO܄!zpڔ837nύb|A8iӦh'Sбz2 Q<D wqe l- ƃ'N3N N Ez4a`/~*HT`/5Wzn7|3.ܢē0+Jq[8爒4s=K{Ĺ9Fx e@t P3D̽Kt,[ ~Pc#^ԡ&yB4]WgԨQD)Y6'9(ނ +K&2a+OME _ 4KE &3ydM7TreIC-/w"9oӦչxb),{1fe M ~- 6,"Z_'ⴷPK 3բǭiUwr P|Zz-3 aYDnV[tʕ+e{c_o&S@+ZQ:Ia<9t(҄Y-'m"MSypAR^I̠W%_pW&vaЭÇG۶mv>="rc*HX8j(Lp̡jN%Zjg = *`qƙN-JH~o2! )="w4*89aL }K?uEx o&}=z\" q!_ƿ"HLF/SN>j _Ko׮ gĂ )aυ@ D'\GK.Č#xsiA<'4TOl%-[MOBU~"we^.;dH,\C.*ܡ Śh^0B[X7=AQ2z<ePSR|Ǵ/_FuC: ~HemRTZ01:R^xVD"Z'Uh'ߤ4clQnzuL4al Κl]ΥڲRrx+hZԮTMԷmV?̙3uk C z}կ_ώ2Lo D_#°b .]4IXޢ\@)SPC;tdPz BHD]l۶C ~/QǓ= hB0׿Z~]6P1#} ҃.HrPTL+.ܸ8x%Kp>jF7q#tjo ڹsXFjd |QǓQ7 A_QZOt'𓪰PRJQDpȤL"!ٖA&5\s5J@͊ "@[(^%X-y&ԦaDH$h Hࢼ֕0)Pp\1q٩/%[J%s[rf%ne yЉ`ho Qx9Awپ}{ '`ь[// R*T;fXƌ7;$;Y&h-W_}&oZ1o}M*UJf 0]KG G>}11|a  ne 9(c8KHcz,DB* 8Gy$^rO\F 52E@ӦMqyl5)n;>k.B1]1ǎV|TdsƠ0hsXA":1OS]v΁MiX VvD]Z@h\1"' &-Ue2T^py-_9dZK'x=Km̄doS;l;C{(jp-hR -9'x$<uP8c Lm36N8-: cV1ڂ^"<8.H]=ѬȖiR$R)E5 2L:;X)\`!'<( -Z&Dj:5oX kf2L cŔbK{D&]S1)QW^3|jz\3Q&1|%nzInUqQLXV+̳ xt+Rq51Us#/{m2TdP\U)6m`mKhjݵڬ8`> ?"j'1;W\֭UtRdv|%#'l2yyF)ҵmTh=zrhd/QA ,/k9AohPkNڨZsv3@2d^ްaÈtBg}2+ۮC T?&31؃umB1W8: ,H[;, FCvAg ԋ;Sn$&xOJ"Z rA>AeB1;Cf(ۻMb[vK'ЌժU;sVN{#y慯RmulѺ8̛7L>R= C1NmXcǎUP yý\:^Ln8T 6lݺuIѩ' ek…;w~H*]vE)^GÀի+6UL.rC/žX.zJZqFwŧ&) 1)1 ^xlM,}d*U$@zAyV,+M(Sm2֭[׮]q5͜C>a׾}~wu<%o%HB=k,܅2HaIiHtޟiaDhk0UTyᇽ}ĸa Z .HB+V EQzJ+`T+9}8STܹs3 sn[nQ5h%ka4FXb1L(͛7u}&^ ܫDѭr/d݇tl[޽u{1Yw΃rl2߭tU\T6n|wCpW`h=/0N3|0cfb\rd=]"4qDZs~w[ݕug.*1<.'P_|u:v'Oٶm[k֬rw qf *СCMbX.2]Fe*]E{n!]7VuvKؤIhgYZ[v`$(IV;~g4%Vd@ -݋'#iw59APX`|rؚ.f8#[hQ]hBhP녨 -l2KJ<˫RC$RvЕX9Җ,Y>8K]0k{'O|GK3 `ԗϵHQmfXM{:,e$:eH;vF:2:HʷVZ})rLP>l^C\o69sV^l, -O&1ljszTN\ EԂ%[l *qM(@@Yށ9艸P֠ -ͪu/ %T "nESmL[.B qQdU EnJ UU(Ў$3=L7aÆa9 G8֚,8{l_|q…h9#"Hfh #ZSϮp3pcZQdYU󸉷.pXH/L(T6^ojC7C-[\xj&nO A6K7Fwe]t3!B S\d2{ר9^^{%ۿ,zCY)vr}5*EqƭZnZ1cZhC]\![43$!nHկ_?mͿ˨PCN]u…իǻT}SҴi+{lE*?NLxPm Eɇ&h)Z$W\bD?rHtHkǶ81~w}7,6K'aN8֙VBjOsy+Z=O1.D!zRAdFAqj6iP ?mpMBb i&:T;Jhu*W!u5cӨӮ6y\$6*CDtNk(gb,`jxH`T~}u[=د:0]Ժڢ3% h _UFcܻj d oϦ+-bϧs׌m.o6 [Op-Z'0<TU`AË\Pa@ŋ 0y¤ j:s f5J:PMK[r2<~ VGƠ3QQ:>m߰aCehٮi]Apn8w=T0iC# L1:A)OA| Q z4xxa\o]+. c~L!S؟6A.|J&ۥRtƜEkK@](m ݏ~#脱x!b;ە+Qxs.]>syZ;$I'I*$">LǦqW^y'pYX1<^{mƍ3g,Rh͚5VNlޢ$yz#Ó&Mݺu+ ZzCRU"#UFzjĉW QRJQgosӦMsf7 H>C F_!m1'<*2vT-evJ0j-@FKɝ;7>5 jA>S7LB@B@iH}QA4vnW}9<n7b6[ SU3<'h` &DmԮ3Ҷm[0S#ߡ(!7#СAEGk8C8~2|(Bx xԩD i:iin˨Q'xN(%|rAy`!M=裚y޾}{AQ  g /?.14NvB%F/JkAQiM6h{j҉Ҏ DfDmo:AE#V 0[7b$*S PҫZ':aҒhzAY/Rnb3v_HN26t]ۙb禴YAuYerޕjVҴZ '@eh"׽IժSTDX|߭IZP*#Tۊ'4DK T[Ν᠎BQ"D',Wrܭ^1/7B62:0(ͳӍ|FsĻGt􍆀P!o&h"VܫCkd: EF1VfE#[! ouxzi:%Q3O˖-y"]RO$n%:N EB"OP"b3W7Z NƁ׶Uwk[0ZU:?`N\+m O9+n%ho H/mݹnW8Xt)$5K1Gg̘sŒ1dL!x ̿4\c$4vD%Og}t\&~:w`&L% s?Q<ٺ|Z3dpϮ °ׯ' 1bNk>#ώ3޳gnwUYf/f1'݀[OV-2iԖoݤq{z'  5nSfZj_7 Uv &Vj.j1'ڇttgG},_bdC&˺"Aszֱd|s2J~Gh)Wx;݂ӐUҞWZյk׶mRLv:QžhI}ٴiӬYSsYn-[&=ASPn΁egLb:ua3M0^zɓ'z뭚Q?caN8y<;v;RDD$16{ 8^]۪hW^ p4;l{@x2nt.L1=Xάe\_i0e-fhn-Ln߼~*xnİ7 ٿw\ΝaD}NYGhg=Ml~⓿/(_7߬U;8Jd',X6) 4).ttegTRvY&-OF]L=!TTvz vZCEfe0&Evޛ e񘓘"NyENhl6@GJeoAzaG? ܝ8;)/]C=^{ͽ.\ұn^x(]_|NUQ=/AΜ9;[˝y+:^Ka KQ0sqI!];FuM_]_:ްa[o-Q֭[SRDWUq˖-{ilْ'SLyVXaEZ2tIXNi/FA:>͋_~9_~%O?vZ9X:u4oF4i&!ӰяҫW֭[#QH+cVz؟%i}g}6j۶m4QL`@~.]4:2Bn͐= 7c\Zϰr2#^z׵&)9U=BF{+X] W_}%)Rw]mPjTڃY7|yIEx3X!%*Txg]wݵjժFkn( vi4 'ww7x{CJjժոq,(AtɴiM0nI}RyKy֫W:.X`Գs-_\b89s`΢,u X=p߀kңϽe$uu;+fFW^ɒa Ƙ&XhnewZ֯_'4:lh0N >tr\CvHOCk.FU*Gֳ: KoK5\ ֑yj.ӠA9]wg[tq޾@w֓،~y;40]^T˝;wBBd0+]b+VL:z!q; K#wŽ3C \w"n:\8TCBP-z'}]7U^UTAte`e-Zd&MkngqFҥ;d"7|33f͚^DK%Zlƍg˜ez"zq*W /]M aG!yƌ3Xt * 4bŊ8P QL8hԩJIpė_~bŊp+ׂ \X'He>/FWo0`*`O?T9:`ݚA07aKݼHutIFgַmۆL}zY'|@A؞ gtxO鞎v+ @"E1"K5XwZzupB1< 2aϛ7h@NrUַo_p*F11XE@MttI?-ɫF]ѪPud/á6,Á?Lw)<+ر#5>{Lx>4k "6^Aht5l׫W Ns ӝT! Wц005HoiKtM@F|h4刂ZηyW6Mi(qdC`~dHL^C W:tABQ[*JQPMrq/v*HNm^AC]F~h$'At>ં=Hs'-T`N8J! l@l '&] nOd~2:E-^ײ=Xzb5Є'Wu@ 6c`~̘1 ᜒȬu _@jo6m`k%]*֦T k'QDcghODw$jvtXRkqlUVz !QV:m0PѧODМQH}Eu 03MQ(.rT7pq9~%=z?t8-O5@ <쳖ꇣ0:qJzYV :#R&^^{259X-a09ۚàwyd Z$ےw*CN]l /J?lP֊$NiХ~-] Nm3?@- ȭ-ٚj&>,Ԝ0 4 !kÆb`HJztx4P"! 5@#CmnRZb)U@(ο4SuCRѿX5:*Og9 Tä FfuE;nٳ'I__=FiF],BaXk%iElm$Ӯv dT+n:7yt4!0n`bt*9(L=~t]7N0tлS_sp$40!zL(RwԠ[UtWh?;qpG(dLWCD\I۪%]M.Bu*t14f f@ e8 &46:Iqbp.؟1™y􄾙tq[n(1W8NR&yx3 6 XA/ZUI '$'X֭y~X64 ;h)ShQȤ9qq wA@50o<'C&5J^[d۶m<xO8b3G7nD#MRyE}]2cnr ܵ{+m UW]Ex B‚edO= Gp 9^ϡeGft=߈&A&$f՜.%j#=Mc6Szr =E3敺^,3^(6 MCP8&@\C^G+V BmߓO>Y@"+:$M.h1/Z]_jXb5jҥ**oa9^ꫯrO#o߾=o&G?u3`Q *Bk"H,ڛXe_N2eذarSo:P }@-dGZj6lt~"(7 %"9t 3N0iwy't͘1f~eʀ8,~_3 I+]*gE,ht1Dx:VEoz+yfYg0ѰLHE=G5ӴtY1ȉ?Xt)9|pŽ#GbV 7gMjSS۶KX$V?H &<$7X@ʨ01&LC Zs,:RC"Ft_L"!HP}5kR@`U|:6僞A}ɓ#l: %SWpzcǎ]U޵^ΝP֔:u*oa)Ǧ$itbJ:t=v )V3MTlۂ*:HWܴ|쉴q'+$n1K{RG{0 ^mPbC) W< SN*8sӧzɶcM -=քmæ2of۟\_u: *KJ6vUN4v)SK.!! đw%?*@+QGK Eq+KyBm!LjӢ%իy‹p/$SʝTLOb:хnߟ'rqGP.ml<"VTL;"t&؞4"~Ю˖ shD1(ڕb2ifP|F'+WlR,ВU'*0^fȨ3vޢU=р)ܨ%EML CmlUV]5B:H o+R_fLTS 7>IoX($u#4khc3*^NDA0DۤXt-+믥Q&lɕ;^w3o+;^/'ꫯ kWB)7$=iz6mڂ (*1;b11M )L'] !/@|]wa4^W1aZ@i|W Njs,NJ&U'bdu)AN@>uԩR JV!=><hOC2H*a;ZBr=w0hѢ'WGt@54ipD32W|*u`^Nj 7E%=`F F,pW2TkE~pa>[5D J ',RԢuwoAXi/Sݻݿ2)N@… >l;k[Z51b"*%H3<7z3fO#?{|A5kyc RDDjngUimWͺ "<{*IrJ gerqFӍ f^{m߰+n۶-ĵhsE^\N]WcL|UWAoS #_<lB -#@}a'`^zCZtmʌG H-~ŊA2ezPs"fG`Ъ^ރMi4hЀi#CCݺu5r&NHkVLU7/YŚ) 8CW/ 'OQ)CI yn޼لG[Pyg|)>g%xR^1 %mcƌ]hݹsgpn!;>&0SO=Uz@C2"dV|)cr%EqtvTEfZ2e"-.sW#wr a'RyNI($>-Zi:t׮]|6NCJ!Rs=ۃ5jP.x]hKd@5)dRƜV Pp#]ø,=}!!ODf9|ݒ6qH'2)I&}c0&qHhPv;uWhbŊ0a)%O<ժUJsGC43GROz#J4@<ByiXW2kR:C O0:abڢwTºhISO=\h-GdaiHf )+KQ; 9H+!ɎYh46@ 0x:tرcAVJ@`5+7YS *E+sT''.[nRsC !{G7n)j֬mi;mI6á|uG[qrr26ZUΓ fanLEo,&V^_'n>F|gȶfeWlFPS/ O 'c`@NmqXpV.*B BщuzGQ]waÆZ Ei]DFOc;t: ,FC4Q0"-ɓe-m۶a΂SJBnR@7~E_ЦM.\C|INm۶y%nFkk ſИx^$/2C&WZjnP4 uzJ2<9JI LC=N^ipDH/ g si!^z%:c\Ko=e>B X֨lEw71C#7T]5kքh֬Y:zNƽ2Wp"L+:b`dDC `O䅇b8 DA2*\|9=iAo3f 5R|\{DhɹsLҷoߡCUOQ{FIJ @%ou0׭[WzBP:C@V"/Zᓠ/ 9L}I÷& -tB7 <7j8"b~x7z 2H:ח:R^9@QBpXBp L_4b5*eV(O !Phf/ꅸy裏L|".ڡ C6%5SJ{== i !xܺHfc!|>"_jUCjZxbtѣ-Sǻ`" ȗs(3b^ `%JO>$Jziӆ ;0 èQΔ)Sx,~C==#*t Z@%SF "*YlEMwr\fa9+U%t޼A11>z`Lefxu5 x ]X28զGCte#VI( Ѣ/3:xOmx 4AaQ MX.ҋ梅A o! yV+Hcb)u[7J8xcOfMmZDaR_dEeZ,!x+zi{j!V.M$.DVf >6?d 3:3{l)kFJ[ATM 1X&M.3^*CM/t}^PcLMLb{M +Eķ ?yirQ' -^2??X(tcKMnQFBk w?X<^wxXaTj/ h6|:}HZi6zzLIIi*ItOH-j ^s0jD41.Qhoj9@ UTPS c`kM8XREa3 ? ro5AdŐsJ @PCt'%}]U(`xb▨9u@jJW4Y[- Yh] PDJ_,Ah@;5jݺ5ç6hQ3gzuxOm^j]cWESF\9l(VRitR,Jwsӕ]y!&y]ƞp{2d&P`q/f6-á{f ªX~bUիW .!$'"J4+oыnxp 䉏WnϽI QwQ>wQ<;4WtiAիWz."YFO sw,b/;֜r|ϟ??̰bŊ]OW92?dʘ٥]mh.T}[|y»$,XjݳzC0cuݒQnwwЦY>b{sx+n=}UsT1*\5kjBjH}>҄3yZ.,P{ufWjC-n,[Ⱇ+@z E2C:i[tý/v-Kɡ=UL,@ O\;/W\so]lrx/e3p\eѹ,7ŋ/_^Zkc8iH YJ^:xi(NC2**aly(ᆈg `[߭c:2a^ʄaKSfkYovD{|  @z~ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @CC! C=4x @p!3 @Jj =#ꀂ/ !@=;c9pd?84 @%d @ 9 ud?3 d-;p @pyRE ȂfZp1߳f2 G!vY KE2衛*uF {ZbXv1IS<ըQk#'~jnFx{y%KԬY3Ӝ'vbV  ۉ[?]ti 5$J*]o'xWxkwLHU4ѱc=zf͢Xwؑ9 ipY=.@vg]|<@膀5n7ʕ+t@ ,(X@tĭފ"nذ!=\R~O? ʖ-ۡCM6UZQÙXbեK5k2v߲e .ԁ&aQJ뮣WAx67x#Dlժ~^:ubbJ-qyA^p-Z]%)K- Ɓ/ LŊ[othɯ^zzpڴiPyĉ3g}tM=Xp )/={3@S*ZxWq_v Gѽ:u\r%W\qnI%pO=2>,Z~u83h8֭Bk !YFPHѭB(n~ׯOP Q;wn|#Fnٸruǣʔ)(ğ~I2F2}VZi|*Pw}wƍ ,v-4CѢE{9`Q 0Df>Oڊ5bBp1$ fiرf}FqP-QD| Kcs9r$^矏Μ۝]+P- ND ?~J_:u*᢭5j3>xkh& l#@Y #~ۗ!-(\-'MpQP[Lt PXJ #.`W4{=HM+^J*͝;w̙ݺuP>'O^vmoݽ{w 6]7dcq/^wt?ޮ]Ν;w zcƌ?3m4"9r A5k֬\2ON;4<@~鱴GR8$kO}D_ғ!!@bMi5IT瞋0 ~=Y$(;\r b6 H{gkYg:vϮs-X $ 4mR#}wgժUM6=#F@N:i%;1'>k˖-MVJr]s5Ԩ1|y''L@dN _r%`TRǁ{ɒ%M4jիW (I/Xg`߈^@iwW̙8_|w7|w,]tΜ9| ;3ͱﺷ h޼9<݄n wlvUm3qw5h[A%K:o62cQ𪫮BƏ 3N-[(ʔ)k׮]-In]:&a4̞ܹS._f sX  ݜ^xgt#rJbX|-v̙ GAd;ݳoܪU9蝘kBLwvرZ2Fr `#[h1YV-eKxp3!#8Q\S {##ޱ`G6Op߄ FݤIeE/_n{$p,A 3M@y!6lQ2ܡe1:֫W/Oo)+A-)t'@KuƬ4(-Z.]:%k0B Ų̖~|b}2svJГWd59}Z?;Q:Ơk׭[5Y^}ww:uj,;W+n֭;w̲9ۅ DX2 x嗕Tu Pz:}]v߿e.Mo߾\r+%%&<ꨣ̙/d͐cIx3W6#2(3_#lܸqO>W_ݶm]Ui[:try"7*HGQ b^c5jz1ڽXb Fc0cŎQQizǼ<''uY?gٳ={~ffVUUtŴ%)VMsᾐW^ud_8r%ellLCS%ihV Ew_QQI{⭿b<@_3xm˗/ <͕癤:;Nֶv}T|({{ LI(oܸo'FٍO}ׯ9az5sL555iT"g*,Qnq_ha_+mݺFA 4'dJӓ*.oj95ROByd7ݚ ?|Nˤvb9KB411QWWD.r0 ""B&9#F044T=4njS-y5bcxZl/%4(usVDhҼGL)Hy@--A|* KIRșڝm߿~)hPVeTS[4tҭ[7բ$%G)߬Y3w$++&*+ŒItbUUU666Ыã~vbѠԭX1 |IWMrS{yfi*ًubZl9dȐZ }cp6hC[[Ȉu^|thCnjRRLt e \xz(Ьڰaӡ4(c[<~8--_|;wjj_uuuÆ =<<aeeU[\R41dA{O>]IeLm6RuO<AvF) /))1cdxMm GWES(++S&0=Q \Ҵ.\PQQQ*?pwޥGTq@AAL[۰aC)?x`a``P/Irz= J :uIJJʕ+Wh"RiY4KVJ.pS̙SAj@OVjej(\--|b`[{322DT )|||jaÆZ,4Ě7o2ѣ/h5]\\j-,,bccs1t= J9 N:%"hդ`GGGY\8p^rE$MCCcڴiKj/ ׯ)))y!X40E;:3GxKYPh81AS***}bP!W^mddDm'''c*MLjkk8՝}4{ .DFFO ]/"M=TKce˖I|4~x߿{вAȥ@şBs7n۷ŋQCAiKIItQKrψK  ...kCwj,\Ʈ| IxM'nMaaa- W. l<&MDDDo>55^^^_^ЕP}}]0ի;tCx$++ 'IꦐDnp-ٿOHQ4ܹsMLLlX^ +FEE5ӽ{={ $5ͳ']lMmXWDžy>]]]MvɂUUU++WCuObX=wG)B#,+000\|y={ Xr'øa~]Jd8;_)SoSSS///JXVgg۷oP---ի㋊ģsaj|KH/x)5kֵkΞ=[VVV0p2oM6?~|eR]]-\,2vwa:j_G/Ea^] fgg_x }<֋/ڵ#Gz}EQӲ+W466.))y䉕 *ab.)tuu-,, /ͭٳg0(0 A7@tyP&OxiÆ 333+**j| 8I(?POO/,,l„ S_Fth`a^z%&&.^~Z/xڗ@.+ā @YddYZlIcںL9sիWO<%n:>>9r/-vҥiӦdae46Z_|E;ֻwFc充PUU5x;wkhh(",'O:i@ɗ&O>Wp;aEïb:::ZC?xZÇh;99?_&. 7nsРA'NMs t䚚CA>)SC:._3l_-[h ~da lll`mm {~ h&)Rhüy`qA#hx#y={&C_G˞ eesrr q lll?~ƍCO }ooZ0 0ńI@4hܹs e 'ŀHoذ! փ"""п9m/N’r |}}O8A#=O>yfxGA!tdaFE0¨4^zϞ={4R!Ĵmmmuu2SSSTl 2#=%%%--M3 DF:CMM`hb͛>|E0 xk7_ }N0ֱYf^^^keeuܹ l8::bBA4g ɓ'Pα'N,))I2E)B2J xPN 9{lv˞aFKIyzza[KK+22rC^=VI#H4uA` ׋OO>ܷotҥB2bÆ /޹s'u840 $A8 4h`lllkk{q##8իW:u4Ͱs. &*++l٢J#ٰ؅t (5ZUU[nݻEEEZD͛7pԉ'bY40 0J!'&&vs&MZfM^^È#>c2w܁$UannM#:FR]]]???s $LUoذ~uttNjkkCIm&B\Cmڴo߾Raao𨫫w)""BKK Vpڴi4{H!y􎊊=cFBF;v _vvvcƌ\bŀlll9wW]\\B* 4x_Z0 04guƍB4@Æ C".OOO@ JY`da׊$#TUU@XDmJx"%JyQ\1ci˗ϟ?/4+W֭[עE :@4(.0 0" F:::{rr)M Y8T> }=?/))PHOO?qℯoRRRƍ(*]{ttѣ)"dAAAbb"zyy@HaF9400߾}{\\tp'FW₋nժUϞ=mVD:Aǎ$>|Y^r0 0R(4LcTTTJJ Zղ3(õ~=@y!:uʕ+IHZ Yf|u~a4P;[[[4Hs͈zMFm۶ 2D&4aaa"60 (PDuu xyyz{{`߿䔡all,e~%X 0 R`d…  ٱc4KSL u&{1cȐ!˖-#Š ?aPߚh ٳ'6tttvvڊ<ZYYUV"d\\\ 0 â]xgdd`YfQQQΝ @Q(6m#BF8ayGPQQW&mPb֭7n\PPЫW/ٯHMMѡ͛7VWWCG@ 0BhCyyyuu5u(hbժU?<տwx5UUUR 񾾾n aa<44I&i_"zUPPGpmGYXXb,a!00p4a…&&&{@6}}}1!III)SL3-s̘1BB+@7Pi]v?>D{{;wpH^aM[\WNTt8҂'OWUU=}e۶mx}Pgttillloܸqر@* vKKKKIIiӦb1 0ߧ>x$333q׮]ͭ@z~yyy5^zUEE222rUUUifffeeHa{^׽b2eXZrM]]]m۶PONNNT 6 a6mV]ɓ'eee8ɓ(455m۶z6mB%dmm \~0 7#𩥥`ggKϟGQȂ&ML: ۷/ ׮]СLݻ  =;wnܸqj/aa 76rrr`544򬭭 Қ5kB:4p;>CkODEEk׎2\BE!5jHd>qℛ+a{ 1,,gϞH Ab\\imڴٰaR@[ !}uqqQm۶ SN=z=zDM|a{CZZZ4UV#5sڵ}}б%3g߿?<0 wo24@f&/bܿP O>%CWWך(lϟG!#GBFFF#Fdu|aE2J06E///رc\\ z@@cǨ|ݾ}_]VV痕OOOO|u(a.)555x꒰vww%+W&(nLL 4A CCT777lhii! tصk-&L)0 ðЫW/{{7n@=Ʀjժۯ* 硡t䯩СÑ#G~JHO?tΝ\XX8f̘3gdgg#nnKJJaix;[ZZbiӦw-oٲe||ŘO;ud@(Hybbbh 6X*p8aa u2~aTTą `ae/:)@#dɒ>@EER2x`J)**Zxqhh(D xСC)O?4e0 0,O>uqqɹy󦻻{bbbee%&L>TlatT¾}|}}ŨӧO9E#ĉG®k׮]rSN$8 a 7 Y `vGAz.]LҰaC7hhhmT&SW$4 }m̌{8;;GEEAOTWWSβ={8pRjjjhy @vv6r[lYQQqu%Grr22vѣG,E0 HZ4]Q^====Z6L͛7d  oӦMLLXGYYYvӦM3hWxx_|AKbr0 ÞIHH(//s))<6󃃃9"-ZHHHI<|000@1'MNnnnƍ߿ FE!,azH111ٻw/l6l~kkk|;v8o<1RaРA޽EOL0_~2I 0 HUUՐ &MXW'e˖a/u+Pq.ijj:uϏR hq\\qk׮b`O0 H kk뤤$[[ 6t7Eib%LWWWncc#ׯߺu넪4hb̙t Ν;4aalܹs!,,,F9l0xZ$BPտ%KǏObSRR &'*ȇ啜l``@zCś0 !U_?~\^=--ܹsg*(~|SaFΆB+GFFR痲F߰aK&L0zhً&&&vvvTJNMM500vNCk`"i0 0O|'/7***hwe֭ذwvv}9_۷FZZy5k֠,$kii5jŋ ?툈˗/ Hao^ }PFCd/)I*!t@۵kw߹?'tooݻw{xx+JМIr- ~ꫯ444HOZW&Bĝ;wvĄ6"## W\\elO"`2 0L d4R#XDlKWҥKEEEzzz?~īWn߾{6m~0g@"Q}]h۷ӧ:rZYYEGG7i҄⇍ahiiO0!%%%55^M7 ?YPIR3͛7?|0L_~TTtV߿H~h={^t(/_JPZ $Hc!8r#Fach"A4y;=Ms]]]E&b (~5H 666t"Pb~rSـĭ[B i:t {ޕwtt$5tPr6 6vNhYm~aA'h_7n+xE6mpy++|4Ѱ MKKsqqA˰UUU<Š?{充$#JJJp!b$ȏ˄ Dbƍ---^J UTT 6,66H充ݾ}&bddd;ԩSFFFnnnqqq***._aKjMpذj1͚5111PhO>mnh;;;E}90x̿~rr2JRf46͕&ḥ"{۷+ :dǎG8ʕ[nS o裏W J]6j(55}u v: 0LR1ڵk`FLuFQOOJ{Rx Mєl1 0o+ݻ7.]e˖u-^W^'OTUU%{VSS:`|EEGD:t5k,** F0BQ4Pl؇awXh,*l .=42 0Hnʥh]ZZZYY){ы_]] vvv+WuǏ=ߺukMMh1AUTTTsprrjݺD\xq!jjjQQQPH|ɺuH*\ bl𙛛keeՠA˗/SzAϞ=>|M'\RReiiBʊ:vxQZb ͚5;v˛1cFbbbNNbg0 #i~7774ufffVPP)tL#{{{߽{D(ڞ氣00ɰ,>Giaaٳ`ah'9}U20M6㏟={6L 5a cd4"GKGڵkw9H'2孥h"ȋSNꑵu!0(ɓ۶mC#Ft۷׮]{MX~հb5KϜ\W@@Dpɹ$p,DsmѢE Bᷠ-jjjHq/vر|aabLh;w.^v"""B1NXi%L.Hda=A fO?Cx1 !lmuuuJJ:t9L9?ٳgo߾MQ iHaTI*Aڢ")ѥ)z(Ԁ8#sssccd!Ӊ'>|r455(v@+WXd¸>AαcB!Qyyy666eeet B2 0r0Aavr>}hiiQ(NꞠI_ON!h<y~s&M@'999~=b/N*544bFFF9@=L b ba^KĈ>nɒ%=z\̓>{Y||Ç!,_YrܹSUU㜜www ¯Dd5jqs-|mڴCTT3Af@DDԩS\w}ݵkא@"?g"D&򤧧4rݺu.]B!]tرɓKݻXYY_O>A%n`+a"S~ luLĹ  uC hjjQ[ѣG>z(*v8 ,XÇSiqtF?cFFƖ-[RRRĈ>`ҤIȿ~/Tp={ CEE sgΜ.''':޹sg˖-!0 Hh՝:u:wl?tu7@?ZcI;тi/ZSZ9ę}l2Zx%d sIt85]ծ];ًn bС4@(<7nʔ)2ykR ć`a Sʕ+nѢE۶mѼtIC˘ F~~1!5LMMaRSSQγgbѣG\\Wk$۷q@WWW4kjj(։LaD$%:t}vVYYz%'$$TWWSM^J97nxرR4i޽{۶mǏ/pVW\011 ػw/UaI@c`Fm4h$ĤAfffh#DãI&0r>>>;wvtt8+]]ӧ@1!h$vOۿ9}vRq)e1'O& ۷/ N...?:uT|%y ڴib 40 0R4 %0bĈ'O3Fshz!q-4\L *a EEEW^0aڵkw»vzcǎ)޷o3gb}ի/]cyǎ| mC-9_\\~zh/|ȼf͚{.[L__.11,))I0 üFDcرP ƃ1caaJ*L5aTUU-ammiMM 7oޔA=pttD#Vcǎ>LNNԩN{ap;wF~'<'NވTN˖-Ϟ=K]9gϞQO !Dƍׯɢr曣GB(>bk6lb'vA,X1]6sL7771VK///񻮮P\)ӦM1bX۶mO:C<<׬Y+-ŋS6sssԭ _D(h/‍uQ s̡0 üMp˗5*99y׮]^qkhhSMM Al'W 5~p?^ӡCk׊E>ŮӧS~zOhUVAl={DNً~lni*Fe p2qqqHj:60 T} CxA5k,""b…6l())IOO#+*j8$33֔Yw:K.ﯨxi.yW^8MUԠAK.ԩрM6DB=zzW`ee_N8&Mѣ;wbXhСCImҶn݊30 vhݻwϞ=p©S&L;>6S[O9Lu*zAI-մiSO+DGGE'4iѰaCボ70"$rR-͛߼yFGZ[[a7A=s0")h %$$V8 8066ʊߢ򷨪RSS/+++)))--2I.?*%L)@\~o߾j.~Z իdr6<~X[[&Jw0`f8goZ_T+iP} Wa4Ms&ov8PQQEp'{onn7l۶7#ϟ?{u;lziDD$ 8J@ H4d C!MÇ;vLLLQ8?ɓ666P8IH ///nvv6sa/hҤɸq㨋mw'?~?%KJJJ~9s 0b>RiGԤ4vrƍ'NDNT2Arr22_~8K"' $?¸x"0 0oh3qnj# 2dHNоھ};i/F?Yz{P"-22R]]]6cƌ޽{^ ]f u !t;mo޼UV4C&?:xke1 0ʀ$'дnܸܹs5h.Cwܹ>ď?He #"aBG]bő#G={s311rȏD۷idQQѨQ:TYY n݊y&)++ڵǑu3ܷo_ii)Dӧ!V\]]uttRRR8`WKKK԰Ԣ2 üXXXjdw{FAr0C]jhc[Q.UVI!((}ڴi^J&g777+11Dɋ-NTORRͷ"emXDB ֯_G Ͻ 0`^1 Þ7 ޹h޸q naUO@MMMcccua 4㫫i(UB֭G7CӇ SB (BCC?N+ ET CFFƧ~z1ȏ[P\\\SSWXXf͚EEEQ 999JENxOa7*DX &[;v֭[͝׬YM K"[޽ׯ_!֭i111<&9!Pzdd$Myf+*O>Ql%#?΄F6PTi4GƍO>l0q߿DDL“{aAOL!ҫuEGK;ilpuuׯԩS-,, 8;mooc$?~eeeIII>gϞ=W^'NRiii7n,(((ԦM3g9={"ÃpVEEE(A:?&;;{}͐:bĈ,˗/h`FYQ uK6f9?'d#~k׮ٝ:u fwkڴi˖-MLL`摭444o޼XJ1}ԩHgrrpÇΑɓ'w &SRRo߾U9Bf}}}q :T[hAYӪU+%C.yl0 DP iIv}ƍ&M*H_@ cLLL" 8IN;d!#ܒlmm';vhݺ5ɓi`&? bh sK/ayqԊSmnaokjj`7n܀aw M=Ν;9s>oѣG8044:)Ǐ'Op.A{qqÇaij#Ocsrr Da%q ?Syy9Jػw/ѹrJ^^ޘ1chLZcJ\3 ԥ7׫/'IBPvaa;v(])XfH0H5ܺu[jkkp}}}[[۸&MP~3s̶mM6W&葜ܢE 555N+j0`ڴi­hcx tc\ DL2:R"=O2% @(h"0Ν366E(333!s1t~ SקOEnݺXF-SNa/ܹs8~xZ1bϞ=ԁ(rX4HG )b<- <555^^^C ϸq `G.]j׮鑂\GϟH9r@ ю&&&F` +yq 7۶mc>noo:@%<ئM_PHFy(cj0 G= %%ECN\\aϞ=?zr~%>ǎPohiikkڵS ^tuD=zTWW'Ν;iO?tȳcǎMn:22RP Ɠiٲ%n ׃^R4h**CzO>&x/9Z5k+ 7n,Sh޼… IP6}}}([AD͛Gݻ'&/ ѫW/+p 6߿?yZ ˔/>[6lH_3rsU]evi۶---[hqe|LbP&d3g477t JXzuDDٳ4L]AA'OLS= ػiӦŋ*++'N [l ?}4Zr=ٳ'~E (aT 芊 IH?Go OPR~: h۷R #F4jԨsFɉl?iB,]?Ԥ?!>vލAAAte˖A[XXЂHԩu<~!|С>Ϝ9Mcffvƍ%K쨨(Z888K]S}:cƌݻԀ@f Cmn4)'; œ/ٷwh`ʰZZZ00î׮]Ƀ6^~~B'O;ٳD6-['Sx(W.]@L@w}gbbҾ}{~&tt4i$H{9+--ݳgtt̖-[>쳻w"[v𙒒2zh3!YP?Р~V DEsΕ/-Z#C[_SS󫯾{޸q#P"4sٳg4Rb_pPPQ0ׯ' =HFFV -@G)OweŊ8|EG|dbbShhen6lR[_oZ&9cxVnaadɒvk0u#v^h9::޾}tooo>|}VV֩S('Tŋ:tׯTڸ$UUUբ;\"11Ʀu'Npd'{ZZ2yBE!1==}޼yϧ<PQQ##Q&*++XfӧO %ܹr=zg ?7OF)ۊp|Ej}… lb#<<|!Y4##:;/\@*gϞMқ6m C3ϙ3Gyֲ !נxQSqqqK]o]:guF >\o #ڷoOM%''ô_rPq @c΋ĸ~=9q?O7JM6999A}AΝ; [vޝs;wݻwO4 Z8ȗ͛7=F.%%)Ju%LyBX@ 7]{7uS[ޙ1.&?m1yyy666x6n̙3= hKNmիW;ufg8E{}g4qٳE/+W2DKKa.^8n8C4m{a~DZcA=z488"bɗ.]v횿QQ?Lc#j^p'yk}ݢ?Q^^>qD}y ޽{Ljl߾>Ѐ8񱳳}y\OhӾR*I"[$4e4b0,c cgd[T%Umxs)B{=s=ykH@%qqq%%%NNNzzzD״Dnt^W\HBg>4xTTT|`'>M.ERC/Zㆆ0G$kjjR *!! "3H4gg稨(~ˡK&^?n # \nv=ƍSPPЯ_zpƥ}}} _Pxl'44޽{#Fu?GE56^)_{h߇ ͽ=k/gc]\gdd#4/ 6RUUݰa͛!۷l3flڴ6 0'0Wlz-9NT llܸ1P4,'O]/iӏ? ŋ{xxF9%$$XC0qI&板kn;h!Pi#,*@{ݺu؞3gW_}F6:|Bԋm1En_NOUbCTTtΝl7|H7J …2a„{Ҷۉ)o۶:j*B&...s L.,AT# ,7j𑀬|8811Q[[;th"-LMMhAA! &uс&NիWS8Hjsa͞=+ĉ$,Ń97Xd4bڵ7(6ݻ7T\;OD4aA̜9Sax:) m`߃e`t𴺺:̟? b1KKKPr.]x-V(ػw/ p=:0~4^t.޽hϘ1c֯_O8p#G@aƌ[nWhllGl O@0L6<%G/š'G`ԣВdв7bٲez\322444oxƍ›ذa!erAQ쌍@IpQZs׮]Ǐ4hBzAc"`hgۗ2|l= l*7N3֫ο[膗/ &+++8HZp!^pϦM 7oLlllJJJ׾cH=z4k`)))A ___@0| Ά>Bw@*OX|XPDgϖ,Y"%%\QQAy\ 111Æ 8p`dd$>MMMiii4Ǐ1ŝJs޽'666fggѣG<~ ,,,\~}TTrsqqIIIA544V||ŇRSSCsꄁ 7бcGZ~yz"֡n6Ɩ-[/^L A۷oy\gN2e+O c$$$8iӦ\044<|p>,--?ĔnjSzxxP#""v*))y%%%sdh_!.Sn>}:Qe= o Aƍ޽{СC^^^wܩ՞؊xEXXرcEEE322:ɓ'dӦMIIItz~~[QQQZRRj711+W={B,yyy]]]7,GC3L:a`xǟJ`eej*,EXnn"'A0R<($hy:Xb);wS>zwر#CEE%((HQQmw$-=iҤ3gM[NGGb zw^ 5ϼ _}Ռ3X=|l 4/{r㡕 )EEE߿_SSӺx΅}gff=iY{{s6@E9;;JWW^Ο?4vXPqq׼yȣߟQH"66vrrr!!! DGGB0Ν GDmq O|0`gg{ĈP 0]5LY}~P g())ANNN`q[ZZjee%##Nz=z4xర0?? 4@ P`5''wb}}=G>}pʃ(@.v!kh &{ƗUGd[7nTTT a`x>00p„ 4;4r#r >x8pޑ_5 E,6 m۶q>}VFںu+J0 `)SP LYY9 @ZZZMMRRR.\ԩO {Œ%Kz=Ϊ40qOn+WΛ7O[[ӧԡ >P2cqbbb87== ;*#GaOuu1uuuSXX8hРz:\vv[rrǏEEE!t$u&..Ѐ qJppdJff&J/Is~~>ZV+42<==~ɓ'ܹ/LsZI_Jq…)8-1qa)ߨ ?Ei\~ ]qFs2,55UQQNܹǩ`\^}}}ڳgʀX[[C1PEfFCX6>{'}*h&pp)vYi*#D6`gw s! XTٳ D=@R --ޞ<_kI/_朓ıcz=tЧOBŭ^z=P^^~ҥc; ή{(mRR҈#p;O>1.>}000)cǒc#dAjj*5!-[888Bv PB(d׮]w0H/!>A҂MOUS fz͚5ڵH$%%ʼn wwwgϞ=w\+**}v%Æ q aȑسlٲ3g:99Q\䩩;k84ꁁ=>6hGm ZZZE/^?>-//ٳԝ;wp_~yOuuq.]W___QQ!!!q5777Vd`Қ/\z7aff@=ͺ l2d!**zA6 OeddvڥuWL6Y(+55 .P<~3gѣYUVqh"g( uuuё=== 11`}}}ٳO<Ǐti`x?v@kW644/0􋋋_ /_.++#)\DBkkkIIIhA׮]ӿ+V^^~Ν;$''C%tHܵkW( H˗?ٳgHLfΜ…eSZ$Ԇ^z."vVV%e )> WH ۷oulSTTtΝϘ8s SPPJv\t:4.]СC8\9I00000Z0G! 2ii+ѣGQQQ .,))( ]~}uuukff6xPR!UEEKxx8={VVVɓR]]]CA{{W"ssssv5\CPذsYOE pim]$aaa\A3R';vx? Wo>>漿ulVZ~=K,n2*AZ`z(f p„ :taee;8y򤔔ʕ+$9~x߻w$:r@LzhŊVSSkjjJOO744,..Fw޵E!#$ 222Й3g_uttqΝwuǏBӂz(#@n :t'&&=ZBB%ߑ5n8$Ɂ@nyyy۷o:{,xd%,,vر>}@I~lС.--e/ / BBBGYv-,=z>xUmTHXXS=)){PM &\ UUU!!!!z!r8sLΝ-.lٲӧOC=@v uX`^z޽{Ǐ_r%v $(**Ql6f߾}kjjhlR -x]zر7o&11gR&~ $++ Y0x` W9yZy0ׯ_@ao.%%\&EDD`K. A7N<D5ˁݻ;w,J6,11{QӬӦMo)sccc ===???'OĆӜ9spZpp֭[qѣ̑F !xӧ]vݱcL파S8::*((۷}DDDmm- t338^[)ꐐP/rrr\@I  ;GFF6&&T,77’FKKJ𺺺=z@\p᧟~رc}}=!+W%y15p5JF>>&L߿|||SSGojò7o^mmmAAA˲0#F@Ag^vͭ"EBBB QQQ(ҝ;w\\\n޼?~ۻ j`СׯGqIII r t%>} &`.]L4)$$W^}Ǿ,tR0>fHKKO yyy›{///Z2P,&زe mC@(++#??cjkkCرCSS Ç~wwf"_#ر#7uMu6000001p.555yȬZjڴiKtB鍌9k̙36Eܹ3ƍajjŋO<suuutt_ y˗/@2CC ʵ6&qDhܬ ++#G2Q1gZXX_BC&L"NӧOHH$'N  !!JfݺuҊPTT߼y&4TE^fϞ6lDM1?r1ah ꁁ-|>=p h󃂂@Ɯ x}__II)99Y0$2)**5j4 Rfggwo޼I#ݻW[[ 1kii)..t֭5k\xΝ;.]Ԩڵkdd$4Bqq1uwws\\\? 9se`x{2%%%ԩ۷iHB~>} >qℤddd$OK.ŵKKK;k֬<* cbb~7o>r劕Փ'OPcǢD޽prWWW膔>} C;󫔔 Ȼ魦_s 81000@ëW^r M s)͛'MjCBB(Z.\pÆ \j9z(ux޽[HHHWW7((HLLk׮k֬1000`}vZ$𐕕eO....,,;ҫ ''J.*{ hjjAoccSXXmy܌:u*;-- V?~PRR2rH(L1cƌ7o4K.W^QFkkk#τ'''???UCC AN> ݠn;os xs^UT$k)##SWWǞ,%-1n(**&$$$~G7774]B6.@ڮ_64)))uVH]v-,^Y/{0(E7tؑ?200|nd߶)X`C^^-Ib"~V< \]])`!膈?pdMMMN( Œ%KfΜ{ņuVVxzzBp$''c;4ƾ} V/_M`[W!25n`Ds^ӦMՍ)]<^8zhcccH*'C899!AQQQ\\ܸqbccq!$}rC[AU[XX666_- ܹ[VXݐ{a>dc^bA>dO`?xn)11WRRjeR_Օz!JlBF~A\\8BҥK(*ȦgϞ;v  2dtaϷ~:N~~d*9B1㞁40TXQr 'O\ lC ?`Zo 8DFF=ZOO/!!A0duZZСCCCC]۫WD+**:ut35kѣGSSSqϟwqq) Y544 A} 6l^+/x`UA0?DEEmmm_}H]]}U;w>|8g;PhjjTPPy4Adݺu ٷo_:  >} "3g~<.s)S܁x Qbx@ձ&|`cРA!!!#GuIqpp[B)*6m2445kNybҥ)H]]޽{wލd8d[n7n̓طo@$2 WWWѣǥK@NP FFFzz?~f%QUU~zee?SEE5uE_񈦦~ 7p8M`eePQQ shlDGGC78qٹ@UUqʆk 444N:_00000E!!!Pk@o655z߲Cy tv _#H:@7l߾W^GNOx{{AٳUDDWVV;v ϝ;O<ٱcåKw^cc:(((@EAO 1P?+1f2000N >|ݻw'vyVV nW˩Խ@u=ςX嵸N"@yXB__gN81<<\OOϞ=op"6Ξ=kbbjXP555Æ ޽# RWWՍ `^B%ݿݺu0aC16m8$cǎOQ ݽ{WMMm̘1gϞ-..>ukKKK_7nVI&N= ##ɓǏEhhГ%Qꟁ=@ q#GlٲGBBBII~Q+""(0e/R^^z\p" - GaժU^^^z Ć khh;rPJ1m6 @0UUU(!}}}??;bgC0^ܦLbccvZӧO[ZZb[n!!!ZZZ˗/g+^~(;@ a``= kjj JĀAKOO/((J^OuE<}@S#$$T]]=cƌ+W`{ԩ [~'L m)''7rCxo߾cǎŹJӺ:|9slܸrDçEA3ftW$2D/VTT Z Q[[{ơ76ETtE'''OO… 8 sWPWWGz##D|)++4OF7ƍٰ9/7]KFWVVC 2$229jDp'NCpXʆ5dddv5eONNNffѣ$%%uttpkk[n)))ﯿکS'r_U^^Zl|z5 rʔ)'OرduuB^^3MDEEi*6,, ,;b|ZZZ]]傑^WQQQ /((xS"###]]]哒ٳgo^vӧUTT,,,7oyqM{{{KKK>! ݻ糹J"k@;tfee5p@ww˗Cegg3DFX))+V/ѶF3233o>Hnܸ1j(pODD2ill2]rUUU"zE&na֭ǏDžp%Ğ;yOELPu6t)SL>]LLBBBxRy&h`@NOO=z48ߦo#+++!! 999>} `ccӣGH쩫+,,?#!##ӹsTggh;w̙36O8ѷo_$fH+5͑511 eC _ 4\0665kÇ?xkېoEDD6lr2^a ZZ|g϶nD:uj``I-Z46m4/yxx?C@ A݆~f;,,,(hFF6 СC={b>% 7h|oQ4ێ{`)^~}Ȑ!R%p]Ln޼.{n]] A 6V,.t۷]\\ tuu 2׮]p-Cd}}^-.h7EZZZ__ĉ|󍤤$wCkɽNAAAUUUlns84#WY`hviiiee%9ѴL*RSSq͛@6m\$F`XIIIEEIOO#N:eggyyy/__uuuL#gLj5TDEE N:c 6TQxS[ шF g=nsuaƍ } *,,{Pnn. =⥺!662$$ !P!ة`mm߷oߚxQXQQGMM!YWyNx͠lmmlү_?->ܹS__O]_!M{n}K&\5F5 JAUUUA`JYYنx߽%B\\ԴD{kAL4B0!rbxչHiddetaY 0D]Í7***CNNcbb^e9߫feٳ'7GGG>> xK[*l+j.AV7k߿=@CCC??? H_~Ȫo߾Ay R`5k@4Pۼ#?,)) " R$ssp 麺NyɓKJJPK***(XJSS"66K[)r 5ڣ~/___&)+lSST]||<kh`hu(i`4G F&$$r:t=;Bp;w9RKKZpN S__yǏs'/ TZQbРA('޽{ץKkkk Az655 ֭[qqq:vLrss:udcc3rooodJJ Dj-}>8W<,ʊoĉ,N o(X 9c-2nO|Kc]^n]mmmNNΛWȢ"𽽽###{.C(AvY @|@`PNTeee̢ۼ(:tVٳQ 7"AAx8p ""J MBهѬ4A~ x7vqS000ffkD2p6mPCCaii9꺀fzϯS6^jee5l0OYY`@+N\>MMM0vvvV/͛7z 1rӧ3c jjjLLL\􉉉('7+x2dܹsQKǏy5b)%\:WJJk׮Yj!99HDû|nݠ`Ӄa:/_F9SN|8<*0:#%5@ x`EAĤ=~Mu ,/Fv"J80AQXXaÆPcǎy|_4dȐ7ojRR'---\1** bرc . bPQ 0u놿(D|ʬ:bĈTTT8|0$TZZ p*d! T!*̙xj|ه|xxx@ABOdeeA L40{k#hLJ:333sssa ÒC I ko߾mjj_&!)ȶnbh]v! %[g#c'Gd"++ ݀ۡ"j6RE|p'.}̙`PK4'OSQ׉l*sM3qJJJ_++}B矐kyyyxt__1p/56 ).Z OQbrxcSRRP(Nh%*c*hjXD˯FZё<)@̂xމIZZ毭5kgG _;r >*SGutttNHH #J}7l*l]222^AMBjU-߁ bx,m6zhT>```= ?En'nggeYV o„ 8ZZZJM9C+++A أD\[n͊V(@f؀E+9sfPTrrr i?oV; ׽{wЭx@@?n4f>W͛`ܧ!''gmmEEEx^999xIZJV[l,[ ݀mllvidd .x|'|4ڿ)܃;Ѡ;o%$$L2_z=|ŋ:u !׊F^rJu7;ׯ_/""ޭ[\%%%cǎ+W GLLLP1}!_Zٿ.]#&&֭[yyyuuugB >mŰċDޣm}{y=55'NL8J5 7>Uq]v=s持Amm- b*ݻ#F :TZZ'ɉן͡9"##Q3SNP\']oZ 2}tcc|V+ ]ZZ755t9~;xbTT/㇗U7ᥳLʨAM \/4 @K7öiW%022\@y-ڽiB Og;Grr2 ߤ$.ʂ`6۾ܸq!&P9VZc}Tr \ٰ y;v\bů_ >|{m#a$X rȐ0` fJ~=;5!tXll,N)= \$bee%KU3000~4*}}}= }lZ|a>u!JB0s)^Yٓܞ233QwG_SEimwr-cccGGGoݺv/_hR+ǎ;k֬3fݻmIII{u!!|Zz{#k׮VFFjBsVh7~uttPZZZ }WTx x>|hccC% L4|x@h kCFF&;;daaaKǹHd4m4::yyy}֬Yf}io `sVVVP4UUU&􁵵œ'O JN͛7/[,** %'o^0lSW_}umYYYoF7kkk[XXdffB@+TTTpQC`6$ Rsss! !C#!!q5III|]UTTT1c݀ 駟PB$>|]h]++"RfJMMt`hlqGA XZZZ)S=k1fK1A+yt|%nZ. `\dbb"j̙O>ABݸqlO9|l t҅W[*Pxp?9DEEq.@ Ψٳx)7>L֟,^|!TZAAr![XX(Q ӦMN*aaa蹸8l+**Bdݻ-z#FpժU0߆OFvy+~nG@]=x"{Kɔ?8{ɒ% tơVfJٓ/Hܬ ƾRdLdاO &(T2nJ__-&4ul^###)Ҋ}ռ9s .\_ɓ'!Μ9sq<;w;w c``6EK.XU#vˆD5 ;J')gP4`hp(srrad@IkϞ=) أF$i]]]"tlW-U8Y@\zƎGDD$%%Q4 6Bjjj=P Vhg-In%:th|||PPPYY.p:w7eʔ'׮]kEjiimڴi̙uuuH?n8x! Ѡ2400|~'/_uV4a-8-HA #dX600Y lakk{ypɺu`F,*٠.`YvvvP6{` +TTTDEEu )))$P>C6T,uBztmT2*4QWz)%pÆ צ| ɓaZXk~]M6)eѢEoabbcڴiѿ2 7դyѥK9FNrZjԒ* F=$55uŊbbbݻwtܳgD jU>D!; a,[ӧ(C[[[i%=gl@AFDD'E>^L|_57rȑϼyzٻwf .u"% M lþ#...##SRNNÇ8˘h?ΉaԩMMM111h8#IIIP{ܝ5 Ux"2$SR#*DSS~C2Ӄ Μ97Voyy9rχ ?\yxK@0ܹCn"T;,(uuBηlE2\ccO8o>3fmb O000H _~͛`M6A@dDN(pu֭&! #`սޕN72enx (3xҤI`q>\@F3FS !X' ,4r׮] ?!%AlHIC;+Ä́myyÇɢX7n k;q zA2;k,ѣ= =ggddxW e1000޽{=\ǛIݪș[^#qχ} YƷjԩhYcAQҬT`Wn,G%&ƨ` (X@"PZxo1Y3{;sy s*4İJ*y{{g^;w wvFcooO7l ;زeVP+WNQƇ'NlѢ*R ܆^NMv\͛ ]~Kd;%7*Z!JOqSD 땉ۿ> B[lnӦ x|؉|Q;?3Ε^.5)OfY5[6Ր4J:{l=fΜټy-[޽f8|u+\6ϙ1:,ŐC 'e\l)! 2!_֋˜xʕ+-,,P4:uT :'O&$׾}"E*=z̙`ٹ(5C@At h MMw0eH @@nܸ_pA0 ~M~ԩ!!!P^iܸ xc۶m>|z/wͲv mF  ĉu!Wu> /ϟ??|fQ+..Bgҥwmڴ)^/PA7t!nݺ=@2.]F={6J?~!e.Aۗ3==%5> k%KT1bĔ)SɳaÆ:AQ02ePVVV\#QЬ)&˂ a"L@Tٝ)PA iZ &)'UR REN>LF>ٱc{mA>| (`SSӗ/_:)~JJ@…ܨ(Ǐ_~"CH_' @TNNN-[47mڄ.\e&= B@Zn_h4aE7t-Ӏ>YMLLQi4:߻w/ hNa +;n D+I-/n Ҡ#Vx+W\v &hѢֈZȓԮZett """*T NCij5_HƍQ]vBCC׮] x{{S%1x#{Ρ!޽{HlG`O~c ]KBYbRÇW >ڪUy˖-~xձ<]t)Wp!+ć [S\2D Rdr.>HnzO9r0͘1eIߩS'ZaQ۶miz_6`ٳgr]6Ơ> B nuqrJm0'TŊZmF.k@hߞ9PgF( rqqKbbbv}EeIk w-eO5kիƕC:ۧOuӉ˗STJ*_Th#0|.Ō,Mɴ (Y ZfMTTvxH9*l6l=qD"$I֞oYf\lLJ+5I&ɓ'aΝ)wޫ^馓Ji_G@?"kz{) ЂIIIHBBɓ' +T9v9+d'LO[n޼yԩu@CdA5/ˮGI: Ajժ!U˗oԨDFBW… Sr[n߾ڵkwIxk4ekk;zׯSӑ#Gi|.XoPgfj5IU()XhQ>rO=E#3UTi޼9]~(I> m\]]q/lٲ{~QΜ9s1"""z1gΜy慆rqF___ޓ&MUnjn馓C]ӆPZ: l@N_T" '˗jWxq~$M<e-,,Ћp,grrlc`"'Hb' t) H^ڵmxŋ{Vko:t|:x`xxxy;vl vvv^jՑ#Gx/6~իWk'զOBΜ9s= "YѴiÇa ,#/S t>x =ґÿOBO3{}W^/^ tM74| v={l֭QFśK;,! HOW\чWeG)PTzg޼yЅZ FSh|U֔)S6o?+&E_5,DHCLL q6lئM\g(_˕+Ԯ]?~!(YN6 xgϟGpqaJA{E:NK{{QD3f@#mll+ nHL/ݾ}{ɺu봂U!vrQӦ&S]c#<@JTNoβR Yɩ"W\}W6b|8pi(6췷?7dʋ}R+|X ]٪HGuQxzzΛ7O> 3gαcd {rDI\ȡ8T$^cm@Z֥Kٲe˴;\6ٳ@\zU2uk֬ ѐhq`ݺunj Inw6l:u0K#!H-5JQ03offVd˃D=ɆrAt#DZ'''Ј BCCS42?)S/$3ve6e))5gСܹs V֫Wo(iKKKJΡ077;z8W۷oGEEi*~Z%2*UVymQnϞ=JLL|4Pm 66k޼y| :yd|6nؽ{wM7t!A`Qh=z 6t^Bf2#$ l`xOЮ7+.]Zv~Ypp(lhx[P? 8~8M2XSD^zM6M2 ۽{w֭;@1&&&<<<""B"KRQzPy'ӜSBi]^x޽{'N`4$F<E )dvqܸqԟ?~" %s̡ݻW馛N>r 0@ u^Bc砩 J>}ŋBJWX [Ϟ=@knu$GW^re[[[n^QA+*rR;qDZd E*gϞ}^^^UT_Q 2sP95w%R}'VZyzzʮhú~Eğ`9M^|9 … φ2?Ϝ9׼ưlٲRdf+++Xn:iec =D36ᣃPGٜ1[lHe?RJٳ>qydB\XhCʱ;w޷ov(f nҤ7|| rիWڵI6AUD=@U]FI?z8ԩ 6H,Aq. ^5jΝ;W۾_W Eo,r;e;vGܨuMOڲʎڙevZov6N(WL @ѽ{D- ZQ0Eo߾gϞ5hz葬DW8{{U$u{I E#p*aLLL%ښ_/]0`U%***tM7AO=0ΝH"u֭Pڵk@2p-[ҥKC666-C-:[mmmUV9rD3|L^ ڝ(ׯp;w={RJp3g΄$>A.Hv 3gN%~PZlWv d6'˵j"<… 7UF-U5@Da;BYb!11y>>>=z~߾}) @K馓m/^HpwwvB Baaa8 ) 2ݎZ^Ѹqc9F4RVnڴ)::;hРe˖I/1=رcfff%J3gNVlْ#G;vkqwmR5jݻ{Vk/^x9؛,WySOhtJvq5ݛ%Kڵk… *f͚N:%''úG޽hѢWҥ u?Q19Ydyn馓2B^lƍ/_;j)vU/UTjdCwJW.Ԝ!FǏW/I@Ŋ]\\?]v-$$RJǏwʕ+ \lI&ZZZx`g<pss Mj& =x`{ƍϛJqvv9"w5DZ~Fgnn_(A|u֭\pR`Ǐ{{{./$r >|O?gϞ]vA,`fzG릛n:iOЛo(F[͛E?(x҃ s:* ;wn|͚5˧C<{HUAFAzgϞCdj۶mQid۷{xx|7W\4N"6mZhQ=DFLq2*T&IL_v-(C]xz@1U^4h~󈊊9Z'm޼y87Cf FJNNŋԸqT˗/7Jn馓ݲ(c.;r\2MijjFkL~(mllbŊY[[FH Ν;ڭ՘z:mtBaĈ0@# (0dln@G8aHhקO͛7>|2m~ri׮۰a͛7tH*'Zh%:ulh m#_yDj!X… ˈ4իK3W{yyzg,YұcG ?}縋$fL"[Fzzz4חIgt-g L5r\rhJ:22I Q DN]ةSNѢE$$J*ߗˇF(+4믿 Nt'Oa",Xѣ ϙ3_A,QE]:?p1Hq])8\w֭+W`o4zA(ȺMI8wܪU={z O+VqqqPI'E QүC4PF| ?tMi}:Y~cF Άi`*8K. SR+cP# aÆ`A`@ pׇd e]'8tPRR!6Se˖urrBKWG| 1G"OݻwGvC/zѤIٿA- 1| } Ҳeٳϝ;!ցݻwX(*Uvuu)pիWF}<)yV p~-^EAA.]JB  @/_\vn#(L%}նȀD3,,,ozHCL+@CV'N8]xQ΋ʑ#YƄ4#-bUTiӦMݺunݺo>ǨѼV!BJO>P%JL:9Yf}E1+iyԚ ֬Y#`Tjժ\\v- M$DG I ,Lฉӈyڵ666O.ezHnϟ +Vp]W^zΝ;CCC/_N+>7Qn޼ sjkHJKßy+V$oo#G Ӂ^m7~ƌGPM6 1'{Ml{쁦`' b† ?~Æ 0u25qy5qp!6)wsss;;;5jt݈H͛O {W̝;w˖-&zj ɓ 'WX/_cǎ 4@tIn}@:v3g΀...p F4bѭ[7i`2>>mdp[D d![L-\AF"  3BW&c. y޽ER@57q<̅ Sq cQ_ ^DÇ P 2339gRH^tJ9epG7KKK(u_~%JHLL}߿ŋ'GW\y)ٔIz#nzOnِ'OYϞ=iO Κ5kʔ)FkX%'zqZs@ "Qce/Xbu-[,ҥKGqRJA&ٳӧO]f'n"ܛ7o>|0 ׸qc| &rDEE}wM4a˗/Ǐ*T NkH'֭[k˄G;; @P |5/U ttt$~:Q:`-,,H6}y5F!xxʕcƌ_ѣI㹳n:M74ΨIӿpB4?uT.hsdڵkSנZ|%ZRUv>ђz#" j!BodFڵe%!NzΜ9!rڵk /^e?I.]|x̙)GEE@;.]4!e'J\\w^^^˗!(_Uor̕+װaʔ)CY?do߾VZ2D#wV@ݹsq8%OzUzRz &S:vލ+ٓt1! uQ+W.kJG?^7tҠ;4i RĉGB73gN `3-a޽{GDDlٲe d %W@eoooO@AOHHњ@\* .kԨѩS'Ops/E.-lŋ*j pBB`YvjkkKTkkeC͚5۶m Ν;`>>>߭[lٲժU#%&&5 ]V]EK2&Xʕ+qΥKX9pI9nAAA\A7>a]QHQGb>.ڞ={͛$)&1AD,^fW~MJ{ sJQ?D`.wܪUZCCCe/֭8@k<,'h=~XέQF@ \tqq!BbEj;(L ڴiCRN:%J8z(lNbC;996˗WI);8i{>DsW\J!p=5kp[hӥKݻ WoAC7t4WO| ?'O=z4 }o۶~7nM0/8DF:˹Aڭx@=:~#!naaFepqڵ@24J_GW o޼E;v !vݛ`ʕ游8!x… =z@޸q`ȑ#)ʕ+gϞRK(eq2YЪUnݺA(A :tGÆ 9BYfڈ+d;T(PBcƌYbŵkdHȲeHvɒ%j o (CTR5ú馛NtKh+Qff͚6mڹs<==ѬGr芎F8Q&z^CLYiu,F^rŋ'83j(3>4Zɓ5S Z e?u˟9s&88xȐ![[\r)ޠ{ԡҥKرnݺVVVظDH@\ 22Rmc9VgApy!ӳgfϞ ₯k>q,s:t?  -`B_nٲ%lՠn:i/K0-O?AUFڿEÇ8`NZHX///___d4h?|||rHooGBhV:dȐk׆9s.\Hq Cu6G4.mݺĉO>=sP삕+W.R~%LE-U+++\~~Ánnn)OF j3C7tI'o2GBfӰ"-,,vH:9+9 -oPH#;*UDF 5C{bf0ZyVf:u ,D@ Pgg]R4k֬C25nذ! on mM9e,?ʹH2?몾 ӧhѢg&/B$00`TxRvvR $p~ZEFF^z'4j(::Zm7 ck5 ?..6 v-[6t9z9TxTTښ0#MPبd4qʕ}@6mڴe8DratnL!]xvH=<< Щvz###ễ  M6 >|8XH7t$.:`Lm1<oSy:::!I@[nÑ#Gڵk#7oncc5|QٳgJ{ŋk֬0"[FX$Sp)StԩS+O F߼y7ɓ'vZD +٠ ؕp 7 uѢE tMi 3 K Bg7طoիWޔڽԾRkW@R S:ިQ#~gϞrJtt,ٿXE~Ν;n8ya ̙3/]t=#1-[jgd&⍔m۶ݻw-Y$""Bf45o3pHll˗/_qY8p]d5>zks i.7覛Nta Z@MOOOoorɐOnAەbDq7oիOP~Ν;&&&k֬!{O>5k<"{ӧO>Qrqeʔ)j'DEV2Wwɪϟ?_NKʕ܅ʙ0Ç֭[C%q˗//\͛ٳg/]TV8::nN7>&TwnibKܹTR^ CPPh,vJ=Q\Ds#uΜ9yҥKC @;QX MMM۸q#YYY͙3g̘1={TבߗH3GSnnn}.\bBC*T֭< T=zȸ  |ٲe[bGqww߿?݆D7׹0;*UruufppAM9+R;"K4EaHk&XK,I[h7m޽{.]Zl?_F@c||<JoU[tPP1pQhQ; 11^^^7olٲ]v #C$J(!A *+n=Z'paaa1lذRJ[n}YXIƏ=z"d4| @V ^p@B,XM8D7odI9|aÆL>޽{/$x|WwRYALLL-BCC>|Hq-[LR7tҠ[V7%+6WWWiE.jjW*y#G4=µiӦuրW\?{, ̣ՠvڀmݺ5""q+\0,YsrrBRWZϊ+vvv珊jҤ %7nܰ۷o'}|TR9..>ԩSxI$$$P4xD&dӧO- )Q"#$ ARIs.]8$cǎ0aZR9.%P@ѣGIC 󓒒-O1֭˴CtM74B\ tqqiРFs '"AGoЍFS"gggGGG//: _zu!iumWմiSQ'@5j5JN$OLLi I yd!l#,,dԯ__Z7y0 9C#p"VZ͚5Ix8Iiw:wL$lkMivr4eUlقOeLq,aѢEaB$ {Ǐ'><+$vu5'Ҕ!4'# @3v8dooonnYpBddg?J#nDTi bCd@*WɔQv>PAd}ʕo߾~u=z4̃)S ޽;o>B2<<<;!4覛Nth= (uquuY&>sL>,x…vgN`oon>|~YْRhP'tDÞ={-Ĵ0 Ç#J(affVdI8֪U+Ho411 ? ǫV 5k& ` @,4ÇUŊ ϻ5j[Wpʪk׮pE#U-eapZj}AAAӦMrK*&gSQaPsSmp h"r/+) #GCŖpF )Ba~SNTӦMyTO' 馓i99!!رc` %ڞ@Fd*-W\ FϟA#:C4u x¹s=>_|9Y!=ʽّS 1<ߟ ɓZse$ŋx`$YZJ3tIn45j]U{vww/[,,g g!Xi F~<@ (waaaHRFfrul٠P0yf<6d$ ۶m[zy#FSm'''Aǎu/_VZSd˖-.,+9vX??? <trIh Y+TiffXbZjUreʋjRyq/ #իW0`@9 =Ov<|‚{ T'~{PR2E7!{P]lP~}  `, "Ovڝ8qnݺʕ+eʔ={6'^ꦛNtk4%gϞ=>,d]TCZprN:^^^mѸDMf ԡDqz]6YA \GN:H2NP ޣgHHȎ;o"=! 'ȑ#&шQW7؃ĐlPaMl",Y_"A\  >}:8ԇTJ}AAA/_$%WTTԅ :uHeϞ7o^XzСrՋ8h(Z/>zhXaBlXK%Ŋ߿…K.M'I#F,Yrҥ1#2))iРA0TT>a?p 'O8p@ͮY&5_D3g\'uM' ʕ 8eG&Ҽ@o߾sN:`) zabC쪙tY1-[ș3'"[YVVVܿ?:em_a2[ZnMԾ}-@ZurƲe˂}֭W.SǭZvfӧOsM6<rڶm+[)Aʗ[l?1Sp;AO: ٸqdQBJʻ(V<@j'3z$JZQ1HaMLLy#Ӧ_ 8::^sE+mO q~z$1ݺuŸq;IM/yGB2lmmQҹsؠ| *1uԩ=z(^8'> ^$hso8&Msqof͛7Eؓ r'/"F!e8I );A2bO܇حY&{znzOn3 @Dx4H4t63-xVJ8Ck#9 (Pvm`@(A=z>}-~=vEM6Fs2s#^inn"d K}/"]]Ի&@oߖQkk7or >~ . /4^ǝ'ňd 6lǎ\ ) BŖ-[ 3%СC lw.`y{{CHm|ϟ?w\vŐn馛NȑTr ,71iZܹBpf>~W1؃vkgx걌o#8p 1uH6#ƍ5jVœ+W( :tзo 899ᮉ'lmmIrqq8 )UV 7 &͛KjyvĈ/#֧OUA+PLK,qtt.x)(W!e\w;vҤIoK˙|Bvy܇0p UÇWVL͜9ˋ_H<KO_N{t[2Cf"K([eF Q (Ђ|)A8q|"sf{{-NWϓ'innyڷo신^]9/ ,8fg[nUK?TGqWXXELLLbb"QϦQQQrH)O:`XT5abcc!!!gΜYz:u5kIn gϞuֽpITwޕud@;n޼y͚5III~~UVsH;!ˈIX``!e%uȺJdϞ=˗/9w\Μ9 KKIlȐ!6l婤$""Bo& ^XTǏMB Sޏ4ɓ'T_L@&OP;w.VQߌY|E#[hHl}ئMŋ;X:uӲeK`?g޻wӧ#q~l<::Z|Zdɮ]VXqUxyy*U*""B6j4y CΨuJ*yizvK`c3g.H.8jBI CO>M 0K.!=V۶mÙ#F ſ4PuG 'f4M4H˗ӂ$i4ެ=Wh~:tZjմiSi@|;)rmv„ ;w.]tjvCիaC !P7`+V Ԓ{;sS*YlPP! bMnܸ1#G4薆޲e 2GF;wnwܙ}21CkРo o߾=Jݽ{7@~)H۞={,--ie mܼK.Dn߾ <㍨]6$$D0ȣGڵkGH7޻wpႬˠx}DxL xiPn cmm ccc?f_ɻ$aHI彤Q{Tf>[n}ʕ%J<}Qݻʕ#kTf___>>{է5A74薆MNhm*UUW4Dz3Z}AرcW^Et9 Ҳ-׮][n;w<|e!eiZ尥-[$`EF8O0&UW=ܞ={EhѢ3gΌԩSP47Pe`HSNΝS)n޼x<5kFm!̬Yi~2AԩSjH (wqAA>}x`:$3>,Sy0000..mĈe˖K12p@ʋk8UHH,$5jԀQ\2`._<G[/_zjk&@okժu%2eʔGCɓ'?$:L:޴rB@ !SC[ DZY)C$D 6jgH@J&tpA7:u@b "Rv<tf ͛7ˤ]hAMn׮݁{[ @]%&&mFd {lٲbrPnW:#>UOJK۪#NO3z`)HK;v/Lg9Yퟨ];F|kpM d09-Z%-EE>Ӗ۷y @O[?0@ (uNNN&LŷիW_t)n1x` (s(ԯ_ҤIr0ҮYR6bԒt/iӦr<þ?sR[9[/^,z)]4p rdW_}==H×_~/5}I e^Yp?JM6sL" kll[PrC_jw("[{J5\GV@͓'Oǫu\=kRy.@ڼgVOK͚5Ϝ9~zQ.|x F'%%A"##Q'yB9T'${Bp#/LDsHHH>}.^355'&&[PBŋCEҩ) *?/Clyg L1L~%;vd_Q#U:p9%;-*;` _%z*0$`Æ [v{I׾}ֿnI_+ML.1A9O&gvww/_Ç[huv<(1bĨQ` j$ g"{H?̲RfK,ALoݺ>|*ׯ|)'oBZnmM A(|ʕz2d"T_H8YתUK.sLrݠA^:7LxUTڰ0I4hR;LLMMY* (DS[j5c nlْO2XSA)yn۶ >xY#O[uV\Cd$៖nMihOeXlllpppVpL2H"AMҬ-[600~@˄ތxXAp%9QNRG ރ ͛7`d6m:/44 ->#""5jdHY!ICrr2۷?ze|Y?aeeUNyxʕ+ bJ_ďG8P 9s GFyKx#C :ď3sp޽NAhb>wpzE9W<~j, .]'͛7DqeʔI5tDV7YʤaÆߣV7>>i@XZZE}~?δAKn۶mŊ%+VSNo׮Z+@՜{4 C8qնyt0yd†|:w6l̙3ADeGjK!CDC1nݺ\SK..DK P9S lM*ƨQddDMAF=42Ԑ8! ݺuF' F&a Y3RyI"ù-ɜ<lݺ{w5]v*UJo`㿀*2>E_Ӏ}ҩ4dFB"z2G*'5%$$cŗ9yRd%_˗/ߣG-Zܽ{wɒ%GM|S#jtY5:u쓨"|.IHR+Νi&Y> )))iٲe-UpMʲe2bZAzBBBJ%|˗MFׯ_AUV㦸 8{$ ~zɒ%5j$((Myݯ]mڴ!D-%=[RмV^.''ϻl۶ żfGGG]dHNNqڬY7n)!"8h]@Bv|! -R qqΝE/Jl( N؀Q]12jE  ojJMH7nj4ioo_ti < -H0|܅w D͏9P+`Nx$ޭQH^@@oѷj#G_~N>9? 슐ihBLH!kf<==O:?wE8Ml޼6}ذa` h,Y!odA4Xb̘1);;`0_\9n˖-ۉD7?]pЭ[$]zuΝe@F޽!ԩSZA<)P=wȑ#kժL}rI%}NvzjMn_;$/6m*S yCxɋ_N#~2.HÿO< -gΜ$Ѿ}ŋc]흼*\!,Y/Y䧟~Zjխ[V<Κ dgʕw  lFMNN??5pu  AAA[lݻiN_~/M]6rȘ9& k׮(\r… A!2ޠvc17o^ttB ?~ ?r,N$QgXSNjj˗ @CnڴITiJJ TDU-Zjbbb^ڮ]pⴴ)iRSN%~ݹSf6/^'4§uA wdT9VVV[ۣ֭G:;I?&yK%K;ĉʼ$eAC_~Tʕ+-}_-˕+- .]ڥKzub={|rf6msHC\\\ƍa<5 ) &!"@ C9J%Hӊ7P0FiJwIp:o޼h(MI bkذ!%gs')gBxeG{^s7))ٰaC88`B G%f`\H5“=[rr2[ )iϜ9C*Aޗ_~I|Aao^@L%PK ;䊄Q1hH˵^-:i%,`mmmŤ{oġiRzYjSN-[ o AM]ˋ ?y䠠 uR-3cP@%5 cB4j'0NHH8ve 2CTxپ}{\JXxuMpՕ˗/Ksr.6H"&&~Б8-‚^XwLN@e˖`jOdk..+b2.Y$SNstSʕ{ h`cf͚T?5,SL9hPiӦ<- ; u"t'jJ:ԖQ]f͚UXQ"z:l"""L!Ԫؓ'O[7*4GIZ[.3f u _o !:#Fh7g颏4Zz/^wu`W-gدX϶(^z0sq|Q#ڵ `L"E7oޣGe˖osaccYf\RJXtwwy+W[nݼys„ Ǐ۵k NLI!ٓ "aM!=jA069 ;_Kp3WK)]Z8t;wnX!ݎ8jaaaP 2~xNy*[ݻw{ h O . ;rͣSLQ[^z0,4=M7 _tNN (C:biiInݺc /'oR ƍQ:"iA)TB@ēe߿o%|XKV*"z# .uPdX֨t055Eʮ?P[𭬬P]vj\p%KbbbdZ7CI˗oƌOV{3G)_|>}J,tҽ{}Ef͚ R}vrr25&8F'Ow%ii$ !I, "##Ӝ&Snnn3McQYгgDdxJk˾ Z P"ϟW^䈤$$X"U_Xa(ѣ׮]K~ DK`94!!ښ̬[NM# bM0ID]H N͠Al˖-X πiv |aÆU\9hDF1z5onn_z5z~3 ׯߜ9sVI~cչ* f}߾}۴iStil]6?ZXXpz1}t΋'L"ǏOEYZZE/4[pW颋.3Q-N:}|?W"ZRHV#F̛7rέ ̨!78CRdj;N3 w 6B!{ g :rGUP|/GCE|4hMȶmvM^iGS\[n|ܯڡ\_`LÇXujA4B"sjɓٳg5ѣ\V\IHȮ]BT!CTaiu(P`V&uwwIÿTCe@r|6ѠO?De/s A3mP}+5k"##Aj$mCkBM: }Ŋi|<|@LNn޼9qƷ~{EzxM_ .%JVZqF9JULNN[. @}p7""e߾}4(OD+s/J 7otuu}ɝ;w(K&M*73&&Jy# G2A* m%(rI`i$#~HQF21qP~'Nq|}}`t /F#.?gΜallǏ gϞÏ=zӦMTE޼y)kHުXrMF@}F#S>6>pdt.jٲ% uDCiiOBOL^@Z?*Ev4?[!;*T"CMHWmllN0˜=d+\|^ZFu?NI'ЅTդId+G_ƴiӦN*Jipܼy,,~y~ij233/BgѣC8_#S0Yf.4̙3jDo𺼟DIEuGt]UȗSxǏ_|[hO/L7-cnnn,À ʔɎwecBJVI7<<\MdbFݻw/_8TecW N_qy/X`BBÇ+QlٻwbMNN0aV5NLL,Yd\K7Hȑ#_V|EFFJrܡoGIرcuAwK.Q"4~5W.\!3Zgd/gΜE={,SF-.ݻ2!8QQQA֭["|vGt T|̟??|NE QF}q9f\FRk8y5%Ar UGud`\cQF'N$f"$$vڼ`@.۵k75Ml.MacDo-_ j1%%iӦTyl>P ={֨Q~xD%>Ql] b 4id(f$jX|Xrrv=rniu*U1ccǎ T>~#,i Ma]4m'OZjmݺ"+W`j TW^mӦQܼy3࠶g|}}/_naa!+6ᔰ5m nݺ oЮ GP!EihDξQ gggBB|T_tq'..ZkDFFvIҺ dh)h9UtRb}5Tڵkɓ'FdoT钩HuuT]ty50kժ >EAo-VC& WO̙Cp֬YM(h4L"s Z9/qlll,lٲaiv͜9!\ :3"KP9&LPBlٲ:oiM41Bg@<8 )~x!.JyM2jquum*a j%dW_w%*K◿Pavvv{!K)IH"+<ףk܇H-^XiȄUB]/: L2׮]=~ӹslׅEgϞi},3Pa&:$bU.]ZVcC j#kF9`BU`􃈲o2vyZҰw^ttӦM...? ԩS(C'N྘)))@~Bē }/P֯__6j 133rd 9vؑWo+wU+T$9s̓'OdD O.W`,B_xANT%(5Et]O6hЀR ܺu+55UN:rnpٺ2rHqkL:wMɿT [f פIpΝ;я>>>X~-w-[vwKV++A(QbݺuN ܘ૜άP+"Rr΍} gy5Q  {?%-`^&"Ξ={ ͱ <.[,Ly$Kۊ/M -toooo KZ‚>{t- tPK֭[H;˗NͩCb.TPZV?v%.9H@U]tyC6WgQcz Gqs&ݸqcsImVfՂGÇ2FQ,YҢE " 3[l]t0aZvÆ sssMLL˦M[%śeG" osqqa痿UT>}U355Vi;yb2sƍݻGEEݼyS3;;\rϧORק\Z\SNyzzRX b0۟8q2.]ÇN`2F$8<gÆ <8p M# y4GҬE' 2ʱsABݶm[ۀ#GIw޹sgbb>H(Vy_ 73388ex J1vnݪeFlٲ8by/^ǰJK(KPlmmϜ9CafL HC5kB TAbccׯKpA9::k4'D;wn8b 2@~QF:"ժU JL2_~?~ܻwoP9&Wpbƻwi׮m% 4 4I@666>@$@Ea?~/YTPԒd2Ԯ]_9J}!dJ*aT͝;W 3 ,gOb...CQN:ΐE-Z;v,~;[&A "v95I)Ν;WNZ\sȁ5}-Z@:u, swwWjȦ_"GqD 響SB\HZMfdpp޽{GmeevGdW7 k$/_gϞƍ US)~bd@r6a*ev횬<}tFifQh߾=/Zy`]2,YA]*RoL;D+6m7cTv;%$"榠m$jOrR͛wܸqcƌQWvȑ#'NvVZu׮]r8޽;4$$FTaBkbbߒ ]20lPU k2w%Ci> 0ebӧLtɹᣕ<Кo&88X6x4[V,"^$ZL{TD!u$01?uݺugϞ=}4 `$ŧΝ;Ga:t8vS⧁e}eBB'Kիٳ۷o \pN"6{$kNu4{%ÇeOȐYTTy055@x 3R\./\0"vСCE׮]K'HǏ===ׯ_ŰR4.l FH=Z%S v̙W޻w}znܸPSڡckůPjժ9;;UV; 7g0i2 o0k}&6Ա}WXѿA۷o@@,X`0nO>@5bٔ>, fc HB۝*WS+ ~Ӱ 5ܠA[|2}WWӧdEɳzjYg 0)͛6l(!r8K!DK<0Y9gN ^HCfo:kA*+]?~<_o\{0hsrrV{d^\ 2&NcbbF/-cǎ%o8T/ .LZpTUdd$H%K$-lfffooؤIysS1|RtE' dQй 4T0Ti˖-===ɕ+WID}l_~”wwwoݺ+WV^ J}C4BSb+lذaxikkϣ1c CI^?w˙3gd߿?O fcGGG _zɉWPkCBB7n ?^ejxh&[n)V!|XrG-JAȒnQlٜ9sFEE~#2SHڅB x F0'%ZjQpK֯_obbB C]tIvgF*G;g͚([>q*Yu֭üIqjQٓu2QB3gR 庼rN-(P@O`gA0z /:6Ei5jr(a0eK%ϟ/RoQ"3QKL;hРaÆPx@-UTJrM6lأGy0&L~%KÇVZyyyADK$ӦM("1ވuEiT+4A+[f;}dECՎիWD-ZQ+v?6ҔKl&OlٲjiP cXʕ#FZ {LiĖ-[5oܸA$7o-. $V]]]'(cֱcǔ]΅쀶JܺuK7EFF4.5/^,ޓdɒqqqoVdv+σHbŊ$Jh}I^ttt$$4 DKҔtpDEE*hcbb .S K.sT<5[Dڵ1"ٳd9PYXYc^R,_|^;vjǼE\A_M`80w#G?S9ɕ+lNQЂ#)#G%''ýr:)S&::Zƍ!}SSS LFW\ZjA8TK- 2:䓧\jDHr"UE]>0Gu֙R1CeYz^?~̘1VVV܀:ر7aÆM6MyxHΜ9gΜ˗"{ .hnnnqlb"VU@uǎUЗ&O,,+i}5~֬Y%СC ":ڼye˖eϞ]!$[}OVa$r*̦3#+ݘ!Eߘ0ao޼YJϠAZhu6mE[/ˋV:w\ tM.|*6?I? dҥvvv2ѣG̰vA 'f oh֭K%"~鱷/S v?5ٮ];Xp#9.:4-TH&Wix饛t'(04Up$_ݶm[4:u34H]#PrQ`Aĉk@q.<{XbV.B;v(8T^]W#D 666Ee5HSLpvFÞP6׍5B_xqΨڥ y>ƾPpA1[{hzpڵŋ1118SRR d W^rr͛7Ç$,,LN$5DEE!:v숁.deRR588XvhKj<Ԯ][|*jݻw1gJݻw?xӧOU zڿ:rHh% =zH6X hѢ>رcW^~bb"UTD BOggÇXXXPE *ٳ&Ed(Up-[,I,;w֯_?|٧NpBu|_z}.hT2v"Ex{{_0tI'u}T˗ H'KJ*Ut%K8::b/ւ@۵k'GN#ഋAH`Ν;uԑJGm۶N%g^08*HH.H݂}>}4"}͛Gϟ'Bҕ|6o\F3~CB0]>tDDf%hM:d=Ja'6l'''҅j4nXBՉ ]tE' ʔ)SdI4 PĘƆ߿޽{?%U;0?x_| YjAP1C#> 1ة 9?NXdg r׫V[\/B 6mI%Ku \ߤI˅ nztfjj݆C3f̨Y&4ELٳ@lb/^*/>biz d\2*OC ׵E YIWp?))ݻ\¹s \ &3g[nܜhAHHO]jD]t:qԨQ?0T' "/+c֬Y?~sܹsw֭sΧNUi[4@9qs:4cy۟={ LKB#F ~Si{iٲWVMs^c\vE`؈RfY_]v2}3_O>ꫯ|||ȏ ?QJIȑ#NNNP>66bŊPL"9x ֖ؠŲ`111p L$b"̖-4~oࣨ[a60l(Ç!"Wdu.D_caÆ +mʕ-Z3DsҤyGu^j~T,׍7/^̯v_{¡T;6:h F9s3gPjx67ݏ;6iMc[[[lz4OMx񢳳3 :&ZSSS6<<\{1l鹩L@Մ VX!Q0]tH4)RPٳsMDI= .\XVkccCkժxCAϜ9Ŋ̛7/o]X؊((z 5_lYf>}ƍe']U3"7)#W^ Eꈊ:'Rl5knݺA4+A|A_rF['>pʕ+C2dȎ;*U;wngx߾}P5% ֭[?KY;w677W'ܑ߽{VRs_^!HlFC=N>MZN޳gOHII9wfBBHe˖`?/Z(TѣաC7l߾dkI.# NzX|CCC\,-(ح[7t#eSBЧO(t;E,:tݻ]֭['4}>|hVZNNNrDD5(QQQ͛7w 5XΌ?&[@Ȓ%KIb0Qn޼9~x???uɓ-[~tvvv\W%*ٿtRfѓᥫJ9(vr(kN:;vr({U=(8 0 ']tI,H9oȑ#_XcƌEJ.]tݻwcա^|i?i ZG۷/?\tI1 (28]nSNI [[۳gΝt ~ yt7n|GQ׮][P32 !2ʕ+%7|+$M:11vVVV@zc Y۴i8-}x F<܄r8ˑl@_:vH&&&0Qlja\=h'$`< %ԨQ#((WO |"<<`ĩxRt݉>= .P;! n42Z+ PΜ9 ={Ę… ѣ5#On۶Yn5Fǚm٢;ܹCjkb+!);)غu+ƽL^ѳf͒CdJÇ˖-kҤt -dr ~NN+Fo';::By>C!,׹I ٲe-eɒ^E]ppp&tEi%Qh@4A4`whHiرK,$^ /C*h1gqo33*@˗Y#""xTti.x$lvځ(,YիRUT㠄u"X8Ӯ/Vb{ x|2!@^ijyfL p_~,%BOf etss-,, G &4k2{ҢE rE#cPjVW{xջDoGY-\088< ZwAou 1۴i# fϞzjx@~@ƍCMLL;v (k׮9s$0;u}؆v͛uV H///Rt Dkժ-RCKKKHL@(v-`Ȑ!vw&Mڴi)RRzuI  YfVC'9utqqRÍ(lLL ܄|(袓]f9r@E4{]t+S cLc63 b78qbժU җ&C!!!s>J,+llliSSSDTZŊϞ=+0%%-[,wd R2ٝ;wbcc1O>-Q}"ſ+lzY3|א^dܸq{m58T+pEա>5eE~PPx o5dC铭Z:rܹs'LN:ɕ+'H]>iCWnerY?` 3ʂ֭[;1_Ijʔ)|́Ч6'-5 [AAG˗"rPdXXX SťK4iFh8lt(ug;;ŋm)pbvvv>k|Cy 9r 0al$`3vttΝskեU͚5e1Ł_r.'iA2dm.\ }A[[`"|6n844T<;X袋Nt!QӦMΝcI;2j6o֬ق ~Çjr6<1:`Ȗ-[.]<<<@9sRѣG[n摑j*_ÇCBBāt\\gC||<@εq~zjU(͊k.wwYJ.]ZT),{R=+W$ʕ+j{˪FAd! -[Rh%8r=zWvmq'ȆUR`)V!oLL, 6))H".|jOO|h?Ν7o^rr1؆$]jsihK/?7D===AŋˉS5jzΛ7Lv.7orʠAXO:ý\]]Xi8 }S\z.\2*cuE'O I۷ݻwe0*TL Xe)+:4::jX+{ 4oԖ-[r---/ |JJSpp0B CnݺUhQCׯIE}Е{oLMM x5rr3iӦ۷o w!-#'N6o<|pBƓ!eSlh@=GzÆ ΝqF7Oȑm֮]ۮ];:' #w܊A8@k>hmA*=fPPrWNIII0{{{bŊO}PA뵇G bbbFr.\={6u-$115jw^p:|00/Vcx%Kj/O<*}Q4]p+؆&﹠+PZ/<ꫯ?#qqqrb0BB+RKZ"LFBBBWλ\DGG͛Rvvv.'x޽PBPOFbł(ꡋ.:iDI6k֬\(Ǻub/^ܠfΙ3lGtqqA P^l>ܼ{zڴi VيΗ/HÆ d-ZϡV={bL {xx 5)@, 8ƍ+GǚT~ h߾=ּ, %%;v,E;Ő- 0@P9 ̛7O^ZCaM4!ȍpDa2" )O ]q۶T\;w4hЀׯ_1CURzt̙ejtE' zQ mvlQQQzgggT'tGEѰ"5U;/"nӦ? 0L{e*$ڵkG8q"՘\X}{" 0?{/B`k1bD>}l#wa0GիBh8vPN:C!2>!K7xJɶQa0jemm+W.Nh]ףORdd$,aǎDEnwmii)`8..N-/q0ZRm+W[N?MDDIDruto֬… c*@=@r}%T|y?q^NP*1*(ѦM%VF]t׋5֭bժU2i]UVh@lgѦT?~lZ3 ,J|ҤISL|Tʪ:7m5B:q՘T`,,iP*VFSNXd *a ?___~VʤUFFQ B^҈>|رcUO!uZb pRJcUB.]Zʲ}v"711!ɤ|xʕ<-X ߈##üN.K;ggg3Z.Hÿ ̔Iunb/Yv58h tuNsThpuv6&Z.]߱cfJ&Lfjn(o6dȐgbcsA( /i/P3vvv.]"+WLMM/_^HӧRNc`C K.͔СCe "lQ$1rH5#FȀV`7o!C4hEnxfݦm۶֙3g*VW@G.HZbEVɓgժU9r֭[!U}0hĉ N>.H_iٴV}iɓ_UYbߛҥKcimРnݺϟјouQŖJVڣG"Шqzo~?qڵk={OMMŶ;w`W8vMw[n$66Șa߿֩S]u;wpӧ A<;S|ΝSt颭Z:p4ܹsTe˖|R"## /g: /^ đ7Hlٲ{aJ...(\0UAfAT=J]2ذTtATRh'˵rBigՅ`T5=Aee&7 t5`0QN&"[X`^^^7F}ϟ?ڳ?鄛SLAeo۶MΐGD7$aaaݺu>1[|jFi0f\uj+դIҝxtW8ʹd]vE*T޽Autуuի;t@2?ݒ҅`ק*n! ~ٹXbp.LLL(8LrP"/\RQ^SP%sss1G;Ҡ@EЫWݻw޽{4XkAJ|y7dv(VҞ*  100ʕ0`U\w@KCŊ]b)K|}^D *;>""`u%%%?@Fܹu떌XŵmҥK)RӦM<ׯ2 D>!LC֭ ?rΝ֭[KR1˗… rıc߿b٢I;w\wQΡkרx RvmHըQdj>}o߮=[]tH̙pB5jS02-f)`aa J*hѢٲeC-[,oɖl钽9rxL6lݍ/Ci*U H(e:1ƨv2j}ٲehp }P!ą ?oذ_~D0'h֬Yxx8D2@g;a\TVOёD`=*\Z66CGfJgC^;%EYo+`y` 䇎5k܇C %i \mmmJ|2(BW 2ï|Vjc-q&ؒܡ.dyn*^ٳg/_ PF Vyxx\r֬Y8N:7ibPd [0L6"`?~<1bЩS'trէ/tTbgg{ "~ȭ&j-&Mt3feYHt!c ~ ePPݛ;qƲټysVhɓ|ut "M yd>OiF$**JLP)P{ZsΑIH?Eor+WTXQE%كQXD_P%7LgI]t㴮D@ AC ٳoEaР5x^>sq˯]E733[bM0#_~Q|$QE CƍC#aTOgI髮VZQF֌LB>n֭w1qD!yYYFyORJjСZG^ 9s$`:tж&iBek ̙36m]`qzj:*0w ۷o~E &$||>}6ʢEH*"&Mtܙt1'm޼֭[e.蒑Mx?~κ>*=Qۺuk~5j@W6lذwXزOV>PCsqqT*XŦQ(PTBe{)r-0Ly"D  Yœ2d"ѣGK,yE?r~m@b܌EHgdNzyy.]z۶md@N]3iq_590`m-n:F/]DȤ;={^J/m3rm@T Yf"I%z5X8/IZjǏ~>|ٲe _Gdkk$~Jg[@ ^z-d|nNHX ͛txIp0˗/ [*P3g(<}]v(44qFxuEdL(Peak~5e8{ `G666d7Bʛ7,6GP.x˗/ 7vعsN<i26$nڴicƌ>|'TPCɌ^.n@Ъ0=zHe&{nȍԧv=1> #T3zÆ QQQXPÇӋhz)SW :y&Mx+WB1/\ L^gϞ={Θ1C@EPsL %˗/yh޼y j۷O'ԩS7o?pE |2%@Ŕ>ȇש]6 Q0$d&E -q.B * >a-TЎ;MNNufW%QI2d \x)ٍbjuCJ]QX"I;sss_nfc2DAEEroѢk֬Fa+++B4G41䕇P,X3i$9rS]6,o:6/G88BIϩQw~hGv 5hhĉr܉vcǎH5k˺ \:d7N-s/le(Bd(E9s&۷޽2?~q!^zqӓ >dH%}L]2ؘZUpȑ|W\A?Wh@OanӦMKH׫W傊ܹ#ɨ,j2#""\]]O>=FuF(:wԪU+0f׮]k֬Q΂BK]4o޼9;DܱtGEg+w|86((`! ?55U-&6fxtE[E˪yҥKͣoHƃrqpxChh(Ef||<>x-<$όW[7~ H7q u9|%.,&Ѿ}c;uD-=zAA_|.p׷kMj.Ԯ];͈Ÿ& (A`gs'; $ (5< zj̬_~d0PYب"*o]C:]VZ5@Μ>>/$L?߾}utt֬Yb!Li.F6`܋"76L*ʕc6a"lݺU ڼypW PrkMHU ,]TVV0HQNPc4mڴ_~0 ,˗/߿cPj]ꢋ.o2C&LLL 2CBB ҭ[-ZXo^Ȑ ؾROM%T#}Ȍ2cuԡXQ(e2o```Jj֬ (_sU#.Dz _$R: Kܹ~JLL|w;Gty'+Hի .\hܸa۶me ƍ;v(4bŊmVKl`3wd'NdϞ]ޒe Ħ߻wo˖-ӏ>I؉/Bym>^{d^„A#G=z( @#|;'Olذ~(n!䄋+WB|333ؐۢE0I3P6mħ>H.o/bzE0gTDE7/>}`UdkѕhVZqD~yԺukl5jϠA2ovZg;5̠*b*9/_`rz[$~ |'( 8{lR.(_=uAF9/^f X?~Æ ܑτVvjVnqaY$Oݨ(*|5"%Ǒp;3ֹ٥K:r}P(^v8M$jiAbTe75_(իWvѣh >[(oPP/ʊB߾})lܹX[[CS0xm'+HtbA>.i(Vta.]zĉsݲe 6wرm6.0&_s]va֠nq^xQ+ 9!c-H> Ι3'JJۣݻ G~:طoxK?VP+T_~iiid#]f7"i, h i̵j:~8GKte$dv\jUlB{9ԄG6qٳ+Ο?_n]DBWu!20`F/a t3mۗؐ<֭(;kQޣES|#J@_ _&?*t9rdTTZ`/$UZUj0fwށRt6H \:Kl8MVhOK^z2s !͛7Ξ;w._mNQiUbHG[[[>dOOO6/]5Uu4iТCq/ VpRC Bo: ߔY e0^L0fHIIr 4HU-ZWLܬyƍ*Txb Adzg@n`3gS{Ɖ)~9Ԥ0_M֭AV ZsNNiѢVhGiR[ر#**jĉ+V`CGPXcQ(y.]]]4ivJ:򫯾JLL,R&˭qmmmqa>>>˗oР " ._ 8?U,*wG}tرO휎ࠢ U]v?x̣B$J{.%(( GQF޿_"B iӦtUF>|F=H͚57oNoH?iP%} 0mJ:cO1sLL liM=z~j§ӧ{p֏9ҷo_|/I׿ёA S  jJ $'O<~x333Ȩ@Ы{O8Ca *%ك֭[WRjf$?-B3/25Aj۽{7 Cn:22,Y266YfPCA╖-[*U T NruurRFk-ŏ4@_L^[oaSV\٥K<`;8/3s| V?g=  V=@`XX߼ysvB?>"8pF+V{{{ oݺgϞ|=lC,wذaJ=|HH$q5qq6mڨ18͚5k $*ʍ@~ fx> 4jԈC(m~MYb˗/oߞ_ ;E1TjՌhѢ_ZAA H۶m-,,F~p=>[yb2Q0GڡC?/ m--Rՠl2#N.OCTC߿pp0{a .Zv5k'(VLx/D]hҢ5)2|ƭZ0`@˖- R(><믿;v, ƪWWq$ * ydm·~[F 6p|}}E4ir !\%Ks…_ ϗQH͛LYX!7nbŊ>LB;v駟JVXQlȐ!UBSLi*.Ν;WHa.qFY2~Çgϖ|$^/_N ]tϿK*tppXxՙ3g6lڴIZe+h= g*D& 8Cqqqxkz+O[d:{Ma"4cΜ9I=O>mѢBaaccitTy^zQ3~8ʅdC{0Zj0N4i۶m7E-ŀ4(`{ (<~S#cǎmٲ/tA=sL67ΦX-^v>:xdPGq%´FŖj,1LY@Ν###U6 ġCyIu rs|||$ G *7,,:a3ssssI h P &3ؠ$߿2akk y1ZU$\֭.]45`*Qrrɓ' ܈ТHvӉ :R ?W ƌSL<2 S9r (EE wDeJ`@@ 6d777oٲt@/$ץnLGJ*w=`@8$}TAAAK.Bihe޽`ٳ-,,-68Z~}˕+'={fY"VիiѢ|#GBnJ,9č@Yχ@G{#Z'*Q?LcLrJL֭[}vL=dZ?bqu:tŅ <^9رZ0Z^7J * H۷-ϟGڷo_(mꫯ@k'''&TC [nԨQP/^!W vYȏ?ȽȄ0"cp:7Sa{Q`I& js̤{qVZQzꐡK.W-Z8A/ XXEᐍ3f,[ :d ᧟g" ٭[GC#0Uɓ'ooo/I޽{WWW *RϜ9So86n(x&d"**W^Z8wU{+W$2Dh ҥS~Um۶FtIHv̨688ƶm٬Y3aeʔ-ZPm͚5EwiE{&g`_&oT2vغub2DjҵkWx Ȅ>PĉYYYX\Gq%գGe)dz뭷8YJn߾y5߅_ TƊDy@5$ " PR[ݧf9:2j4EFFrzffo e Jiۇ Fs)Yi N> RԮ]{Ϟ=“4wQYT8[P(J'eEs +NPD `…+VC^?L"{a5-bL`#ۿ\j|hޠM6@OIII,BzuIOO߹sy<%Y1(1%2K+Vu5k bkk5ݻwB)I hI];6`OK௒"0062S'taܸq$36RSS4ib(X!vppݻ<Zxy lZ螆Ԟe~z333ZNNNFp 1mlU%m +zjܦ_TGqa ťSjCBBBW^r億냋8߼\+++]= \\\$O4A\\p\s *e{TaN'G{tmc*|׮]ϝ;Wh3G 7,+8 7B€:`6-oذ!$Pgԩ~~~BI΅ Θ˻A28_ :4,,,??foߞf5? ʼn<걶9,Z>ԊEi(6FUj̮w:u>쳚5kNu޽ .l۶g}}vhv/[ LƄ+3g,](M q & H H>|* mY &eb1#AvI 2OB(tBP3+Sg(i( #;u:tPf4r";e,ReeAWWWkʔ)|#:udU^RJu…6mMlٲI&H*UD^$KV$-Z4i(6 j# ۇUT)# U1|pϟ?ߨQƍ*^}FFFvvv.]][ãiӦW^MRTPR7 ,H4,="$u'y֭FRoC| ekkĂ90'{{{vڵkuݰam㾠 |tZshe'^i%@ʔ)633/vMM Slݺu2)P?ɩY5،]v˗/*Wlgg e;>>~̙,Ԅzvܙf dWX?`\K.,oܸ1` + 3"oȿ}~9%?7o|#""(&i5N:%+#h漼<4*))6Ct PmV2dBx 4x76ngECM>ѣ˗/W1/עEi0]QH\d~yzz'#F` S .bToƹ@tЧ"2d8l0oFI=H $N{w~޻ p,TTN@zĉnnnJ=Ş={P dʚIջvBU&w'm 5@\]] iƎ5P3?077MXӰ6oذ!DVdKӢELֵkW\.,vɒ%͚5[jբE#e{.ԏ/5k_b^RLSB 0ִiStرΝ; !I.,>VU ax;wVV*`9>q+ر, Ϸ8s >}J=0M6HX*Ug֢E& ـ"QZ5U&LYTYJ:uH*P0aחmu@ʰиqLVLO֭^$Tz_NKx 6Hr/.$7W iѢ{k^O?q>JPH.<01E6>><>RIÇG%9s#.s\ɓ':u={'ѩS'GjjjrDlszJJ wmeeu@ڶm ̚5K@Fڵ! zi-@w12 ˌts]9]۵k'k/k׮, FvvvޞK,\zu ~KKKxFFIhMi/]Çׯ_߷o3<޽;p_פ-q=zY`AJJ$^۷۷o.<鼯zj [<33o߾QQQBOɓ''&&rH .K%(%ٳg7mt=@aLvv6uV:u*Wl ?'MKe1w>|ހ*ʕXd///Z+tL vb?._mtt4pۡC 黂5 |-ziƍ`{.o7` zpyѸ v CP@q%MR䒳hoݻw/==>rVVVnnn)Y$ڵk'OVFiiinÇ}m۶QF0!F9/KX艽ZE^hѬYoߎ0ذaC!q԰K.ݸq#Zژ_ё|jn=BTY k"x#oѣGR, !LkgϞ=zh߾}ءz견Qz ȡrjǏ7ߴiӦPvҸnݺ &$G2h%K\\\$ՅYYY;wA]rUU~~~fN9v옓`_\ .@*V(F +Tp̙֭[S Dw$..$^ ԲeK>(N1'-Z4i0A'}ob<~;wFoKGkٳĬUVZ&QH5ҤEML4G獍 Ċa֮]+Ktr sӆ ?%.2`|>ׯ+'! x` :u*3;;f͚~0}tZ A%xb0 C^=={iRׯ_59<+Ȅ7 F2ю;RSS{-8cii >t 3e[BLv҅~{eT!_ٜ9s*UTbHj߾Lky(hkl=}T4m,QNpɒ%ey.>۶m.K|vکJ8dSkf&#jdw] .d9{lefhfzz:ڷo_c#-Pfc޽χ7MPL[n>ӦMd/kA%ҥKd"IXFIޥ}Tŝ¶k׮ ]p6MZh`AYDŽ5 7x 7T8Fؾٷo_2ox-37`ӧO7CL0wfW*T@DDDHtHN+) QQYBPGӠSp+>cݓѽzZ`U)poO?ZXu ׯ_7i$ ;1Bo߾M3z왜|MJZ[[ puu n2iԨQZZP335j mh/O?ne%6?LfGD#Gnذ!:گ&k؆SoxXJÇoyyy`'+SK, $TF\zRSS.\\[jմiS؆qdF*UZh'P!11VLM4 Ԯ] A$%PC~~~ pNNF oӬY3soܸ]fĉ9B3f@8;###4^OhѢ{L1-y{{SBH DZUְaÌ}"@2T氰08|R$ȱH*KCh;>}nnsd5uʕwC%-[sdKz ҥKGթS'Q˗/8p 8 z&s7|ӽ{wY~˓~ӧOq_M+!ݻwN: yk׮`$ ghEi0P # U^֭[? (L֭[q2G.sNS;% B7rI&⻻Jn'( ԬYʕ+PGO?aHX$c:{ΝC_rriCRR҉'6nx}Ze٪Cfbxz$Lڼy3ٳ ̞={׮] f m*LNNBwQjUcǎqלQ?QXzhѢ{LTt;,\:|& }ҥ Z":uJr]o^3|7 KYdA-wϞ=mLMxxرcfp8IlGⲣx8:tPZoccciijNNҥKWZ)D jRBiӦKJ*UshܹSRҀAһ&ZtIJ K Ç\788բ%׾}{ծ]{񹹹e˖ӀUGWRRR#GH4k-Zh`)//_>j(YV~}l=zhȑ/( ?ĔshDьSr!`6mԴi?p`^СCeƔ㉉UTy}75.\֭q?xoʂ ڔSyIT cMQ'Z"DɯzȐ!mڴQ$7o<}tU42!Sdr Q\<__)SH|*7| p_ sΔa9p;&jՊ#yXXX>}-;::BZhq PmIMLNؼ%htRRRtt4IO<,ZgciLg}pBRԚߕ7(rX5k 0@"稸9}4fj _^իW]\\G7Ν;;v(!Ah{NݻwI-xI*d6 +WJُsm `]\S j cU& =h ???@u5kLZCW+@ǷmVz&:tpΝ(6A 76<ϟy-4*Uj[nȐA I'ѠA9YD._8ZËj_|X`PBZli ~l{ &+ 7X u.] 4mT!Bp]zyy)Z Y@7iDZơ@tQcϛ7ﭷ!nݺB593fL2ez*ed~%UZ@DUɝ;wYB8t~Di${}٪UR9P[A`9'Nsp/'Ox"YXXp][.;cƌÇ[[[X <x-4#-Zy8%&?_>9ÖY%ۇW/Qz F .Q G-6Vjwd >C9iҤ}!@tɒ%hFyΝ+ րA'|xԳbŊ%0HA ,--/ Epߍ7Jkvuɍ5Zl0={Ed2 fPZcǎرjZbׂP-Oo_-+\UܦLe;w_#$DŽYW}IIIQ+hw$h"""^ x Pl]ټt tD P$_|#Z7R8x!!!j8zҥ'OHX_x1Zeqm۶sqlѩSӧO1s `? mmm%2U-P`9 =W\QzQ SLZOA(?G'sm繺ρWNSN755uoذ!5p9L^Ek=E,.))Iw_`>.]+kދǏcy|כw}~իW%Y6pȑƍˋ8s bŊ1HL ߻w&!!Իӧ q" 0a²eBj*YUwjزe ;+Uą؆4ohhD;x`=D/\@K,yu{{{oooϹ=ݻ)_t7j>ѴiS, /-Z4i(T[n ;884/g 2w޵k׾ZRy5<ϣ q~'oM}? B pF'OHhSBKo( )OSTd|3g LLpo@_~9o<.6 FGFF[0d7oބSMp>-!"`3 Zb\B-Zvڭ[7rK.կ_?!!`>-Z4iJ[x1S\(L)S$3P){mV:}*u2RtoP\Jj>:uRNf))=/_rJ^~G"*%%eمVf>^O?rAu;vlJA}C\ +*r v5uT؃%[͛۴iCLXm1nfSβ3A<@7npwwZzN-4?tZIxG1d۶m[2<~Y7qUG+M֬Y8k|ܟ DMظq#V^e\(f͚K&N71޽;֭[z:qa_߻wo[ 0`0^I!l\vmȑ ,P%U{֬YSjՎ;ޯ˗O9E_}СC 4%۷92wq+B)6OLC8;tAkp-PrjԨQrK.uhѢI_(͘1N:2GU{޾};6'7'OXfH# /ESאy$7%"CCC9Hٳg;5eIJ~zXqH1ڼyiӤrƜe˖#G֢wMLL0aҞ?,)cL pssU*,,F6jH8nj}ŋ7nx(^ҥ!O4577k׎֪U+00syDֺA(z讘t5iap1W%&0Ge[c#Ҋx╢6J/|2'q%} Y\\ܻ_LW_}%W!{ HHH0;w M 0˗;w.##C%i%xyyݳ)))ԓogg .-pS^MIԫW| QIIIh\ݸ_!|wxTko<DzĠAN!ae8 '''^W߫W/QJ޾TR))'`*tppXPf oUjոիSN:(GGP{p1gXSN{uf2-<<|ԨQXՈESKV^xQ(.` 6!MJ$45w+/BB)SӀ!- xkcǎW ޼y<7nBYrF$>ջu$J%ycǎI3}q6(Ƃ fIgn޼E;wV߰eAFF`-YkxG>~ .,S {:u$)4<n9//˼Vx Tnݺ#[MLm~/oe+֣JW_}8u"i2}9s+?x"+%..n޽䲐HO= F^{XX䞐=Ge7/-JBjH'O.]$F"K(׭[7j(:!=z~>H_[RȞ;w@sG UR@A(tQÁ(:H{d"55 6mC"Ӣ=>}Z\Q՟Ϝ9ѣw} 7ǏWRvڲBtN>-!))IͅTڵswwG jBWJMj :!yA 2sNʕ+3f̀~ l%-Z^^^)8886ǒ >6nܸQzRJQVZT0dNhZ螆?(\lݻ+WN0UI_ApKj4j^$ϰwQP!~L1 FY* "@7U_pSNRW[Ҥ߿ !f׭[׻woj 8pɶ=z&ԩ2eʨSYfÔG}'ח۷ֶDݻCj 7n\p!T;֭/]TjUhK\\\ P´4 ؓf Zh`ZF;vJEI_Xr%/*Eœ$ӟCxz_:>.]HT%MQll$S_7l؀T\q%3gAr_)UZbȐ!rV_B-,, K%ESN˖-8Я_?l/_,( TX^=CA:+z 1dhڴiY733I\ܹsM4s!h7OU?NJ/puVL+vUj0,_t+_`ʱсYJSdR{5jx|M+׮]3Nh&7{m;$$e߻wO֭.o!11q'NP 59g}aaa b#G]ͣ?\A=wrגpO=j*v...,Ilmm!*UI2bggljULJJioooYF؃YfMtZj7nܠ<08Zh' x6 ,Fa1_qxؐݺukҥnYi9/6%F~CQYgΜ {q#S{w \8 G~Emy`+W{:::Ċ̩v7q@-T%"U'VXQRIބH `zĴiΜ9E<4hlFգG,C?~<_ģG;wEGG/[l>wwjvù߽{:ܸqc ѣ;hx :t"И,>&oرc%VŊ9|0]V-L|0n* qٳgW^dᥐJ]t5&u2@VL\p ~1%?}\DN`Y /{%K: ɴ֮]駟J{?~\,د_? d---9fMIV-ncǎ0 \2ed񑝝MLLLJJJa$˗E`*oZvm /lJ(Au^tIY$<|~' (.J.o긧84RdIzYXXš-$>7nt5$$D7C_}QXfE3ϗ\ ͟?ѣGjvv6' WC+ĉO8]Ͼ[C&M4hU8p݊+dmZh`0o<[[[wi{1}͖,Dp0 JWDk 03bŊC^TXWyZ^uqӧO*KڠB^^^vffDmRrE1E$IJeˀXiw%лn:X͛7{)PBfD4{xx)J͉cƌ1\ 4&A .rrr ACCC{ xɓ:Giժliȑ?cӦM#S(E-S_ c4uiӦ*Uj}͚52 -(Q'@܀yoұHmm۶5 07Ty ELݻ%vΜ9 6T4j(}Ѱ.(/XjRoJe6aO6mOIVg͚5x`s~+WuJ*CbAK,7|s}nB \n<4?fvZqm۪Wc>I&5hЀD333-Z螆fUΝ;c{!=W/X 6IW98bei*` q1 GcbbԴUP0@PLQ:p5jtw)e"7}kO?I%7w?66o^2Xg,[B?|?}ܹR=OO<3fL@@@jjjv>^-E> 8Ř4P&--fȐ!2JoPseZj gϮ\R2qK(߭[GGGؚY4wssDZ8j(|{n,N}TcyŻjݺuXX/`cq18^Ef@y`''@kobN:iӦ2R7++k׮] 4: oPc\vggg[[[@.~~~ǏW/tНm8'Oh [JHKG4tP(ullѣi9*Tkر[S=zK` kצ6AQSNE%Ip*U4i҄FJyѺE-&b0aP},Y# _>AV@`/_Yܕ/:1/^Q+Y$f(xXy-@&Ome%( Wsww5JD䠳gΜQ: 3PŜ5A {΅j zJM;>B6(y|||#^9seddL0F! lll7xZ{CC}||Pr/SLbb"diƠEb sU@zbڴi) Z/t''',;oh(/^E& Z^Y HÇ̙$_BKz{{bj_^U[$#X[;/1Ep'ZF e<[~W[O`Ǎ'k/9 ֶk׎W ,Au>}K.7?/Y$Xn|.{9K"IC 5j$EFCnݺYp &Q\ Uoݺ5ʉBJV^} IX*333T1UVP!Nc^zڵ4TZ[hҠ؈{{{*:e޽+.گvc!5k)TS.~9ƉTʐ{~@}~X/AM ;uL\x1 6$ KzcHf ȹaaaC%(-1dȐ<޵ZO4)%%2 `ѣG~%K(pΝ.]R-;NÀ>\jU8hR- {WT)''lٲZǴhҠ {:w\r^.oӦ <7$1… 1jw% OCIR>} Qny`)SQЂwⲛB HK,{P ߴiӹs$ڏ:}~~~P rN:ty!C4[ngϞH)ݻ%fz`0 ѣÇܹ.o߾jժY[[swW^QZtԛ.\JE-R0xN9_cp1yÆ nJWAn՗6::: AϷ_aS>}xZ+~ϟ?!ԩYeX WRKA"; 8* j pVVJr111q͐]^.P9::nzPX C=<<ݻݻ7*fE*fŜQ0gs1sdtLc0(`Έ 8FP `:s]^]QfKYkv^U]] ]>>> ! 96mZn"k֬׿٩S'ooԩSgʔҥKŋB AT`ccֱ^:E zp[,8$1i~EʕFr?L!֌IJL%۵q,$?suu E ȱRBbW֌gŊEr3KFLF)\ keS8[BZjT@ң7mڔvRh  厐4ʤJʕ+nܾ}{ʔ)۶mCB2GTT Iڵu VB,,,@Gm~͛ƍ[vঝ]/^( )+pIO|gA']~=^UNot ]z]?~<Çhb4޼y"E CTݿ!ta 8p߾}QQQX4iL(Dž˗//_NrԩSTAGՒLiذ!ѣG*xM5&Nx9D 7o|֭6VNf6j… jZP"`Z V*[ur`$o߾}͛7AW^:ϟ?ߦM___K'A/> :t(^7S?[QΘ1cΝAĆp0dl^©eʒx@޽;ڪyB֌$" RH >}“Í&"HEooo/ش~*hw`O?$( /_>zLu~ݨQ#<(U"%u2eΨn$nxPP[ kժd +@~HMd$SvE矽MGPI[nDpΝ;GMm_~ShO>-]Mn„ bON8Ġ :%!3 ݻ/R3z rFH1m4DSN-sD_fQ ;Yۀ2i\ݻnݺjGh| ,(_1.]бcGzϞ=GpEB֭ի7"C ߿TRK,iժӧOselٲŊ˖-ĉTxV$V͡ĺiz9zX5\U۟;wNJDsP4ҥKp3aƂxE _Ҳ9,G`˗GgϞF.DCzÆ ~ FT|+((Hn>ZCwޝHOq{ȑ`9iSOd͚~=qyqF@sUP_^ b ]xо}G6nX)A?aii"@ A;J/:hKf)Rƍ1WWaapOڱ9H}4ȦM0䈙+WdϞztOpCB@A q@kuܠ۷آ`nFDD5S̲͠An޼)OhѢu֥YWH"`"Jힰv*ga 6n܈Py!_|ٴiӧOH !ۡa xymذx^ &71<>޽{޽{{{{X Bʔ)鞕եK@N4NStnJ ̪i)iڑ#80#[/:hqL[lC;vLNPYH&W\pox<~UoL\CGɃ4i"z#x$At0b_A Qƌ<"d͚g0nKO0 F'-y*XΝ˘C&&"mhLS7o8wD[3":0hѢDݻo۶ , \DE`^gccC;*UO?a>-NL9r䐍k׮4̞=; tkH0,<\B P6=|g޽˗Gj( J[UasĞ9sf׮]+U$XS/}ժU3fHPcQ*W,.&r˳f0`@4i9=SЭQmmmK.m0ڵk֭[BZ&'b炎ޮ]:L8Q`z<==RJ&J%%Kʕ+'dxdGKitxU1w޵|MݺuWPXGZ:w"=zhܡ'޲Cq122288Hb,Z*}7nF!t IZFJvuLC8KB]O@f߾} ~Z.ܿTǏ++f/BQ$i<,xΝp_ !,n:6)(0zC7774< N,mڴx"rNmoA^DD``gϞ*EAwwwg0o޼)T0}e`` bxq9!hO;wtޝ l#!ԦGZ=*B Wrљ /3NehLh_~>>>T>{eʔ5kdQPB@:2-3[lPlL|xA%ɴ^#+Λ7 )GZt_x ¼S֨;'On:x0eP _Tr\-۷oQQʎs E^ďi~A9rǎr؁rqq)Y$kAZ}HtҨH_IKƨ1k߲eK <D6m޽{N ]D :_ 77ȠH"`aaquөS'???=Hѭ[7;n߾bŊ +++n*UT,+.X):y$9Bf tР.ٹsv rJbP֯_/ 2ٳm6V7-BCCaNNN3>:tкG7o\RT$> JJa3tb0ț7/S#AJ@(>$I xRPAѠ_?h uƩicc778mz #9 sAZ4%6޽{߿߫W/___4AZR 5،3 ,--i`r7fʔ!^40ʕcACZw!H:uj]1 LF12=jWi,˧R8&%KHUiGvک 7!pEk䌜9vo-" [eaT)(PPʬd9s2;&BCfڴi֎1O4 H-^[n"QyӓkĿ<.o H ugٲe|pppÐ#G@'Ճ '۷YC%Js/VINj%I@ǼɓG-v1薆XYY̙s׮]B[nKN̞Hk؜IHf<~gʕ(=1PԮ]>uTDDD N{eȐGL"T עE {{{Jw8cKpb@iҤ iաɓ'cƌ9|XXup7u0iݷoĬB">|FٳG2J8q0Y049#DyO0Ahv0Jdd$,oݻw% ="<[.‚HA=z *gɒK;S4@˗/胣M^iT2c Ė-[V6`p.+ftGZh~*;A"GC/}eI`hWm`o9'˜EVTR%CX<"E`0ߖ2e2glyK<}tw. '!LeWV"VZ@*)w7o W{zz Zv|}}SN;vdfӧOտeU3iӦ-thҤIl͛@͚5O^x1>|8ksݳgφ>V}+7bŜd~QufT/!tmE;=I%v\ZhQbŀo)Xc_ḺPׯO߿8PނfaaѼysJmv_tiȐ!S:ZA._lUȑ# 2>((Hjƈ`H\pкݾ}:LО={xm۶g!{www0³#PӧO߽{G5(ښFXYYQ۷EH/Jђ%KWGF/e𷒵`WS̗ʰNzΎ666MqIQ!lrʭZ*SLDɅ%huԩjJ1FGxr[/^|߾}cǎM;M64ҤIaÆIFb$*U Й%K޽{#KdOJa˩u͚57rHjjݠX![[[Ɓθ.ZzW%1iRyawal[KEbPwGְ/^oyxxڵÇ_\b&OC")*w~MXyih(...ΝSIuMkիW?t萸C4h&>|8ԩSb:@PR%7,&ׯ߿|̯n*RcT?zз]ӧOYLӧW^ѣd/Aߟ*U*4lٲbw@@ܩ\2yeϞ=((Ḣ:$~LoqXZ Gȑ#o63a%xGh]p 5/E< (':djNˣҦMkggI7Q$]9Y iMca"@Z(9,.^aÆgB… (QBNIk>}'8 1M jժ f͚L-2dqss;s `ӦM۶m{1@B qy @5xUV4`̮/^t(K$Ç˗B8N4I 6DW4-=G+ի޽;w ..~gљΗ5 CZ#)YU&7jG j*R1 ʨ0a„e*ԨL./RN=w\v9,XadH.7Vl׮xK.AZٳ'wo>yd:0j(hyWݺuׯ_?p@gglٲ_p͛5Ǎ'&I\w2ЋniЋ隑,s{n+N~ZL ngd-[DLe苡cǎ>JOK,=z6~xVBNYԩ3m4H.6ԩSYf5$N /Z 솄 !8i${{{ҮSI b 1z YBf$qtB "!Kz 4kiܸqK"QOxlsjժI߳gOXYYɝu"Xp!Gծ]!Yf`^zA7(( ҷo_D׭[1cFBDqb~t}&Oև*f  . aymܸcǾ-?۷mڴOn0фS5{&>̙3|xb a4בЌQzU&2 ÇA fͺv63yA<ŋMܾ}_W\weBΝ?rs?zĉÆ  aĈ, %dڴi% ÇqZ ߿p\xQN>ŋ5jrBxѣGGTD`z%j2')XtӠbk Wr5k={V,~z-p={~ͯXpg(VmO"o᧟~B&xҥ#$<,YUB`6رcaÆ}0c|BHjÑܣFB ˙IIڵks$zrH ޗ`9kYf}is?}iӦ^^^0ȪU.]jkk y AVX+W̙1|>2'f.)ᯁ|ࡎ3fzZ28`ϟ{F"`h舻wf}J6\ZDrBtPBBB`8cSϟ?7Іϭ[ -!% NNNuٯM #@]:uj,̙3C)R .].+BCCׯI(P=zC;wX[[80tIdʔ4< 1Zΐ!Qt0@{PA/fIS`m'NpqqiAx7 cǎǏY%x ~6mA"{)Iڵ+^8"!3_7XdDݻ1R_,f*={7o^\9&T;R5"Ő/6x{ӦM5J*[ DwI'I^'ÇGDDp?:t;x#(Y nݚeEgrn޽;VXPBu3CRJՀuЦdĖh%j՞9[ӤIӲeKu>M)YG͚5Y*tI&vVrEoxتU+$7Qa%!۫22|,Ǽ͙3OzbbGLyD  F/Z(ݻ\L4:tW!³aaa4 OO  /*T'NJWWMS}!O>]`AILuܹwBU ' /I"aBe{B?&h8Sƍ)zR*Unܸ!LPi'UGI2… a1w#k֬pjqO; ofysp9GiȑI/`μ7yiӦeϞ]k2q Fk׮ *>0ӭ[7///9`j+>^Pt 6LvyNռyISTpqq… _]tW#vӧO$L Xe˖]hQvL2޽{/XLuT*+dE4$#>;x[R{ҥK7͜|ݺu'ODZ51yϟ?ʉlgΜɜ93… *sDH-[5ߧOB~L ֭[=LJaSgԩ7o|ɶ BaaaHwTyPG SN!ϝ;СTӧwrrWp#':|:u>~HMZΖ-[m_d()X ҢE kkk9Flٲ?ЧO9JՋ~@]zVl%={6dȐ``xx'Ϯ]"##s8RIb @ʕ+(M4H},չhѢ.n,-ETV-pA4` U,Yrȑ.]W^юA$56po޼m :hCڴi}}}ѱ{)φQ805sxuȑ#_4 =|2N-ѝHD :_z֟`򳳳ː!Ï}%^0*ߺuk0te$s!.u֭_~``о `^t)8d"x0wʔ)~N[[ې"껻#T@iԨѹslmaaQ|ytv[n6lQ<;wn/TPhh(h+7k֬|0t_D66PD~XmL8KŊ&Lh׮ݾ}Jkk\B12RN kccIH4-8#P6Mb6P#Tkڴ)Vڕ#Uׯ_{xx *T6/OЕ]]]jZBV7&MG2;ӧOG#b%1Zj*iVR2"""!(̙3]tA6J£>sI%}";i$h_Uyٌ2%`7T!G~۷lٲCdBoSb=n&[Zj_E(0UVEtZ$tfѢE^*-[ 0 d?}۽{k ,HZ1@W|>k󼝛T8qd?QQQŊ㦜Wҋ^tРx@ iӢXY"^|ݨQPr 0`+++4q9!sQ*kL_ѽTRAU$J8q`Ϟ=KBf%NƑ#GZlc$$!~`Р(L.ݻwfm۶\ Dy֠sibl"5.\BZ'qbܹ"dyߵkWȖg?:uD3Ξ=;|p&k׎"fwnfj9ВrD)SHӤIy^tРx sIVI1ÇQS0H&L8pwIg |7o@A (bH-O!0}#^6!B"cƌ[Ծ̏]z%"j:aٲek׮`2@ϒ*$$DL_yf>}wĠ(go߾ Lܷox> &?9;;#U2控6lr85k;\BKKK 9c>ueʔChݭA/:hK|$+E+ ɓ"_|YR%T40a+WTZTbE0`ahl pE9Ӻ5244lٲ\VV6jdyPPЈ#`j탯s۷a`ǽArͫWfb\r!zcwG ϙ3g5k#*TGUglAe`Q VҝܠɓH˗KNE>|9b\K$Yd `d<>h֬Ν;˔)#0 U:/իWKo̙Efs&X]vE-C nnnܩTPh@T ۷[n\O~Hܠ^o+awakk7CǍ7}tB A,˫TRaNoUeZ$?>uظ mDO2aOޠO*Mdl;t<Ο?!V;Z <` MjExKLP CĶy,Y?vXIz_^3jժ'NBƌO:u ?tlٲ1;wn{{{۶m۠A>}:PvO/oѷ'hPҾV`4_͛iժUC+$ٳgH- JDܿȐ!w5?f ?/\/_={6^Ք14ޢE MzjݺuڹV4\\zݮXϑ{L!iӦ J{𡟟_Foߖ * իaK*{E?͛7Uħ"EԮ]Gf͚ ~Ŏ;Wsrwwg(6lL =\| 4xMΜ9%۷o˖->}z._C |$tA^4^6h0|Ni0/nv3`>zhJ ] \SW.\=Æ K.!|/3,Y(]o! ő0..d&o̜9!CװaUZfMkII&ׂpB ʕ+q Ig͚U]ɓӧe̘1|W߾}3d=zP ۷1cƜ9sr=nܸ͛C;v&@4),=薆ubQMNà m۶9sF&f=Jgzekɒ% Zj&j%?~H;-[IO蚃C.\]]={ŋ8TdLI {%.+ONdA$X»wz-qbj ԩSW\iѢERP46ǦشN>=k֬O ~x4̵: ̤]=z$֭ ƴjբetbJ4i֭["`V睜n"ӦM[pa O_X3 l@m%T0 bkoF, 9s&{l3;b{rZ;|ٳg-ZJm5uqh0gΜ"%B yɓ'Vj%(((eʔm۶s n^vMжbmmm+W IGFD*U)R^zuSY@!y䁐,,,XCSye1(d 2J6̆^bYbެYx/9|l6nرcGh>hY`Ǎ'U}ҥK:}([(^2;i&Hi>,fj.\]]=<< lٲ-ZDDD`Zj|-Vؒ%K\b3%Iʖ- VZHHQZF5 u;ooo֘«':yYf:k,sMW%i6m`8/Rr׮]`&fY]v-{숺ǏgȐ! 006ŋ6[DGڵkAt5qf  |@%KDFF\u"FKI.> {޽HLܹsG xƒBWCQ[nծ]F&qs ]7n `hK_tGPaIUЅ;td n"?)Dmx ~˗/{xѴ79stҹr=/ dXXAAI!TRGi۶?S _jӴ;J8&C?~̜9zVQ"?|]|B}Xs_LXv ȣ}СC0Iƒ#Rn]ZN& @L |,< m'cƌdGD8z5bĈ;vdH]J7\ߞK,9=((ȿhѢs碝PySwa ڤZe26ӚէűόWqv͟ϴi\]] LGq5SIJ1u|o _zA:99Sq`ԩM)&CeʎwfϞ-o#GN8QhL-FmG"T_+s_%[: : DJn3|pZd Qqڐ;͚5;vDۧ#Xv"t%Kt޲eK{-ƍ;|ƍ۷oD,ވlY#d… c֯_?cƌB 5h=22RC;YٜÒ5k&zUŀwrԨQ02dǏ%̅M7O:_VՋW\"J(3gfج] {˖-O#:pӧE%7/ۀHشiSooo7v?.]*g%Laׯ_ٳ'iZhQpalTu ׯ_z޼y#?2dȐ[n[YY!;x˗/;w@) z]CedʔL3a0,.ͩPrL UVZ;Yz ƜICuqqWиӏ|C_"/_ >!Whn7ikNNN`߂ j-g0'@={gφJ 6(([v *Ph8.Rti~޽رcgϞlٲSKf"X<==A& v4o<=N^bOE Exە~Pn]mӦ aܼymV\f͚,W.QFT^zÆ E:uE2*%sР 1eNO|lkxMᆘGCQ5QΝEء=jIJhA> m )bo3u|u$ ^WGHBBz(WW}~Ho͛~M'ŋ @)Ke`:~ *Yֆxt5 @ J*8qjժ&FLTi ˗/3Se˖_V`P.\ح[-Z/^2dHo߾ OE#MA{~֭:h~$! e>_|)Ǐ:u=zɓ'"&M9s~YZZ&nEܹjpbŊ&XOENUֶm֮]ΠǺ_zչs=,,Lb" xgϞEsz/xNXPT|1&'ycVa~HhIoQ1!d 4i×/_F,$Ў;&Lp}];Tw2 `kw~ lq9x; p7N4O5kfeeu u +W0/3g@xEyApp0߅SPPPǎQZBCC+V,Z vhGXJRWh#$PAMX"wbtw^=^bQZ_~9|0lƍ](^sNv=8 _(׮]m++:rŋW\YJ>a\#>#@ ^*'<zLS2{bHuK'e.kǏ[ww#K!c^z qր, .JE֮a%D©Z3,,,D* e˖… kwb vuAo6At^|9:xNQ3fy޽ڵ8 hjӦMHc"<ɝXӆ<~1h[-Ɂˇ!Фa֭7 "vh*@ ͼ1EiDŋ=<<@$bť^$FG5x.]@iE;cHYҦMThxܹGFRJ&L>ƍ nnn=z?֬YӸqc fe ę'g%fd=^b)ϪWCY&e,2Bbf͚̟?ϢUuo?B-@ɄJLBI8r*^TlrXS9[? a ,GSUf)WsFW0-P^^^ X Mujl⏃<r(Ra}DZ1ـkR-Kiˤ\@6ɓo"kܸq;R{840~Ν;k*˔)yf91+W.@UT퀀پGHIҥK% *c9Ϟ={̙p+VD_, ۷o&G HltZ/EIbGϟ.]Ϛ=QV~'(x?O< S׮];j4o?qrE[߿ԩ}Il" MD^ehT[c,EI- ʆȨ(T9s\|21HtRHHH"|/xQ :1eyى'|q';ȠM6OV%W^AAAֳgOV(X{:u={:uS7^`A۶myCzp. epILvޝ<-2!^K5j$qݑݺuCE]Q2ի,r\FJ{ LMDu떐&hu&L[.Rn0%$޽{$`ՁҧOp GZ\¹eˆXEG-Ztz\?~8z̖-[!<9ï_ޡC͛f^PQ{Ib{5hЀv0,[Nf8ڎIĘisNfD&"D&1 'E%xHp$X6UT] TR|@NӘQ ZpƑ#G(uT4$3gx]|#*.1~u>(OtUVpnrÇ,--[@0\f3gNEaFhcM}ĉ!P=޽{1Z9RM8"sΜ92ߋ"BoU*#C3" g̘Er+V  H qXB,$)S]<żKa*Dc *{ذaz:i"{5:h)֭LHDAr_ >DrttD"D -G)={VarT}43r]*>ܼy3`b2 V}LE(p`̙3Z=zԦF\@"]Dk09s4Dl(rѭ["p۷$/.) Yd"G3N1cF$ CJ"Aj7Na() ̎;~tʕ B,'fr5kJg$,1`4@DbEs73ea>y SNڷo7aP߬Ye ӧ3<Tu*~J`tV;;;wmc֠ tH TVIa B9w﹛7on߾="""888.=?<~xbP/^(>f>X`7 ]>/\h2"WΝ;#^gȧOn|8t{e*4 a?!܉#G;u;>Ez WE);i$pq$A":88@9OAPa C"C:17oٳg۶m~F)f&N'ϑ#Gp`@ a@u/_\cCu̙3:bիWYAnnn[n /[,3 \.kk-[Ğ={ƻۯ%"44#1 jڿykm3k-&;BJ`=(Q>Y Ŵ{YT-(=SN9s2Ej7}z1x`y;]B2)1cdE/iҥK#c}Hk H7ȅ$SĢ~'kڴ?lH0H"2pABKZYXXx{{mߘ+VL0A9j3+膊?ݵ堍5lܹԩ]|lPPD4;H}0}&M ƨ۾|X̙3j(ƐN8T>E-CXZZ&WY2_;jZɓ@ 嚣lP"f7q`b]_B. D%ݸq! Ɠx1p+uRx֭?ԃ۷s玄[eE:Ã, )Zh:AnSɓ*X` .R:b㋢ ]GGGIm%1'bJܻw$(N^vN@>l޼Y;wrm۶Q'NР a3?0 ۷ ۷oϟz1RW?b!>=@W\}ԘѣGC;XwB#G@=0v:tBBBXP֖dp$嬤J<0 .4M#nfѓsJY@]2kbX5s.0Z۬IQs C㰬ӧOWݾ E3~T3siu8qk>OwmxUgfgf&:mڴ#Gfq#A] GZaÆ)OXSh. 1ch=Z2hɐM̙{3eʴ|/>x`9 =Ugώ^>mu''q}ɯEη`-3™2eʎ;B*|XgVhvАdCWl <ڀSG_;̒U.Ӯ Ip$ rqqQ' 7qpBqȕ+ѣGzjģbkAD=D&&LyUr:QɮRcU1qF:(~I J :R:tׯ%H9!WZm'''ٳg̙3x`G~$ m|}v@s[Fө.&ZRɩ=-A 4'Om9]Aimo'13t!ϟ͚5&$}"ibTIСCJ3('4` ȑ#U+n5J*a XpF=tpxd4P5jd-ԓ ZΝYЌ0\6- [:uDFp.ێ. J0*$`ZE ƍZ ];_~^^^_U$]N(6D<+++dl:֭[jՊY֮][(G` RH: 60kC њho&Mˊ dͩS [^-8}tV%p6юT"?/_[qX=~̙aÆ6(.E"u*/FNP)8y*La2j(wݽ{4ih]Rh<0 ;/yfmycΝ!!!Z $>\pF ,(XIi̙` wF'TyŋR=X W\1 *[ -(!** ӧwݻwի &@⌌dժUvځÏ9"灙۷o|R=ʾXB+޸q0 ò6K(q%IAw sʳ,cfnO:ٳg{TXRXK,"Cޙ]̙ӥK>00YEcƌ)VXժU,>7jJUx u1tL2ɧ}HSF t1q ZdJbLnfȐujܹ7a Tjfgɒ% qDdeBl5Y9{, #V{U~Ch>~=zĥ8YlR$9kkktM'H᧟~Ե|O:q9pϴi@S+V"FTFS޶m[X#Դ7n?~ ߮׺FoҤI"ZvGu MrsY~}DHpIa*-[&~({5oذѣGyG*͛x>P{zJ ÜBwSl/ wׯH|e ][vmJ2Æ Stb):ubZAfy$`;3f:ŇȃN.Sʕ+ P98vXXz޼yGP,W2e}Y4GIę^i^btvlX拈3A=2m_ib8IEf% 2-k7*J}'RΒ% M *bs`]v];6R ; ej*+Bxi_/hg͚%⇇"'M׸|U NثmEaQ$}ɝ;wPndža\ C%a DMPk}ӦMV!k'nΌBiJǏ7Xuom$Ξ=*U*kL|+>gߗG#iF_t+MǎB+"JŁ磁z9yWD;%OZlv k֬xLv,Xu-m6&ĉ3`lg{tR"j7Lb|TCTT= nJ$s:B%!zB7 Lf,m9ص/ԩӿ>wP3AHGydԩ!\aŊu7QJB xm!mڴ3fptaÆ54 qK{<(4(s=d\p}DXR~xrp] _ahMb^@7K.p(AJ2zEYM 4{*ۖ/M6M4?>UiӦ͚5 WKvCEٲe!]Lm~w4P3۷#;y  mc\ل7%Ա˽EOR6h#Z1%(GGZtM~{J}]v5,3f̈r}Dd*π|=`$эh1bD\p =zas6G…}=n΢k F@'q/MvE0jԩS˗/x0ܹs,X0uTĒ%KE1Кʊ+l LJ|8JJ2"UTU$4}XEQzb#d+WKl A2Sz:Um~ M#%%KqiPC㶷j {62p|X9.\HΝ;իx rH6cvt֭74*UlYzݻw  X2D1Ӎ@#G$HD;8[S)R5l^у6mܹ3""b̞=ܰl2 7^-V?1ql)B%T-[-[ (Ɋm|"6lrI-0+]eA&,Ce*Tʈ94߷ԨQCr7_bIM9@YK %Q&)F̴ͣaKӘ{ǎ}l׮\jAWw/ ' |= oٳgڵ+T׀\Vbr/a۶m pY3h&)?tC3LHJ|H) y˗?c< -(ϟ~gt>hJN>}zƍ 6p.δwS~={T^O9sƤe֭[G^ pʕ 1)L7mڄj̛7}Wk,Wgɒ>pYUW_??}O&L| U)x>D .j3?0J,i ?s3輘.]:CN QX ^h4&Kj @}AΝfzaF Ɲ͛79s&_7Vׯ_<ݵkWʕfnC%3˝;w߾}ׯ2LD8p"q(r+B0}oBV|e1K"֐ibJUlE:tzĨcǎh?z_D օ b0N`܅ot}T56~B]꫌ɓd"E ,QFy\~!E)}"My@  jȕ+S{+dDC[8_x'aJJU(_C1cƌWc=s2o'gÐ :=ԺukˑHÍ5תU+0 BE˗+g2;Rw\Xa'OfDP۶m:wo>`]et`̙׬Y2!JwIlb,e 1J;Qmrt͛vHy]vڦM?+-[ܹs]ݘY_/&P-+rZ} {˾bGy2>v옛@7oS?fɒŠ3!QeH2eZ>7nb_!~!>{ɓ'4h@\]n`9sFu֧~hѢ @SI4iL>J?_J@H=+Ԁ/^8߂I4VatwDž ڰaݴ .Pw}M[ݳgOҥfJ >a{VZʕ+ՠʦcht|/8WR$YիW߱cI̦ *;PEU̩s2 qL}3|4߹s': dTʝ;rȖ-[iV@h_\&coT\$FO~KߟHO0|onH.JQK mfʝ;""2DIXXrUܕꕺ <jܹ"D5֣G >y~Px hh~G8tvA1/RRNy/$ٳ'%mCljO>|rיA ŊC 8\" dQFSƍS !|@SW\iӍg pq 'CE!jpaM[laJ*ň̈Mի-C65ko$6N|5x/˘̒㯁|]ti1 G=pp} PI07R֜1cޓ86>֭6ʙ3'b%uXTJ+mR^)<Ҭf͚=x$x3 \H\5H 5\J[D :fܸqҲ>K#&>BI%xߖRݻMW,mu`!C\WQTeo_۶m:x>:h!/%Az//NJ+૬Y2)w ;jA:y5@MRnΝ[yr@M=P`۶m]v PI^%UT{$x9<(6:H#G^ 1 l'^x'p)ڵk'B80x |}~W!v*'@x[XtR(C ʦ((&`y4f;1a CctQ*xvHѦM7cZL~2NȿXJe{s\@c2 ٳgcsgժUDdʔ'q@4fS)e5jו>ڪL/^,EbV .IPU[fMaÆ+WT E߿(ѤIԵk׮WӤIhț7/<+C*>_Q7vωOo; |nٲQE@ "5g.& fN- %͂|q]J}]!,oG[c-*ӺZDCBpinٲO}d=}Asb߀ @픇)PZhWQSW7Ξ= VuVbEXv-߭Q-8&_|zMiӦM^tlUd|Wٲeۿ""ŞzRÇ/_.ґ_*D>ժU:<CH7UbrJ@Y EٳGM h (5kֹsjpEFLbŊWjo'߿߾}r [-_|:GZaiu(vjtReq52dȀt6&t>Jڹyf z&]~=9>W\9e˖dnѼ3gԩS_ra( b[~=&c. <:2|}4=t@R-`i /̕ Fnb?Y_yfGϞ=ax07-BQ%0Pچp*T3_`c^4@O?ŋ 47o"YᄏtR,Yu"oauKx \^Fmڴ'iSJ)"6!._|gL }D2 Xڵi`=z'. n:!ÝCW_}_Ht5zЕdX… 5jyG iPy&1#( MLF=ڂ,YIn*Tg}f熐 V̙\TИٳgnH}V>sSNZ-|TX 1/nպvڴiS_\ 59d;R(w-uKJ 0-@1٧8c6iLe@uxc?p@m@>ƃ$#୘/MS>}ܓ/Aǎ1c7ЦGWt!(|믿-ȘHrF TևSLYx1Jhذaă >E2J2.]#G|dƌbFp€*qDkظqҥK z+qF<裺2eʹsALHb0(J"E xyJ$4He%?+lyW0Q33f \}3<1ҧOҥ%ӊ tFa*7dM*gxK6Uf%M4:tc:R֌Ė}KY\`dáu$.T7k!b@ hÇWU|qڴi9KHЪ+<a# ET0zd'fҤI9Wu^]bpaԩʫVj/hA3g5rF{gϞ @+xUV1z*y˷,h6ѣ ;vhg|r.YnwhV3Gׯ_@.Gh{"I_z6勰efknq~ׯ]wq=S֒}Æ ız˖ayСڵk߾}_HEh4ݻڵ kP][TL2aڊ.U `Ƌk׮^lٲz{U;jÇSJi9پǿA%JJ۴im1#3q֭jo߾4!C7d!aakJ&d7\UK.t磏>1v/^gVZƍebطozl}ׯMu6#C !h21hUֳgOnFx3:Q w 0$Ztٳ-[0+9s&t>h@)>TTժU} aaے㗸|0:Y %K-q'vH7J-IhǓ(۫W/tkG^.L[u#Dq x%0P `{۶06[O6l炖Ba&q7}xP=ZSNׯO>͢T8g @ƓNrTX1e&:4e4+W0oX˗{rm͛rn%Og1iܹsaZxZf $ N8q۶m{}Y&OL"##-ZF#фz5pYpy!cNJs7OP dTPoH^E+J5F ۷oo΢[6VdI%mEW)XF]68NجW= PBJ -`S#ʕ#@T'%Fa۶m4;v,Q;\rT)RK;1_9%=|p[ص 9D6,Xz9Ho9RD7o2ϟivk :~wv 9sB*SWXa-[W@ի9d.rͳZ[gϞK̠۷O?\pAJUhe_wy[>&*xG{=>2$AStqF.z 2>}mFSM8~?PZ?ɓn+u8pT^}׮]ں6jC 6mڤ3ڧT<)_'N"WKs(! "^G.{ղy=_֭[7p@zʐҞy9^dw١VJÆ Q `ڵk,`y "@!>:/ꫯy.ݸqiӦW ۽2~ tpO>$:qz9_;0wZjA^W`T&+x6oЅ)R@mڰaC/ŋ۷oUPC):ZіQQQgLyVR%F,w\d9蘴F tfPઘ>0!N r^mvk18֤I)TOTiT91!СC1ߙ:F%"Q;v>|K/o3F3B<ؽ{wwXH4O{k4D̙i0K*,ωAC!$tҕ-[>}v vZn0+_{y.X@џO? 2uTԩ_!S 1 ?(@_~\n=y!b:Y֭[fzW˹sv=׾[F_j4h(Yf{fr ry1l0xCuZhV铡sډVZ͝;wܸq  ܼys +VylԦMVZqbfʾ}bBc#Y ^z>34C#F0օv`ҥKqbʕc h 8< iӦ[Zա} mO$\ٳg`\32Po7odesvR'hɓTҸqcEnEĉX| dQt?7m4v$mSFZ4 zd"& yS:~׷oߎ}I$ @y`/xnϞ=:RH3DإKqƠ7ύܣG?/E.P.۳E܅[f͚ pw=< ǎ'V_wQ4Xtay6ue˖_^Z\YvmRPGUM_2j*I7m7nP&"y&w(mۮ^zСtҥ2d0a]idOht۵kW 1nNtW_%vt|ݻwwᅦ8-'#L:tŋ ػwo4JFӪ}`g0Fe H얻]@ 3_&Ξ=;WsTnUGepc30|7o^j_͵%UPÈ . ./?8R߄z$iֺMю(x?E/|ExsuFDd)ЎzB ݰ8AQMw>pV,VP׹"/rPil׆ M#bŊ[NT2uv]W_flブUTA\I`D$*ዀ={*3nJ(B)R-ƌnK:}/ڑ@q6m .K̘1mP{w Oq)B7,v DrKϑ#&M@PFn&=_N@EËMp5@(~!w=M 1tƑdݛiG_jąeP7CUP8S^aԐ K(k)>vU&!$hȑ# tZ7[ S&@+( z&XA"vs'N4uci\ ٴiD\*KT>BK1px\֊9Iġukp#FpK/.cJ13O!gΜ;|իGO\s`-vj]*:`@ C%{w6[+V^DZ5k@4hLGfʔI# cŊ}` ( y=T)EbȹA'2s&6mڤc,$9(=3Ç˃/\w^`r K.DtT\W\ɟ??رc7n5LSнRۮx"K.0﾿:ړnﰥ^?lϜ9c! mƟ:u*W\ RNQj]E֮]O?/U2K}#F jS ~}ƈ|ꩧΝ}8k׮XQ툼P .]:%0o9)uF-Vw۷; ETݺu+_:l}vy 7Ν;GhO?隞<}4^Z;vl0wiٲe+S ͳn*TH"7oVUgϞ̆ QL EsZ裏x.օl/+iڴ)Dc,䀒3G*.}oЬPndd% A,yZn hL4ի-zBoFÍFgv]V#a=+eY+ϟ8qI+fmc_~mcÔݜ8* ⒰`X &5Fd-P=z\2d2z% g% Αtz%S34n1VPǎ۷ogB}6TvqmB%Gm?V&8RGf\ԹJM,Y,Z+кܰaCkm<dK[Kjn>Rd]q3#yaÆa+"ǀ-VƷE"\MZe @7nN:k,P  ,7o#""LիWǮ6mF?+d{IW^.L m_Ʊ4\J&Yfd̘{1ab`)KmKz5C .T]7h&Mڵ9х_x$6D˖-3"1#g40&Mvϣ+bML f5'/_[ -:;} @ mlOl޼9cYlPyݺuc&~1̘1Ck[gЋ`a]G4cE C"dʕΜ9sxL 4`@@7hB 9~˖-`+ed6ѵ5k0ANl+V;M mZO&Ar$@C2DLB +W|%ptƽ1[>7shD5 … AO&,[[8qbÆ }4?L<1Za!G 'jS:$%m# +T;wn uֶm۞}N<Ʌ2ܛ6m| ]& d .d@E:""heP []5k֣"tEkJ ) 5F oQdIp~ܐ2eʺuY1P\ (θ|4QtN :y#_|iӦ tر_:f6w!Vy`y~n3v/3Њ%ڸqcxu,Q&Z()ܯ]6jfOŤSг_n=zA΢ ^Kܮ]j!_´g:s@bXZFԝ_|oI}~tm„ [BېZBC7}|=}#s(.wΝ;ETXWW_]tپ 8իjA RzU{J* R:Y[ <]OzЀdɒ(5w(Yf͞=Μ9=zUڏ [iЃ N6M;tZjlra^6Ct89ɂ&A8Ä-ё"dі-[00,0y--[xbhbN 8m۶\SpE`t>7b,41-P $*:oϘ1Cbw>1@aDL2*00@ C&NH:l킻WDbbjԨaD6E!+!}/+E k;~xIZ6^=u / X /Gc_Р˗/oN1lZ@@`ӤI3}tK-aAr]bvTT\9TB@۶mS !.ZhΜ9 rBUevFg)Dyƍ9r5 5jČ ̳6h?W2d)8xj@Vb䁫׭[+{4pI&ɕ gϞ:DŽyF*B02kU9sDV"C۷ovq$ȜwA >U2eJ32 " gʉ~zsX!ܓRBX\7a1 ,,%mJb`-*Ytxr?Nj6HkW,jlUZ*7,Rr򗈈EAus..]`k}܀9*TbGѩ Ije˖#s{ߓhr>ϩ`r֮XXV0BrԨQHa8N0j7/!G/0a6mڴw޼ykN-.^x-sI؏7 !W;r\cvһ.\{gy}0 g h%3L'xL2ܗFSv풯\r#9b]zuڵܩUC-EӧO|M3f4PNdEI?Z:tӧO?ڶmˇFS9r^p8~8E%nTGn~)Z٩<˭f>(5.Ϝ={ܹ={Gl|ByPHܸ=̃fݲeΝ;bŊN:Q+WC#!,g(dڮE\r'I&ͻᄏcVʔ)o޼ ϣ?ӓ'O/_d,C}zY4>)juHpPi@Rnj>Ԟ6܁W'QN ` 裏hI̙g>m4k/X|ɺuw;v D:jz+:,4a:t@tBrא hpH ( (f]Yj7@شt_&HMI(З+W4?ϴ0[;sL16n8sRԺ=v[ رcͬ|w\͆Ε+kC(Ϙy*c]BJ2ЍѧZs; BZX`Gp[Ό5ozbX5|-Ӹq^{5#]ӭXbC Q6/?$sڀcڒ%K,@ 5k֤I0/_ߥK-V ,W>}r 6lРAgN0_,XA{ЮrnG]t8[N9C-PhgݺuU+ p wP` VIa$p`n)V%spP \'sfNٲe=kΒ%Whc) <1RTx >!lݺ߻59<{lCJku-]txhx1iB%Tb=N:HT)b2]J W_}ԩS Ν;]͊`%Kp\4i61obV83dp۲gq)`.P6jPe>.1 N:TrE 3@U0B,@j@K :D O*>Ϻ`&!*^p{]̙3yi֬Yԩ? =ȟ >s[^|x%J/}' 6Xiv:~EgӧÇϝ;'AO?}[n!R-[ir>*˪T\ѣ;v@}ݻwU"uѢEQ_$AJ*Y$  xEI~I=SJ:t{l[6#(2 k޼9V1#n*Hĉ&Y2*kMݶm2, bA6U[6輫WZׯ9ϓ'O"dիT+R'wVoeP`<?0jq.\Ț5+ F/ y&؝t0=:}8C7x#n,8y5m05t U{n_;ehbR~OժU۴iLɶm*^'T ĵA޼yp0"yUwQ |0RûJǸ(e˖E=`pԬYfp>{x.t4h`?AL۴UA$Ϳٳn@7s΍u&Q k[bBҥVwPf&*02f\LZ`|llZΝms!_O,{[k&$e4ёȄWe -߽{3-Z xq/Q- >+0I-'u^ࣝ:uҸxrG$ *ᩇ/la$^Fm`4u&ApJIMv%FP 8~w]&Mz 2hР_=Lܵ_;͇Ĭ^4m"ƍM\O\rܹ5ˇ9sdIXOA+V FQl0t gP1[=(c#c=o׮{\B4i={ip{i9-wtfmj W򪃁Ek֬oG hp[3{stŊvRwBs9Vb/4رc.\:ӡC &̝;wĉh b0/͛ǿ#G2dcp10Z׮];bOqP.5k^KOVZ*b҃OVu.o,_]@B!T-pz2X&liAۀ4G~ׯ5kVXɾc~ݼys$CZj^@&b*T9E/Użzp&ҥK(o+$oƌj?M#Π/4}tsah\SV}(pXfn\R`ݻl}kذ!H.H{%jD772>x97ğ܊;oߖv)8ٳ""" (*#Rjоkt-[f W\t 7fUOkݐAAw*јWDzM*/&HF+0}b5uիWG׆#7Ar[XѨuvNI1RdA[N<ٓ+܀HE.YdkҀςdAa5 %$uCWY;:Ypt 廈~`ey?wGkx[ sA*+Y'KҥKSO3gώ.ů)3VB6[w ~a1Œ4p@˖-7nfɒe֬Yeʔ&_W;+ H`e08 ݃M*te<Zǎ1 F2Y孯Ν(kׯM~޶|Vln /".;uꔔK>j> 6Lhc]B ՞ &(uQrtO ӁqAeQgϞU⮠ֹEmӦ V*:讔p]fMb[ MԠD'}X(K ϟ?22]E:B<5c EA.da$[׿F3,(=cƌӧo۶͎yq5lE' K:f0 X቏b2 b!"g)OԨQ)CH9R5y1;`G$l[82$t%r|/f"&Nf͚˗/+V``~AZ/psۧzBH4%8//b2Qh ./ejOWg>uQUEK eɅ 6褆e},2.h O2E'f\ PT3lÚ&MOr??Zjw^պuk?Gdɒ4f0ω0 k5+W>}tgΜ9cƌt#'>ڵk5/|KFQ-oԨQ\3'Z;@͛7[Jz0ҥKI^3pZiiEmv"fk׮̑#G]$$n<p'O;LI&a5y_t'h;8̦3EӥKElƲ`󡊨ie",bпSf O|0/<)dA*W(wsSiO%4̼ z(>HI $mOO>$͐ALgdڴiJz뭷I]-)ƞ>y)Xj~ҥ:`s|<%KLӜ9s ,(hzgn dիW%' eӃƍY&nރTղeKѣE͞={ժUfΝ hX=z x[ZX1^XX cLn*j\Lެ` ўYfYF@)5jR4eG?jժ)ߛmTL1o*Kɒ%~a.rŅϿzdX6TV zt\x7 GȠ j ׯ]6?` /kx6_{HA 15 (r%UTI0|hС|0c  3?PP&M2ZRN[q5AsC 5#DtG(}< ͕+Wj)%PK߂`wkĉm\RhQ, jdޔ 毫=[Z:JԀqlD+cj= eWnݺTChϣrYɏ _ ˢ~*Wׁ4|~~{7n,Ws>C(5=dCOg-݇*T_LCxL# 3e4k, &Ӟ>J)RXj(mpF+`{*B2?Iw崵s_A 8[`bL<"Mxw^G^ĄP b"+MO|8zǐSIgr?V_k5bСZ02h>1Tb?Dk*r̙};!l=Xy͚5og!LP2;aRX".OJddd7#>}`9VD0%A*X2zQJHVfe'L@0Gˠ4ƍ`,69r@b[N68G;n$oiU:u;`0,YZ-m۶U^9819uPĀ˷~[ "oѢ;H>g}4@ 0dPp-[B"Ȟ+W.h[8l* a!4gyΛ4iReѻ[u7L&L`TZ?垶9@EMAZ<*P6xTTB{0Sӊ>J:mo GSNW# e˖ ; C|@PHh;4p$6(UN\E_Z ށݮ];jx6_+B(\b`MOBmh= (pmy<Ȅ rnXk a'_k =lIep#ЀٳÞ rJwlfg")QIc4%VI4ô)-_\j5|tl>>|1F"1t?{ !lkR܇_l n6hޅ1oۅJĽm۷1 A976mZ zgϞSKP 0Ȧ3f0[M3yѹsg2/?KƒSlk  Ok7M4r1b~Bl 8PJ$M,%D򆇇l=lРϠuΚ5˲|̙pE[p~׋Pv7/_oG!\~tFM6#{4]OXk/OҀSꈣc1;ȘvP͛ Ri֬ v=r䈼UohѢp4 rCq? >abn7pQB=Qf{,\rOoʐ$h@!c]F J)޵kW;"pcy9NS杛[;B](t܃u{2Z6} aoOD7=E,b0eZ `]UTi| Txbi[53He@L߾}{ݻRJ@oi ]n][jB&Q`]bux;B!ZO&nBz<ԴiS3<ViB2V8a\ m=N!UV)ǿ'#CK0-E-6mꊱnժUҥa6m pGy ;uD0###-tp5GzD AG jdyx0ܵ1 $di<p9vXmݑOOr` H@Oʔ)lŗ1O]saz :իWNf͚;wFr;my0[h86#ÓiH͘"/zwС HСKwWi1#GзMczʢ Jo!O,I4ހT\dT-\ĉ:Q&rߕY~967ߒR`k5úo>% z(Z@ 6ӈwz; N5k֊+5j.]+Wؐs„ $ÓYTxxɓO_ Y"TsPEjGZwT@ !sZ-%U';\ԗ"APCro[0u.PҮpCIH BQHgF=쳶M4׭[lY;Byx\(4چE AϏ3u35_"""Dswiv}1K(03L*kk|Q "#AEI9HΩQr46 9#Y$$H"" 0:μw}ꢺE::gZ{amM$fq=]jD9zEd`ܢP5mM7"g_&bkLMz< Jho׮p]<`3j(󟮉xf(K⑥3.]:BLwmv'`ذaԓ:%moժA9K:< (d[,g$Z\l8h Tu5f Ԧ0-@B<ɐ!(,^B$IP̙3S??K.6'XY"պʔ)TB(=!P6pN~I%K%mҤe;uBi,\_hGX~h`k="&0f*4w+MtQ&Y~LcŤI,/^6 \Q2Opw,(RvmtѣYf;,>v޽{u`g4hP1x c0 !_OAX&uhݍYC)[l-yVx6_zT]!a0[V5kVr<8*-[6m W>7j%/O[ys C%:oٲ-´%?`!@2kTU #+WZ`A]hnzժUƍC'P49U|ٻwopxjߞɻQ;VZ۶m*v [>UKC/ r2ZgYgtaQIMS$__z%~i;wFAEs9sݻC2l.GaSi 謵(i^)j o"?[r=F>>}zn~7m#{ի5 Ĭ`O.\H.OlQ| 2D)b@ Q (E31Q .D| c2^(͛7? G> ]60kQm]B ioԨ->1lX`xI5ЦNugfbW̙3hڵ+H|1LFeHF&MWj (NWR|۶mmw`׮=d& ^f4;v$7!P|`3_efge 3zDDiinݬzݻBPHjզLuЈ -#PD;ݮ%r6n)i$3i:;K!'O޽;ɓ栨CG^^^`>&&R?L{-$H,VZ.K&8??s% 0Hx#G܃InX 8Ў}‘ Tds]qMƺu뀨͛ q'6 ORꙉ qtIC$:g_U; A/%uOrd)5e>v&]T3_I 4A#w4^<#A[ؾcB@ܹs[n%A0"罞'㴤2ȇlC _)}5t֩ФY?iLLMIKq)*>DQyZI/1fQT^{T "8?L}N6  ˒AڞAD/mnN\7VzPCp ęH*F91G Q뤓- l^ .$o\.[ j)5CdajetW* # <*|l ,td mqYN`VJX@_Cиqc0ƨQP.:v쨴H0'$fkB;m^_>1ya *ZalѢE͚5S-/ _8%v{-W2 +V2D픀@|Zj`hWl5i2y'.6)Ymh?O L>y&0!7|WT>?;wԩSϟO.]*Uɓ&M?={6{m۶s~ċ*Uv1dpƞ={~q@+[N>]d ԬYڵk6mEf֭ >\%S,:̟?7RE +n|B 06trVk.-`tu%nR/Ƌop”CsTO9rm<}4qROyf:@Pp8p,Xb y۷#Ty  '7%gU'(xÇS1ɔ)S(`TbƍT &+@<[-ąm2>K,C x7\#SD %Da"p~:}ph>5DDh--8_b`rǹM{hkn w5ay[O>yd[<+\&*ڵ+Lk/i !Z)p3f$o<'S_C2P68%(:sΐ;kUN !66OFise˖4ibncNB[XLhvĂ0nj>!4h?KJApFy CA ~ѢE ˗/w^ A3Q"v1׭[tqƭ^k֬9{,uD}U6!ϨBʁݛ/GŗaF P9*E`-x޽iQũ@4dhNÆ s΍2#1T gsAQ'|+uEQ꡵/Uȓ8p SLkFkT@&hURVm^*=G>/"P"*SOaT ,c2e M>cCcpzi1m[lXbΝ4'5qnVS.!ԫwM+Yڶ#DIC4͆wnҤL C˗)!n%OL'#%7H^!RL٣G8kB3gL<!q=׌WKj|W^]hQxs VA˶s4 1cхp+m$ !Lb@-vsf6ƍgtC ڵsh Uo޼$j bHq9r*CPt @p\\amڴI^CU.]4V)S&0aBݺu<#X0ՆdHʕ{ D(1cFZ;{ mje.\ =GEMXC<`[,C+tvLO(i^ϟ3~'(-W e-*^8g͚5Yƴ# .d#:Ƚ|Ν;gϞO ]hݺ/ \lnnJ#Yܹ񏔜9s9s>\ E3UTמL'ʍ*"f:BCЈn LQ%`E2aNR&ݻܥt;?S-0;qD%IT37.#CMdɒkB+O<9~D= }QLKʖ-tIpJ_}UO 0 ,MPQ gA7Cq L6#=T3`Y3K.KJԉ3gΜhѢx]vmܸfݰiЎT~Jp)8+W|W7nqT>}4B;t*o8_hтVWZH+ԨI&ٵkרE͛7@;ٳ'/L{lĉQ"VH+)Sh^B#w:AeaFOm۶oF׮] ۵k3iڷoPH>%C >6;v$QF`i_fýqIr!"!'0d\ߌôC7 Rbn9[[x2=tOl0t4;[@D =h>}"snuA۬Y3f͚E_86`-|PĆ!i)_5mڴ=< EÆ [vAp#vhh{g 53;PVB*UdC4og.])2c ZA ޡ1^A*zu᧹sROke"?>|XEN-%;)UkԨN4DHu =t/WZ82k ",s8Y9E5DoE4@2eJ@@Eʗ׷jՊ;-[.YKB)צ0YI&i%`27DZ@  } $bJ¼=!@TzuwO9J L<_| {|}\֭[BtݻvڀUBez ցK}!DT#pAA0TtiB[h"?`96@\RICmF(a\7|s:J[֠L]{|SV-Pp5wb[" 4oD/O!lPBDHo);wK7n܈ WCL)iS=I_9r]a/ܹst1zAHK, 1#o oI{V^9"XoM+Fx]mF$4)S&&&RlY~9J\螹p^j!!zEFk-Z <!ZؤIݻN0@cǎYYBevZVzDBǏ'Ғ ϜEBe;X.玐L"Єl< bNG:u 1Fn7A:Mm[ jX/j`E$* 4Fjj?P˫TrЊU+V֭tR eVDbrQ9%lQoƍ7lg9B ۣA6o,~ A<[©s:uh;J9r:w G*uvUR5*Uİ9sbE=  "X6IٴiooTX|χ1cЮo,G;̴Zj`5]tc/|E:pn9aN@ PMf:K..hHZ'O|U ~}M\Oݺu۶mC2aX܁[LOe̘DիzOhZBs1z@ Zw%0ҵx2eJxݻ]d`8=GͶ:2k_![>h 7we˖YB_I4:{^p`5 ;v,0m6 S (ΉH E`H !VΙ3'7uGe%,ByL 2`n "#+y]t  w?9aPlX)wvС-5g*@*@ԁJU G (mroPgtBy x*Gاmdqqqb'Q4͜9%կ_ߎ _ |駱W:25p kRzjodԯ4G)^uʔ)"xL\]x"x+Ko~Di##ܱy5nlBPKp:j8hC#QFyW!1x{ʩٞl6yz)~iӦ'NyٳXi֬ϿVlR 'oѢVC Cy%P&]kYaӧ%@)e]Az*p+UTp"i\pAaÆ ā7`+:ҽaE`ahpUM2ꗿYfU@H;wnll,~j„ nB^ g|M0}0iOhZ% }MxЂ_\ATL7pYa4!XbV6lPR%TOT*D|%z9s&тթSVsmܸ1P *"E랆j` 6]&M?.{pǢ-mhˊ/lْHm۶H}gnX~Ԣ1h"hv LMUBE sR6ـޅ:$^A"We+qo+ cqqqtN:itA6;>y$=%MɂOZMW)𛄛`?gcf̘1ydUcG&$¡?ӦMss6D0K_ O*p.b:l=^K,^z`~4g&B$qP2Bzr9 (DلI!q؛١C* S[&P]9`f(H sΡkB?V pkرXE̙3t.W^!R>c]$D0'tJ+T2!wgDP=z怂n]!eQN,C q@!C :f gnݺt邬`uؼZ&TmcK/ՐR%"1٧ܼL %*= U&̉k4ul_f;wnp_;G-R?|ogCH'W[LO>DGOz1 :KppqLRJu֭ŋk7nܾ}۷AvsUl'Z'|bڵ^zȑ$D5Pgyw~d\$(k׻ Ԣ@¿9s佈bǏw["5jԨ ]nׯ_G/A<)*W\UTٺu+OepP#Fh*/J={6\! 4a͚5_~%;<^jQ83`VZ5kLǠcI<&[.X ~#J'̗/:>M+7g׿\VȐ/ B<[n}EKaiA؝;wynh(kq}_vyE;{ :@.J)q3f11APދ A~M i./ ._\ݻZPtidԄ=o&$0` 2e" VP}YX'O͛9>>?azUB7n;8J(bprWAS^4i׿fAz 2K*Ìz]UX͛To1-QV~ F%PHaTȄp# ԫWXz_n3gN^)X0../_>zhXz'3!*L(O"*i (:qjݰaG} ii!m&,T8 ;G _rlْgxD`$ .04-[6W_=u2WEO(8890}f[/B^ baD8z&FV#$OpPu85Kne~ёXNA|X`qݻiC B :$DdĉfsQ~V~a;w,[s+WΧM[9C t>}hkLى` `*REPhQ`p֭QJ ']?Pø'3cx( q%6tu/RzuIO8#OPb4E-RȰa.\wo֬DjPpaӻᆱLp2Ǝ۾}yM>!+e?W 4iEÏׯ_'5j[oE $ݻA$1YfQ r$% Cy>gh"iL>;wxALI&_zPq>LUV9y(2t(a|3f̘)SX/sEǡW„ԭhU`ٞck:-(zQ|0TO?MdRre>3[`ӑP#Q?5d˥7ʩңG7aSQGkСx%001bذfk.]ƍ^x@<~6mW|-‰wׯ_!%a, z u"HgR !/ڡCw,4VB=0ȑ#61 &X{R8A/=C3 ׏L>=Z{ P):u%ʧ4-G ֭.@ K.:ԩS4u% k׮8qlC/G٫W/'W/ZCm+4.߾}*[,`ҥK1.}cЎ>`<_fMeLA$k@֑j۶m5 :נAkg޼y3VkW\JӥK t@kؽXbq.=rN!48ڬQvEm55_|ō7RC '-CO?c "շ~@A .A%~07(Сo:|TM1.O6-dɒxnݺk^y$>Ex֭[!pbMk<@ :3HD |.~׸נ6_y嗉ꈱ(ٞkDRTR:\x$DV4guˍ*TaÆ .៑9m/zrBUQZP͛ǝ;nXti \Q?J'(~`6wsȖ(~fŅXn*pPZa3fԼ;> hNCPN0E 3cΜ9ϟ!ðyиcH8x`Jce.gΜRjUt!q7!Pۙb~-[6EϚ5UV)# ժU>|_A0Im < C8~-v qǖ5H,Q.@Gۮ6ϢjV%,TP̀~<۶m $@:s+:rjMSzZ \k:uD$  Aٲe9s&> Tp(KR>7zx>\94s?`͏wh SO,]d L$सg Nü!>,ꃐ|b[xNbb̃"&"..m&L%=zji)}m̘1 zܸqD()2<- 2yWΝ{M'' (_x… w~Ky]paҥYAqAB]hƍi EB H+ū@>HS C{!DFtyȐ!зFGtvad/1Ahf7̙3]ߐ Q5Aq͚5 H#FaiM6HcY&pG{w4׭[e>O4[?nIxpn?9bOߤK5w!gz*&.ĹoذAӨFPB<_|UV03DCSZQ.rhހ3Q~~t$VGݱcaw 9c*HE 8z{Ј|yX=t ڦuB89s9rVe@ԩܝxJjOa- ȗ/:} G8N]q#F` d"R믿N\p?8L0 R6pٲeq oR,'a P:j}Ӣ<ಞ A+W@uFsU]L]B%Xur'.>LE%{ A/b D<8,xf2e^ i⥄ӧOk8G}tx@ @!4_ fO>$n8\!o޼,9ȍNR-Mc#Z`dh/&M+IoO(iCaN!AdӆXC0 +q:Z9‚tȖE/tXFW&MjѢe 端+۷/ Z֌3EatuOdC1bǵ @kj_zU8l)' )R ux>z) ˨<YQN~iF{dH1ʕ+X-Ğ+pw> ]!G yE͚5!ʈZb0< 2C3&}PCn$СC!R]vy ҃JwQRӧmڴHi͚5SriΜ9 )Ҹqc;v+ftR`,N*)_ITgm t ;__hK,C'lJN2p={j=#]vE'Zt[KB[Nذh{gk;# 6|g`º c M  EI64_ݛ󜑆Z*:֭qax~4/w:FǡkcY@>bx nNʑu\A ލP6DK.iQ"``ʔ)^BLd @r̉Jsh+Bt9nH>γ#~9sf0jժc5wܩt@e˨@QPXfUL; 륨CSTZm* b¨Q F <3-[Ԃutp"W7Ȥba'^zAAxiVE೶]`X/ag}ԩS aN2C=ʕ+a`18 vۖ`:lm۶WJƅft@p34?<}Ȩ^Yu=C FDE/aph.]iC {6ns_RC؊cJt(#ĝ6qkM2e0Æ yW0xS%2 ohl ߽{$lQD *ܹ37ؾ}{lla&1w\Q ҡ Ey txa wxUDW?wHI^B4\Ͼ}K쌟+`@JHEp /x@(54=qD \Yh7%8 5@#F3Z7]tн{w?={ \E. INg'.i8Y)Q @&(ĉ| .c]hYi%Q%cP9r`Hl~pD7V#a>-nHE/ E虵ygL&:PB{뭷̗_~IK}> ( 37[/u*'| (i xtq?a| ak78i&d<ɓ0 &t `9N2!>, &4aBXdBI&biE @`ҦM;i$ Ai@2X=Sp.c!`[#.- g}Fa{쫯B qԃf1хVH Xݻwo9Fdg19@>kڵa.rObio+u֙t?HT` 4iʗ.] !]vYC `*.oؿ:&M@QF?cmڴWrjР aϟoE)8k&U>@7n7׹706Y2 |?ggm6OClxRl'*'0gΜi H<P=~"($߹sg'_7o{!3ȮZ Rح[7T޴W^xpd:L[݃Ơ}}/ٳgnQ1|N$e_p:+yLӗ/_惹DY|;J 17nLe˖%BkpdD… ӧOϖ-v7i5 [N@jժ}֭ &=}]BGYf@Ȍ3nܸAExKepeʔ3e˭?~:Љ}o.,Woڵn1)u!1Z _O? 5 6mڤcn#M6]~Gy\ȁmC[nuÆ -5kVXq9aSL3ccc\B | 6@)+^|P޽6|V<"FpaА!CΑ_] ! j:6$_wÈDIuqL8?8D{ =@¿q|~?G&M50[)[[g;)،"ww]S8OeȐW̜9B`!2'pNxL\v- J3ϨV>txayJ; ;e6J~/^ @y>l帝"[lSV-XQ۫%d:w/<kAݠt>/}5TmOaԙʕ2q0 FޠA뿀 E W"cu3~> UU,dСK"5} 4E2i5ԄC_&7o^`L+Pt/!U~͕+ icÙ2eܹ3PA!E9t0NRa jH+h }mfƃ<:2B 6m 5Iﱙ F^wc-&P*O*lMtUi~(G(\0|`, ! J,ZzuhM )JAۉCAr=珡/)FA ڵk/wR  2Ď{ $ںu') |wN>m l\% ?\_8peo]|Y3gΜ9q('u1 Nstヒx@BI!?~h(J:w0 8<;wυ hRIcJKs^znDk׮%/QDll,".0SB+b /^9I4iҠSPhӧeVT >A:G3WO Nf լZj߾}ԖWQ qPSKny_AlyrP( Kn Tǜtw7l@Sf Xs򗿀4‘[hȖ-[5&k@p SN <ѣǏ[ \`MV ,6nHTgϞ4?H$?7,^hѢwBL,(hٲeҥvGDJEZ!d~+<ƌ> WbJkERiJ'9掗Dw*@6i BP* `XΌɒ%'¬=z0uDVzuRa)~=9q%(~~H楗^Jhw׾}è3nE_b=NLzVBif͚W!vDơCX? O|͚53 ҥ wL8}tgêW㸇M6xI|7 ^W" _*[… |Eqs5*x €m۶QO%H,ip_*Is0^z,Y` ژB_+@% cH'!lG iذ!z!jԱXV6`R>>g5%PD_GQR 4Tkymeuf͚\*{|ҠbTǡ4ÆrZ^\R; uAiiE#k /(u5j5A@Db!U:G޽{ac$ouȐub !nI!U&ݓ\tD9#.q\(|J*"1SJE̓МZ+9T I U+Nq^/oW$gVtn)~ &~EI4+HOu3χ_'PO<|MG6ƀcŸ/G ``q9D*{Ƀ'P$@ffq%+7%4|'P%lذN^ ͧNJN #x @D)J֭@&X _.y"cq\b˗/G >hB yFDT!Wll,' 97n( -e"* %]п3gV )d.]:(LkȐ!0T9wcǎvTMA0?$ТE _`TaQ;H\؋B^(f6l0 H" i(kٲ%_]@(at}Tz̬v/D9w$C$aqɅ 1B}nES3̘& [>Fkwjw3QFvMI <Xs%.^3JP(݇o8rGAmݓR<4@Tl. :uj *[!l=)@#|@墰-"`SOpW%j$@t[;"3Fۺ#iҤ3g͛7BŊg툒q=6+0M,HSw)׉gɗ/O>k׮6<uwzJxA2계BPB ҽ{%K4 h8p RNٛ7o :pNą/Ď&L V\ϧ}z0'c"CASO=ТkbD`RQ:T&6mDA@,\@z=Wus}YPKheF nٲP8!C*tbyx @p_ZZFe˚]:%VM4 J|Yd`I80n&<Ah^.xZĂ@jrꀈC˔pȊ O[BsMRPFA5ދ@/xD|.۴mȑDEelT6oLEL=#gUhB bQSn Q| _ŋH 01\'H ltv3\&vy鹰jqg 3{A@ %Wy/zff|Ε+wذaح |G#=ٛ8ɓ gn \/K_=Ŷ3hxK(Rx5w#RԭSz:P(VT O(B-gPnuW4? hb-`i۶-z]dpQ!@/7n|1>jj Ւ~=2WcKYW0uL%Gr'PBЈV;a{–<ȵ{Ν[lYhST!N&/᠐u *KpǮ9 4htP޽bU`H4))N嘒FtSؘ!2c9>S%d7@lV6?ڃ YE{d=Z86OwFcbbz&@1>eʔ)Oi=Z9s.QAŊ} ows \'$΀^6fa Vڵ;u4uT(O?!20YQZ~FC5UKDh+3@,- ="j?$X[@h۠u"X;G$cuOK13gZn> } 1(Muݻw]` fe4!&9G+r5O؂!L K(aJO`5ܦlЗRp\h9@a e.{p]˗ _., ЉƶnI+u֭]vͻxT'Lpʕ#FP 7CQKbt4_`#:|.X1Sʳgn޼Oߦ-{x~piڵvZѣqvv.T+W.ڵkǏw|Z|10[l.\}2 Ol0;w`6MQ~ ^+4J@jg뼵:6Cu&Jp$_H0O(Wa"ȳ> i(Qի2S.G`gQ$N>"7>۷o/]ѣ舾~PN::thɒ%QP? j?cZBs̉S*XMDnV*]UR%k֬ׯ_oA۷;Jm9r H[G< ˇPʞ={c&!mU׫W;TYzDijС99SSXBɓL>'YjD H#94뤌I!gl5GkV'C spw5_u¦FA 1c4fe[ ڴi'O73P~~aƌ@NkHk\,xWKQ=gl33 /^\_j3~H[G džضmW\3*U4p)SѺCV=*u0)fN+_  :03Bzvʿ wY)70aB,/66 >|CRR.]'jS;gb:-˗/A7gp[lIeFrha4 =[hQ q`8&4҂z0_dKa lDu0yQ]Z`lጻ c ٬"EZ)oIԋp0Ϟ$y5Խz4mtؑH3Z;mլY3xkd܉R@Ν;._;o\TgH}ӦM|%~GY3% L}m\2sLZ(Fٳg99Y_V,OhI$32!Y ip?b)&l'x}Djk|&+ W vXjuSNL( *ݾ};C`JB=M6~]lz=@@bŊD9rXz#GFբE'Np/3gL2>}zI  |@/^pd_A1ʕ+%`y={6Ŧ4ŤI._z7 b'TRvmnݺurM}-VrȚ5ktU;2)3l/*QDm۶Y-ϑǔ⢦~AbΝ-DzYĞ={~ѣG#hLY!k׮floF;wnAZl!66~xAl pW_}"żyMS׿*WLK '?裏xnu\ynG ~g֮]Rӊ~Ұ~z@l2șB`$۠V!?4& 8L @pc!zSs]k+Wq(]˦Cy _b挃V|ZbEJp"o*1-LPj㸑=UO!?9@sÇ=j4ӤI^~i;>?cl?!_K.< |w @eܠ;v`-8E:ޣ"^g) `P $r@4xשS\꣓/5j%'N%Kr8"@G"8'hD 8p/sVoҥcbb:uU\ πp%Kŗw09ZBq FQΝSD(=pD PQ z.c=/tL{`s;L*73zGAA Q2Ȉ$9IFr94-94ԀDA$I$0* qP;zvc?>}j^^{Ey-*+7 zs bݳgA"dR>?NǼN+2~x&ڵkB~2@cQm۶E3F;vFQ^v #13u^z|?>oVlIUpl:uFΜ9GKM;:˗ÅwU˖-AE߳#N{-w Coeʔiڴ)n LGS@*UԲewA=K= [ *9 %뢎qO%;f… *P.* s)3g{@,ItکX"LN:Q饗 *Μ9H> NqƎ /An>}ĝh%PBx1v*|% CC"=QzLm#Bqp[#,~Œ6xQ+ݹ| nAn6w\"##-}C=yTcKSIN}TnQC.O<,'F ȢJW^a'x~;wI+RE_2/u]xq͚5-Y`eDD{%$.Y#ZxqXnܸqgϞݰa>)wz Y&kƍC]'@T,\LP[fΜ -ZԆdnH]lYgbIr L8M:Uѝ pn$PK'ٷiJ41:nKjPş-c8!ṊO(s\OԾ`ڙ͹wC7x‚b7 .Kp!I߹Kv=fiӦB`9pV#MgzN n?۷oH>}<k[F <O%+իhҥKm('jA(K.uoPbx֟AP|]veD ٭Xb?8_|tڵkTK@0Zꫯ0|(q}cša޹sg@GTlDALLL۶maQ.50=/sEI.:!&v+" A43P~8M8իW5kctbfȐ; @@ |] $Ι3?.`G  Qq 9(Y9s &~uƢ,anxb`H p pv:S7"d#T D6 44 >Cj׮=o< Fbɖk4_hz*z, jAh L$M<5j;m[ +V :gϞ;w_34jԈF۴iB@A8p֭l DmT ̀^dI*3zwqzgv@9X)`BL)GHE 2;LHACڄp0'> AarA[`vQ%1kCR@] 8z(1f-Co۶ ŋ1~k+#PDN+V .]&M={veʔ-ZAw رH n`q_{52TYMftϱp|0b| :;wnj*X=l{lݺu"E0a׈#PGLmTq d~=G [d͗,Y?2Iڴiٳ3|<>%K|0f1ܕ#G]¹W2 >6SH`[cǎ-fwKG"##-]^t֕SJީS' tnpnׯ;w.M2s lU(42b]R2<$SWyJ_m$xr^`(#?\r9spy{\`/:֨Qɓ' p袧U|AeK0|s<5<ymڴ3f. a<8n80(Xoݺ5[l֔^ W\@)EЉ'`'wq}Jl2|n.a/^ܴiSدriX/0`ӦM@ ^jue²P7j ݰA3p{jB Fx,nvZjIxb3fHyaWM2YիW/WnѢ /Bea՟ux{z<0w₳щ<V@P_g1~aj?g"-MHI ܅V~z<Uå_(Ν;C+ W_}գGYf2؋ Pܹ͌t˗O:hE_>~HG/^~Zo4kC;3HҎ;m\Wts1h~|_fGeҤISJ}K}˲2(Lѣ3D= 6ߟb/|pe_h%pvqAi=ŝ}wOA3y x㍈4ik7oĭHuqҕ+W4RFcMyLZ8s8vhrͭj۸q'NYi;i~!٤IZB(ӧ "PVy菓imذA%?Dž*)X?~˕+Wࢽ146& <` &@+WB% åZ2Iբ0ooرc|Hg4p c7mڤqƥMA :o_|EHScǎEK*D3hzCq% 4ݦӠ-Ue6o޼qAU@}a\CLժU_ըPǘ ,Wƅñ IZ%pFuH/1b߱܌3l&xl }5ND_@y'|D21G}폍쯾g}+_'CCE'Bv )R%Ro[l`'QAy$FWR"x /(m߾`<:uj^EDDH4UXի 6L>3gv "y7X߭Jn0VaR"?p]vHˢiҤQ nq(o ڵkTD*{/whל+;b QIsx`ԩ?CaD#w']+Wh+|>z΁ =A*gw)t_tPŝ֎.q 4 :`82YaR x~iZQgzF/ԩE\f͚I[1b5£Ws:vqqj\ hє.+Z(H :'<׹M)RV! uQF!s .+_Dz$o4b/ z!]B0Re-ptCxceD& MOvl޿ E0l@3s%K@H7p.l߿$&ë¦MgnFH& a.\{hhp'a19^` FN;^,acyC -RZGʆ:x".De˖3O & @$kԨjz*Cwܙm<@A8عs'?T`Yy$Ə) ݳҟ? &}p # 0EV.1H<#HM'I£nz b>}Pd>ӭ ;dį0û쨳)"fߞ7zzNw0mUdE]jժ'O&޸qPB_};+W0gb}UҝaC+D;rxha4=ղ Ǻ͖(Q>@-Q|݃lFPD(ڪ/忦M" ɇCZ .QlǛıSr_wk"&?d:9bh:u*՟G%W^Y`ݺu'Mu'M4@u)٫X"b'm[[( q>I WB1cΝ;$7CXv-QVLĢ2,⃾bUkKC_cblذ5k<$-\{ۧJ}\<ڮ];Р%46^n{G!iհ1ѯ+BDFL='Q`P %0eʔy)S,Xy;2/^a%_1g2q2zi?LGn[M6mժmCl_^>={>ͭ!u@ 񚻢E*+\vRn$Eyΐ!҅Tzu Bz#{6]ٺuR28qB뙶"d{'.lȑ'gϞvԩs4. O0aذa Heƌ/0Rh$MP Y?ƍ1- L}0p7[Z5`7c)~bs|-( κ%ؠڒ b`;wqCZ{TNɿ`>i/U =k֬]'VSi@=+ qb@ԣQ B/CRt.ADu"p.;UէOmBm0 + M4ydE;ƴ8x۱7C@~]yH h(V',\J$.p;);.B^th"8S@Уm80T bN u'Ow ӦM0`=: 1(GBL0}*vأG5.$; tu/Ui NBF#]h\&.T=8d"|>,X&hn23gM,wN駟2Fe#y֬Yw UMPhLa H˨KB '60EID3f Zp7|#p;9g֡5?|QZﱅ|A>- F,:~0[*&M,YhuL]v=rH֫sEgq&O%\GիByoǎgg?W>p1o5k;F3ZE~+}SP +ڧfԩW>޽{Ϝ9sqkWH(b jA'zfٱcʕ+C`"r'U#;HLׯ_/'P N>4H!\b|p=l9 ⻟:u 1Rm/2&23;wn~:Z]u(I #F{d@˗/?eN`hv:|02G?xj@؂ .o޼e4BC;:G۷%8Ĝ4Po۶C3"L os\0֥xڣZX#ݡO!e[ϙO5oޜ㠧gk V/ڵkXw/&Bchvb4h:xœ@U&S0 \rwܹJ*֭[gMŴ/)E']=Z;ÇapBf0fE#޽ .*1 |ɬʕ 73 ~ RBq L}~B#hLJVZ|J `gZF1$PH\>@scg`#xUZ u>@ ܉D.u+J0X8F7̇n `zgwO1QHQFQ e9C|,Aވ>v옒F+{x'esbh4;(!ZϮ:zg3E=2 2}Yd?W82Z3K a|^|i6=y"u̚5 oa wNE|E( 1116mﮦJZ B, [V8|0D>p -]zuA?.ToaqB(PaqX&w 2}I䗉;z6qCL8otQL\7MZ'>8q""#~-u!S裏k&\pTm/:t￯=2Xlذ^MøZj fu?j5GxRȰ=3%J`"{r^C\!z|fP|b""" c؁p$RJM0Aǯ aR @Zp&C~GQb bɄvI3RBף+UÐN==`?i>ALX݊LqX谟KإKX5# X(=%TAx@g$y)FCಠ6lp`_~N-^ȑ#:ET؁bg{/ 7^{3gtĵڹs/t1Fsڤcu<3\XHǯqz[֮]A$ir7ٿib֭1>}4}"0NN0/a<`N:ΠU ^qxsJ)f <A`AB~~#G(ݻ78fܹ &=[o,4DP+Wtd@۷gc'Oz!v{)/Wɒ%aSNa9F zl۶m8͛70_h?bNW8o"{ܩR bq!Qr[(!Xnٳ'aqa2(2qVJ/_V`]{:?>z0tҥ0h=5caLL SA'H@Z͂9s"]L?w"@~ a֎%K0M(B6 Ez _jԨst6k,)GǏ'Z1cFpA)mĆOKFwJ3ȴ4=x") ݼysŊJΙEX(|)UjVZz[.sdQ‹2es2(r߿aqC7AƾgϞ%Y |n`-Ʒ3rW]YD za>#|)>1UsDwpgϞ}IL/U^!6V&@*U':u -ZЖ$EaZ8:rH1jkm֖5ttgB =ܰab2cƌe2"O-r A"wRY<`U%杖c<7҈`r: .h=(M6ܱkD*;=M1f}wR%!SBD!.=ևU= %@6߅`X_SO)eaR?~Nǵ)zҝ[|!Jl?Bg8XhPBӦMIv֭ /4Qd} &z¯`'h޼yx: woȎӌqcʔ)IBcg+CSPtUDN@:g_@.0L6oР>}zwdܳ/?Nj` M4;vdSN%(gYX1+ K ^BŖ/_nI\|C Ö1 9ēm= fDDo۶ms?%K䡩q"1sxg*TzƘ1chM6N @իW(i[]bF0$ul]yw6t0;:b``XsӦMxLiѢE۶my@^{ `b&M0F7gΜ|^~]v֌3@?#<c{8 r8g׮]_)Sݻw^jWCG[={v&t!Z;v,NJ^z,\fMpzj=K#E>gS)Eg*μwҤIF0M*ӻ\$W(9p<ˉ;vҖ @"ώ5ʎbZv[qt4^zG57l0Op@4Bk֬Kak-hР*k7 eCܟ AyK*UΝK9sĉ_|*JX"&LoK>}TTf<˞aah˵,73" }v}u!c)>L6'9˨:Ko ª?Sc%xT2nEB(;! {+K$V ,+M 0*u;2r>vQ2ܲeK .d⼨=K,i޼9Cgԩø)zpӦMy&C`ʕ+_?U-޽;_&NcȿƏO; kԨQ6ms?}ts`h֠Rٲe͖' oX <ؿ7nݺUc `iz?@-0_*UYj^PoӦMVmPB8p@%v+G#'d1b8RmhoРAhH%L-tۓL=|N)$; L)14Ԓ{vaiO2{ qEǡd.~SOɢ!Q,~Ik`G@0%J rr{px| BO?sΞcsA=)YO(: 3 u&M2CxÇC_"j$#+UT}7o|̙;v̖-^>pjժ\ƹsΘ1c` *Ew ,klmBCJ>2Xxtޝ6lz_\r^Jk` w*f IJ+tC"̤ƞBZ`LL Q]kRe  E2rzC-ݫ*RJM˟UϠ`KԧK]I@#M{B(=K.$@B+"#GWv#-0̓jc$.]0Ҁ7h6ד3dȀVE"Tm.=qDzNN=[ {?v})q'u0` lm9mnݺM y.[̖CDoKed u۷o˗/_t) ,hPɬY~՝RET!gl)˸ʨfm6c0P{|z[ c;)bȑ.]:vرcׯ_;xbl^=cM6gp`J ApL̞=m!## ;Goڵ*R->իWGHH*תA 8jڊb*L/իV_9J™4`/D*@OUV4XnÇk4uV%љb_+@I<_7o<𕘥i$G{ ŽQ7hk+ u?>~, Aˣpw䢹L!G͛Qxgw'!r 6Fq\( MUvZɱ-> 1Xje$NzV E-vxc4 G9b'M$+MuzT)SMbhMM-CؕWl+_sA8 =@Hoa-ZUHT1DxnVR%z;zh Z}u޽ MWN7|̘1q[[ [y͛mi8GDΕ+P Ya~193kHƍ'&ib8%7S1he L0 UICX|ܹ[lpLɓ+~7nٳG)|NAE %KRaqAҥiEsH*bŊ+zz>3%Oi[7P$BODY 4hƍt6#To#0v) n%draoǎLL0bմ4aa^yO>ē@*Ki%gPٰtWp>\_GwcwjD`3_k]ʷeXH"B ǎ >+L6(|Q_׮X1p?~?ch3sIo_$j=TNH*\ܹ[n m VULƁeG{ )xx)dAo 1bD6mh׮΍ 3%KMPe]o߾N)iRhxs+q@; sN*e ,=|wo>CCvϿyfTmKJ XӧOGw FʕyͮC[A ΝC'ꫯ*M\Y- ^ApjW? 뷘# ?5@&^JnePYnFJLKп@uh M}qB-:ĕeJUϜ9K(ڵ fC|T9+5iy3 va0hѢ8p ԩ322/6l𩧞Zp#G40!섽H GĐ?`H{gΜ'JiL5pm /җzӶPa=| ŕ~u%RރhB@F19*9sf﫯aklܸ1jСVB_BQV4Kb<̠[BfuZf ԒoOҴ7KME³e˦zQOɨIqC/^o ÉAτ6d?nc>sv>JT`*x?yd-51!dt)<>/ׯoI(qΜ9(W&[᷉7Л)U`ԨQw-b Jdy&nD3ldil'\A(={VXh:~'>(ƍ2d_xMj j*y?<#@j p7bα+WlҤ <X/SL7ݐdktUFq`l$@"e2 йbO_jܢJX{&)j`F&Sׯ/YijԣKےT7 (p%fEi͛_lj{U)҅c+Sm5[lFjŨ0pw֛7H 6^961 n-n=|0rm\%HgzyfO>/7ߔ]߶mՋ$'rcgjm֬Y|zKeB ԺuL21R){h(6m̚5 xgnVēףb9P_OEWY7lb˓b0an7j̙'NPEmuN1(8 0o6`<"V,ҁxƕ+"/:w{jL=G^|Yf:$-k2f8rH *6K/drM y/~sW cǎ?nڍE w!ȋWtRJ0 ; .<}4\ʡAg^vm>(:: ,YrEM:믿*U* ȋ0HJP^xSN@vpˇI  |wWz7l ?33e|T-\0s$Gp-[U6ɓg@2e8r'/7bӦM5 Xx xR,yC=+L2#K|q2y,Y``Zb-d:l?؅1={1qp˔)ӤIPP!.6ǘ3g?޾}{^_0I9tpCoM.]3f`1ȟn"wNʕv0} =X:p<ᨨ:|D -eREPN /UtFbQ*B}PbD -;{NɺCpM[04۷/cK4eFm`Ą,X=N?R &p>-0?R qK:3dPhQ$"8|\ \Eߴ4Ki:~8lΫJXC\dT|+^m0{(!V_<сJOB_H= ( TrVFݨ ouCsZtqsVW?g`ƍHv>B¯B'V_yU1S(z|_QI>|87]Rf.\*o# ,w-l -HNŊcGvIT͋rDFM(&E t;vlϞ=Qh[͐8y.-X9n8P+8&L}dPm۶&Jڡ< /Bv  -[BV?O.ƞ/ ܹ͛zgx5]Dٳoݺի/[ao8 p…kϟ4lw]xs=)G" YlL`y={ N/~oSO=F/X 20Twx xڶm"ytЇڵkȵ<{8AQwذa,F_ ρ̤6".\gN*(}8ț6mZe1\ a ! >Q(b 2vXc]EbΛ6m:}֭[#x$nN77S9 vڇ mڴЂ-mC!1̥J;Ŝ[z p4V2tU@P ,Y<BF"Jr!Z} `:rJp_* (D+@O@(gY5a;ŏ߿Vz1b048o<8N#*軕 >~G/*,Xe&O9URUO@Qƭ|`$DƳlԨ-[ [~} ͚5T(?kPZ55jTk֬Oxe˖৥K6lP5-r"m1HBH[Qȑ# *0ɴiP\ hT3@-{{y<4SgZ})*XÖ,p0?** (X|Gm-Z={v׮]Ζ$?tx8h޼9"@T$г_Yr\> kCwߙ`i׮j4"oϷ|%V"C hFsua `EAØ1c?M=S.'RYmذA $ ™XNsQu\zuU[z_~P$Ɯm۪g"qܙ4iF:t/PLWC4iTXР5lCX|yn UV 9rd˖/&b%G܂XH b=_Ԣ0L}UB9H bۺukQny [iO))SJ\ I_ .] 7nogkn[z5}U`rCi%X\99{F8) uOw'?J 8ШDžR9s&ӧ(̈#T7⦠6(U糉E2D WW„ arm:ɞQ+Wرc֬Y8`n7-2 C7 ʀ{T}H 0L{8 , A `"5"$͛@0stӦM I?b){AQ/x e(.nƌa$Uh3N:ӦMsK]cѓ'OA&N)T7l0)s\fȂ1_ŗڵkR)M6J}G0/|u4vtM = < ƍn:Q&[|y~o|'[ACQu 4Wv%._bŊѣGϝ;̞=;rhyʓ'O:t<NΝi|֬Yڪ <ǎKI~I e)믿f^RDN!/~!xs{f\pa׮]gϞ-10S|:7[Lo߾E(Z)zxN"5L^A׭[Ǔ>u7{pDQh͛ɓ6o;ĖJS=7|.9ArHey$y.^a8q"϶l׮ސ¢\a9rL0A P1%?RՁm?3h *\0Lz\xQ3ciӚp SQV Pkx>nzBJ.=zh{ڵfXV)щӧORuc< ݹ]tJSAj# ]lQN)hwtR.$޿5j5|W&:z;ww}'CKA$EI۔S9sfZtׯ>iA5[Xjy Na^6`=Ի`Ç ӰaCm2eZlD>[x1ޡB)3R1@sA(VdI ňo:{1cƌ^EjTJ M4EF*XEicǎxGmUTݪ5#P"s6/ʍ.3 Vn&,nCٳ'}2M4H#ƍϪeX~(Zc( Go!AܼySn? 4AZ~Vl:01pf_Įw4ѣ1-!˗/WGVhM?P)Z)O0,%>*%(]ڵcbb@L1T9(ЍhjC 0z *Փ1tP`_X2MĚ-_Ot)0w+NYf/>.1e&MRl8}խ[$-{ŵ/ Tzg? &l{F+|4*~kN2N:N:*z.; }aõ3ftk0|-۷kOkݸqc7$>CFABgv}Ags;wnHcǴcY͚5yv/zZrqc;{|{|w {Vlp&%tUV)D C=c 0v;9tJО1>-J:534m? 00@3xA1IkinqEU?jn"֪[. ȫhO|BKM٤s]v/06w&?nԨx-[VE{X}$ݻWa4x]L7k.sN-ۤDALnP/w]Jv萀{.ܹf=;3μ=3۶mkܸSO=OBskSN>gI* :Ge'OVFxױnR -FzSm Ձb[`;Axm\p\χVZ)4'1KOī5R?q [e |G{3CMWZMkآDrB?s^R%,͛7MsQ@`s$[2c m4rUVAӧO޽W^ZW]i\GXʻ0xӣ}GyqֹCpE6&>t\#G֫WjZ5[˝;75** o͵`XUP^3q؉h-R'0Xs-Z؞ҥKϞ='  , 4C0`}TO n2nܸ+Z2pP]v111?jb;v"22?SW:uZf* &رc4"""H{ __f .3 =/dZ N/]Tg<`nQ!C4hdv-ś >l(6>׭[wƌn4Y&7}&AZGhHziS0jGLCNfi`&Gh #LիWpW\) }͞=`XF(ܩ֭[ϝ;I&iӦ d ʛ7o=}e:n9M&lm({||p2eBwa'z_^a /]c4S+W4i8тk'fi|6lH[)7tݻrJ.Z*dXV É'm-͛7Àg-[6?TGَ3(d֬Y_|ESb`[Z=mtZ#ܥ&[Z]6VٳKhB5#l ͛7WV /Y$u|M6 ܁;s陁"D͜9SjJM)fa%WJ_oCڸqO{ù!uϩSN ,3\0~v{O ͚5u3C,ɧ\x1œt;22R!=5QFttЇ^zI0MWաCF€D >}h};C92 ە5k֨P=P aRU /B&XϓoUVXbKd_3!**/S R|Ǝ۲eKv!(Ynh^p@ك ebdSUcBo]EGG˝ blF6QU `@65_>څV$n"""6nܨzXb-{a sv8nC6mTJ"/ة? hᕕd{F K۶m۽{7|h7P&pPZK.)a`ncZ"͚5CթSc t2q8} ' `㩷n&< ,1$ 4  $ӎ1bJ xq=!h Q"X 0hn^x…{LAܹۡsܹS  &lS*/<"S }K\Ts1_+v1_sj. b$THϞ= n# } HB/D5$ݻWgy&&&fҤIZ}g}-k֬:tv^&4Hq,Xp|pv\ qݬ]atu"""@(,20H 6{lY [15@SXPzҥ3g~-ˍxL{ cੜXױ=zՋ 3 ֌MV߾}˕+Oڏܹ""ĉ7lؐ7o^8$mڴWVϜ9S w\/e˖JAC o+FO*lٲMotR(ġ ޽;.Ny3@̝>}Z:]0zh>'úZF 7#^`]"##ۡ&M2@ AUP_2edmv]D;a;#@ZjM<~^kX52 (v֭[RJ5m4U.ZUx,pP1chvZht Li n_`U_(B "-1(:F.-;2 ]hJn&sMNU^zIiS-G,6|ȑٳʻ>|8dB ŋǢ4hРk׮ եJjڴ_t'O[*DO)S7Sv[+jg1b~Yԭ[ytDzƍ/_afM'}(+zg9qℝx~ժU f]ubqvO=^߱-}Vq=US;C)/_+WIsyo_*TR"3;KoKh-vÝ۶m_ٻw/MUX1IR6k֬_~n TT.ѴiӪvg1ydIVؑ _+e/XUuJ0SgtZL3gFFFWJ 1v/YD$߹sgZclp&^~a= RF^zC XP@=8p3tܐ?~();`Cc߁;vܾ}{5\ !up vٲe v w*ڷo_-ѣLǎW _I - ]01|ϟ/J%7ӌ׮xwU-;ҤI|r7,NrԩSׯ_OΞ=k94; OP|d7I16)٘(nq#N8v^zu2F[˹rwjԁ8 \RJM#ـԡ+*q0Wt[+OjWC%r@g<.eGyyk֬iҤuq nCʈ>׫Woذa3gGF :x*`V֯_A Ӿ}=X 70\[E8q6A3fdpSLQzfoݺ] @I&!C'xbÆ it+*Fx1sLa׮]+т'@ `g۞@ըQC,Eeh0Jow{-4R .Їeʔ[hQƍmUw13n(v}Ůtmqڷx #N$#wܟ~q}Y ۷aгdXb'O1Pqz!/R}e߳gϾ /:σ!jy̙c7Ѕk׮ ?yw(y\׹6|9iD)#*38 2b@yXPZ-XZ1ƚؘ9IkLd0xgfPuo3gurrruVi3-D14ݻwCgUalܹa߿&u96x<`aa-[$Ԩ2kFL/t٨/0\auڴi@0P*5 $44TO:rBB@]h׬Y{̙իW#Ӡ°;w.>>>::[Q~Fu..Nz~p ௯J^zacnw 7|HDD| dRKuƞN-Z ~.] ?@rssmNFM:"2s P6m%3 8=z(**6laeM jƍr);)ݼySj!:UAKTpQ#J큠$SaG+?wfeea2G4|19!glٱcOʕ+8 Oub-ZZ0x+W,Ydҥr B7:}t>}_~_`)kxS\aٕt;$Xtt( =u@@j+; 'O _O`[Ļw^'K۷85-[AFM6EEEXVZ`!,u 7 СCzMRQ@d;-V.8/غu ~aŒc_H߿ʕ+//_6M=j=O,Ҙgfw=//O6bZEMꡌ1l2իMl/;;;22R6I|TRRҿ ]PX\`ͿĚ4`a1%ѢEK $v44'SʐmR yӦMʅs> Vu=͛ӥ} @4h%66~ZR\kjMÒg3**ʞQio)T>|ܸqbQc G& a2̛7 I/AvEF|&M>Ikkke;Z@I#--[#ToRɸ/2G_u<''GIY|cbbYi)@\˺,c{n(AAARF{'Mo W[OJJ=Ld$jD?zʕ+YĉG/UTT0˅X/8bv$ٳ{^x1% #>@pA`x&4AtK-Z7\S* (k֬Ot.x5/+@ܹ|%::jܹPX To7r˗/;vȟ}Oա8 dD72ݭ2 ?);## m V6X\RIf2,Ak׮gLn J?FZMf(~%Chyxh#Iνhk ӆ윖gffBAoW&?ɳӧ3g>D&c ;*Za:PM0!66Vi2Rv x6%4h֭[ꒃCYPP=a C-//EA-c&WǥL"VIr.AfΜ)^\\\\iӤA4sǎSrS5f`Q~ꩧNd &&&99Y6a{C` .Νcv!C9?_pgjjjTT7Oܤ ,++K6F}%(|I$~N;vs@=Cb(--5apw.ÇA@qFҥKbiǬ^UqLNNN)b[0g̘`Iz-ZxE nPP۷o7|S#iӦ h;+ԍ7pK*Fv555{uu5+eў͛7ƒy|8$ s̠A1Wyŋ3 $** Ĵ4 8رcѢŬ54޺u oEXXt)`ҵk׆ dɒ7obUUK_w^Omۮ_w7D'N'c0UTIJJ1]͘>}:n:(qy:4R@:! eYgm9 1 H8er>jˣF:x`^^.汮]^rP1-0^7,Fww0 `&I4<`Gh_]s޼y/_ڊ^Pv bAT6iXU{1{찰0d:3[QpuVRh8tnڴ n[x{{j~{,5*++Q5[-Msذa.]P2G2~Zr%5k` U݂dmp300pݺu;w*77k۠_`T%fKBXϝ;'Ͳ Anӡth'LOxSj` u汐߆%oO?kOƆ%%emV_!]WEEIbV]v=rL/h)W-%ǖ-[g(1C B3&? F]ta"`vh `ۛ :WWW9sFv͛\ThP衜]z2{U/?5QVÇ0OcXb T'MBcƌ~/ƿLdp-"ALa[/FwrHxDEGEELϺjG|`mUXlݺ5""B& y$pFrݻe'A@@3yyy4 $yv%Т~x_'0'N`-[G\X2ٳ7l؀YYY!!!K,ܦM k`޽СCQQQ޽ lY ]v[fMmmmll,(K^ԤG}T@TAtAfZZꭟۛ-@rrr KBL# ] ƄSju+8G>"j.m@þ+@1N/N6c^wIRǏANAD a!\> ߝ?~aa!{ S1%%ŚjѢNeI;-rQyѣG%g_]ppptt44o}hâ$0nV`p7M;v&yxx_paÆ^q [*oS!#))Ius,A2ԞKiQ/~i y'q4BǏEa6,d7n0VM^\\XܹsLf+WK֤ ><,22R8ڧE-[/+@7) tv {%K 4Ʃ/bT7M"7Hug͚PS-'/<\ gM.]pTΝgret, gd,6 ضm7l3_E+s`ڴi 4<ȜׯӧE+_8&- زe ia ---%,,,4hѢEv'hǎcS;7n> N-V"CjJ¡²10ĉ>(tGN6&L}vۀgSLh$h۶mFF=u=Lh@b4%kؿ?$qx]TFY ؼy3]AI%r:GZZN߲2u$G3ϪE-]޽J0VVm@ ;w^\333M~ԫBF A3WzzCa&p@hkG?J0u/} 2e/4X"旦rqqqgϞ5k֨ah"DAAJTK?/O<"0 3gڴiCFk.%yJkѢE:֭[gX"!puuMJJRU;J00@ @*6i}x"hv60cǎU$LDׯ%58}v%JSq( ޒТE;ѣGC_$,U=Y5[  llw2-׮]?~II QP%Kw)߈Z1AhB-D'Lm쐟v||Cx& Zhހ1;wf[5`Æ 6@Z:/$%%EA޽{vv67;Bdn۶Ã,2Y[[ 02dudӰ322-[FKd5vۡ4gffJNU^|Hi+tE[g6mbH5le-ZilI0X1u213K`(| >gfpZxqdd-[Ӈ]|9jZh0i0,?e Dbٳgcnr_$(( 72'} r@=zڵj7߿ =EnݜXm +VHMMNsS|||JJJ;7$%%o0m:c8t_===ԜN رcVbsm/ W__tgq$F_ᾪ6??_jtt4)x@ZZxYX0N:T 4hѢ&n YfImFGLY}i61NQ5i0,Nst)h-./.\hEpe˖^رcҥ@@ǺU6,"&}vb&nylݺU'cP=$ثc `څQc@grLI Xs`VC`x aqq1Yd_Z@3ƌTUU%-Ze42Zhr?DaWM$IoW &S=S$Nl &@%CRtFCqW*ú7dС  aaa0\,RbA._<&J᐀5*]jg f5PC|yi{[hׯ_gj=ayA dDffƍM0 &!%}2bĈzID9Y)Nio9sHBbेv4xtOjN7Pब5-L6lX=322L̀ SL1399O>$0&555$$ +B=>;hކ hrw [ ;/%EEE98`hm;dH( l1M0::)?M+/^O.={ܽ{ATadee dnGbRxL |] [PSۧ{C۰IbѣG3="uH2,5?*++}Q]YzBsss'''[Z]ͱ Y;x@蠒Ъta@˗/\:ec͌[la; B~P :yG`֭[LSnmF`*m?GEEM& ĉk׮ܒ`I?GSvv69aɃ北.],FGGc`r4;I8+ҤE&M.y4ϝ;(-[ z[n^oC^^bv`X@MєW~V͘CHHy.ºsNL0A*i5x٬2&paO?0h=Iwrӽ{w# fzJ^{ ~ jn7iH@x'46ݺu)T+& rNNZ,tiΜ9#~*11P8GΝ:D\MMd|4r'Dќ1c8z72={KCеI&q[ĔYA||@KQQM x:<="w޽vvwwGmF?M v^@-Lh*9Q8V^Bן:ujɵ:qqqco<ؒ~v|=zRJuM{g  ƎA.7olVLPP YPX |LQ\U^JT\z ]d1+3R*#::K.o>cz5j EO5-~ujMs* zR6,io^SS= >ɓ;v4nG6;q;XeXߡ Pk0%`\\ʰxˋ:O|2S?XZVVFgҥ4@<_qqq[lF{ę[nӦMLh@,@3cUaŊ999RIgffZ/H@)L~Tã +]`Y!!!s^OΧ7s~I>KK& s… #։+ReOnݪڻwlFaYx.X&cJ#|0iӦ:TsNPsBCmE`ΙTJ.V[hJi-PdD,%K.427[g>h>@(G K,ڵ+fLtʰDaDEEv ;{lN:YU,9Rl$G'TUUY{@`}ИR bOSvz~%4D1>0C%BxEٳ@&͛7d,umb/ }hPQQޥPm9RC\hhs[{Z)i|N ees2yfe ⍟ ON|>>>,p;-q V0bVJY5zRXvtqĈXCCC~K.@9ԓH)5MNN[EUjxȔ0,;G׮]h&ca޺u6C|#77Wb+p\ff@@ocp$S8=gxbHH ܄LkѢNeСv"$LKKP vk׮-((zj0 D9/_f" t j 9gddYqPw(x)S0L_K,Uپ;M>j+gϞb51"l@Hz//W 7XC`r|~ ?fSNq$ZH>2a$Yfixꩧ@+us-Z9] T43B}||ѩmo m=Cl(~*A233ŏI&ѡC^zAڴipt׮]PǍ'CР:$%|PZXׯ_pBЗ~x4fر7oT>[p ).i#$Lp\Ò311Ql2ҝ;N14͍1;GZb1MX1~ 8p˖-tŷmKr辮`*u3 ʾgr[92`@8G}}=>L@F%X^|uuuӧOWcL{DEl$"5Jr9T(//ǭE [תh?ɗ{MM6гL_[[o߾y1BtML j!{N1_F(>8\RR#H(o1g0=fV R+ܴ[nw$;ߞz *zeʏE-r8##b'cPa`+==ݰ*{mB $5& :**`c:1=?\տGL=d4Rܴ8J>oc=`};e1crssm* t%ɰ=C/g-ƸQ___-[/Bп*F('&&Ξ=P3d&xzzn޼YrtFk׮)TKZ)[ Mla r Zc* >aJGq0`9$jU_O\65^>Zmnko߾7h/eX9rٳgјZ G9UFzvEoy>zjM'aܹ,pe8R\Ͳ~vj=z4GgFDD۷/>>Tgј,i8Fƍ;s /([WPOBIqq#<͛:1b޽!fIl hvRaYի| pI&u#~zɓnݺEFFq5l|o߾ุ-[z <㫯!ܹ_yiAzpӧU_d & ~1bx7'z?Ŀxv ^rN;ZhiXCUΡyV0s̤"JŐ!Cjkke v`???~46<ٿ⋢"tM~+cvٳÆ ;yԟd93@a?'w|_||p%#սKi]S36\?99K.x/b¨Ǡ/^9>>>?Opk|)ƍ[o /_`h{~[f h4+͙B{ N~СCDРۿl, Bugϝ;wNJJjnUo &ܹFEkJKKKIIa(4:Mzzz8 ޻woÒC>00pGp̩ޢO>`;zh}}}UU?T~ZfPQ퓶Y7,X_Me!CCpxxxVd3æ ICs[],ZhhJ:3M`E2>O4)337tߜӡw`! Ha4m÷* ʽw4Ӱ0OOόӧR-" RҔ$ʰ?~s{]]HnĿ 7n՛5kTTFC`v*&")yWPP@l5O:yba܎|rJBCC|I:&3l !͐4~PAP(S-ZmB'w` ް3e^.RVyAx˗3GA1gϞ͈)BWU+OcRM5: ~ olRKzDPϟ|%7q d+WHNwww4 --֭Õ@V{d󬴄 !!A,8FRRRBq۶m UuEdפ&5UREK|yMϞ=Ks,s ,t%͛7EV,:t]X@5 >\? =zfUĉ̆rID|>}:Y+$13>gee1"Bׯ}&+qa23L8  Eeec=fm3fO6 O>$Nlh"j#{nx-Z-%88X9FMM[!6-Š!ןVbWKƐaX;Iu5=)X!C7AAAbaN:-fd6 ￯o]]`􅅅֨ߠ1dgg H :cL[1Hoz 6if8> w]o^v10;wduJ8Ruر#˛_ ]-6 22SNB4sL4Nd -kFGs̙3;w={vJJ Բ2VJ?9x%iOd=\x٠k`o? 3fL.]>lXA/߿W^>~¿ŋ_~e:%G 5558JJJxzyyaCo^rߘrwi˻vӦM{gq/@hGtwߟU4SlrO҄`ݾ}{xx8/ @Sܑͪa>>>S`uA8qbNN34vU>-}s K^uu5!YP7<&w}-:\p+U4?pnćz\!11}\S[-l "fr/dܹҬ N+z#P?'@‘#GyPSShNOO>ٳ;0EEE 8ɓ`wԨQ3P+t2"ׯ;wٳglvGXF\T'2off&f/q0`$026s l?~<'7x7y#$wwK.}`Z-ƌaFcmjɉ'21a 1߶msiKڟG2n8 A_۷1Uk~⥦N/_7nBFDDHE3Kǃ.9y)\sŊ}:SzH 09&$$ż>7)]ܱBfE8#GE/b0`oCŮ}ݻw /^lG:OX*:$1-Zˢ6ܹsbb".b30,^V^o#A xc?`xAX|XX)߭[.l8W')6 9w+++{)u}K77'M`{4x'z~67bm Z8CԔ8~~~Ν]bjj$ilT+qBb֬Y<qqq+@b:thٜfSPSK;0HQ_!''Gҡ+Wc+W2a6'M`/c=~ 9Fy&%%Ga &~ʠ|^aҤIj{4ÇWshi&A} h0>{luu̙3`cۘe:`ݿ*4nb dGYY #=$pKEj%+ ȟ;wu9 s!Q]vIIIӦMqz=z+**$Uh72j_[nƷJXףjӦMnn.  Y˗/3ݸq| wҥ4)<CwHTHKKڵӁEEEB8RRRװm|xC=&njtk.p٪'sF-Zu@9200o0 p6^`[bbx BRm(==]12*Bq:juMɓ'9r&V|aÆ_0904(שּׁ,1^^^ &c(N} ojh@@dy`jCm𯍈 -Zܣ%Kiߩ Eв+Qs_dڵk T8sLee!Cp$bT(dddHԢ=ot>Nٳ'-QQQ k#رcoN7j@/--5snnc֭Ro:i[}}=#Dx@w<+33y(^hJv>?$d &Wa ƍKLLĢ?o޼{Ϟ=[(Ta|#y4'Nt#@MGVx)4*U@#įveee,c=޽{Äh#ٳv8 T丸8I$JJJEЅ;wf$.nffF6;OMMcP_pASDx2q5sXoXh˼ lT`?GQQ%uyTTTgThhcѹ eעE=pwfFƆVMdtMQt8.*cpp0tb'͜93 )Yru+|ȋ-0KX+R385=JQQjhЩM6-!DG' /˫E˃6.h*/OEFF~駿oTu :ȫVf % YlHߟr)(kSZA]]*KW7VxIjEM \رcom`$о?zzo߾U70cM)RP W0aƔP-G6N~g.X@JU5x7o~GRtK/|Ɠ^xQj͚5_F˫E-JSgÕAU@-$/@\0B,fh~s:~u)cƌyٓR 1Ơ:@GT5Ҟ삂]vm?##;v6m͘1C ڱ=X/Ӕ)S6o IpK-Zo$ _~!Ki;0999Ƅkii)=( KSoWZe[h`RRRǎMd~Q__/ilGGGGEEtu@. rssħuҤIFrr̙3UԒC IOO]P<&բE'I ek6zIL$$h6nHСtDzj%4RI*5͜.],!!yyN: [f[-&L8wTV}'#)Ab2R"##.\(C;]-222@w-ZW X]%Y% %ӎ`IVV@ VvAHH3Bͪ LDC}hh(1tJJ >cZv¤8ԦT=L<իƩR&.~0 ݻwee$t­A1M2t"-ZhΝ;LzeeeA+B}}}egzɸHB@S?'B;:ue"XJ?^T? KsL>QbW`tk]lIua=AەhѢEZ/_2dH *} hx EB RRx->@荚٘w4H2ɼoc|qqq;*.8epq ů,|CD䪤Aw 6x`#LT@: \\ssst[ah *E-X ę@R0ni _,j^rM,qޱcG|eVq̠A;X@V de0tG||ɓ FAW^>>>Ʒ'Lpԩqab\v#qXvvvff0,~&v]m:*//Ov0=:<;[mB0-ZhSJ>. n Jm&Qpiiim۶l-ߏf:B&teD2^JJJZvVmLY555 l i?%%%tnǴӯ_??M >/+s665ν|bE@)XCU3-ZhqFاO2e P,mڴJ^b>KAS(cZopK9D`(:Y)xzzzG,'M0a֭yd]Z ǏQO6N߸qɓ'po0''GX4vUΑ.] YETT4!sNWӢE=QEyvWWvvL`b fuqqXf n:,c֭[\L|ꩧHS}j"`Əȑl8-6h"c~E2 ;|Q*M& rA F *>yZu01x^4̟?4&-߿aaČ/jy-4XdhfX .]o>/{8}Ò믿u 0w?fLfOx___hch\YY+`YLrcJY TG}t߾}](M?#f >G?|]DةS+W~p􌍭ŨAqׯ}[|+48F>;'@/Z… [fY⫯‡X H͛7Νm۶W^y\T__yy4ӭ~j?<A.]Ø7cZhrGj-&&Kٳg8Є Xߡѐok3G (Cڸq#>`f,hZRH2CI R ecFЀЌiR*$VAdTw"JݾlٲhEuAz@k5vDtI'q;v,`{:Rv>+)iby]VWW3ҒE̚5K/kZhW8,ƍ۵kÇھ};[CX ,@t_xGS@{qÆ [f C(8EPͶ3OAٳ ԩSU!vr__߸8A{{wDYz[bb" 3ctu*hҏrʊ @ DG_=,`!fi{kXq"I`gee%^LE) y'MUoy2{,_'|W@?Oz1X{a‡s۶m駟b@l>,l_|EDG6>(={|}YŚ46~@D%'' :7np'zꜜop͛7(aUAESRyn˃`lP00T\Ν3ݨp xʔ)׮]h\aӦM)$ o3&ga&L>h۶mMn V7ŋYSMhѢԩS'O<~8Xn̙#Tؙ}~ !~YYsxG}]v@q!辀mmtEl蠸СCoI444TudÇ sDj z{{Y%ٸM}~- DRRY}. Ú!l)x:5鄨4o<5o kD\ Wjjj۶m#Fسgn߾;:t 4݄HѤWiHD0T@ۓ!""Bl#Jؓeܹ3FŊMnjH իKck2$ #-V#$B= &** J70.jЉ]Ƀ^3/`{jůM5 Ӄl$NP fʕ4 _ҕ}5o>>?1`:6F)`D0нDɼ__+,YhZ\\̭7Lve˖?4mlO3;RTTs-Di /|;?OaDzXɟg9 GYw-Z}E+9+\DZ ...M{B.|v|>N(V $&&8Z[W;v3g$Q9SZZJ⒆~ N>=&&F/eZ<ͤ| P ͛7Fꫯb{饗?}@k׮uz'=l۶…  IKhWM 'wj6lPUUrWao_W/@6 m jڒ%K~_pJ\>D}&^YYYhh /@=4⤂0 RҼcǎ>L}"T8SiӦٳg %xY i&̓zt=zOSjѢ> pzavvI'u+V(,|w>|pyy8s Tz}W_)hUc 3++i.jXboTn>}[nZC H>MIPSSTNX`BNXC# Bf7|<1 X,~w2pgb. :=FcUUU/bT6l8qŋO)SٳgX|1cƈ#v-H*W^%%%[Eb^A5?wܯ~+'N:uСxn޼y/BE/"8ɓx㍏?XBaz-\x{.((g]put-4 J a5yfw XaXX@l~~~qI>4 on_^^'4PmFddO~W_}U5={VVp0yij-ZKb1N,{/>sۯ]Mjrpuuuss$V, ,ݶm@ kbb!C(1yܸqWv+: IJ- 6,򚬜ق{/h2܎ud\\ QǁkRcXbEff 'aڻw\2 KN@@."pL@<ӷkѢ偕&ϙ3 tzz:u6l ԰怬v]@ :111*-**bUe~*,,t P7YȞd0B3f84Bgƪ>kX*Qf={Yz57_1;_AApUYmѢx:ccrWp k= z!tlFw#uk?)W[[7YG}ьAh0ѵU ;(})-OOOg``ܹsٜXL|˖-8̰#-q3Nbbb|qDpݻw6P+9' Kb..l6sKUXxL#F8D0NJ,Y")C'iUTVgiM!2ۈjXSSC|R3`7l :vDcf̘!E-;4x[ g3 Q&N;'66 }&phN2ׯ;6`*m€(]0(.s8q)֋^|G 8tS;Ͳ`ߞ{x1`ez YmX4K/T -4Bm6;7ݛY4*Sƍ۹s'ҝxQ!!!2 'EJp 6ľ3\} O#Gܿ%Kd&7f.C{ĩnǯ$ 83%n!WL>~ڵu 릺Ϝ9SJPڿ nl*<ٰBaqss;rȭ[H`P 8l >]Yd+Vطoɓ'oQ *Q1հ+//G{k,),{\ۑw2 TUUǥ֬Y{nl4_Lf//۷o!h۶`Zdq'ÃyJ m.Sdq,cʢ5]rVwUueap)ұШ((KX=X Ec/XF8!FG81cDI4.U/P΅pξ޵k?r &Q-h,xV>bĈӧqJJ ЋynӘbie˖] lI@R=kSqmA#SZZڊ+QaL6 S;vPԩS`՟} /h"ЂK.$[nnƐpvv8p %ŘifDnذ3%oA% .~7COx7Zl}2Ab/6Dl>}팁7jԨ<[b9i\eO ~ŋ I LoFu Ǣ4{))udd^-BBB ʁ;wNPÐۄ0Uiә8#yO蜨 Kw޽ 4P}RhnÌȁJeF)Jff T1 vaECP1oj"cWPSQQQ,͚HA<kBDP0* )##vyjGՐd; .Af|X clѰc}4q)V)HIf 8t= |XNlS xрCOBPpLy@;n:!K, !,d>0Caab̓@ŝ ,[GQhZ/11Q]XОV7&09O8V`A0fȉ+Gl/+uppٳŎ\ދ7*%c{&ch=,`B԰B^`JޑܠN ܹs;|0.>FcfQ~~ի1s0   :64\L:;\ qcl޼~\8a+OFE)V1qX̙珊Ox֗ҌѹsgFիD)>Z ;0X*IХKJAf@b8q6wIII8f:tkSL߿}#YYYP r:ODDaEq ~1#OީS'H億m۶QQrO#FVHOumرc+ :Hz~Dm{QUL{"K&HtLS܌i# C! `؋27n?>.R !eEV  S~ (ͯ BҥKWXZhQj*>٩S_|M1dȐ/5G@CUA@hMf0j4`̄8!7^ C$W,~ 8A檰(XD̙EEޑtp&h"Y RtAScMJ >NBy#OJY,ߴ?a 97H v"Ht"ـ.]xK ". 7 +z ۷o"5k`ZAq"O֭[_,yyy(sǎuA=z! AbO\C1:Ob i;v߂]:}tX:AAAhmb%#`H8m CCGASNfٷo:/ ]=2~r6674*ӻw/RC̸s̙/HՌ 2MX@\d05F>j"kZq0@1L')vSLLA/` P$1@5OPĶѮFxdرPȃ 1! ,YPMLLJ'ֻO jj+E抠 $ 4qpK[n$@6ٴiSaՓF@A06oތ ߐ/.>>^nA$B* wDžΟ?/ݺu`i;Ew >u]t{=͢FEk@pR"S1GHW>^k׮p>|;j0aG:u"&M*zGY#),-ZVPr&?:GU+fC32j͚52d;EK.!uB,3_^yIZWmS'2- |>mڴZ | ~ $ ;8PFa̙#Ҳo6Qicf " *!}#|R^ՉG$ ]Y'a͚*9rs*UGgSR.ը? jTG{J.ő#K!!!ғP{Cr-=J| W -ϧ$ђYśBmݺ<.nr`  ج,zS(4m̤AGHO,!r \HV!SEHΟ$~f5jNdTOt1aFTVY޼'): `%3_%е2[:]yrgUq S O>w\M((((99YWgigXĢ#=N, JuMW8w[$L ,@7c F`iR dN8rbi jweŸAc8  eLН:u:x HضmńQl>yf]7n?B~=888;;裕}h{XM?xbo<\Q4T6"ʍUJfsI\߭,̬8гgO!H4Hz@&gLLMd5 OnDQ/11Q'H'&E%_?}R]eFTTTttȋ{#D~3x"H F]‚egEEE]fϞ]PP_b\ܹs .;իY/ڢ-*nݺ"#- j7j4|ƃcƌҥ˚5kPFWiرXKJJ' Fg%^^^.Ć>0)Lݽ{wFGL֭W_}_qC 0RΝ lkk/~d *pwy! 7nܸwF)&V^LZOTƔ_]_ݻwƌw!???%%ի"dСCKKK?|U""^~…O޵kxqS96cy3gGqqhgKd4<:v옓S@b?bŊg>hHv1O11Ϟ=Kifko=z46nyC똼d' v?L}Νח>A>C u FZ_8 QۧmaBXr'/D/)=yeϞ=^A{T=zlذ_~M,F666K.5.pXSSSnNJJLw%& h)Sx PvرR|t?eg~aL@ɴPٷo8:n8\Ї6rzzzΝ{М %0 XS[ZZzzzb?~\kҒ/o{I!//a,.Ҁ5ʓp{48SiӦ` 8kAA$+ҧCA鐽A> 8::^r_xs011aɒ%Za7ΦT2b cm۶ O:u|}"u*{D0x&K@rggg26i&!!!88/ܲM ǣG@)pôih/CǎÇJ8p F > :NBtt{ؖ-[w}?6(Q+b ׮]{7\A)nݺ.11 {3g`GFFnz̙6m*--.]TXX!11STT` .ܿd`\m.wrܹsVBBB{|:{hP4iӗ/_E!##cС 7Rfffllz/K#""ȼ L'4rJ'u@'B\=rss 6-b?|kP5ϊp+V\vlnF\cǎQ^^^ڹsI֭[ ,vڽ4;Fw^:1z2SRRp޽ 6 ѐ1y␐1cG.]L2ҸGGgu*000;;['1F9oʃF@ uI5i2@bOG~ @~S]3pLcǎVZ=-ԣ<=>` #á d$3]va}.`08lٲyPD6^Pӧ1 ^Үrv__SZK,!*dfrxbN07n܈),h#FWf0u."E)) =Xn,(YYY8['>D*ޢe˖[lWpVHi֏uK` x|i`0j'N  /jQY66H.cu\\\)pDJbٲezrV$`(wpUH{ӧO/++?sH޽{={SaԨQΝ;wpG͛7޾}{QQ$2 'OnӦMnnݻwEnYdɧ~JJаx$bZF7` (ʡI7oٳg5j]ׁ'nݺtZn=z8<9X-zVCѬZJS4*Pb|R4` a䔕E"*K,qe#F*E%!A۷oߕ+WHO<0E(,^x„ SmcǎuAz҉CX[['''bCWVbEf0 F ;b镝ҥȁYA]-datoA>t8DEE 2nӍ@Dy wwwjrp1 c3fS Qec>>>[n%Yt_++7KvP"Ujjjll,rҀڵ[f|7A$엒!5hJJLL0aG+ !tr`0FW ԁ"ԒP=<<.] l);9c= ,wz@9˖-ֿ2kkkK(4ôih`0u 7Uc ѡb>޽gϞrfcDi:Dׯ'2(?9f̘beeeIu .\x\# B(KJJ }A4m\\P4/q0Qy&RtW_ݲe !pK,ٽ{7Iix𡟟ߢE>ÿo9a4AJc9{,^lf: *|AC(=11 /2eHa0li` >2?wA(dQ /_||ƃ5ei*088xĈ{9Fs5kO>/0|HOO'[XЏꨨG6 q/+++Jƭ`0uI&M6mƍ۷ 9yZ KKAadgj4HZLHe˖H&oTqT*ٻw#GhBC@<؈/_>rH_7fۃ1A4LD=R 3HQFQ$%;v쫯"W ( KLLoܸaz0Yf>}hrP_o?aĻf<|4CD%Nd4)'`0u0ȭ}ZXX8pJ).]js2`dddӇ6K8&Jy5qm ? "Z._|ђ&[Lbи{]`0uJ3ѬY3ptXH _'x%?(q^vݥK Hrf/1G9Cc50MN(gذaUO P0tP i`0Zȑ#>L )//MF%#DAAARM: .7oqry /P #ʡV  IxfۂFGG `0vvv :&1cƀIPux+gϞ -\D6(*ZȘ5klD=mڴ$yo\RRRD %Qcہ`0:6 &DDDHpJ䥻;oZ~FğhժUrrr~ %!v D]ˈv(yBf 55b ,`0VJ.E(u5+tЃڶmp4ȃO֭(Jh4-"bD6*b0z$… )ڿ$z\\pb0}ѧ6))ڧ1رl ~a͚5WK39iβ礠 Qk1Ք&'׼/_tRqҠj'ƐEy3Y>>?t}6lX\\q߿bbmHJJ dqyP@z-40 y]lgŊ9⃳U(r3 ;wnbb"1JGGYf;V46rrr afnJj6oСC zT*0Tb FMff&dW:r8"$` NRsʔ)k׮mӦ8pr JPPƍ-= $ŋ-[fʑH8w0i3JMm`0GGG^Sy<cHLLtpp3@ ` ܦ۶m#ܣG:( Ҕӕжm3M\\EpbM`0r@I$O➈M6lRz|bJڣk#HJۼysHHFb(j܏V2 qYիWgddPڧ*eJ?~LLOD[l۶MlyScQsJJ8aP 9cHKK#[9 `4Ҁz񩨨 ԩSxx8T|y"Xw2xƌ FʌϯpРAR-=EN ܖ/_޿SHMrr2Ň``0){= ۷{xxtŋw7nT)?spt(o)O5iD*6 v~Iӕ"J4[ K 5u}g̘!ɜ j!}}}"n^Av٢E ICAd;] V^-rW2i`0 F#ǖ-[@pĉoֶm۠KS]cǎrBTuNII Ld$ ֭$s0 ؏`0!_}qDFF;vL`0 nǃZlٳgOoo#F@ڵ+w}h/GI&Zꨨ?_"~$ARu q d@CcX`SP+A;p `(pe''Ϗ?8dWWװ/O>~K/_ȏ l>|ɓ'׍ Ї~_PaOU裏h `T.]̜9+W\ti&g~~~thA^MZU^KVph`0!utuгĄ u  nb)Db ƥ̖333(:1 B?۷oRRR' ,Z(%%Ko-xCTTTjj*DG+0< `4d 0?E H:mllbccORmTMzj|2@OD[n{q'`0:@Ư[GGd]R\Ѥ̝;WG Ht*2;;{ѢEo *Pnhٲ޽{{%`0H:88lڴIVK쒓kHRSSӅ@Tt`0 19CKZx___y=V1b n敠r@8bbbD KKKc`0 cH_$P~8 i;'%%͜9!ac )걏x2 ;99"H̓-&===22ҸB9C :Fd2rU`0C l2GGG?0a9W]߿I `0IIZTTTrr29QEӇRؠb:ٮͱuL`0 +֮]Kj$쁻5k¤'KhWB2 7oͤ',xbӆJ…1L}z % h& :tpss`4NcA*pq֭ۦM(`4e Ν;?~_P( FI @_aʔ) 8akT{ĉ>+ W.MD׮]z-b!bi\˗/9rPD+Z0iP ;ĝC.""bܸq nyCEEEO:AAAiii&L8|ÉQڵk5>aFB |EICc5XйD2ԁGuԩ` BZӿbO>Mejubb;'4iWJAK-D[4QJKKMΌ`r4q; ӗ ׬A"..m۶s),,$ "ihmd֭5kq-ZXpÇѐ,|tPҀ!gzwFm,P'ƍWTT –fVVV[0t|())1]ܻͥwyNq~>/D97*>9rbn A)s]rEin堼~*++`0􅵵urr N:R#33Cj000e GJt]zC!Χ,üg4M֖f/:pk06~M02_:t뚳:uKڬǎ2e sWCa6mSu%JMQ? @a7Y2)T*US }+5k"##O8~0JϯC #i_lܸQѐ3%ڵk-R[hѹsgXYY͙3,@{*-5 1chOgL2GGGW& 6>r x ;88mhiӦ"DAp/&MzW%Y MB!}a ^zcǎf,˸ xi:Pp=|(///**,-}TTԟ/RpӥСC{iӦ۷oC i#uvv~{o?MF řlII =Wn޼iy*c gkTܹs'a_hQs"@E=pRQ~BBCNN)vǞ={׿1J*ˣ]MY )7`jB]vLz& >XYYᯧiU* ]Ipĉݻ_ps}D&~wߗ;Y8hfΜSMENJvFD'cAmۖ45x/N<22 z޽?{|!iv(<hwE[[DQ_4g|V///ZM`<¤-Yf6:tE 8qD=Nze:,?"!b)1_LWp0:%!v| " ׳1bkk׮2zwvTZare.cƌԩ7RBeeemڴ{ºaÆ~-00իmRȍ ¸)f)~͛gϟ?/@=J\h!l,h'oka&D666!77w߾}&j"L$I2 ܹs'KR[lm6 )H U6x}jf 8PG^<_ I&ab'/puuMOO ϸ] >--mTN{1xT5kI& 137 __DGj4'a;v A=R.]JQRbJ<K'O6MW7?vvJ͔c0_W]C9f?pΝ?KLL' .{vw)uEwOAu9wG}D勣jX jgg'!MW7{˽Ph~XA 5WF.`bW a(0ؙ3gr=OTHb#VWdర0Hzy g Sdc8w.ۜz޾.Y7i0=*6x\NX0KEĬG!V^ݾ}{4?#GH@GCqqq|ͻ+W g~PdԊC5(qw(QI}w^~- g Z(kĉi V~\:o} _}į :JW7o駟^|hw}…~t[7Q~| r1Rippp-6eNI≛I\A3fhݺ5BII_bF3dȐegg9sFdsOΝ #iiiW\#%J[ZEAlpi:0$G9yΝ>}@&:t(44ܸt@n߾iӦF0]1$$$'H & q,j4OJJbK%K\x[xZߵkW2kq5==~Æ C da+4_t _{Gyme4,`[BYva3/og ^vmRR''|8z(Q 37EEDDy>f40vh(:7ҺF1WMPgr }&nE}Q``?LŖ>EEEⳉ;W^ݵk%v[9wK&ya0b MYfw^aaaAܯjЈP'ebb"gf4ƃ %:D?9sٳg.7۾};4cD#>.2cƌlٲNK3g0 ,G.!7mԢE kkݻءC|ԩSyyݻt;h4*QlGKK˥K޼ys֭`0[1 w܁...;|.]‡k׮Oo{ȑ'O?S@1k֬yO`0Y~^*輎ܹ3肏OHHHϞ=%0(*իMk`0 44C"wwwf͚9 KK˒#89K,^fMyy `0F)s!899M8qϞ=s΅7"^_RX9x0 AAl1!-,,6m M5AB|)""Jz_I`0 i {YK͔-8Zh^?333**J'Yg0DDg ,aSPE)n_211Ç۷o' 1ę5^ADfrժU+W$C 10F+++OOO2XP A<<<ڶm믿NPTK.1`0!JKK W+Z 8>>>++… \Ç=zܯVhQRRR ;8p]*򑤘IIIhr`0ii {x@llɓ'۴ihv osίz PʧZ1 nA5`}w =Z ;O ƐWf`0Z"!!BBB%++8 ÷~ M/y&9H^r2GAzB D"۰'nxT0'+`0ZP 722_W6m򗿜9su7nO@!)EF2C&lOM>ܹs /ςܐFHJJNKK3#b+G6`0ֶw>>>͚5ׯ={[lYn>sfqBvssÃNNN/_7D/K)))] 630 !h%%%~᧟~ x鰰0++#Fܻwoȑt'IDq6)H(-**B9666?;wdC(Z &&mŌ`04DDDmҤJRkG:<͹NL@4)GGG@,ZL<=4At%0a0 Fc@~ 0n8H}EpQRiAMo###J< (, c>kL0`>>{͛7!RAR?qpppssuW_}u޽{;;;_~^^^;w|U%sOazk8(e{7nXRRZTTD1pڹsg۷o;;;/?'=okaakkKNX෠лW(*!C[nN  (u'O=6ЫW~)<<<55rҾ}ss„ ׮] D@QtwO nYB;;YfAR,2Bk׮7nXdɥK zE*W^m۶ŝj{ -..\# {_}ՙ3gN@ Z_A(s˖-A}@PGťJqh[nɓq3J0c`0yT *!RZC Ξ=I.^lM6 ,ua > 8@Cx'p9111-ZpBPPPIIɀ۽{w\iٶmpGe#?կC`46=p#4-vjxxx.]\>xC|||L^ĿK7Tg~ ?T&,, _ڵ+_w '!qvɫ`0ZXr < 4jj޼yǎ˻|S ;2"{*>ꫠxaǎ8&T*E9` aP/yY3$'p|h$+wʽ+ڵSЕW ,,lʔ)`?CCR⍚6m]!&;f0 .,}C(RSN{ηo߆=sLsmANCe!;W`%My޽w}WT '1'MsN%$*..R a*V3Ng x\p!]kiiIz1Bf͚)4O O߃׼yfh 9w2pk0m"dm| Fhĉ{HVfes  FܧO???rP4qʹ=BPs)0L 4(Aҿǎ/hڴoMn^{5 5~x͟h.]8s !.UL޳gFEف`0*, ;{ly֭[C?mwe/#E!+$oy=hx0li`0Jq}U++VZ(L7yU#[pVO?QӍQ_뼰 s_q?*.00̙3thiG$2Fn8 +0k@'ȰsD|iD@&UFb0 3B!f& ! 2/LʷgJo<ά`09k0lذf͚&J%#0=Fc4s3Y[[3+Wc_oo#Fp(HJӂk:ws0iZDCjT_+?aqmVja($rrk(M B?;& fVZRhA)Y[[wƍL40j~I<5J$ƽ";I&&Lhڴ)FkKh---oݺ:r:E-8X!%ʛ 5& 'jΎwg+++%ƑjGGG[[[2jՊ|aMd:2u&HsS( W\\,24P"u?k>Zə),,`0=[츈^#@͂g+666:zN''G A;9ΨiT!>ڒ.52p L1gC3IƯ}֕s={,ہg@ViFzuI%Fg2LipLFR jjt](cY0_]ի6=SA{ kk>)J)'ƍ7JKKE\y}}Pժ? d&Ǥl<|P{Z7o AM>4-:1ww"Ƭa3t T ,k L[n]p>*iii[CiPmڨe)؋U鰲FPΒ'vR)Zl/ݛ>}zYYF $ZPڧs**m@, ef *t￟={6wR#[ZZb(dc~7Ucر#40i`‡YWXX?* H4p  -777n:[xjmmG.=a"eBCwNaQ#>~ lxmR0SA CI3hj Wvr7c[M6aH,B+:'^R3bKGDH pHYsgRIDATx]c:i{oL`cݘ-e]ލUyz$:tСC:tСC:tСC:tСC:tСC:tСC:tСC:tСC:tСC:tСC:tСC:tСC:tСC:tСC:tСC:t`@_xz0CZA(+?]F@t!y<{ ^pG,iNBaÝB_:t\o*B4@ DG|q(lСCG$cRk;c3< b\;h=:t08DV XeFHᬆh=:t08~D+&:'gcS"RbfJ̮ ?{AzC_:tx1LN9{P:2AZzΆ@"RAX60W: (U;2%wdpƮ*vH3dM Z] f%h=:t0esU>88<9JĻ#_)8% _yd( )Dա#3 `V̚F+Y,2zz69_]0<9(DCGXAV@at^p&t΁밢דa|Gj͢h yJ(=#Y)@Ѽҫߎ w֏,ht+hv0;Vw!DHTAxo}aדa|xJo"ǍBGZRر^O:t^$w\\b _-qŕBJ+Îzҡ#@ƣF}ܜ@(Z;&xoh8ر^O:t^Hf>|嘀%=ėEp6zҡ#yt>xc{˒;&wKCGXA9_bJc%($#Gb:b1q%DCGXA"EzqD Œxٿht+h.X5 7ަP_{zҡ#@j8[{0UԌvg%8+!Z': Z/? ({7 ֫ڪ`GB! pQBzҡ#`"I%?jH [:Zr5Wדaz_*v^Amagؠ1>o*!Z': Z/([֫V}n8)!Y`zҡ#kB-t9q3r\E3I oʭWQW8+!ǩόzҡ#S2:`z }fK#wXZ': Z/?bd˭W6poV Oht+h } +#Jw+@CGXAKctȍװDS/K]7I WQ!T䯰^: [p|`,דa/NB^uT(ĕq ez=Vz>6#ܐ`WEd zҡ#ma[ CSE`Q`кQCCGXAW[}UNoT?xAfj3I 72z25 RwѿRz=Vz"@jui<3T"I JTX~דa/v~ WK>XV!2I W-!8?nkLT/sKI k3 J9m)< zҡ#}@04W+{>f7' zҡ#u Uiէqʂ7tSoLkzҡ#m U 1ot\b8 r rtדa|(Gr;'w~R|U?xpc0Å^HӚ:DCGXA€3⤓ǧ%:ijى֘\TQc 3rz=Vz, c{@dh*9q/iZ_xagl41oKΫzҡ#Q7":l(BǕFj5~!ɚb/iڊD\$DCGXA@ ]*#g\ʦ#{zGQTg0G9E v1 )(.O— \W1I >j;F{cbS"k'V" D~zҡ#9 H|[^=?<:\e]?obit+hC PR$FcUSvPS!n!NEwm~X, ̯aדa|hOlSk+HF#Ub$})xo[ R5ѼZ': Z/PeBs]Zrݽb Yp0-'+"..fl'7oܮYD0gOb_`''e_DCGXA:W˄}ʾ􁥹i밁[)2̋%S͟{*䆈ʭ+"AͻϦ,eV4:1ȯjzҡ#%FxV+żAdFjB,Wٓ2s7j9t%?R  b5 zҡ# Yy^&iv'=/nff`|YﳺLCm.a@, z=Vzpny>>n'<{Gb?s8WG=_g'er$Jj$i65hزfήVht+hCbE!5s0%郗E Uy;-7P9d)BE= ӿ|I ^s@a˼]|杝9}L\mWSp|I(=O{n 6e|D!N R zҡ#H&vJc|Q(\N~'-ᦐ!NWϣx& p}jt+h5zYP'б'whY~ۭ_&r恓VSB! `$!DCGXA!ΰIn֣%>lj|a)^?b xV?(}N R zҡ# z-(rʧ2} ⢄bЇC~8(elh3I ^# V¾γ!O.1f}`nz*,Jy‚^4InH3I ^ 2`#lyL->V@ !P N,J%2ht+h5in ?^O郍ˡ҇y >[\\7ߑ),״Xi! Z': Z/IR& w}`[X{ߓ*4e4slZ4J3-霕k ]z=Vz|"}dx41_;ThNzڊra:H׋3`ա@1tht+h Hv聼zG kMf{l=-1';vmTy_wj]{ڐ7 n^ŎËjRדa|@()*}|m6d>@gAځKZtht+hч]ha,mZчؾ'i /ч }7$5z=Vz Q?AZ=J{@K۸?IvWyobA$șOCA^O:t^Ao buWQu΄k{~cAD1s Z': Z/ON;Oe I9#kGO \hǪV RGz^(n(z=Vz"}~>jDXxvD;eCIcU ljt+h ٵPD+=* )Hcz0gI Z': Z/o?i }$P= j̀W3}]{YКA^O:t^rG䓍WчixY{!9'vD%;%P,cոz=Vz8+>N:,x)j f+O[f\H|cדa| m>&r+q5W>BQ J ajF2DCGXA`=e%dž{IyQ`D%dR'7uH1I rtH64i֊ M9IbJC RwJXZ': Z/xD6(cՊЇmƐE Œł$SuP z=Vz|F"}eAIٮ'y7'U!xE엌'eNJY91ȇN :t'^5,¿θM` =c-5dRx7r3Y89ҹqht+h#ww:0}Q]JE9W?Oic3i"esL0I /vejgk/W{À C> &E Z': Z/x?j2룹i>\, OXi4DCGXA3pm! JJkSJIhwFM[<\._ R Z': Z/xDLm^yFAcfz_iPsG=fi2czҡ# 9_tc-azM%} ꉧKfW@Y3@4cy `r$A`UOtѡ#z{>eɺ,5yHw}Qw}4 nׇ3P4E"33 RB {CAz=Vz{ 9_!zι#j1 d: /10 iyA2^#]CGXAB63Hsjj8#}dܟp}>6h"n*Aj !DCGXABлZD[g*ϓ%J}Obࡇ 2KCGXA1*"W> *T57`=.c9Č8':9M^O:t4^sPGz5lhWݕ~9M.[=b-8A~mDCGXA;q7T8ffFiە+$Gȸ ]<83ȀN :t \j:\@] ޫhn&2~Oxň`U2 n ‚Vi}B zҡ#ZW |\>r T }>]@5nB튧 4@&+pg]&u9K zҡ#RWL  ]J Vj!?ٮx:ܺ'5m(::zbmƎϊȈDZ<wA);6f;vܑzҡ#JW5 w>M튲gc+Bk̑Ɏ"( x%RT\ٞUv:!ޟ1F-XfNuz^ rtדa{pZ{+8GX:P<wu[V |]ٹnh(0+Xnof{\X9Hf5 ‚(iu)xnvF,דa;`f)YQ@,9I/qYەp>\|Si_*0bu49J u2 ҠzS ׌A^O:t4Zîmd僫SQ++ċJ7Ҵ9U)^L :*~'^(NsKm0و]tדamxO.ʐT;Aq!}qW{Y=e?v'2CXO Sˀ>g zҡ#*WȣBRuU*i=U:=0{DxC:} mzݾkWYD2 *y{Vg7ȀF*I&,;,[okOq*B K=|W}W !qCH- Xtvpht+ɣKxA0]磙Z(7ǹk|+]hM]Cf{_X ,B,Qʊ)s#T1 N9g7H' דapW"tH`,Wz#꬞:;|qMel1ka{Y;b'N&XtIgd#s!e ᳝8QHWJk`z=V w/ YWE~r:q YPv K+YtzGc~Te;*h"}gW&2b&8Agדa`/p'$ ӻKd{vWO^/DWUv^V:8I;{/lcȋ蠑F+/l 0kP ,u6b zҡ#/{Kp 7c (_I2](2x}B쁾*\¶%_lNk_$ߑƖ|  ݚ݄&V6F9яDCGX!.V9{MW>NHKNjpuWG {{NO-$[wIRh9U ON'z=V #gأ(|3֦cYcpo8HT mhy$񜽭]4Wn4zƉF Xxf KCGXW$IQ$ Ik7PZu~~pTyS j}wQ\ mmF9C=PH×3L}. ,DCGXkWtzL$͌mp$C0^SZq ii<ݗ =?M Ħ^=B=ݒh$SƽIe5s: h }[ ht+i݊aڡo |َk쁷a\qA)eNNin;BesQ'0BJa-fode;aCJpXZ': ~d|5D=) ^wkF%{`qf"䍸TL/6Y8JPdiMFrDVcv,it.̃k%8)M^O:t|\"y dRKMtw92k8OI 5O v/?yV퀞=vԋlG aATkq ,ص'KCGXgDhOA|ۖ +;o.(5ǧ`)^=S!~a,X]vwԸR דaVrN8\UBXp0 t1b zҡ#up{yN%$/`@䭋kڊzҡ# 6+`^iB.E(l\LƧ[>5NIK;y9rE+ :#WQVr vLh9g4Zz=V )uo'c C&G0yJ^=';{nG2ilg< {*TJr-(4T0J٫vjo0D1(٤vb*p,I80u28䂝^bGyAEFѭZ٣s[mt`geJȕC*x//DiRj{buѡ! "o8uMǝ.j; 6VFyyǢ{X:Ӂj9ϳ;S]qm'wްC*TBXHd.L9>@k#!iQ]}M:$r\T2_ӽ|Еrdg*?Jp=2{`H^&;ӏSSBXp]O(rk榕ǀ!g#+$h-t8g8Ky="j6kxܱiJv6LPng5S3=Q}.vUDTE3!;%ɄSp(fIF,ge9yyO`gg0X)gGQ\[axOK?hٙ}gAl'A.3h-@CG^X@yxSp9.!^2ziuc},$f:q89Ѝ͟=EI! _t~zRע)\s0P}Wg:TBRBXMHjP\XQc #Ic/U濵A-p}p0P9\VeFe'֪g3jϏ.l-Ґ(v_p:Ɗ75C`ݯJ@ỆQ6?j(!;zM>I~@mϔEUB  bY2 ՈU ZF4FV<<-/]AZB[aaᠤc8b kzz:k&93{ a?z!::GݸE3#ѧKK#YM%E6+Ҁ JCe^ M!N6I.α8Vjn`W|I/N`Oo|*pl: 5a8ct/SI _8KLUh=``܊Wq|;B ~Xgdmn:M 2\,]=ҀJ#pIX~jvсfJH4Y \ 8M R`fs1b Z';yDm}M 6X N*o, TB5U~m7,7 +Oo{Sύ]q7;ǟ]S٣tꔬx"2HcZf #ք D$Ԙ+5#Wēǟ~zF\tsxvߛ.N7϶!:-=L'|)*#uUÙ==d%$X ? hM@DSʢQ\% g >$ʐ[J6˚g{S&$= Ymqኒ%{JT?h _3R5KI}~G,x%2H5p Z_%wȉ Z;A sPY/r߭ͧ̊w s{.\C# UWhcpՈ x蟃?3@%dc3yK:NF,xvUAbҚ0$+/"5{9@zhlSqWߠƕב訡l\MP=R.p%֐9jFml8$/>l_< WVyC&/'b'&oPCnh,na ׀]w|}C/zK7#qCB,H.p>ˆ5a1^ZB[;s7^^.*_IT(YO2GҒb; =opRB"N|Wg\lLTzĄkKgE01]a4S=PW Wloy}"ޱ@'N\@y F| 5MlkA&?E xMl :vqafi?9-^w_+'n`"x oqBᣊ ɟO&n#IyP&Hx)cVU|޿ 93ɏOR'xMR웤\+C3  m uFlHך0J,&G~y[u89Rȥ2 q&w F83X˞|" zY5P+#1cIEo`3&1U D_gJ|Z# vTZ]Xm7biM.+י%捱!h&"v@ #$Pҍ}LyUɯ$lRcGږ<Ԫ쟎ōƒ챧 ;0׹`I6mʽPkܲ`ՈZߐW>bkQ Wr̾I84s:LB$6HW5|WoE4lL+`WLVխmx`q"1}BN~(^'{]Gf,L\uC]젫kF, /+S^8yrko:19,A9Lp٥EC`NΚ.Ŭf/8Hw[Ybbt3'VS€W>*Aںk@r.58OYg_Tw3W1O9%+ o 4R{zc\>1:^~*wQ&b=ɍyIF,juTYaWК0~B7rr]-H<\8 _Zʆ0W"XgS5 eivoKےU_ӧPGnbSɢMr`.kPj4u358 z ZƯW>z2/ecL%(Fs:28=h=S"A(<&ղ'ynS/i,uB-/tܙFJTe4 \e[ZP\D570`& BbuݿF, +Lm;bxcƀ..OlkHUPaJ:J l|BORzvUK}P%,?xtzo?S-17Kx^db C\b{/ ZƯWùQ`2)ڕBx /Ug掋( 昃hH"a Du֠r$G`Z>)S&!<^sU5u8pqq2=uص\W|wkGDMdq"gI 3ΓYA^A&_(}2OS(0 k++EQAW1 rf8%Xkq5bш5a>yׂD BF /frKh~yץRk#r6{Hqb-d(TD07\6T9u4# j@чN ! +7Ϭy,{FbmCh^StsTN{H#" glyYG)PJ/͛/~qS|`%9bC`R!j;  CK\W#5o 5a.yN']w gyJ-ە?> ٍ#:w?uLኂ?#G3/P+l<}Ns? =\H"w?Z:j)H՜Q.ݾ{ã -S,e4)0 ZoW>W}'? PLcIP8g4Q-O2(x⧲Rժq~zDܹII" bA_dbYz&yxYF[T +YN6\zT҇N !,3D5 08x%"z*+z,q/5-۱,tpaԠ-=J8ޱ^ӿ&j~JY-iS\mFBAс],z!?ԺY^Hdmktõ2O 5ayԏ;W8z;>ʲCMzpY'"kY.-^W>qO*^].r*ph?dg6^W,lƣ-\,`ItVJgG̫Hbl3XZ/W>;dsMtӇN W CTX]:8GҬ*6'2U0\]޷|ՉDVqqgh~K~w\)` I$ZΧu8UCˉ:A *un5ayzmzHPye㷻)ɍn٥-:GBU3+@NrXߊ>?;:#{ JyN1.,b5)f%m(t8pهUHr/)@;@; Z ]X$vך0~!#oOH!/b^YwnÚk '%u//g1>:L1I %Ϙ_R;3i/2&bحYsh(C @CrĩەAxTT'Ԛ0B_^!#m5p@B7DkL]}KI.ߖ֜F=g+7_Ig/+jbA|PUqWp=z9)6.(=_ RWo:d/ &WSHΏڪ^a-k ׻՟_ 759E,x)W"6q<{>+CϢ#x){F#_>!r aG>!WA /H jhM!.pU8C'b"rbfQxS[\ַP\+vœ>$uDĦT4al g Ԩ},LV:y rDib<%3|3ȣXZFh+8?]8<$!؀. 2DT%=H&TBUᘂV!"I=_9tn{9c{V"GQ\qx9,8fFfkYHX*$hĺ&΀EuhM,X]s9h;? ::9i6_X]n^KpUŎ]kœ(ӫ*i|.OȤѼcҨj/bR. dOuL4eX 3 "R0V&M"x NF U>1 #{uI^__HaxlM_:+(t|i<5UWFi@v4U![*d}+:<5_o*n͋zU?'~ʽ꺙p%  R  j;:3>zjInA0\a9D`#>7k*:<֢ɏ^Vl/mXbYbO!e$|f,5 Ku+JQњ0B@ !U}3HY_>_Ol~  RxJuu ;nLj^UlL~u|BB}|zX`nbÝ+U5EMә[bHrՃi힪tA^N'oĸZ{-m/ؔ$~tXkm澙N!P7yռhj x7Ao:7;&|pyd P$;t?{W:_z $n,:S`GIdv~8\K kW;n=فPrU?N F)7klȽ9J8m5Pݻ#$H~4$L5+拺hﳺakoYz% }so "eH *5g# gd+pfQњ0B@$9'^xorgڱ [A'zI 6"[Q(IS؊sWgbzD<)f̍Tۼ8ug/"mp v߇8% փ6k!PTH4YCdj2hvz|A&#ZgwޏUwզy @1*2E u#wkz4*q/+(׎ GHL|x;ႊ `5d(3so aAAvܿ Bd2IF[YbsT #R q5a_YG4t; :7Ce%X %˵5C^9qDle=-f%cۛv8Z)-'eW3E6!Wm/ 咸!DE'ēsY&SA_Dk1!8b/c:)jp%:(uC΢wch0Cq:_:Y'$lgL;ȣ|_] y4W uCmg&md1 `"]0@vȘLL |0biME ;{?=U?UOsׁNVd&§ Ĕ6diju$352m2b'Fgfou+ŏGܳ;7aD_4)k`z+D!W~M6 x;~s;YɌX|PA&P"8c"ԨgEISB,Rʹ`xG Ս6{]L/»MIU)Jj .Ѩx8;Q$GAvcccJSD _41~Li/tN~K! :9)kAf2zZF̍'x2K#-quP[ ʽ@Z6qllA EI:'7KoFj*>wZGSI/ W="9anV[qSQv~G=ywjb,axto(dˏ`#nAbs#VĆLy>-ք:&~!(Jk.bbQ>XK#f?3>!GmO"or&xL]1Xt'`j K ^[Ll?fᦔ% ovFv 3*s KyT7C1CDr2yx& ù(zeܾ² -;]B{U #TNyQe}0| |` 4rHg~zTPZ1b2Ry\%RPu-傔E=l_3\g 9Z/חĀ+-obJ;Qyu^ZwBl A_%HbZƍgX;gCWdFVoU #Dvp{~?xGoM]GIbGglkjQP&GU,h.jɓB&3Ϗ$?Ցbis}wyu6@=P5@5QRIڔA 72 v-2#ֲzք‚vIe.oẔC\49 'SwPЈ)zZ?: Ϡۗռs)[J 帍yf? Z-S GRM'VIus#N\o}Z^ #.>=R? IT`Vfb}"}Т< @oFgG&oUegb2_{* S'W.vs˂-~- {Wky6X]!>b7!X,O ¡_q@6Խ5(Eu17m#JP?Y85&Ɏł!B)+wY&1 FF|Yb^T^՚0W,0W}"317φ$Mݐp@0eNCPEX%nu'zɣ(]l< bOttHeoLd gAWF, CkyDT#|U|+8@d8,ɿn@,D̮}N H<s3q:#&Q<`+@}BZ9O+l)IYU:R *WA:e~>jM+رjJ9,g'.V[ށk ȟ}f>.XPptwb۲)J Kyš=+}F 9 +/ 7W* ,5&ǂmW1s'ްքvF0_2nWhl˔lQV& /?.Sa8Of`J[(q5w!~DE@VLfÎG y LW2?ś&ZʨvbUR|q=B=N e6Qx#*Q{p3AzWAƾ(pP (}B#`ǂCRK0q k3Qy(fKG"ք[/S $7Z(M3Y@B=N LJ>;b]P="w̜k{ޝ]t8dPV< {,F bLTfGd.}LsӚ0W2rUxk45؄NN<xQ:E7_޴ShWycPns\7z)>Lz.:\@Trw;fBr^YIb'dAr̈ 5ah&X'6]\_;0j%ႀ2 8 cduf{n]rXzOPѺ/|^E(z.:z2@N!Bd!݊Wfd?GEzDkF^8-NlR"w;}fg"_2 #i-p-wǙٰ SytCm;ƉP]BX>oMDe6%a@`,"a?+6yhM+8F֠@J_ > $hHSh@O S!G }xH6!av2q)B$|ǂ?gAXj# _Xe&kMZ+x?͓ 2}[@H*b@~xǏ8}4cq#oR]zEt^&Dyut ExG ?P@cq^{L*RA>nY @G7Wz ZrG~˜.5 ]*}gHD~O=4A;Ę x WX t*Ǽ-$/d'߇RRR{{[3yL;:ٝ8^5$K/Ipƣ hǪS]P$Z`, r7j: umњ0. 'ș h.ZQ28QDdFy]ޒ_ Oz|> <<ȟ>}o^aVVr4|20յrww{oԡe+k&!u]V] Y'c}s #Au1HG5a[^'3Q{ -DxS0B~@B~yIYP99 iN ‚$\I@eҚ0*X:f66kü,]7=xCW&u~&˰\"Xڽ'0YP=zN-M)Ŝ$~=+2-_?;`~c E"~gٻKݗD;r/ !s ̂i RAe #3׷F[4$/@Tq&"*Won-9:캁x,GGU|{=^g(9ns\}5sf:.f(h x]Ǎ4]PdYt#w`=gdňQ$O;^њ0'BB_C:(A9ӄǝ'p#Ŀ?t'V B>x{9$%ݪtBD"Yzcou g( fua SfM!>8YWa, 9Bu)8b:gnք4y~9*2,u1'kBw@UA*#O?Η/lFPRf:rB$RΩEMdYKm;9,Y5s. o8 Wގ7\!|).Jfw('3>M/(nI{^< `Bj"՛A&`+JrGYvG8~|/eMisF)utgGvVv+^33|M_ɃJHϘ;(t%O9t6~7r3=zv| y=hPklqUscYbϞ#&ӌ\] Bu49‚}NGVP #H|>fe;?oOzxHvE;DYOc}xvb5UvvklwzXsqrDCX*yλ܇Ǜϸ޵9]җ/*zw<|w9˼2IeDk̸F*քyłQBF4q4a-9>ˆ@/F#1)-_; N2ٽt6[;Oc$1>k1qW"8֖VRW5hz^%s T/;n揖# FHH#I>Ug˃ ~>yO'_:@TBx qD7٩6~@\,M! %aW  4K(dr ;1Ժ?sR֔S4}8xowHl_v ދz~fSБ"vP6T < 9>QFkh'wej|%7reQ12x%Vw[+p8Z䱇pKJ'O:Uk'82*7& +H 1 RzWFlw9?< JhdkTtgByOceՅ]+}ߪL'Ñ\7%qILaQpoob6Tv9Lq%?r$siv7e>LjMog?ByeΆ˛י5Ӆ5bPg󬴞Y`6Sp_H !zBTB Jbohĺ+a@\9 j<|P%ך0҅ &R޾ۤf^/h ̊#f DpIhe{Y \ElKdsLxWQg+ݨN֪Ά㳋t1Dg6-Ÿ9"b+}銃Vd쉑dGxbvw3g 0 k: ~~Ok,瑐=q_1pU\O/G;ޫVvVz-8xM 6sY"VWi N_T&NeSuTK[szj7ZRFnWa;kꑴ<ĈЯ'|VEĚ3͇y8=!w޽RĶG A%'@)/ u #‚\yEɻ~+WU5_q!Mo 1 F1]FkF_MmVslzD[$x?FQ?轸,d.yo5,-0uцߟXy}}=A}КDQW  3n,nêv#*qGr;ͳ4{e?A~9e)|OERBn?xOcEdQ4U H+g-6A& BH<'x?V< O?Mή݂@ 㳁owi@F)E-1,zc$N6Ԫv'p>UR=z,8$%a /0q:_S緆C, hr $2ȍD "FY9q#&/Ay|71c*cgѥ| y_wbekg&v@wǰm_))\E1{LÇłabʞNCw1h[TCЮs/=c%~UBduPGUA& +lӗG;ɡQY~;\C|MԦBs ȟHLd{6gb,4+ơx7&?*{3w;023 88ٍl{w$_+i f ,H& &5bJ Ӛ0.X.cZ,} ."xϷ=:xJN-HAٮNӆ;3Z5b01x]62`@DkbukNwwf=#;]9Uȫ}Ҹ7aZvZ:/ԭŵޔV=˸6LĭN:w8م;n,\P{+e8x07$G?X9o%nҚ0,X'kK=}Wځ|4;am<5 zGj=)!b7[fNS3C`&5n L'BZ#k{]k" 6s/Ni2&5>f;kN`={m Rd[tzxz;Q[6jpjef[Ր BI[=4c u ~Rj^ZJTG6JkbA?C韞KO7D= %T;Ѹxe:YeyOTꁎ7{XJ:?,_k95 bɂwOx.X, |AcQ)rZIkքGył|W34rU`\qނJ)N B7Z~_!խOGQ^ W AY%VBm{NnՐក]%*=3c I)OȂri~t -&09U$?:u8𦫜Ǝ@#i"6.W&\2vFx,cI$NKQOUn^ j8hN % :F0cY<3c` 7" @cy`*qT@ BL.)F*Q3^xUw:ۮW`$ܑvaE7 ^u1zɗdUkMtb2 )jNpy L_,`Έf,6#0C\1མ ے턥kMWp|WrT a+Fo+e{ <}N jH2\G[Pu8H֞ij]ch<(^ƃ`~S}<3]){;*" W a?| C瞵;=wq zEe=z ""P%Y-C N'i h x-4,Y˼@6E[g=cLcyGFW LaiMWp !+xlc'd=~_ Pr߸[p+|bw&d)(M^3A?0#aN|a  \qd51ܾ۟E2c5&{@H[&g;o*OˈG5$Y5aA^Rʝ5y v#ӌ wHѵ& \D`$sw׭/F̒vk:5Vs.z I tq/GW<L wXꗛ"^j<{08KzXVF&/ug׏wr^|W7~6jZܣ–u3du#3 )7֙' BLnf`A9/p,A5Z v2#vB,+GK7e'݊E:ieۇJ^JzkNTyaT7r~^k\͟gOWN 32+5c{*MLP;>U9>q|R|}8n2#"Ŋ'1-sNiwYEau&U Wy?P. /AyD+QN .DdF[X㭔!«{y0/s:},=|)qO,}ޔ󱗝Njq8'|~8u0G*Dۥ?O rcɸjcV}VEpDr-IeXo[|oYȣXxj|;CBZˢfe N70Ov}mFح[!cOg8% }yOYoG5Ψ7c NyRĚIyy{¡P^{JZoFgx_&l>p3*hD[]G8Q2E?O7=Ycd-n&}|BR(84qay r\⸧xi>!&` '(ׄUmkݲ EU!Fs=ઃhM>+sDŮʙAȸKn?K&$ ){mS9:# sZ_bH8hn8"fBfn W*b0 ݋7r7w<ŦIk ZRY?}ßG0c eAAF]A^~|ƒ iM+j?A]?m.׷}2U%5/t\C=upw?ϳC~=ގ)߷fy=m鍛?7۟}uWPsW7U5jV+dZ\\C c++7*EŰ`݈UCPA#]T y?`G#?#꺕Ji>8혖0Y]+}wgNp+ޜDxcgzpY_yɘrLapuw!tSc_Wyn4RDxUJW{{ 'OS++%WcTC&<;;tA#8HPQ!nfoW 0. {y?LSK|ܔ*ՔI &`e`&+槻ƥUXL(> 31Qֻ?]Yu~\W_d8}paq#>6R7S/t\ᭂ%'@={؝loϢ#ѼQգ^nF"GM;%"4Ґzݺ[lgpqܕ&atlwQbυ y?jFB5-GU볠 g €<n^B£' *HК0Wl!%2xHIkOlk;>+k:.m;_7w!hW?OKIb)4ө+ϽSMNet᷂ޔ vJ"$}ZepKq J4bkQ($?rުkPiƂ-;v R͑by;#YGb6hM^;8j D k c&I⠋#xV`>=˞SDU0$sՄw|_,X+V e nhU osڛc` !?{|BaWݍQx!e~{;rz?Hm NTVo?M^n[J_d܅%5 DB}*I$u/l.$#)gA1I.5axE #hfFBT?0$ܑӗI37u ?kyACĽwF VxZm*C&xx0UӟOB$ᓦ"!XזsBŚ)$q6F |K#.Ĝ=YL13Q)~ǷaLJ5axC ?t}? w7}S{]W/^Ӈ;zNkj_vוajHxlrڏ緖L jBpvgun4f˓}UfȏhapO׎ +"I"ⶻ:,քw73|9x 4t{c A%(΂;e"^Ohք`?0LqS"Hw.32 ]Lg l ?# i.h [7bW{Ȑ!\\얟IDATW]_Cք>"_5- S#BЈ4#Ωv 9 . R+D7 *yҚ0<'l!)v/zoF ={f_hu ;u7_ϟ1.uc*V1|U|S`Kvj؃'A<+ɣa~b(X&N U8|j_2I?/]g.5O.F.hX+ByGQk@XpJ?tSe=t^y1ª塚?<0 uoVXhyǕ姧G-{ɭ=)䄽G.Aaɩ[Ԕd26+]|%V3SYƫ #uRM*RcٶT7%ƭh%j-*^Ek@XmǍ?FϿhԏ[gUC#/|'ĕoĘu{Vݻ ћ`2hq ^Vx1N|l :&Az$ ='9'$>vffzh<; 1#Rcը2XUB9s~@ܐ~c@6, C! or@:ڑ5FبfTK͏kWO,+ e/-йؘ4zvٖٶh>JeŠla9ikGa9Gr=lcG)@5P\m=/&SfGSy=!ti~L>#*"蟢5t:|]La[L/`4rTqO0/&w"f( Ry>BwѾQ v#䟊] dř|XpOTĬbJ, Cb?R04)iH~Gك九k\:KwYKah<U!Sf zACܟ:;B NM@KA-($Slɷ,uICI%0HP7g XĚ5aWd(#sdNg5HF5riDd1D^*/C'_!n Ol8%S~baČ1I?њ|{D] ̪Rεs BP McTHp4FaX+ANd# Y&.=QXHoM.:Į; rJs E/%XV62)j{fVd:#=f_i4S:,8u+4Sm!2Czx֗RcCc5{t-EЋW͇\-X9Ҩwc JBuј%pbmt}r!dAnsJG5nenZv Ū%y?zĆL1r=BcYǾ*)t`zԌ+&יuF{}~S-y@`bۯ(Y G%QrkcbTbʹ2XmYpz@Mf/Rz"x#V&GOW-N 1q Y#Dޏ[gr_=Qbd>DR,8C'!OXeԅ<%/_fZJJ"{,%Nf@4fuQ"v^O.}M8 śnC޻By5rWQΪs8UaAqCzʪ6G/ 9 + P\j!t*PjpN\ªM C' :=2Ald+FoMncKpk[޷vLᐁ}e҂B0ߒ NϬ׮x7ɕ>֕<(J89WF1 DRA~~&d؝U+P+[ ѝ"²dz~Z -DO55\GM0\5u'U z,/~d৒f8“sʚ(z9LC,9)@ :+ k[WWz @wvlUG.B/CL!<x"fo8̪55G˘|6UB'EÜ@qfZ~8G'xsdfMDjDuJ垈%B{2 ? Y4ᙹ)A!'ht8-mWz;!֗ If^uDFBB(Fjh ʰI `jwQjyG/n:ww=_hɇ8{@`D0DϵC6{ÕG)Ӣ8%Gcs:=FvO/F>rnooo ,"lžՑ!VuO>jf仧>,+m'zӑveж+AxLum3H4ZYQB.0BRA>BK=t2+Inl\c%R m<Ŀ߶ϲ!n v#t&;ϢHxs_VAOdx5oDȧ&[)9ظe]^rsELz/CwhòcAW,lXʹMt,-"3vJga+4 Iy'*HArH @(i] SlLW=:/šSrl\s!wH t`I^:"ypcB <Ճe)b#]oX ?bj/ǭΗF0pLFq]\Kҵv!]~!Ǝ/ ) rjǺa‚A+}”@ uϦzK<,;mIH_?BeǝS_]QJ>6E:ە"FblDzq{LE4":wv (nՅ+]t|T06l deW"\GDDE\g3*憛-/lZƌrjbMU/8Rv\T棼K3 ]!hk/X:HSx-Bf(TJ D#z"R(oo0! Zufw4\OT9Zm;=;3s„@ ]/E2G^>| uNTӖW5t)I'lgCEELԐsp55p\wp[(IGOK*"Ի;k)ǂz Y7Bzwh lR0V? _Y}' c!còwM0p]Y]utmwPM#9}+@xOPaITC~Y5 `YpK qE @J,^u?w4eq!>ӕ4# cDf ϗ=^wPZMB 9$ClFbՎu ?@ʌլt)se 1ĬGPAPQA'x#9*TxT8Y(-à m59bAJn\vk)>/݋4\BU<ϗZuw)>pr:y07lEK`-tiLjRkiqx7+y+YTEN}!H"|L\ _I-h\9ڠٱ A*2 Γd?,}$L B EjQB" \zﮙXJ4ddx $ٴʭNqD)9܋ZIE~L-S%+y[o-ny}wg;fΚ %$ շ*:2p6bQYL|1fZHoǬImd!cm*)d"!~ b}O$EH!ϷKH5Rs߹`V^I `V:W1 Gs;MHYͮ˳Ynr2˦F7Gvw‰{O4RNqLBG=ɛd>7*Ъ׷5;40;w> DR(`D0Qٱ`!Nn􍟲4򾼶cĴL)*#*"}x]ȟDes Zϖw|eq1I!7g 9)k818 RЉ; ۱Z|1`THFaAʉF&ʋ>qIH`CFVn9!ɻ31}K.u!叀{DfT?oo/6\W-tBҨ@|=y%2i 9Yd'bbN* k]^$F5i7$C.u[_˷zQKzN!a[Aij!=Z$Zm{*`(v&*iKٷbGoy|+X;K^-܊MKK<XԴ;d [ !%pr` 5E#R=ewv)s<{e8h02sf >3V3[%JOvuBδ$|[#˗AjY_WU$l =v]a\hkf 1~]s;:@:P?wQҴ4'(Kos!͎u\ 5#V+1È _扻 KB +/*.߀~q8K.W6RG ЇSDMNQӃ+758u:YVj0%?) B@P>OƄ<x(A  ,-ZRķ('Sr5olFq&=?ʭX@0?NPCPTݒ(GbCy.i!É?N+3WK0_?)6&m:i#q;)џۇ/;FJwC zuugT^ۃYVA8֜n(`U4-F`κ#HC)(PKPDWj<%n[@;$;./}GI F*0^Ί' Xgd$P(vYDWتy&g`r_K#K WpWFJz;k,r<ů&*N1:^2vS$u9]H0]!9=nt%pgR81# M3n YZy(- !4t5xHGv=r  ȫȐv7I RzLTZ> .gуG}Fr7ɬ}pH~3D4V[bdvRL$ u¦ hv o&*GRe{!z_d;hl8Ǒ j?nA)Rv=RBX3I*>J(?R̫H̽$I -Z ,sS:Q0s%yv@t~{?SGZt[{I}٘#[aK/ആj/(~Y9\?~돍29uC3Ig|bn9a^)h,[y@h-]S@73^|{Ր@W!E2鳞fʛj(yi hguIG* JI*ȱ‚<9\"+fSF09?d|l(jx2PNC/Cc( !a[UK@nFMccǫ#3mqq{kh#Vj乎jr)ʗ\`"<]ŗښ)" K<* WC9rSYf3aΓ{rVN3󠬊Âu TkfbAE0pe'-u=_޽7()@hzqFkaaa~0$sQgv!pߌ+(nj\0HKve|is7^us8ROٛLN)?bL d8w)˼dhE +fZI@8A;@-e Lpx¼1h\A,`k ROfy+D.^3׼I,ksWFE7rm|w|ZZOP$:M&`0=/VQC'1܊B|zNaz^aVRNIO㐝C.^}rtP(B =HJ,AXPUD`1" >~3#fH>:1D?r'ZDWc RJE<$̷c_ Q`.oyA LQ,`ӽ2cI>z_@,/B?W{@M8jŧ:ԑ}4WB($'R$,z&dhȻ 5QAB9m?Gc8i':?=/حbslRLYwJfSQ&{O a^9}9&VZ%GQ>.3h؇x$acQ:ĉZfdՐx1(tsV^bAWEeR>a"z~Q$V,$1ȶ* pC֛R{説0i}aaTw Ft\'oؾk ^>Y(fUdæJiD6~Cbzaz*~5~$pTzވ 4b%m jQ/X)(n R.3FX,7lU&nB[UUQKZ 0`|Kثj3t`vo5HE?b݉Q @<?)+6Ki G+](XVwvua ;t4#HeC^RCBIC3;B}W٨m,H%w/lE" XY)B@HH,2ù?\scF_$땇)/޲g攳r}!KY'8r&t%iWax8Z9xDͅ\.k/ `:֞b~bV:KnPt"( }!Ę@ @ `IF,)616F,\ccrzU0I~mq"B\MC'5^#oIbN`$Nԭ!gw)f-/x D*p|cxOܭOls 3%:72ԠTѻ=AS ,>m աfB;vv,چr-TY1L|WTZIFK" eAO?6F aFn68̑NKOM.'*!(O-?E'aaP!C's×|8t>:_c@D9Iٝ?{y,k(rD wŗ%]G{QCGӴ|5ҥ> JkM iyq,Y8`tL7r ƒjHBrɄ, BW4ZHrTS!m1sL#O.ɯ!8Ճ{ͯ8J0Z+D :(C`Ne]_ q?veP|H*×"lFTIk); 7s?.ZzS)"JjiJ\*/M5!z!\-Yls'G~xLV 7L]4 KHF,n1sW 9r ߎGE*fΒ5hk~a1M[K|pʯ-.gV^HN e[؃G }t{$%cφ=?WsFIMIFJ!fBd^u"/δ KR8r[!b#w \l^5$#V} Rn}r=~K#hT8 kL.?LGqB<t@p{~4ݰ\W萪 rfHEvdQ\f9itt5/>c.2'{KFzAg* dg0h,=s ޗ$0QpBxO1K5#2IIPT *H@p1oG$zwKR\Տ;RR";Ӵw?3ѡ1 p5TùaD>q9n#>19){^)rP?J8%,wTK4 yuG%x8K SY/vÛZU*!PuE 5"^2Cv Ɉ5$jY 3?I.M΋~!i؛/7)GC_ 4:: 1y_=d%*FOl39z|RRh۹*{\suU<^kT(mfYX|_ic 鵜rTeT?$4%D+En)dUn:>x&ɭϵr$?*yo}2L:u!n0sE=$! z_[ AyvhT̕ I zIGG8IYҹ9B@[ښ,Ack_Q+o3^O! w<5ǟVT v"-;s:eC 2S\>^XNp]꼞GJ-'e*/kX|fdENR5JlN3tj( x"]e.*!l 6#T!.|q S仈G$]_m%d tV0'*yx‹%!bBnO^'\ָ8v2!9SZ ~R؛9|cVbD:o(94QC +Z:^4ך%Fq,.I "{(cG(وL pa<6+!y"ڛ:.IR?w@b5~c0&y@gN($APߦOK*!.\"Y T">њ88|}Wn4 t6up -Lh|XT/VDzq*o3A ὾A@-ݱGRAFgYk;9%a ̈{7QX=i'/7 < ĞM[!\{1+3:dO}oUKC(1*CZgFŐ2;8XH"[  byp&Tn%f.9=9 նAcM)5ł[g)CXQH"3~A@aAe蚎e"?Rt+`q&a+ זrHI%! ۚPwj9CR8f/)Jș=!,``;11C 6fo`I('@|8n8`+?L RKأ1q-5 ɻ6?izeV`D9I XBD 1;ݦ]O&jչmiXZ,w#3 2KI aVDHq(bgG! @ː@] ڜE&kz@6kM6iзl/>bQ8n1'3I C[Σ0N:)=` ƺ, aE+cy[3׃OsR$FXv\ F Hㄐ+ ;$T>mW81گW>0~=a@CjTKtvc}Ш6+I*,ސ畍V)G$9vP-TcېNPD9v$5$rV'[ 5g)?&CWxBNfm{ [e/~I%h^`4Ot~5*e7WT2>E~95/#LAohM_Xn̷gTgw\>E fZORig /KPq$L}LCJ-Gׁ;8 |q[~T-̆F^G"~uLh>w cD^))CEk֨ƄYz `r<g0rϊ|w__G r0ģɫq":$͏H!:/&b"=DQA%q_9R59Vb(^+.-4()Hh^Xt^@x3z(@L3dZ q_mX m+ũ<0S.sH®Y'  chY'l_z] i6F X읝{{:[^iJjvSpaкvIHgݦEqϩJ O4oͷC9ۿxAPCPҘw#&3p=OÍn5IVBܥeARkZg y?lS TAX?m `}e s`N2EqHrL`eD#>_dCP2XTt_h+0 rUl^F{.RK>e j5\џ}DgpэSnIY=<TQNWJH[I'5tMk‚#(4̪'q7! BX(cU8cw\N>4lcT(hrn;}9=ty5x# r`뵺@jv[s)W88;*mA~ȡCk DەqT-N+V;WC'PMYR{ʄ6fuyB%ɤ(!ʶ2 jM ri45bs7! b* zqȏ;Ӛ<Q` [(_g)>T5[]q}~GFzA\moh*¬f"ϴ+] l#frrG ~VVK9=TBJJHBKk5sQd3IaZ9|xn Q!{>@.h=~wI 7 $'E@l*B\AKI|lջ}|7*$AΊݭ%\D» ?G8rDlCoBj粂7Ė {Ƿ4.ld%I9, L7?z?w9pXXQA3?bV:qĽ[DUG)uV:͗Є'\/'>t|_\wq?e>?\yX8k*L"},Ó5m52xqB4,!ׇzOAYrԴ_~顅OGh$)!FMQ j'PCg ~'!ڏ~^FX10]N|1%=+Nx^8󥻣Gwg~v췲ӆ~H5'&=|>RYe/Jp70I֍gLUgE_'uYIQpP$DT hĞ}q:.f9zCpNI`3g&qjX '"JZ P*X6bAdPcǩ Qw I}>$&[f_ P4DB 9-]j\隮k,!_ZtUh= )3>=}l8||bfރ|xE P,e۬"1 & dWC 4Uuys$5k .=/"]M5uΧaIįV; )^>ޠ ڧf.KnW?cL.xRhD7Y[8{zJh.$6P|aB9tv뺑D婪&4E=JuZْY>5Ք}Rt:9@h[_ŦmlAܼI7mW4qa>wRBHXj 4%1J-:N5UD)Ppגy~Bc\+^҇]Hq$Y^xސܙ3Xr =)Yb +a '׊ˢ{U $ՕMIa,6j6y}a'ݢ}zNA)b- (44q'_CݣmcK:?cέ/f׉d*oɝ:Vj+RY9D`^|,o(1R&e>UGdd[Z[GWJS,/$oNb}hSX+}a+#W]cgoGb&yd=3.Xh1}KvRh*uE* r2z#dtr<bS>V(ƻǚo<&*& ͌=մ\ FE"8OҊꃸ9Qa;/iNprgH $*!rEIڐ%2sN B(Pn/ʏ5F 0P:tV2CWȂ&D N>%nJ^ϵ %Q5rt# ÿ`[' }8h9 \x}6HQܭL"y\o}Ӕ S"aNW)#9x$9J_2zCKs=ڗQ!Y䄜8 8G <7҃XкHH ,Hݑ3H;k*XF{a{ajt=fiFu҇hꮽ2 v.g;Gr:ެz>]O5CB1>v.LJKRD-Bb7uGD0r*:8RnVGOu;Gϣ1_DS@TB /J 3j楙[ڍn*vQtt }F*ɵgВĤvS9\ݕ|te%Ghe(L90eYҏAw-|8n텣 َM*ݣnK[Yqn6뗛JBj~H0l$IS+5[U:."z.NJ6uG3+E$?>AGLOL#bRMG[⎂31ג𗐠:ЀIBvV>ۍ.跍rz5^WurZbplp9'~mH"/ۧ&pXp3͡-BzG&+md} +!gGK%iPYTq\xS  7ss~_=R /x5cFu\Ҿ_,%n'ҏH>*7ĨN Df;|Ҋ,G$N_OOGG~/qld]$&UE.eL90:&%)yڊk21J`Qߔ:wٜ4e %f{1qʂB?#A 1r-JA [ Wo;$5u){Sjc%KvAUn7Nt[cGfncyic"w`"X;+ˢ`"92?F?Awt}DEHOt ˖4d(=񫽮?OU5lE륟SKEM >Bü)KwׂEz4M d%dD8LZ$dz -OFh|U*X3 Z*eờd2~"5Em,QkwB8'DC'oi (yV]c:׿ݕ2w?Ib=-0fO}U"' [ !nAlb-+1ۜqD⅔Uky!,1'̏Bs ^_!m<{|=<@^<`^$C_{n*3o@MY 2Ws*r(M¯`6 y_%P4"|="nKTb~Ҫ x:xZ;띬?qoEP]|]fݫeW&| CI`#a[mfX 2\'OłˌPӥUNj6Pe$4?Kj"e=agr!^"O%]S"jAT9`Yx[*K,YWc@mq/T@r)YSs\Sl" x6c,R?ycМ<;ȊU[^\{uqwy,:0=  ୬aAj>muBF5ÚUI6]]l-;B;z`!U/3QCoGWjXs*гr B 9w7~d!C}eY a\JS.Q GjBT\\~O ܗfFЄEme2CpR_+Jg3BuVlܕ 4|jXgYZsAOEy"Bj't_/ģ3yVe Z]qd;ڷO-94z0Ltr,%L ¯o&'<{\eRIؖCírCF$FfSCGoS?H9oR_{`$ѵ0WJQ`Ú@wѷm=qA?؈~kB zA?7(7)?W"z"!R|.P4Q |:=rr^j-i߿do ^CRC'5@1Wk"p,hs`)ߠ|5J, @8XB X7~T@}eov:|TۙAs5? ¢uLXN"*Al,]x7CU(BZ"=lMdPdf]h9FCaS fh3# I@ !(1JΫwCMܐކYA(E+P1P3Jh:+^ b>%{HCl@Đ"q$+sj[bW(E?2|gN@kz_pGB&jn5t ҭ >M=yL)/ ~$*,oyG7Q`_W2(,JC+JoSБ ?Fϙޭ/cex8TD|jXnFu觊b"n:uhqH6Ǘ8w!3 mIRxL+ rŀ걜PTeQ2E۝#F K BqB IR+f %֚IMN,#1y^z(B'UN6WnQ0s'֧]<_dn&H[& <|ٰМ԰ RO>L;t |g dE;tI9(6X@ɿ]Vx]Ch*m˯$VС:һgI?"GsҚ:+H5R!@^2i/h[EJsduw$OSU,<3G")ujwD%jOrkMA}8p͗ }^u]5W-eXKb@]$lsH^Q?ɋ[Ѥ1ӍȏItQ@-WD %)9qrЎM'V C׊~={IKꔅ!խ+= _ î!hz?қ8 U奏f .aУ cd_wHGS!̀P#]Pd- “+$a.qAVMJep!g;MtT#0aW$Am -c~MD}ϧ2zED3Xt~4ޓp9$afO`hβ2GV%-Eqx ; BBurl K 0ڠi|*%Lejަ.LW̄`%!Tt-e㇦W#t /O% ~]IPAW7Ǖ5IsFO>0:w/yFnOae*=ęx}3VȤ[-hR-q}n,nPP!f+Sam%jk%L 16l/X,bȼpڮ=<T62_mdY)/5Bes} :ѥ" b*3{,^#pV)\0~`!L% "? r_4+t48Vi~h{Hֹ W N|%c $/Ћi`RNϾϳ#e1}DN9 9?PY ŽJqlKgԣ%#wXTD\VLV@GBJFr dPy\ gE39ᡨ10x\ɹjIE|{0̈: Cɣv?dP 1w Rxɳj4G`cB$]Lu@y"U"Hh,%zOhQ ܉)pO%aJ!JϙH_  I\fn]saWg/ECIzg4FmjK>aNɜ$$pNp!Ӌ@y0%tW4gZ\ FĐٻ4"Bzv~ń))wB^59?k';.9{Ebhb VbHb[AhBaqR i8V({!4[k`ѹgoշ^68t\qG!4x@ q6]#VG$ e5%ͤ\J'' 4,{z2Eg)+b;(a!X&.H!Zt~WBuaP RM X͡Y@ ?VQX51- vd $Uy29 6goU&%/?X]aUya)hud #o]dF~4AyI%(a 4R޴$Khdcx]1:&evu!MwWp]Ȍ0$ײ7Ac$NB,vgV-4D*O^c. K%{WsK {B_ ahjX:vsm,Um~ц'%pXRYDFKQkE.XD`Zm <YˆUQ ,W$2:t k#3ٳ62_-/ܿnJA+I{K 6S6o R`W \8aYo, {f&PkY)&E{8yAUղO&+3^Kpf?|SNGD]83=cX~p w+;0;$U ngk}0Ϗ*ZY0Y:Wz];Z矉nu5out}}iѭp ] 8Jg;c>v ;/uh|`ﰈg]{\e< (IVʯrr40bgˢZ[X-p.T.)GoPs=MEHna9Z}}9ł.(K{0S7b[0׿>D369ׁpȘsJ/n6D=bwWfsG/+u4y ?l$x4a˄\bRx*萍_xĖu$z.ǯZP:Zt2yW;e;&4kO'Q ֖zz8MBFUvsY^K!F?^9S6 SZ+?gLg?[~oɘ՛Y u蚅 @ȧ4A8q[f 2-~ 52kfcCJ6-J3Z`@ªtB^,,sha9F~e[*K*#SRTۭ)wƫ-Ls"+&^dxtw olπg!rƧK>J/+|x!GJd@Fm[gQތ?@9t^̶^'I!z&P(cʕ8M/PS!ć.N tͼ ▇t05h^,[!!Y!5404%˓4.:UK["Rpt=v !A%yF8y0X@( csBT,mD g=#"%kA 4O$ҒyOn21E/]0"h0D:>j`I`6O эTY-Iv_u9̲;& m<Tk:T)<#M_{+㔇ݲ4z40$E |αz]vh: - ~}[q*Joq;[4  &qt&i]VrPw/E \]?@b#l+g7 =o{MazR\6->~32sFS{Rk6b 2](c02ai)10I@"T+`H` >e ӂl 13_G٠7CL<+"v6>2 q2zK{^NAHF4bk\"r/PUR%$8\BSo^}+r严GÝţNӵ5ϻoȵXC+ N?V֛7χ= (~ABjփop)YEd=o-=3z:\^6V(ρR; '9<W&-.".s,C AO< B,HđS:kV ])te_!}WXs4L2 T>4 9&TNϩ;yRwAp2yR@2,1 "T$PЉ,c br,9]nہijw Z Z^+*BŜR/Je:A+ۼPt؃;+I ^"zznf{"@Ab0NX!PH ͐fBf_\3 cAt [R.08˜~N` HA ~xXe$ \7ݫ B4<,~X4ML}L@~ٰbZ']/EpsUeTOF&w|2]ɛ2OBלB13Bַpe+`:u6$Vd NϽ]nUvw F*^VȋMO Td!$CQw((RbvBu=FNU6Z$[ ʚ-n3$KJn~ȷ 7N6&g}~ݰc}]`ÅzSw1Ӱr[87( =bO_1VZuhE\ žچbϑPr'tb2Ozm RCd!4V#o ?XC{@M^.yH SdH0BHgL Ly9in C\& AZ;XL"p@]pDŽlаǫޯ|%s#CgV,D{n֒{m 2BuhZ-ɢ8f^Wf~ࣣ&Q]cus9P$Us^(1 [ҳX܊$b 3#MXyZYr@C>YQ-~Q֏fEz][[P_fߋ">OYs,065Sb-3ߕS&K2{EW^˝ʘp>쫵Yb3&(|0u(?Io;<3j| GT$o'Pf8*d!Ϙ# ŐNJ`Z7өb U/;ҍ"4 4 vb_ υB  &Qye<Y[>y+ϩDžS̒E.0\=T, !}CS ]9s]i sB!qZJ _q2S ztyk޿^%'r)PsѦ%Kho0 <떍aq}\U Z!+CG`xUhHC=G:|)2T8XOAfp!!GK-K85#üo9r? 1{0Љ;PtY^9@e@RvWD Pބ:Gދc& |=g9]=Ik/;i۰KȬ-;sKΧt .{y|,|v}e(<#E+KBL]l4lLg (Y l;cZ"7d91dꢖ!DrgaB)fol@ $N=Ōyxo _Ke9V[KE4cZVWYOҳ? ;h ^6著D>\`BLhD$P'⯼hug1dOYYǀZ ~*}aH^u;]R8`{-lCy#YG2Ur sCl<o,=qz"+Rü>>~tK$r5wCe]NyeVKs3+M7Rn@(Ӫryjc:'"Vacx4i,ĺB~]Cql!ByT%^^`XuVU#6+b  2oaBW/qΑ b0?Wφщ/`cf%< >,Ke=R*jL}~"JrZ4Y%=daF˻X@2ݧLsk !|/ Qr(h&S#] ~Ҕ"!3BYB,4[ebĔp1+ t=AJñ? ‘|j [>R! {0K{uˢ҇VS$}s췸@I-ABph$S&Kꎩbȳ0\+'$zyMmV(" <<>-ՆA7(,~Z >x BQ=Ox.v'ߋ"h@ Tueh9 1S ?um<5ګ/KDF!3":{BHP.,_&T#;wCDEZyV^1>:}Ȅ$y\ l2mR5iGChxg{:hC̷[;H_pȂwCR[ǥJKh1DغU<"gs+|w[+kg 45y?7a5㯬|"@Hd EwC$B3peB!>#1<OL!'mC=f6S`#;Ѳ S+X;Rr]ǶmK֮_ -6`E";ΈWmԠm>1-O?lhXaCm $M{hT! RtEghp7Wa7Vz%$N‚8i 9zv2Z/<`#""By{&c t 9hq?E:86=/FwLuwG&=\Dg(IFHiĘn0t8t&',b-+BWMbM ]Xp@MDj >jDj%y CL.eJJwC 9= _ҒvD\uSTCݵf.AۉLؼa tMMiSwE5 ٱq3t<{.% Fɐ"@=ViI ln}lB_Я.=wνL ތ3m0 "BXd>VG' B$qGW!-iŏ2l&|>19oÇGl̺Of9~5r̆0Qs] !wH]\&|)1gd? Cg$az0a:?p줅{nJK{XDf c5|3]tQ/%șTJ!?[JdX'P4"p OܟVHJϢ\8atnJ*{:}S N o<#0!u B38|@Fe|ʈ6h*[8o#4C!漌?@#WE>89y@6'f lNHLϊ[E=&hs|wf:$ۍU\FTv`n`6ϹAŐd~J+ !dx<^$f"!]څv|۟BD{, D$Y /?gAӉ-79 ydZE -n峳bC1뾄UZ…M\Qq˷Wb`CVDWzNβ|7I.~DžC>rx@ޡ1\571! uy,~6Wml}7,'2gӛh#l?-a#d+8EDȜTp*y,ɹ.ҿȝ !6 cm2#;LV/qG(x^ /w %Gvf?#s<^_yԲpvpmZq>;#U ּ?,|މj:jHf⬭y2ɃR~6E7\vRo&sҷ\HK2!!yXh(ծo*Y|riPLOBN }iT⿾@5z4& E<OwؠO<(J#ʼn95x})Ѻ?/e.ncCY]g5 !ĐTr@by,r A3W4)_Tfsf˄q@BgV7`x A>O!FdyτW#鉙L[LCF9>w %%&656urr<jQ!_g-q;oaFԶ|/tzsS|, nJ#憇L<حXL'$1ƒHD/o8"B.!w@R&aIDATXFfxP/I5;Iw8>TL*Dw[0씤x{'9q !OC֌%9 Z=W>J,^oC!P\@ÛS›b'o O{krm8mc_H[>i@w:{,e&^83{܉U"4aMlr@B. !!o r( etp JgB$}1D5xh\=:cppqj3,CY~dfrb:˧Kޗ$*} v$DD] -\29B3?78BP^L=ٸȯ>n)ğ5tXeC'B-1Oݧ4tVm7C d֐d *Dx5Ɗ5@XPբS1Փ@"i>ʬת1d<[ Pke@!Y6."Z&=z[U˂vsaFSLcvy(+4sJgELsCOjƕуPlWl!iwQ?W,R0knɬth+T_պdwn0#8ү.y;d$lj #jz;{A5VbHE(G`wqPPfB -g?:Yory* ,XivC {',NIyd ҆{ĨѮ|gIġEG = ֜At#\1Nv{T>ƀB>H=airiSz Qm_*7& P9G!jϧǪԝ$G47XyF>\1De|p5U^"O;q^{=DZc} ^"Xl)(Nvɥ~%\|ȃMUIr^!V_21P bsQU?Y$GE/$P? O?4SdA& )@ɍBHVa } 9 ^!HĄe*zCvcDgӊx`\KK8pUE{? Apu~2/gVKS :w3[.&9h13)oP 9@p~M2[9OX8 YKc4Uge9d}1D,rz}QKׅ-9Sb,?CXuuٖ\ۧ݌n_r}(Xz6xq㡺K[F_0U~P6Y?qtQ>V|[jy=YJ;3N{%(~J[s]}(̀=GۻWB[Lj,NJ}XΩ2E0:A)lAD 0ي|ϝehDnܒO?G?#‡Zʒ-G) i2xtat}GT2J<ÑA[W8sVݫ_W pHkal0,_h_K`BAsF_0tB:<k{J=t1%%ʡK 26CƳ1MwQw qX$%QB ѯk/{zaBg?H,M =wgC6M L zx";}>9[ysk6nnnNJ˗I||5@ܲHB,L=MFw&%uDAHipݍ+^P\Y69=)S)38`1r|IOXy{P3hK?66`LgH%"fr "z) Ӭn>+GC!s !e1+Xi{7NR!}ZOy/j%M?D3GΕ,t:C `)kf$pߨ|9y=LM x'O !Cvk?BFvGJ-'576[*wQ%2S) Cam:QtXwd6I5!B3uGVj_=B+HY$TPx(H% /P !!kdY$LL;3\P5sJÐF%\ׄX|%\݌Kܜӏ̞舤aq<9Vl?Jz%|j{ArR¯^^4}v=!DK*޷u5F#*^ЬkUJ7S "2.ɯO$PDe pO+5j#T1ST:.bϝj&(t /m Z\:+yW6*"@FmFز[|.s=R^:PXyט$G""'MbQcEuD[j!9н/ Rw.f5:}Qo(l"-SzM.Y/Mh a!!iλtU?2M0ھT_g\SFwFafkEgA,@HQ0;o/lYﲕі8і]уj,Y i55ft!D' w2Arf[Dz tس_*Ci7Ȁn !!B[oaXMoT%JݡC17#Sah ^x([?*gGN^'e=OŏЎ++Ac'D5l4YI~s{^:\!ș2f9.\6]fu6ׯ=!XJx1 BhrUZvL5BZRBs){5v !5:ZWbFc}-!`o+eޱ:I +Ph;_KGgkɅ Wi~xǯ|xN|Uy'QzC1? |׽/fp#p˅a!ԓȒ%:IL!BsbxnMd+dɟKΙS:ܑvV4S&qLp nXqc1K=料 s|Nw9}HŴjD4M3dZ9(7*!8ߑFﰆK!Ŷ|tgFWaq\ϕ մ=2rY9WxM*PFY'k~UK3, Īc7"B!Ku+k \q;E L7>e! d.dŽdND9tLflcj޸!t~ޗúNdcVņ9(%p\p;VD.qx? Bި<|PG1cR:W (m͊Ŷ!{R7jh$D5,tj;Mܾ.fOH{0zYeM 2=Rd{J}b<4(0G |BzLEfFHimHELÇEUڥ7øR=6_!rx? >*.,.vzuhy!M}Zg'II';fB ; K: tZ,!*XG&&U|?>YĒ ADVG}݋.Ǻ֮D,v_Ÿ^' !b`- Y1M܊}1;Hۙ&;Cl@`nQB`9%>s칐.gg8>$s"2mt]{s~˶V?95ZB𽏐@bBꠗ4V%V.Df'&0o"Rʓ;92p#=63\!.lgt)w7^ȓ(SvךovJߋ r~(_z`j y0`$}Up2lA+˄c$s.8S Z~F1 ; B, ژ4).` $d D*cI_{'"if"BCw7 :1}wGQ,Ǿ0E |]Ž3,3;t ĕw8#PuQ P H>j ɃfRw`l'KRYP5H+`ۇDM"R~8 -[HryB0f"ؿ[ q <8nSg}}% #VkD Dr}zQ{z!SU̡B콣±ͬwyQek?{X՞bLKsgCh @sWy%4BF>1 ?_ r2!qљDwġlES$D !y횎M}!$"^,{+DWg1A^7dVK~?"D'n}9g bNan!OYjV`34C6z ;Oj,Lp[WxVI 9D8g*LІe_ ,*gʺ; UoUX.F;v;Շ4VL;UB')3<:z=8,| ٍQʯ_)ſ#|i@0?N&9G#{gҧ10=nFQ_J=veAԕO^ߵ^9̷!h*N?lrA7<}IJ"ID?@b8˒P\'rasȡ>CVIOjH O28_;*6[wO Lͤ<$BK'Ik/Պ "ةϊ7Di@7Ҁ`J}Y wU$:dats|94Yn^#IXwa>|rNLA焿6wCh@Cc}:J}Ix_]Bq3SE.$=@97k~hK[eLGוY dO$i1!X:4y* DV s鱪H"yႶ4Hn ñ=.6ϱL+lPv#Na)鰲5"_!Wu.NַH~A"G_*=ˍDpWe{b-Rl.=G^<]uf yOUIbd\>C7+" mceſ'}=să D,LQ;Q!\\Rbqb!39 ecg7akd괜K8axyZ_2r>ǘ/o@DoK6P9"1oP}R_1|]HwA X ¤jȈ}8_;vr P@\ b_5jTcS" Qv5ʝЇ Ίv+:ϺNyc%kIb7Cdl:G| 6D`􎪮F(:DW8|b7Uqh'v7xh:)خxZӡ"K0qŧ_;H_ @*L%b{4&] UBHwU0XuȔޮ H5X ]޾0s"׈a+ϰzkOY5c0ڢsϘuR*O=d\o3uR`z; vT-oq#xq,| ZJiB;v!4wt;aD/Ύ{|f|Hre㴟Slk^ w7 ҏT6_Gv)o#!'w,#vr0cd zwDDI,y7DZg4rkZ4YiJ[uμ2vv2^SB;z-o"Q~Lzq8ٷnRWG(Jnj+ =KAH I6~rUS6%'@Nߖ rrDC]:ߋ:Qÿ%HjLq13skٳ5dxVx%87+']A1j&l%a\+;vߗD6}/NY;x`LjA=lB'VfV1_qG~|Hc$wF\6%n q3Kc,${a;4P!Sm{Y{-1ᄽjE[ti6>x_Fm<<v%f9BG+Ȑ68~;d5̽cok&a=Zj (ngZz_m?\2 r{"!H?ZCo1C+Ie !w6L52y<sѷl\n3'E\ΐpWYZeNI$Kv鳺OD΄u'k\WɓwugGycoC{sO=U?:RGkvmJ _ox/(|іjsԒ7nF]j627{0k7q!kNQ|md>F0R?]s{5pR.rϺG CY<&!_Eؑ;m?@ЇO?>B8Cd7-.x 1coC_lhGTGF||Wv'I4UE0I`X(Ë2,RaC@<7_\V X.wF#]$'wEN $Q%Fno>~^y7*mw;vKҒmz]('6h;:u+XTw)#bJ)[ 1W'q@BzAϞz49@XU&2ʄLPZQ\p12f,H] ; ]#M?;g&gaN=-mvFv_g>\ڝhr?oN-W=3ɡ h>^GdP|Q s^*b*ފ0ZYYȃ*϶!q6O'x9ma,~\ e10o6.X B[ oךu_0reK)ݴ d G)!ԟr671%/W{V#4܍‹>u* X}VTUɗ)C׃ 550,MRȰ8e%=H K KHLLLmk-)azz$nF~A_g3bF_4 =sKBh[v2T{o7]3|ߒp Gg0P L' W'EI'-{܍b(ah3cںSH[g+Q<* oO=IF$yua6{(})>_.'E\WiuT-g֙-g%'','mnνNTN?ݴޜyHXj-!iF'јs.J5L2Dep,cQ/ Y?o&?MB*};@CȈ#i~gr+uq3#5p ${̳٣qI&p.8A$,~@BMu6\GH[kY+F(ͪ~y/|)555-9yz<#>33:fc`TޫTʜY8%&A/v!F;8` v;$. 1pKC'|*!B/@lS4ew¨I2K߁m!&8Q Fi'gVДpDRmyd۩[,kLOyX>;wZ+_>ghzm9*B W6wL)a)KK iiS{c- g]g WY+$HS.Mu[g /_M;P؍Ўj7 gzȆ4'铌@=UxoC^ q/UMF1Eg)#wk)[1oX8gQ%$qR[0߶X257ᵒIꃋ'.QrG!3qفd,͈0W |prryyRvtE\SstIrhov]MUr]aWYgTiɫ+r/5СXhyvgO,qssĎ/c>-`$솩FhKIe pH@cOz~VqQqU5y(p {+]c#qau{~H]E*udK̡6 %t~} K12=7s?q3\yQXx3[Bؾr_$%n f @BԀ:6v'bS$G<,wYŏWϡK~I3}-JҭZ:GM@vޖ` ɖDžqw+ E?\f'5,ɉ%^Dan~dVe O7Kߣ܌:}y$mF=,~+a0gKcb D"*CIu)}JV54ыJ!sGgo5}M|! }rDwKhAmZՉ$Nd$WmͨҸ댞̅Z9Ϯ-3nwA \\VW8?tP1m3oRx KvqŁ|Y*TO̒ʲ;u۠l$x;Ous8kge@N1c$6Ln8)"2>--srܹbPX땵~$}ᄏfmvvnv~fxun+rs)e0lX頦S)PLsѳ-ּDpj[: 쬬!K+&s$9haȊ!5֌reA(((k=v !wn*'"-)rAPPGfPVي<"ڨC^2mW9]YmUUG #q1QQ[K)}}ϜMKjR ^ d5cw'v>aR9_CRGSE$,8.Z oX~Ǻ 1j%:./xψK yo)!yel#QS~'v6`즰phlh}d1--r3<|Po :+1gBk=ګv٩CϐjݠeW^/k'xQTA !e0ժU+8cs-;o|A,A!|W8DLIM[Ӌ7]556/+M2hr6'紮#bl'4~02z3|){R'jA,/(Tfmf9~|X~:!0J9aXWKM DkqB!㚇Ӡ-У5+ǷȘ*kmrG1<ɨӳڼAMVy)/ P'=ZV,>sXrfgjTcEc\lllzxKUi9Yr5HF#z@{Ae=<1k\`"w\X{uu%V)|rߵ?I޽ Id)sHs\~v-`p+1X.?3irB vhz5%+6!&sM͓ja! SL8|_{h7hq_-~!W8YTE)5 n\(]ӛLRWO/l@01`}1LHsfvQJ?+wybLgtDrIێ6o UjOjnUˡYH:R!!]?)'0ŃߍYhmzG@)Jkzvqu.4#hoC7rA6s gL{?6F}=?F~76;kН0Q/e7B-` -jJn ̈ӥGr ;(EACLQ@v,-$¡yVEPRX A!ϵ-au!/We\$V2V>KS,eX<.m &;]5JyGV+=!E?ł=žMO~Cw7c6 蜯(p\B.G:=`^)R+^b;D09<3aH[1*"Ƈ$< !b-(ˆqvxHkB2t dvKQ' y5 )¶δN°I}V%ˀ!X۽daP@X :tMw7VqUN¬D pNOUd`Dz\[yhr? )47Ð>rR`y ;R&wa)\,@4?+dþѪ 8#`J?-WYwrµ%Zy_q}S V4!έA_tmC\WM6eGޱҺؙ>v%Z(nXzX {Ч!CkNJ daj^Dl y ď7ûq=P+^j `^] ZX*[^S*K5Pgc ]GR8'ͽqta?VZLPox+z&qt;cdП1z B@9Cb- Ək07ʲS ^`.DŽWr# %TN+B!Բ)Ok"[G\=DPfYcg(4s{vqLOelr}9ԭ=mG>/ݻvIBE._9~L|o'Yo?F塰 ~IUX. U[X޵!H*ɦtүl k/Wf>?'<*&'c^uDEoj2`TQG\7.T4&'DKj@hl+nsH?x9~M+1n[ hsAlj*@w_]@Hd.ӆ 74Qj)H1$1(CW BMDȇ%9禤vO܍%raTؠ SR^óg)٦є^u֪uGFrCZgy[|> zp[<@dY]C8:oKN ?L(lP_Dx'BH}24qPñI $~\|F"RNC%WĐe=@v"9<݇Yt9/  v9KJjfJ7ִGm4U+YpöQXT5̳E'ob&:J@Δ!_D(zvբ&??:奜x~u0`6I@$4t+\CR 6sx!9 /^rexiIzWO&v?y(c)v?:jcX9~.- ]FOv(2Ȧ׷|ے+ IWS )z"@3x%WQĹoABȺBߧ0O"=J3{??9U?q B0c] A8Hh !~ЕO=HkvUs/Thyȑn8efVPa+.-q69]S}fN*,ٸ72csU(H@$]YC1)&ndDݞ/evs7 @ď7? ? A:cP(z!+\X=}T ík-BEb6=kh[(^]Ȉ'ys]?#RB]ueygiGN3й9|_{XVNFwXzSjbScYRrWEz1o Nh`ʞ 5!|Zus?)~<-?Z) wMpc!)P ,A._a)U/=cap ]GScÊmL$w޶N5,vժ&W 3{gjurNɭ'\XA Hkގ=uo%vȢn`Wi9zE'̀$R}\HaU)Ć-F{?xԀkܽj`XhyNXHߩA_,M޼t(ݪƕ,MDL[BG{MQ֠/"Tr}[1׋CC$lGKőғ3W;PG7z1",P9ƈ (5mof"ueċ,Ֆò0=0>UiFU➏|m} =H4z5Y&A9 :,5zC,ʥ:RA!;y5qdê" 4Nkp=}>[t[sGcѷ\rq:|i*?1_gԌ \O" #7e3XoŚ8\bHyŋ I rpw7Wa:-zдy'HM Z(;OgCMxn(a wB5mɡjȡ."j,I 6^"Υl48–>ǿͩѹ=zqz?YXs%rC]e|K|`˘pf5M%!*ΞfXɱR"* ĞXD^ZTBYRߠ]?OO^ٝ &6A Ŷڮ6&L/`5*K+U꼿!?i`>Uz1DM4 vP$"r+X9%3q]vKĹw:mBJa2qѥ'#CY9V7_1GHͯ!j?O8 5#杛ڸ1AWY%K&+0rǏ?: JG~<\ͱ`seo=#ugLxNnDs)7/}OƲ}1ĵ37+^\ ?Ul& Z`MIe{/řY†ssNkAT<)c2i` \?Mԣ@kL)04gMߨ+^ۛ^l[c@h[Gu"n7G^/P_Vt?`x~BZ%͐ AFb·t;×Q4SG2@TeIPy*4.}-kz%鈈ʕ(v;Z^FCQHedTgRJ_YuFG5Ɩ?V]|ܜ\9<(Jí;7c/SR5%J8%aSE1qv"5A|L%g,&Q-)/w4mFeT =`psCE u]ܟ!F ꖧÅ0~^~-ϰOE\ RY%zDsf ȥxPqDkdT Wc7~!DsX4Z 5+u33 Ds]\;u Ce:k`>A.lau[rhY.^II頍{V t,>1:7kR[Q ybd|AOjiΊ-ާJM-@ k'.Kʥ0/[Wn ̒rWN 4}ƫz"_-O@ׁ",a7(ă yZC-ca_iKIL s cW/W.;8]WBۜQv0՘"󖮫i `=`2PF\߬Ѣ&?NILj,z8nY*Xr]wWx {t=mه%'k oDyG`X!1YGӱ L ϐpM it%B\Dhevyza<#5FuX{IU͵bLӟJvirCp )O4Cr:SKɡ2I68nRw?(Qw9S"RcFG{srjk/ ,RUPTX5bGcm(3T7kp$~pg0~%h#/|>eoy;%̑AE<K\B:27U썌ݸٯ<}bsXmU'sۉ.zlƋyE4Q:<QCSjb'ub44H=|; -,p->}`flajf9} ujoJ 9]Z%#:$.-uع4&'%lw*Sԣc9~X)=V^XKHޗwINxX_+B# ~^L D;Z/&͜&ފrnɓ2=}|[*w*V 0?^C֟"hFQEv;B/ ׈?Zn*4h(4>FO Ojڎޞ)ퟸ.mDI7?6-g$:4`[[*8tk10j3n m5˫e///Nd&~/!`#F !MCfـ2l"`^bĨZ`w)m@-& P!3^{|0ANj [:?nBy=*=G"A7In{c$"tU&#"] C:\BCAi\F)y5!!+IHqf+%jaY}Ƅfqġ39~1ANx@?&9mX-1)TSp̓sED]} /VN(_G>x~)af4{ls(*Beye5לU=\mGy iKV#/UR5ݯ:xubx8*/L,D{xWt_pVzmXt2,X<`?@0=YvrȫdQIʋ}ZK!;O z,<{pEy3 _0'XVrW_!h[Ąh:b@`V|bKlQ ZЮf7 oV[z2c˒M$ԙ`葲LP켣"t"$U Ȳ,xۜSz,ajDA j3~B@B9f\ېxZpaJDhF~?_]jB8 + n>8"; Qw:BAVp{ ZBjJ& ޝ:Òbf/VWW0:T\\X2p:t4 Ħt@1 JAP s^Ј&ĸxB{ Bk.'g%0cّG 0;X)?1MAQ12LXrJ{߱=u)N mk?=A + uW:9P'[Gc*iQag9jD00$/Z AbĊ5ul\/%29SBbMJ1+ya y/[3G6db)n8?HRA=oBaSB+c#҄/ޚ~$GkޜkS3~[,O|Q!#ȖTBZ5`9HRz,|U3ۿjo|x8 u =t&cFu缘+C>25AaBU'5FD|WzE4ӿP=3oBze.zǘʔ?0#|֘XFc rB I%)?vǪB[? "M$=k/ͭ3PkKnUơHo;:qG69/ Kf%7d9%(Gl.> "ҜUnhA4OHX?ܳ ~/p* _S ,o ȅC퀬47!]Aޜ=ʕ5&.yV9:EBJK:w oOj 1aBmBIr1?B~T1h F,B B}92+ uejQ?y[/8>;?< 0¡.9Xbu0^ $h^z*![GȔNmhޯ_x>o(,yZ ϡ.<Ь D$Q|r=&"@pp >r߆a&9W;%~lx!8<(6)g@=+ H9PhT9}rThDrCHz?Q ^*'p:@\yf.[[1)|7B5фxUXΗCT">-NQx*z_B@їA|9g0 ZU|;WЂO3@\H~*8"Ϛߞ4W%-|^A" Ч!HZ@n*Œ=Hb_sGrPi# rXiv'ZTD8d.A`mZԨ{!65fe%8 C,o7Օ_ѥ0#6F 4JݾPZj57C3r~&cܝҐ#{[p"b}5 "Em}'v;o2g~_ bTiY&_g1`䠡x} JnOxo~LN"0#ur5GM AڡpK5Ιmƭk{XrDD+b=j!C5eqYED:ܼ'hh$"IIO#Oz E E+UiMzbP"nDJ+$M515BuNj)›Q+zpV9*q?y(n/@~8(~ʴb 7 &*ݪAf,dZbmF!M$^;GQfwGhk3~|}tCyə$_$ۃYPJ]C> "ib -gg1e}۸#@?ȑ:^n1Juȗp\S$G\6Y)Gr8zr[O%!=,!d#HX > /U&*3/GY bF Dh"Ou_+q+~!UwXf ޺;ä 'zT_ 1m y@;Z|W9]\Q&+۷p<.X4ohNBI$)?LS&d)FAՅ'p8$ ѝ^?,M<:+[wEŕu [%'V>w;!UJ8|h(u2>yV>>1kE9B˨Bޞ2='_ a+G`3Y B"~tr֥0(IwZLMq+R!RuB!pEZ,Z0pB+BvF77E {{I񰿹UkBRkt .[)|%C{ !ǝ>U̜Ύ%qWzfG'Kq*y= s>B{'ſ A rY EjluL:;:r.8A>J`- $O(82Sc<4 C7!D)=vX**f^Ƚ>T56E)+l6zYcȤ7tp"=+i5`e=n+G[~Uo FV@Lf~&5ك>dAsF]ogAHq$R ^ˆHaLv"9/!Q/|C@hFu"-Y"?}#5Q(^Eux;K3Z(ˆ.\Q{ :6e4%WV99vDtT'dHQۄzg4ۢ e;HgGc%3&sg^ 1AoBq7v^ S?93-ZIG6hdU^Ֆ]6MMF=P.m!4|r* 릆5&>piyZNJɘ,Q^8[Z^S:$H-r.$D8BԼ{O,<1Ht)&w/$;c,i( 08y͛8{{ZX ĎPh}jlvXxa YYH]Cg4PUYx ,\. m=b:წ26tc{Oo]% XNtΕ\ˣF[dWGǎGM z!p򲨹<f}KDVL,܄eG :VK%I·$%mW-| v"AV3d2x==_ 5%WLQ;~yPꑋ>4%&A9SV "W3-2{8#ݺkܓFڪ-v8B0r.+__+—C1@C_RKۛ쫫K]3iS\.hP&Ǐtig@/-rlA@!W0 kS$xKErbd"R.r-PS v QA{bCIaS8,)[oe `q]^yl7!ߙ%͙K~Թ #`ZemٍoH(9Ƚ)<3o%pu@z~6qZӝcL^_6Jmp ꅬWuD$ !PApgt3|ϡ(ؙ_Sk\)<-񹪌-dCeոK0{R*ފ,Mc4 C40iHREܧ (YuU@T?9)2nd,k'ύp /bQoJԦ1%xK(XS),-{#IHwŒg\ހX)ht4ďNFY/r3VqR%eXPH T6sLCWVSEE?pJl{"]01< YM wqɦe@uFf9Cr[o@ܓqG>5,^>#!0Z(@3B^]^#_I%=8?J0`#oFyXJ؊4h !l!r21vUH]\=Ųy]r2儩/T 0曝aȣO<.Gw>R9QjďnДVh *ݶ>ԛ&xz\G@<5`lW@WD:CkYP6#_#DWF{s%DiW2] _# T&mDzB AZ ^ȬȨ/U銥CwYM)r n!N~,D qQ& bܾ|.Ή$4xtzZokƪ.-Ht۱ivcUN^btSu5n -M..֏u:khZPb0zR&nʼIy5aG$bB`[n! ib <1BW 2ɏC&_Ҫ{>H+ ; q@\C1a+~I:W`>WZZU[#o- ,8iƣ,䝸=${'%ّM4 8$k#3C5~~- Z @BdqM{/w w^˥ufޗp;Ntw3++9dz8{#$ /ABJYs4Z)VLk Mđ/g^Uk%ᄋJ3jE<ߎ=Ͻ'hֽ}HϋD/JNj/M8zl[]=-̳ٵ 2o/д齧í &L}@֕p`Pc'3䆐1=Ak!`(ѣnDB^8FMBDݜ{X5h^a(XL"-GNX/pj1MM,% ,qJB/ZVLj[F͊v< IӨFZ&bDC>q6D(pKOOOטS/ܖ_ȗ%Sts p `yhr~БaVe@4vE) }Ԭ-@]C+֊+ ,P xdY<01^ J|x8svG58 fqGm\|I|&XqMbxF޶sг˭! &"|d2 Y.,q<_ä!}Թ t"-s;fwyAaaCBGCjey{M j;_YX+7IOT4lcb~CoiabuwaG^q"j ~+f5cGܩv!O\{%{?,Re) Iӛ*wyGEqD8Դ#Cs#5:U?+ dΫXSPPo`@PWuvό0)4 ػזL?Y]9S[@ u*n/Ӌ}tOL8@ڮ)_"1>R~v1%I ?@zN:)O|B(ʊ8|#OF@2B xSPbE80a=xM͙bAИD0WXq[L0u&*g'-9 R5:a~lB(VAnז%?T.ώMf/%=?((GDL<6&0ɠs~^6x !V.p b5*y IMz1 y Kcuj7Co,"vߠD%`t7]|[>Õg7a<6U4b-\UOqL^j玅#2w(iEy!>F_MI;jM.~EyG+'LUh_OE{饗¿40N@?VZ0֕.%nU[V7S<٣cLK>i{x>NPf:nLGU0r W3>Rvd!~~:S5EmDT. k2zņ{k-xIgsB*hS3b{U)9kdA`%V^ }F͓KIz}IۙEdp.g@|16^劉;+nO.nCֽمǓ2QR Oxy- ߯q 82TJ)JX ^y(TFӗǐ xAd⇑_:dpmcBOʻMlZjسJG2ء)RnHG -ƑG{Ns+ =qxɯ-(뮘LL  K}#9lp3u+5dnwfg%>b)ud>8zM?->vXM&M7 Ӻe*<r^8ӊ\h :a`;//_~V]j>-R<̻\m$!=!GްA^*2dF D  S麞XYY=lgjn*{+Y`+$ ~[`(JeGb4 bwlJS;tuiSE1Ėׇ~31K4䵣:xoLV#4ZD`e"¿niw2)7E9t=ysL28"[NU+Ý/Ri1"deyLx9G\jzTe+|ns]\EԋhCƃ? $d!?eBr-:7?W9 (UJ6(P vW1IU'?إ^Y&ڡ=Ð? d+ZW]i2u,O(rbԽ^ C!ϔrP0.̼FrBؐ^dH߇A72zws/ڱ9yVf&9nf(3}Pj;(xO3Cj<,|n|0O GV0xammglFz`P4T@Rn h_q+TCpw\@=w 6->0|3`Hxmr FvkNn6YW7%V1:6xޜ0rҘ ] VB.B{u< >&E>YQkpB o@!B¦ӎ&[mɗU Dਝ=lh/<|)AܿW d?TP"SP)hLߘDH|}cn` ,v /\b<8E Pc@塴S|M s3!bbXA^;h!)ƯC02V:5r{Qx3o9츁[m6Mn@{cdSG]e+g ?@?⇐aMmN,<5G1=IX9D`<:,1Yˊ[9|[A#da0o䳖yk-Փ>N3j#ˮ!}6 )5 G2S7L .u'omGokwtVyRI>j@c2yiF" P>A"dH߮aNb&F޼nR.b;DFUl8M dÔez䗜8Fr?e GYk(<&V>p(M#۷!80:?zi!d !잺R`iAE(|׈\ZŲ4uku_r/J?D~1 3jG~gm@H'[Tm.6ݴKi];36aA"ƹ6,Cz\#O -F΢GK>wߨQ:O],T=(w8? tWyw-n@=cBG +5NCbBjϚ "@Ȳqsʘ8HWB"AkNr-,qfȸHWFXf7XuA!3ȞFޏ4-ij܄}—v*S䎩)LkvʨA5X UJ,1U NXg*G ٲ^=-mfD{D&I;w]ܟۊЊXW?đC)!ݜ)%JBQV9S] 48Ç+wõ} 90hHZr~w57jMt.25mpaY]([Yp\aO:Ab6SYM)HžM?@m"Gއp q@,h0mѤ*@=qf\9!A@?b3 `[ V'լ.C'(7JQm(=Rm6|kY_,J'%2{+SM Zu&,'^H|wF~衯#F|X|?iyP6{U·$faH? m80 ) I']3]zwg _ WoY-=Pc5ݫ> j'0AfXe 9>(pTPO՘:(gL BEI케]zoU걄ϋ^ m+<5NP1=q! *~H3Ny^&|x췘< +r )`gι367@lۣ ͊'4N2 :? :4` k?όXQ-njL TɃ)_N8oE CIѓ2#q.%-jy5|+Q"ƕ݆M Fls( @t5妏#<8,xs$CR\ BAjai a 3HjhqC)9)&FVfj,"oTHI +'|Ga/ryU%ơXMeFX*$`P8AD|'"RLncqe@DI蓺(idt"Ϡ:I"~DڵV\K^-^t#`B6N~ QI;l/S= }-~XxJҶZ]{ӡM"Đ"6][7`4_ PyͲR7טz>h|&ns5$d=wsFx.~k3 *ɛyV?! uA|UEs.С A,Fy8 z~AFD A*|)thAX ~]ă-ȯi FR̿E"*j{,Cf?N(~2 LPIDrſqnzB AJUDw@3ȅޞ$ŻQ&\X=% R$_gqV Oʤ_>sV'NК/l}DRꬋDpĻ<=?t{IDATa(sfzbt- 4bH Q;;Yo)j]qzYD5ʗON񡞅b*C(.İ!FY2fz_@ȡ-#; qPT+WhBcwa3H8f 6ffXc޳<~&֨jpfV,U$;BI.ju%VX09z )ơLG*bM?rXj duNH-=<5;W]%[ Z9O{@RBK# xr42Awgo;'A0Jf"ofFnDf Ð^&b5f:.ybO5ȫ̤Q=)tL;r]?z#o|tn/}F:j٦qi')hojO{UD*owFQB <C,|aGY3%؞P^ B  ~O4ƐZ[jX1V¯R8 A9fS/Ȣ =*yf[~xTWK<2($}sX :5~/h ^w)cDžd71/+`{>~zz4j$|a]6a2j $F+tf/ =y#싥Cgr3##ۇXf~ [j/qBXLEysY‡y7_.`eN}IߓBdT,{9G9bx0,Abqd羲黢+.Y,_[t^]KsԐr /IU"TIyMBu9TA.@;X˚h՜o)H2^G ff߁A]1  K [fɲNФj@8Sgs3]MM qBlŝA@}iU 5fJf' 6&_svSpo|K[tUe{w9 ?P42"u/2\0@n1 S {  X6-6Ps|' D@:#+u^a0ďM Zç+o|֛ A,' fS !֖M5bJI,j8۸2:P4ɱF^u]TٛiC5G\,*HOYc8I;^`( > ByTZʫ5d5 oAYKNWs̯/# TX4@a#-z=T >v[v{+Q=_92QuzeC/_g`n8j7NoV^ע#S>~ 2[Dn'OyȖ7| dye`wéA^!¿Vb%_ipt%o=VR^܄\W1$))|4tg./Ҡ#5E+TH3}%k|uwJÀ}J :o7韓BR"F|$wo(C{՛{Z~Di?Bct r15nTtչ$9ݠ? YOf*\D}?,|o3TZ@?q(dYw A* 7okbAs@aٷ$d +1dwBC}\@9l:q?x32א\-RD!Mٗ.6==흊,ֽg4)`6B>C2r(W 8^·-C.YrA^@DbBP`؀HzG[=zy&zИ7r %/Yc` H ,Ҩ/ܣKoCȲszy[o f7,!>0;cLk;(*Uq$*Ѓw@:u_ؑvrZsXY@0[p_@>k2y0>5CEC8Z=c M9U@<=ʥ%~\cW8ǜT` h.dAݐ:>.FO" %*p>@M:G?=cMY7&3xѩ0kĞK?c"E5?ȃ?+w#Ɏgjx/EyF8ٻŻZo @||an\ZW8~+tq(yC @)8Jĺ@3H3h`C ^ơKAz;7Weۑښ؇ ]v!}L(h<`_ZtHhHO"tmVcSuj1 *M_lw]GT`ơ- м0U}8NzƮs!M3gĠ:O WkI8gtW.(0|3bơMa4)]MYK}tוjϤZ!ZX-z3.6]td"j3;h O,YoWIG+ù{{K!R>&f6 ϧs=Xߪ+$lcwqփ5 șO;!l< WgyB,P8Y'aj~2ڟ"~G] p(EKd[v"T^ ҍ|^* @ 2kP(d%t@({ })Cʃ"ݭ(L\/l: u<DdU#C[5~n@1m+kZ9ʵd;{z0uDkTb#cnhLq;-ID{7y=_K= IDpȜDďdDæZ):exK3ңBkxFm3YRm[8骬 1 ďxlS8ByUcJt#oR1Y] }5sΠ+YƭU!էMwK=|Gr3RSֆU-aC [5?(eS7ZSAqh݌:5x9;cQ#shUw`s9$}tq?HX:t^ *8iSs!,ڌB]{2frCR&*k-lq7"SWF1!zJ x"҂lX8|rȼ0@Tj)ndU~,_xx=5:TcAↃ>w01ha`)AE)T:vyNÃ;qw4"a>9oaV$,z-%Fb&srOfb_thFheWFiCz T yϯ’/R`r3HNn *J2 mpwb]8U2' vuR.<~NB4p"%z9jC72W9x2CFZ; Eo5Q6!s#1WY h¡EG =v{dX:0"R6cPb Dܾ3s1%ec ۳vh*K@)x3$Ƀ%q6C*92B?,4!H ǟ8T8aFrNpi0F[ǂJH#F^IOÐ_ d%oq}\!}?Aa˧|x r%VPbAu8,Y"H$P! A<֒ݜq1xX^*RhUGp+[yRgT+pk$R:ʊC~4(5CF x=w#+( Wc"B< (vOy*AHw=!'6-9*`hefUJLG(~1ްcۡG~?CCP_>VQ+AZ|sILZ2lcxҍpu[rlHRwMT&h?P]+$L`hb-b<z7"_k:|0D%h:wZSۿM)'FرX h3R)B Y[9+ޠ0kPiX,%XRARm0BWSG-ڍξaO %FO.t۬.RxE)$oYګJDִB*&/ A<Л W:JCZrPwT^PyDR~\៶heu%V^0X"E8kD܉ز1zR0xlB<>2i|_2c;d |k\:3պ\ ,hFne6Yx !YBDw~M3aKT Y@AE=U@٠( ]Җ6^t]-Iܽy{ |$Ŧq$?xM˒꒭sϋx+-@1B[xn7&*Xub!ω)HU4[@!,]BfALHl 5Kpٓ'sW]%~ɦO5?S(wߖ Bmlt[1BC:7V/`{|c;q&J6cu!w.UTt[ 8 *X;kzN,;TqX; }'n`Uj>9`z80rDhp/Qd E/9}y|^tTT+V:xGy)ώj!ޮKHϼ7CP%(dcƯokdAM=w"uwΠt7>dXYR\Nsb O*zNX.ћu E`1z*V2 x|_j[&aa( ed0FE)F(W1^aڭ׵fhkVn&HE9l_1΀Js CVkW8+/l#:ZgWa% l. 8VxN|Vyav]~S$n׆_3oD [N7/vhE'RګҁB y/2w5!aWv gO@ `\]v@^cjRB5srX H,xn?ІGZ;`;wsX(hr8gl4AXA'A`yg=|2ubp\L-:ț<3e\?温SFw]#v_Q5xOGT4mAzZE?#d=k}뎴Q,b>Nտ;Ӟ_06Ad ):!(yvDZEpW++Exc~mЎ'% AE+d ^bʎDYFp.pUMӿ}F/jه7=!_Y@B$g,lV?gCv2g5oW}24V|yH)vw4}\qPͷ;W{M"cN_˞h^7y1(C_cgZrljw 9tmA\~Y5!o;V{F>~sh[||Y摊AtxD " k 䁷`@cw&\BP9*@';ᐋĺXa{b'gW>Ĭz}tSGkX xu}zݞО1vqKJo0/v<Wt+rUv&熥.^EDʴLߚMx_Vpz :,Uq]ZԖ=TKWt>McmzQ{/vdya0冂0?&7rtѼ`ݱQϣ+'TӓAE}U>!eA6w~|f߻-"M;MII NTU|},mB`yᏁ''Kx(Gc@{j`y5!*2l!# 0%uF@ls8ϣgVZ:xvsoOIqZm" m^iSp|r!H(91G'V_K &(N2Hk˨gX3jh~Uf .KpXAK2S18Khe@q #Aȉenk@'hZӫCAWƀ06nوSPCDn2oik8 @QY[3M6,Mvܦb|DGnt 3+7~lt7qInhӘk Zȏw8η KZ` $ H;xcd̺n?P'FxvT Fs^Ɖ=SpsBq5ai"^!KQXSpV;p 5Ze.} V@D>1KVκ)vZN].'«7X: J .L3{[W+Ai+/Vۦ[+i<{\̗?};U۰0|'rtC?IMAG3hY+"T1} 8ϥЉ5hePQI/)tS >ȭüWEWcO@U ?uw(6׬?8haXK/1; 2r:ݻEsu D7С[}BjN[ϒn@jfnexqP* d#B5D[uJfǓz>kM} %@FyXyVY #C~D"22B (ةET;΋L[,Chq+9 S*qoNp"aq[nhOziTP93w,}0yk"4CE=K5>0:8GibcchC!0|4;0n@!&P:( VCƕWcePUz) :A'KkXGgP;p`7n|csۖ>7ktm3)ڛ֐0ݜ H,mxF%o~ް -'_AcKv"'<XYVDEO&`^8$"Tdan. AcJ&{9zȌ51:t9ńBzB!Q[sb h{[P1q#h@J,=xr9X*g}}bȕ|lqMApD3|^Ә 1t^iͦpPh~H%!u3ȣImUKې xT81CG zq'֞Pzg@H8Xdu Q}uhGMYTF<(Ū j؟ Ϙ=֘f ?!i>g\E ǜBv@dӉT ?qtB966X{ &cqe.KUnUN_7>6Q?[7BE'@ =@(}laaN)D4? )]tŦ ‚<η U^A~&H9  za%|t zp_}+DE,)'*1ȉb lG̋fBFJ!!U+Mw6vwP"`Rff έ@1w/xo몈* /߸tX9GHr"4o?ȫ0+:\A c(*) i4y%@!SBױq01mL5x=ł 0dVh4N -oE-Nv 5\z0B(}( ?o2 B$5oȬh /Zr11VoiFɁfjBZ7Zl"n!%n49/ X3@\Cx wg-> q7.4nAv4M.XSz]x.Iy/zX"d?|(< iF]{UwK!m!DC >˜ {@'-&q@'d6*kҦ>"1tc҅L}V}͐?n_CTI ݆/P:Qg`w^erRqd'2c ` B߼q+dX۳@%40$I24|z[OěLqN !q }x#V#dL4O#_AF>kLt *ffzky[AmF'K4?$;zWG-a}XB&> !yBw(h;*J~q૱5Bí&6:X=zPz5 yd6kPzMlQ ΃(H'K4?$9$ tUa;N>MٝA8 *Axr{b۫*Ptck7n' _.<?Qj+V</ :칱/!Rȫ3'oPL=Y! C4?.s יEVXϱ2 +NLX/@T<=D @7S6Ռz&zs0>z4pCoÌG='[&+#^C KX '2yK!:fcTbh$&X Ud*-lbLK7Py*hJ GubFM6B0fn|?Aտ3xAo ՠB=[{vczݧD\A8HONhQ4懤%ax0Pь5'ЇBE-iC;q&H&m!R8H_ RŏG |ؖC4(vc"#EU|hfk+!:E3k m+(&k(Bf~+I^7k.L QL2?ӑBjW %;|s ÿĠ m 1jޙI84]k]DCR^k ^ᣎ 6qy2 YT N5%\'Tj p N!QѸy+i!1יPs=NDQBP$)ȡi!hYcwBҺ 0G:ɨBD9WAo.D@[ʾݜ7D4`f\rX''϶v1/2?ͣ =pMƤJu@6 cPh- 0/ b{};#!k3 Xۮ<Ƽ-Bc~Ĉ^F+m򇆫Jn7;GW BzFB%_fi鍗C!D /Zsͯ+MVU4 *G?F@d^SEN>D'󦠂O(eGQn|+JpyB=>&~̏ tT;a7q '7\TR>iK7yU I*ԅfaCN+vf!F8G;&QRE9HAAàs/cBV -Ncq۬] 9 ߨͣcnxá?AY_1o>, x^OA!dʃk[56/ A?]Plh~H1|%_9qYhKnSL_W d,01X7+&kꢟ2IA!EQ<ՏyƇN~B!-T;F}w6Abr krV6MY}=ooҌ !~ Ωy>ƾ*qUHB*^N!jOEa\2?^[*诽AB":El0Y>*|m8D^yBp[^^[i nr˧޹S9͓`=Vz0H=eH<ȵ /)8B 9\yՂ9qshY@a Kkdx}笁Dɐ2SKD6ؿ vR'w(zB;k-elJ/sN3ki6A^ _t@8ܟNoudd4>BRYPvkKI"Ptdv8E9Pݵ=!E9e~pYZR5!fC+gkSw|<|u zKPuߩ+{5b㍭|yck]igtg8@|L;Crӹ+|}4݇&`~Db 3x! Ctpj3BK*> M8Lꝴ5A<^Wzʃj%X(~|լO!cxc"bzQKdIŏ8Q#R2^O=7g37n:SN[w2 e1A2A!vb}=_)QJ۫A!Uߞ(6  ݼ\02?w\(>z~E$Q;4N~w:ئ&n3ʭ(4Y3mHX!(x@^c!xkG1Q1y\iE}wg޶5{=>"򇆛^Nǭ;o!d"I *G/l.& f"o~Gހ_zBPzae5W(w<:t\ P9dh6-4MaC_ 55Dk4_CΔ2eߗZYӽƴKZhD";ߖ>GZ+݁ƒ5Nzc jxhA뼷OSt ?TJ&hߜPd-X"5* \X'A;}v9:h@uQ7VEYRq>`5!fSyX +|iWQ:nR|茦txQΆGzaGh=ڏ~g=qAJHl0H  ԽeA ~2O?ҿͳ#1N1IZEᴊ6!8kÉ«&6?[2DIx9[9==pNAfj9tB T 80<7tšPQc 705!r7C|{wn߭ˀujO= ,6m=a&ѡk D=ad=d@53+3|,+ȏu+ &0og'[j>R $T:וͅ[bg[~Yo<`\qt`@^)w^Aj&|MނďPb*P݋F>eU!_ b6r6(|squw(,[˧X .`l$f ye=@|i ja&4XE1uu]g{1o zi%a!6z9MZ,")w:&" R LBnEtnN$/kZ}y9\-f.3v^Tv;A^㧥k>v=P$ ?]?&J xU A,7ĨO㝒@D$!L Nt?w>C+Ӟ<&:N˴G I"DfU1a-ԛ%&/^Y@7oJ߶7O>LV/ Gox?ot|k"pK8!G-Fbe˼@rn/,JYQOo4,4\!Iö SgDzjhMہٝ*R^Z LDֈTW69 rI?n|lӶt:t`BGr-5| }=-%(jb ^-C=of65=Ay+J??վc="(C@ LT? }׃kN) 3Ha*(wz#9)$Vlhndښwt`izh e  C8:r$'<7:QqHT$Dq|O(KY!v@|68wgJ싰L")AL{P0]{xt067X-yLb_p}rWBO Nh*p,n 艊֫o9v6<-3"W?ݞ5@ͪ,L2po#@. o:~PH"t,̶O۪pRrG-t=cZ rv&}5x+'A:F45-4?>콉Rz >3%~^ɣEƥDKh#Hr\>8Qo7:A&1@jiopmA+(` bU,A&}P+hнIt3_}_>y>o0mٽWVaGt힁į & F>KA_#.Z@SsQ2 oΡ|,Ib9\Oi}aY4 =L%ċ`=0<&A?i8wY )dsyNE>Șu~^緾kTG@ 0-+O)#c[B@& /(?-ᠢL=c(9A:쒳g3AQ\>m^m"҈Kh޻ˠ\J{Uaj#0͝Rl>vSz0n`1 B' ,f$x2kwX B'ɲmT1&ȍA7`WE]dt޺z׷ʟk8n;=+^>XJi| `߷ t)m0 Ӗ׍oT#[("_d6n>$ z |響2Cd`d-*,E74oeC0u.T4hAAgMs7SYdTM/>k>`(egߐcA@qˉTy](`LDbiJ)d~APH9 LZU;h1AA>& ]u0X ;K%U.J^_w0>@(hϾ Hъ \fڱR>0w#xta>C$nfz`\(yxeUz_L@d2A C|*".pd06ԭK DNlviuჰAfu%*{m;y" +ǐ'~٠K4׉ : >mn>*[UJ 䑚!dŘ y` RkT.T.jXMP[ ?ȃB#U@hPhLu" |~ݕrCڌ~1ti&:7~$^.׷OkYL~*z usrSe/SAtXm.I`UG *Z>S(UwÚ!΋s EsH00R2?cO\["q1Az& ַGWr@K P}TámΎ*m +DYXCo}.HEg#@pCK*.S!5eD=w#_0zQ6SG e *Z@-? Vjz]h@[,ݸ;'X|͡ʿ'CE h?)0TRIܸg$L*4||ԍAFťX$[wgƜ7m+>oP d+Բ&p&eo< VDE ~Mtg"%py.5NLhLu 0 ͐G]rhl.F03}ceع@_C|`M&* 8 x/NnHl,= )>t~6aB*3aA4" d0L7Cϵt Cغk]bhL۾w7;5d}T[>g@Au^=f $yMk [ Qox"5FRÍekxq͡p^??8;3aE:@ Y"mXX?JwCGl͂#/L}:RlصJo8~. 9MG 2 Ukò'ނ];O'?N} DԕzxBE<)r,iDgÒmI9d}J"/-]?+ W1 "ceJn"0toquR>M_ΔduicLtr;T72o.џo?In#vG9)99i-B2'sP$f]zxȷ~a/&!f!2Qia%< Ū"/{x8DǴ,kKP;d쩘sbM_64\a_?s%bt@XGkWiD_nayH~N3%TUAQ(ro1 9{ī %HEGpAPO`j n0l>G`u6{@Mx_‰P|a!ϭT_η JR#D'P>*f&9{Fz]%g bTM)Z>Se/7,^)jyvl/݉n@DBf'LY'JOa>n3y]'M nO>Lwi߰⯠#~oce0>NNCy:|7 !. ʚy'_BJi$pd$G=O2/knopԮ?f drsUS[w Hi:v5;Dx⑈6?ruz DgÖȠOÖ{ >\8H "D3~{ˏLWrrP V.$ MC񞇘.nCtrWI}W냕P>B<9f?q(%6dik])ΆsվJ.j$0zۮZU.LjI8& `|Lr n~pb)\_(IbPPr?y}Ԅ*pi8"0qT=ɡ+(ЍҾYߧu'2IPç b{x,>z<. $ˁ4D MaC&NUͥ9c&K_M **xW d?DgöqȍU;~ۗu`{J++bɨtxʃ7UY cހ$ }P&S֝.t ҳm(/p4{2?+ 8 d$wk`QWFh{⋖T} Bh!JZ-SUAMVu"s>@,K.'/]\ýԮ  c'ЁjR 9:m9WǏ55\ эw4w+aCOǜ/=?*њF-Z>SH2n_UЈ+X\ɱ( `tP{bY;KD K<`t$h|۶S#!vH 1–O0wr\]EpczLH"M8knz.03$PoG1|+QoP$<?^Q`&H6t I~y)y2!T(=;p~o;qpכCc,C-Ȥ -Pgg!fiK$: ET&(~1A9N:tMz^> ( 5VnAE?M6 {y7p0Ɵ-^TGdE 2B:I-@&DSS+oh?6Le"="HEyv o/:aoF)),#AaVg [J%m}g<,i.Z>Smv !@ K_@ ƚ 9 r|SM**m9{C| yq@"`pBLN2Lڦa^K^Ꮛ*?/hLuD.Z *hcFBF]IG&T<C6K4M&$1TX\ bYɌhD&5¥!+ m/ާd,N+wIx o} 72o5G\|:/^8N|~PQ=7HF0<5Ar!'UPD9=\ 9^ܠ X04{5>whI$粼Ktu3ѳiEg#:!Ce_$KD lw'Rg0UD!>X䎎60D_}C_N!JzL6*>粇ACBcahr8њl}#ܵ^Dg#:I#xw gFM?/\{@H~r&,װ;*4HWL%,Ț?Ի1z=ȷm7C+EHFoᏡ~yo}Eg#jqCc@#<9S8caAp꼀GԸJAmкK D_}y#k>ͣjt CBL7kW7v%ez m,NEg#j#?[e$/H}!?.qH) &HAk✃ ])kY~W`7GϏaM˲QDL68{"ݧ!,+7(-HQG&=oO!JG+4س-J޹YjxݿDN ^ B=c۰cjcL"m\?^m t#5"/6mX?%\76hLoa*o#H :9tx4{Вc0gMF6 ^fb/.t v㈨vȍq(īLmNJD<}jeND\/In8c/'9u81}&˓eoEg# 8B2y/3y 0Z/ktT4A!Y=̡"r`Go31]Q6A_/5/yd_#A5Z629&'g Dg#*y7J&Bb=qYv(YE#6$Hy& كMPa 4 2q!4J,ܧb2U]Cq1BI!%bd5&# o1<tM]~щ{Ғq6vp06 \0*?FD hFA9BuiWF%j!׭W[ 1HҁɀSlpqo&}hyأu'SEv` !<]p{-r\62V͢_r{Q c'_ Q oPЈ]9  H$3*&AI3׻y!:ָ{՗g-BHE=F '<ȸ2LqXsGhLuD-On?t_ws&@5Oq=l~xf"ˇ-ь?)0A 2jT4@o"֮0?)`-Us>455\KwOCs@#wL>i.(v~s%aH%jfchTGn~PB:.d{W`Y^yL? ׶ B:j0͐»_Zp(;"DsB&se/nd/r$03ދ{ !ɎX:# W~h@79|~tbY}Q%Z@yXd2ARX ,A9p!aԾN$0b|ᕭIi"-p+j*rˮ(:&&;b"&'|]8QJ_St 8q#Nu|iy; (Ɵ)XZ `j(.Pp3tVYԩXӊi/D<^wVP9)o]>c8%]ɎIYWB\p@ЗO138E h Jz@&HH-AbوxO KUWdGD^ڗCG' g_s;%?ޙ@33A7= !Jӣ©hsQ{=|iQu-ь?ed"&9kT obuYcO :b'Fn֞Eq$hgB7 #deꈥ #U͐?Ijl:d&a*3Jhfy&2C T! m'0TӬ_wv\pSr\!eiVI#I0cy뿎1w^&YZF7 ܆7b7Mpo+HWd^W*_h7s;L)٪8[^> NnPpm?T09jIu?Eg#~2(+ubK 2Iub$4uezYf=vŪFF)*=ŌzWpKZ"P _ _r,#{σκ{jƱˀ>>a"/Mj?^ R90W/4 ?T]}:.%vّugWhJYRM+h4A>@J 4%ކS_*:SqiFwa o3 G&Q(wޏN_|Yv m CU2Aɭ^gI ͍w ^nUӗq<1~I3 #9叞эhLu$J ѡP\:_o;Y/YU'_|**;2Qŵ ,WE hc׵ :,aW*kaD 應_a9WD6"Sn @-HXҔ>e.@.G "rxn?<p"6c4jwD`lB&;3Bs .Gd< J>=% Lօe$I|:/o'W϶|$jE-dwƒg"&-`$x|cG1LQy 0uC r/nA3͉~0yd0vK E -Z>S"d!jCRh4MF vMZ 4zVd,ՄUP1@x-'=C!rx0~F iDgC7ݬy.]hd![\U&NJF/ j܂L GE!Kb Nq!Q7E@& l~1<UWcT@S|$=WP{Ob@+kwFhC/GP[پLkYPd*ڭ1/.4Y&keࡾW7lBC t_aO'@J"wX:3h[<#^@+B1A^@& 5sB*:1 Gm.ƶM=?b_|:D!ٻM.O&#:\|*xatggוɀqj-`=7t&H6t] (xC%r}C\[jLEgCa5$7]貁+ Ee!$eh+ @kՄ.2Ȉz@/4ڮ|j⩢9g?4-f4Tc^7@D[wbb+ѽ&ZzglgС/-#نrRA?4YU!KEٕA %8Q+1-4f@8CDHDk5ȰȅL,#q% C (C^MA1XڻA E SBBFfDPeCU4= 㷱؛ޫyka??|)D˧aMhCl}bzց|^L! /;`(ڗTSQQo9Sr-E=OКhBn_Zse7L!m|wa$0\@B,C|JHH8V5* O1dtYl= $c ';PV V&,K: {A|JHH8nP)=zuu1HzRPؘx9.: 9H:D+Z>%$$ D߱e;wcqAD/~:7y(}~C+mT2y*j2=cxߢSBBK. VM>(hۆ9fN~4YC]Mp_Uqx3 T}4$+Z>%$$ *2AN8:rqƳwR2U!i:T]#t?D˧a] "Tƛ7Y ;e]H,؉=/J:ޫ,^YwLr T>Xjpan&,F~O ú*Q= } 蔩#*"3!>2^bb{q|(yl*wŚ^E˧aC"eb┮XTN"7; ~^E?p1)!!`%*HMh>B|'PjW􋟍"\hMqpO Î:Dk[*rvRR>@d{: ~ol}XLݸjO Î2Q_O";~hKɑc:9ߍEOM(\-@m.q?61$SBBLTTc쿸kK͑U|^?yh#D!7GlxЛݣy`g!}J--mȪi8os >Xk5BtrXiGX[WHߝwX-=ňvbMn[]rT~8wI4ISB|JHH8ԉ= 21 ׸ D9II)ÌJ#C\Cȅz?w} ?ǭR|JHH8v$ XAisяl/ u2N#'*8p][ UPuO8?_qhp0HԀd!M3l3]ٿ!~,xGxQSfAo[H` ĺVD˧a[MqȨ+q=~#ϻa xa:.ɟG< xCvf1f)ʼn5C 2@UtYXzC4{d+!Ẉ5?ux)!!`VMC=Jvd3#Qz䔎q 8B],@.zܾWE tŕ?$HHHa[$2T5B љa- }E͍0p4??c O þ\i% ܇ydzp^9I~<^Lcc;_؟"MhO@hp0"Ҡ轭r\^{2ZU➿xQk|Tփ1>V(? xoQ/Z>%$$(LI!hbh*)4Q9{Gg=0{П^[mD6b)G׀h??FE|JHH8igBUa/{\Q6J! [ Z {)ՕUxN)#w=T?(0SBBP0A)eTm; sAmo[]URW.7}n8cCAa%Xx? SBBTVQD=Ι$wv@G*ˏ^Xz-ӹAJ:"}TM ^QE[BC+lT B6]N,^>ո}s~"N>[))00^2c[LMT4 tb揾! DBB5 lJ%j L,#U7C.s6v r~秙TGVbw,O@$$$\Y* 4 Ǯ}[ư$ZЗ9Xuʘ>fҒ;>(ud:)!!`DZ5\҉cڕ5|˧a,u^{$R=B"5}E>.ABD˧kA>pfT9]V{ |>3@D,˪<{f4튊:\ 2qh"!!G*Gpw(3AbQ2S7~W˿6 {[ۥ'%! DBBht4ꨶkUAv} F>oA71 H1zC !bWBI |D\L)Ϡ@HTy?V.<<j1C՜Coň^t͠!}lse9GCQ)Dh_0&W ғAzs0cwou[=A7>ռӫ?cƓR(M -F*qJPQ O@'2fd7.3PEEe@`@$$$N)BbhUv 8k2*DIVL<ړf}qki1! DBBh)S+|"k'zm_#(]Lx?.z$ >Tu˜ 䯏rW N-_0+ ܰvI |D_vyVL@g(~H$m}E݂ 2A+$ DBB"/D]&H[ShHw(‰P3@$$$V ` ,C SAL&?$HHHQQ&Q rZ j 9?$HHHDyn B>z**,GkO%!Ҿ NO #J@a:x3SA2?#C1PU|*Jkd!E%$$V5A*&(G`@7Vۡ3>!_{ݓh D˧s t4qlrpk&'vN(}_1? )!!`\諛eA2+o!Jj'C,/sTt$Q Z=7PUy[( Kgz t^=[B|p)?_v`-D˧n|n?M 邌wuPgu+Bxo {L>E$'C-Ff 9d)XufSBBQѮ'#Xj}Ə0Dzn|>`Z.]5Z6Q fECBWXzl&|>O #nGAk潖pU_Z0h!ё!#Tփ4[tEӯ< :<})!!`Oug6{b]5V~+2gY3'7=Ao8=})!!`Q qCO~PUЕ_Q׹O7몌 Q5o ٌIs|SBB!ZQ-laBӣYiƁE)iE΅[2.^,5/*3_ZR?tO #GA0/E)Oϟ {DN8\yK۟7z |N.W-F\џn& QAzUUl1u/ 㭋%gabޢѲ*!]B=J>v/L! DBBaJ7[U?X A;ّn]yiމ"*VT͛&M܀hp0f{B k/mr_SUY;4?s|\upf>wI.5c"*uWQ8S}z5J!wo kɛ-F&)G!7lxSCר;~9ke N)!!`]h3X)RÕ9: 2lZ>}QAQ?$HHH&/6;Uk?;u>າ#AGo뗋+zMՃ/e'W܀hp0⯂8c6@DEٿ3ky~Nҋ YO #:HAAcLG"BVډPFKkٟpZ?i\n&$t_QO #JHEE |C7Z_]~ّ}|uTJs3;'Dn>$cChp0TWtl۰+DpYPQ[?Ouod/56ܡ_ cۙ!Z>%$$Ĩ!R4Ί\B FwXvr›GIj~ I ! =D{h51 6MT D ?OVhp0τA:cW>Ϩ`M'ރ0D˧(EDt7"=u 4;4/ypdͯL-F4g OQ侺+ )!!`$N֔$ׯ>PU=㾚x! DBB"$>j_2e_i1WSBBH2RAzSA&Z>%$$j#zz2#լ x8WSBBH:RQ /3wLw_QO #HEL%n? BeLO$HHH@ryЛږwӺ}{6e \D˧p1ȿ$ 77=y+ )!!`$^%A^[gWa8-" B׎Du;)!!`PJ hI n)ٞ# D˧!D+ NfgyI Z>%$$ 1jI׋E͏!+:s/D˧!H/A rԙ$ B̏+̘IDV!Z>%$$ QIE%=fy Bds$HHH0ͤݭ`"3!џ"!!T[7`ka^Ήnqh~ I ! P7(l48ZĚ)j~ I ! R9hYw:Py7gUq4E)!!`N*R j O9c)!!`UOV~?;Q!SocW-S#SBBIOcr?լЉlCO C"+^/v֪FeF*J%m~ I ! ZAX]i7렅=^}SPͩWz@MuZbeWG@-? aA:;qcm0B(}~/! DBBѴ_oUgʎm :~>i3'!!!! I#0FMX 9>&7"z$$$$A4g@3UAE{Tue$BtS'c M? a ' uJ{cnY@= 05Џ ?K.K!1q'!!!! /ַ#j(D|K}lCV=ƃB;wF>\Q'!!!! ɂu„B\){t$HHH!,SH>5/t]d-X_ɻ Ga\uan/[(z$$$$A47Xr|8g'ھ7dod޻_joB3!sq!DIHHHhfE!( evWWwWW ;(yHCtIB4/آ h:MZqCKqeѬ`CzX-1x<7THlI sbm[gWOmۋC !1lfCf8Ԝ}#zj? asDz~,1?HuŇYA"!!! DSA$w_uuҿ4tr= C{ERs˱楃g_$wJ̸C}?KX@IHHHh3]H1F[= Z(N'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!#_UfIENDB`IanniX-0.9.20/Examples/trigger_loop.png000066400000000000000000000007071317340345000177540ustar00rootroot00000000000000PNG  IHDR226@: cHRMz%u0`:o_FbKGD̿ pHYs  ?IDATXq!PBJH ځ% B:%؁%Rσ2{p&~El.bEt;b$[X Ğx@<;ć/@x/ǧ ~F2eˏ։s}˃iLG\~3c4 28Dd~c.v].QCgɎ']SPOP i П:-BH~ }<š-N+D1pg7cgl1AIENDB`IanniX-0.9.20/Examples/trigger_speaker.png000066400000000000000000000005511317340345000204320ustar00rootroot00000000000000PNG  IHDR226@: cHRMz%u0`:o_FbKGD̿ pHYs  IDATX0c@ )RRPh` aB6d&߅!v0KBb- -#=aPqS"#"?$!L9"#?j=(ID^mW9<)HA R#y>کUoTߨk4TkZfdY cH\ *vi0K]V1]&o"<^IENDB`IanniX-0.9.20/Examples/trigger_speaker_mask.png000066400000000000000000000003321317340345000214420ustar00rootroot00000000000000PNG  IHDR226D cHRMz&u0`:pQ<bKGD݊ pHYs  RIDATc|(-A?P~@(A?@uܽp@'?>} j{IENDB`IanniX-0.9.20/Examples/trigger_triangle.png000066400000000000000000000012421317340345000206030ustar00rootroot00000000000000PNG  IHDR226@: cHRMz&u0`:pQ<bKGD̿/IDATXn0hg4a Kw¥ۀ)ۘ0iA'N9]'4rھ~~TA}s B 3׽0CVVbZ&4jI!WβLY%βL !dXC/ya)9iAam+]' .20ViIߚ$!W^R sX˸-eH~ԙ@=X$dĸð$%5$ sA-,Ʌ] ~pв[~=a|MGaD%_P6,Yy#kHH=Y2Ϛs4Gc93Z {N^gIJ>i~ƾ% 9-^Ӂ%!9lHN;@=s临>X2|y̶uD,dVCv3ƺꣿÕUT>**@g@>b$ڼڏ zQ%ثFW}mdqWæ 6ujJެZ=xfp!\/?r p7W;IENDB`IanniX-0.9.20/IanniX.pro000066400000000000000000000256601317340345000147110ustar00rootroot00000000000000# This file is part of IanniX, a graphical real-time open-source sequencer for digital art # Copyright (C) 2010-2015 — IanniX Association # # Project Manager: Thierry Coduys (http://www.le-hub.org) # Development: Guillaume Jacquemin (https://www.buzzinglight.com) # # This file was written by Guillaume Jacquemin. # # IanniX is a 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 # 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 . QT_VERSION = $$[QT_VERSION] message($$[QT_VERSION]) contains(QT_VERSION, "^4.*") { message("IanniX For QT4") DEFINES += QT4 QT += core gui opengl network script xml } else { message("IanniX For QT5") DEFINES += QT5 QT += widgets core gui opengl network script xml } macx { QMAKE_LFLAGS += -F/Library/Frameworks contains(QT_VERSION, "4.7.4") { message("IanniX for Mac 32bits") DEFINES += IANNIX_32 CONFIG += x86 x86_64 } else { DEFINES += IANNIX_64 CONFIG += x86_64 message("IanniX for Mac 64bits") } } !macx { DEFINES += IANNIX_64 DEFINES += IANNIX_32 CONFIG += x86 x86_64 } TARGET = IanniX TEMPLATE = app unix:!mac { PREFIX = $${PREFIX} isEmpty(PREFIX) { PREFIX = $$(PREFIX) } isEmpty(PREFIX) { PREFIX = /usr/local } message(Install Prefix is: $$PREFIX) TARGET = iannix target.path = $$PREFIX/bin INSTALLS += target desktop.path = $$PREFIX/share/applications desktop.files = iannix.desktop INSTALLS += desktop icons.path = /usr/share/pixmaps icons.files = iannix.png INSTALLS += icons } HEADERS += iannix.h iannixapp.h iannix_spec.h iannix_cmd.h SOURCES += iannix.cpp iannixapp.cpp iannix_spec.cpp HEADERS += misc/help.h misc/application.h misc/options.h misc/applicationexecute.h SOURCES += misc/help.cpp misc/application.cpp misc/options.cpp misc/applicationexecute.cpp HEADERS += messages/messagemanagerlogmini.h messages/messagemanagerlog.h messages/messagemanager.h messages/message.h messages/messagemanagerloginterface.h SOURCES += messages/messagemanagerlogmini.cpp messages/messagemanagerlog.cpp messages/messagemanager.cpp messages/message.cpp FORMS += messages/messagemanagerlogmini.ui messages/messagemanagerlog.ui HEADERS += transport/transport.h transport/uitimer.h transport/uiabout.h transport/uieditor.h SOURCES += transport/transport.cpp transport/uitimer.cpp transport/uiabout.cpp transport/uieditor.cpp FORMS += transport/transport.ui transport/uitimer.ui transport/uiabout.ui transport/uieditor.ui HEADERS += render/uirender.h render/uirenderpreview.h SOURCES += render/uirender.cpp render/uirenderpreview.cpp FORMS += render/uirender.ui HEADERS += geometry/nxpoint.h geometry/nxrect.h geometry/nxsize.h geometry/nxline.h geometry/nxpolygon.h geometry/nxeasing.h SOURCES += geometry/nxpoint.cpp geometry/nxrect.cpp geometry/nxsize.cpp geometry/nxline.cpp geometry/nxpolygon.cpp geometry/nxeasing.cpp HEADERS += geometry/qmuparser/muParser.h geometry/qmuparser/muParserBase.h geometry/qmuparser/muParserBytecode.h geometry/qmuparser/muParserCallback.h geometry/qmuparser/muParserError.h geometry/qmuparser/muParserTokenReader.h geometry/qmuparser/muParserDef.h geometry/qmuparser/muParserFixes.h geometry/qmuparser/muParserStack.h geometry/qmuparser/muParserToken.h SOURCES += geometry/qmuparser/muParser.cpp geometry/qmuparser/muParserBase.cpp geometry/qmuparser/muParserBytecode.cpp geometry/qmuparser/muParserCallback.cpp geometry/qmuparser/muParserError.cpp geometry/qmuparser/muParserTokenReader.cpp HEADERS += objects/nxdocument.h objects/nxtrigger.h objects/nxgroup.h objects/nxcurve.h objects/nxcursor.h objects/nxobject.h SOURCES += objects/nxdocument.cpp objects/nxtrigger.cpp objects/nxgroup.cpp objects/nxcurve.cpp objects/nxcursor.cpp objects/nxobject.cpp HEADERS += gui/uiinspector.h gui/uiview.h gui/uihelp.h gui/uimessagebox.h gui/uisplashscreen.h SOURCES += gui/uiinspector.cpp gui/uiview.cpp gui/uihelp.cpp gui/uimessagebox.cpp gui/uisplashscreen.cpp FORMS += gui/uiinspector.ui gui/uiview.ui gui/uihelp.ui gui/uimessagebox.ui HEADERS += gui/qjsedit/jsedit.h SOURCES += gui/qjsedit/jsedit.cpp SOURCES += items/uitreeview.cpp items/uitreeviewwidget.cpp items/uitreedelegate.cpp items/uifileitem.cpp items/uicoloritem.cpp items/uipathpointsitem.cpp items/uitextureitem.cpp HEADERS += items/uitreeview.h items/uitreeviewwidget.h items/uitreedelegate.h items/uifileitem.h items/uicoloritem.h items/uipathpointsitem.h items/uitextureitem.h FORMS += items/uitreeview.ui HEADERS += interfaces/extscriptvariableask.h interfaces/extoscpatternask.h interfaces/extoscpatterneditor.h SOURCES += interfaces/extscriptvariableask.cpp interfaces/extoscpatternask.cpp interfaces/extoscpatterneditor.cpp FORMS += interfaces/extscriptvariableask.ui interfaces/extoscpatternask.ui interfaces/extoscpatterneditor.ui HEADERS += abstractionsgl.h SOURCES += abstractionsgl.cpp #Native interfaces HEADERS += interfaces/interfacehttp.h interfaces/interfacemidi.h interfaces/interfaceosc.h interfaces/interfaceserial.h interfaces/interfacetcp.h interfaces/interfaceudp.h interfaces/interfacedirect.h interfaces/interfacesyphon.h SOURCES += interfaces/interfacehttp.cpp interfaces/interfacemidi.cpp interfaces/interfaceosc.cpp interfaces/interfaceserial.cpp interfaces/interfacetcp.cpp interfaces/interfaceudp.cpp interfaces/interfacedirect.cpp FORMS += interfaces/interfacehttp.ui interfaces/interfacemidi.ui interfaces/interfaceosc.ui interfaces/interfaceserial.ui interfaces/interfacetcp.ui interfaces/interfaceudp.ui interfaces/interfacedirect.ui interfaces/interfacesyphon.ui #Serial HEADERS += interfaces/qextserialport/qextserialport.h interfaces/qextserialport/qextserialenumerator.h interfaces/qextserialport/qextserialport_global.h interfaces/qextserialport/qextserialport_p.h interfaces/qextserialport/qextserialenumerator_p.h SOURCES += interfaces/qextserialport/qextserialport.cpp interfaces/qextserialport/qextserialenumerator.cpp #MIDI HEADERS += interfaces/qrtmidi/RtMidi.h interfaces/qrtmidi/RtError.h SOURCES += interfaces/qrtmidi/RtMidi.cpp debug:DEFINES += __RTMIDI_DEBUG__ #Websockets SOURCES += interfaces/qwebsockets/websocket.cpp interfaces/qwebsockets/websocketserver.cpp interfaces/qwebsockets/websocketprotocol.cpp interfaces/qwebsockets/handshakerequest.cpp interfaces/qwebsockets/handshakeresponse.cpp interfaces/qwebsockets/dataprocessor.cpp HEADERS += interfaces/qwebsockets/websocket.h interfaces/qwebsockets/websocketserver.h interfaces/qwebsockets/websocketprotocol.h interfaces/qwebsockets/handshakerequest.h interfaces/qwebsockets/handshakeresponse.h interfaces/qwebsockets/dataprocessor.h #Artnet macx { INCLUDEPATH += interfaces HEADERS += interfaces/artnet/artnet.h interfaces/artnet/misc.h interfaces/artnet/packets.h interfaces/artnet/private.h interfaces/artnet/tod.h interfaces/artnet/common.h SOURCES += interfaces/artnet/artnet.c interfaces/artnet/misc.c interfaces/artnet/network.c interfaces/artnet/receive.c interfaces/artnet/tod.c interfaces/artnet/transmit.c } #Zeroconf macx { #DEFINES += ZEROCONF_AS_SERVICE INCLUDEPATH += interfaces/zeroconf SOURCES += interfaces/zeroconf/bonjourserviceregister.cpp interfaces/zeroconf/bonjourserviceresolver.cpp interfaces/zeroconf/bonjourservicebrowser.cpp HEADERS += interfaces/zeroconf/bonjourserviceregister.h interfaces/zeroconf/bonjourserviceresolver.h interfaces/zeroconf/bonjourservicebrowser.h interfaces/zeroconf/bonjourrecord.h } #Syphon macx { DEFINES += SYPHON_INSTALLED OBJECTIVE_SOURCES += interfaces/interfacesyphon.mm LIBS += -framework Cocoa -framework Syphon } #Kinect false { DEFINES += KINECT_INSTALLED CONFIG -= x86 unix:SOURCES += interfaces/qkinect/QKinect.cpp extkinectmanager.cpp unix:HEADERS += interfaces/qkinect/QKinect.h extkinectmanager.h unix:LIBS += -lfreenect unix:INCLUDEPATH += /usr/local/include/libfreenect } #FFMPEG to record false { DEFINES += FFMPEG_INSTALLED CONFIG -= x86 INCLUDEPATH += gui/qffmpeg SOURCES += gui/qffmpeg/QVideoEncoder.cpp gui/qffmpeg/QVideoDecoder.cpp HEADERS += gui/qffmpeg/QVideoEncoder.h gui/qffmpeg/QVideoDecoder.h unix:LIBS +=-L/opt/local/lib -lavutil unix:LIBS +=-L/opt/local/lib -lavcodec unix:LIBS +=-L/opt/local/lib -lavformat unix:LIBS +=-L/opt/local/lib -lswscale win32:DEFINES += __STDC_CONSTANT_MACROS } #Wacom & trackpads false { DEFINES += WACOM_INSTALLED OBJECTIVE_SOURCES += interfaces/extwacommanager.mm interfaces/qwacom/WacomTabletDriver.h interfaces/qwacom/WacomTabletDriver.m HEADERS += interfaces/extwacommanager.h LIBS += -framework Cocoa } TRANSLATIONS = Tools/Translation_fr_FR.ts RESOURCES += icons/IanniX.qrc macx { ICON = icon.icns QMAKE_INFO_PLIST = Info.plist BUNDLE_RES.files = icon_file.icns BUNDLE_RES.path = Contents/Resources QMAKE_BUNDLE_DATA += BUNDLE_RES } win32 { DEFINES += __WINDOWS_MM__ LIBS += -lwinmm -lsetupapi -ladvapi32 -luser32 opengl32.lib RC_FILE = icon.rc SOURCES += interfaces/qextserialport/qextserialport_win.cpp interfaces/qextserialport/qextserialenumerator_win.cpp } unix { SOURCES += interfaces/qextserialport/qextserialport_unix.cpp linux* { SOURCES += interfaces/qextserialport/qextserialenumerator_linux.cpp } else:macx { SOURCES += interfaces/qextserialport/qextserialenumerator_osx.cpp } else { SOURCES += interfaces/qextserialport/qextserialenumerator_unix.cpp } } linux* { DEFINES += __LINUX_ALSA__ DEFINES += AVOID_TIMESTAMPING DEFINES += __linux__ LIBS += -lasound PKGCONFIG += alsa !qesp_linux_udev:DEFINES += QESP_NO_UDEV qesp_linux_udev: LIBS += -ludev } macx { DEFINES += __MACOSX_CORE__ LIBS += -framework CoreMidi -framework CoreAudio -framework CoreFoundation -framework IOKit -framework Carbon } IanniX-0.9.20/Info.plist000066400000000000000000000050061317340345000147410ustar00rootroot00000000000000 CFBundleName IanniX CFBundleExecutable IanniX CFBundleShortVersionString 0.9.20 CFBundleVersion 0.9.20 CFBundleIdentifier org.iannix.desktop NSHumanReadableCopyright IanniX Association LSApplicationCategoryType public.app-category.music CFBundleIconFile icon.icns CFBundlePackageType APPL CFBundleGetInfoString buzzing light CFBundleSignature ???? LSMinimumSystemVersion 10.6.0 CFBundleDevelopmentRegion English NSPrincipalClass NSApplication NSHighResolutionCapable True CFBundleDocumentTypes CFBundleTypeExtensions iannix IANNIX CFBundleTypeIconFile icon_file.icns CFBundleTypeName IanniX Score CFBundleTypeRole Editor CFBundleTypeExtensions nxscore NXSCORE CFBundleTypeIconFile icon_file.icns CFBundleTypeName IanniX Score CFBundleTypeRole Editor CFBundleTypeExtensions nxscript NXSCRIPT CFBundleTypeIconFile icon_file.icns CFBundleTypeName IanniX Score CFBundleTypeRole Editor CFBundleTypeExtensions nxstyle NXSTYLE CFBundleTypeIconFile icon_file.icns CFBundleTypeName IanniX Score CFBundleTypeRole Editor ForAppStore LSAppNapIsDisabled IanniX-0.9.20/Patches/000077500000000000000000000000001317340345000143575ustar00rootroot00000000000000IanniX-0.9.20/Patches/Arduino/000077500000000000000000000000001317340345000157605ustar00rootroot00000000000000IanniX-0.9.20/Patches/Arduino/Arduino.ino000066400000000000000000000027321317340345000200740ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #include "iannix_lib.h" void setup() { IanniX::setup(); IanniX::send("zoom 110"); } float value = 0; void loop() { //Get analog value from PIN A0 (Arduino UNO) float dest = analogRead(0); //Smooth value value = value + (dest - value) / 5; //Control zoom with sensor on PIN A0 (Arduino Uno) Serial.print("zoom "); Serial.println(value); delay(10); //Reception of events from IanniX if((IanniX::hasData()) && (IanniX::count() >= 3)) tone(IanniX::toInt(1), IanniX::toInt(2), IanniX::toInt(3)); } IanniX-0.9.20/Patches/Arduino/Readme.txt000066400000000000000000000023011317340345000177120ustar00rootroot00000000000000/* All the files of this directory are part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) These files were written by Guillaume Jacquemin. IanniX is a 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 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 . */ Arduino ------- - Compile & upload your Arduino project - Change in IanniX the serial port path (you can find it in Arduino menu Tool > Serial Port) - Open the score called "Simple Arduino example" - Reset the Arduino board IanniX-0.9.20/Patches/Arduino/iannix_lib.cpp000066400000000000000000000050011317340345000205740ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #include "iannix_lib.h" char IanniX::iannixBuffer[iannixBufferArgumentIndexMax][iannixBufferDataIndexMax]; unsigned int IanniX::iannixBufferDataIndex = 0; unsigned int IanniX::iannixBufferArgumentIndex = 0; unsigned int IanniX::iannixBufferArgumentIndexCache = 0; boolean IanniX::hasData() { boolean hasDataReturn = false; while(Serial.available() > 0) { //Received char char iannixByte = Serial.read(); //End of frame if((iannixByte == iannixBufferCharEnd1) || (iannixByte == iannixBufferCharEnd2)) { hasDataReturn = true; } //Frame payload else { //Argument separator if(iannixByte == iannixBufferCharSeparator) { //Can store ? if(iannixBufferArgumentIndex < iannixBufferArgumentIndexMax) { //Close the previous argument iannixBuffer[iannixBufferArgumentIndex][iannixBufferDataIndex] = 0; //Open a new argument iannixBufferArgumentIndex++; iannixBufferDataIndex = 0; } //No more memory else hasDataReturn = true; } //Message content else if(iannixBufferDataIndex < iannixBufferArgumentIndexMax) iannixBuffer[iannixBufferArgumentIndex][iannixBufferDataIndex++] = iannixByte; //No more memory else hasDataReturn = true; } } //If the message is over (end of frame OR no more memory) if(hasDataReturn) { iannixBufferArgumentIndexCache = iannixBufferArgumentIndex; iannixBufferDataIndex = 0; iannixBufferArgumentIndex = 0; } //Returns return hasDataReturn; } IanniX-0.9.20/Patches/Arduino/iannix_lib.h000066400000000000000000000041601317340345000202460ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #ifndef IANNIX_LIB_H #define IANNIX_LIB_H #if defined(ARDUINO) && ARDUINO >= 100 #include "Arduino.h" #else #include "WProgram.h" #include #endif #define iannixBufferDataIndexMax 16 #define iannixBufferArgumentIndexMax 10 #define iannixBufferCharEnd1 ';' #define iannixBufferCharEnd2 '\n' #define iannixBufferCharSeparator ' ' class IanniX { public: static char iannixBuffer[iannixBufferArgumentIndexMax][iannixBufferDataIndexMax]; static unsigned int iannixBufferDataIndex, iannixBufferArgumentIndex, iannixBufferArgumentIndexCache; public: static const int count() { return iannixBufferArgumentIndexCache; } static char* toChar(const unsigned int argumentIndex) { return iannixBuffer[argumentIndex]; } static int toInt(const unsigned int argumentIndex) { return atoi(iannixBuffer[argumentIndex]); } static float toFloat(const unsigned int argumentIndex) { return atof(iannixBuffer[argumentIndex]); } public: static boolean hasData(); static void setup() { Serial.begin(115200); } static void send(const char* message) { Serial.println(message); } }; #endif IANNIX_LIB_H IanniX-0.9.20/Patches/PureData/000077500000000000000000000000001317340345000160645ustar00rootroot00000000000000IanniX-0.9.20/Patches/PureData/Iannix-puredata/000077500000000000000000000000001317340345000211155ustar00rootroot00000000000000IanniX-0.9.20/Patches/PureData/Iannix-puredata/example_gem/000077500000000000000000000000001317340345000234005ustar00rootroot00000000000000IanniX-0.9.20/Patches/PureData/Iannix-puredata/example_gem/a-initcursor.pd000066400000000000000000000433131317340345000263500ustar00rootroot00000000000000#N canvas 313 49 781 656 10; #X obj 115 130 bng 25 250 50 0 empty empty init.tab 0 -7 0 10 -262144 -1 -1; #X obj 169 202 t b b; #X msg 215 219 0; #X obj 215 246 s INITGEN; #X obj 27 441 unpack f; #X obj 29 506 tabwrite INDEXcursor; #X obj 29 461 t b f; #X msg 29 484 1; #N canvas 325 80 450 300 subtab 0; #N canvas 0 50 450 300 (subpatch) 0; #X array INDEXcursor 3000 float 3; #A 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; #A 1000 0 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.750312 0.750624 0.750937 0.751249 0.751562 0.751874 0.752187 0.752499 0.752812 0.753124 0.753437 0.753749 0.754062 0.754374 0.754687 0.754999 0.755312 0.755624 0.755937 0.756249 0.756562 0.756874 0.757187 0.757499 0.757812 0.758124 0.758437 0.758749 0.759062 0.759374 0.759687 0.759999 0.760312 0.760624 0.760937 0.761249 0.761562 0.761874 0.762187 0.7625 0.762812 0.763125 0.763437 0.76375 0.764062 0.764375 0.764687 0.765 0.765312 0.765625 0.765937 0.76625 0.766562 0.766875 0.767187 0.7675 0.767812 0.768125 0.768437 0.76875 0.769062 0.769375 0.769687 0.77 0.770312 0.770625 0.770937 0.77125 0.771562 0.771875 0.772187 0.7725 0.772812 0.773125 0.773437 0.77375 0.774062 0.774375 0.774687 0.775 0.775312 0.775625 0.775937 0.77625 0.776562 0.776875 0.777187 0.7775 0.777812 0.778125 0.778437 0.77875 0.779062 0.779375 0.779687 0.78 0.780312 0.780625 0.780937 0.78125 0.781562 0.781875 0.782187 0.7825 0.782812 0.783125 0.783437 0.78375 0.784063 0.784375 0.784688 0.785 0.785313 0.785625 0.785938 0.78625 0.786563 0.786875 0.787188 0.7875 0.787813 0.788125 0.788438 0.78875 0.789063 0.789375 0.789688 0.79 0.790313 0.790625 0.790938 0.79125 0.791563 0.791875 0.792188 0.7925 0.792813 0.793125 0.793438 0.79375 0.794063 0.794375 0.794688 0.795 0.795313 0.795625 0.795938 0.79625 0.796563 0.796875 0.797188 0.7975 0.797813 0.798125 0.798438 0.79875 0.799063 0.799375 0.799688 0.8 0.800313 0.800625 0.800938 0.80125 0.801563 0.801875 0.802188 0.8025 0.802813 0.803125 0.803438 0.80375 0.804063 0.804375 0.804688 0.805 0.805313 0.805625 0.805938 0.806251 0.806563 0.806876 0.807188 0.807501 0.807813 0.808126 0.808438 0.808751 0.809063 0.809376 0.809688 0.810001 0.810313 0.810626 0.810938 0.811251 0.811563 0.811876 0.812188 0.812501 0.812813 0.813126 0.813438 0.813751 0.814063 0.814376 0.814688 0.815001 0.815313 0.815626 0.815938 0.816251 0.816563 0.816876 0.817188 0.817501 0.817813 0.818126 0.818438 0.818751 0.819063 0.819376 0.819688 0.820001 0.820313 0.820626 0.820938 0.821251 0.821563 0.821876 0.822188 0.822501 0.822813 0.823126 0.823438 0.823751 0.824063 0.824376 0.824688 0.825001 0.263439 0.264376 0.265314 0.266251 0.267189 0.268126 0.269064 0.270001 0.270939 0.271876 0.272814 0.273751 0.274689 0.275627 0.276564 0.277502 0.278439 0.279377 0.280314 0.281252 0.282189 0.283127 0.284064 0.285002 0.285939 0.286877 0.287814 0.288752 0.289689 0.290627 0.291564 0.292502 0.293439 0.294377 0.295314 0.296252 0.29719 0.298127 0.299065 0.300002 0.30094 0.301877 0.302815 0.303752 0.30469 0.305627 0.306565 0.307502 0.30844 0.309377 0.310315 0.311252 0.31219 0.313127 0.314065 0.315002 0.31594 0.316877 0.317815 0.318753 0.31969 0.320628 0.321565 0.322503 0.32344 0.324378 0.325315 0.326253 0.32719 0.328128 0.329065 0.330003 0.33094 0.331878 0.332815 0.333753 0.33469 0.335628 0.336565 0.337503 0.33844 0.339378 0.340316 0.341253 0.342191 0.343128 0.344066 0.345003 0.345941 0.346878 0.347816 0.348753 0.349691 0.350628 0.351566 0.352503 0.353441 0.354378 0.355316 0.356253 0.357191 0.358128 0.359066 0.360003 0.360941 0.361879 0.362816 0.363754 0.364691 0.365629 0.366566 0.367504 0.368441 0.369379 0.370316 0.371254 0.372191 0.373129 0.374066 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004; #A 2000 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; #X coords 0 1.5 3000 0 50 20 1; #X restore 244 113 graph; #X restore 467 74 pd subtab; #X obj 27 416 r RouteCursor; #X obj 352 297 tabread INDEXcursor; #X obj 384 257 + 1; #X obj 352 321 sel 1; #X obj 387 341 + 1; #X obj 171 130 bng 25 250 50 0 empty empty create.object 0 -7 0 10 -262144 -1 -1; #X obj 352 257 f; #X obj 352 341 f; #X msg 408 199 0; #X obj 352 556 pack f f f; #X obj 352 422 mod 10; #X obj 395 463 sel 1; #X obj 352 381 t f f; #X obj 395 484 f; #X obj 423 484 + 50; #X obj 385 531 f; #X obj 352 441 t f f b; #X msg 352 577 obj \$1 \$2 abs-cursor \$3; #X obj 384 402 + 0; #X obj 352 483 * 125; #X msg 536 198 clear; #X obj 329 170 t b b b b; #X msg 329 192 loadbang; #X msg 352 215 1000; #X obj 352 237 until; #X obj 352 277 t f f; #X obj 352 361 t f f; #X obj 408 219 t f f f; #X obj 395 504 t f f; #X obj 352 602 s pd-\$1.Rcursor; #X msg 169 269 const 0; #X obj 169 291 s INDEXcursor; #X connect 0 0 1 0; #X connect 1 0 39 0; #X connect 1 1 2 0; #X connect 2 0 3 0; #X connect 4 0 6 0; #X connect 6 0 7 0; #X connect 6 1 5 1; #X connect 7 0 5 0; #X connect 9 0 4 0; #X connect 10 0 12 0; #X connect 11 0 15 1; #X connect 12 0 16 0; #X connect 13 0 16 1; #X connect 14 0 30 0; #X connect 15 0 34 0; #X connect 16 0 35 0; #X connect 17 0 36 0; #X connect 18 0 26 0; #X connect 19 0 25 0; #X connect 20 0 22 0; #X connect 21 0 19 0; #X connect 21 1 27 0; #X connect 22 0 37 0; #X connect 23 0 22 1; #X connect 24 0 18 1; #X connect 25 0 28 0; #X connect 25 1 20 0; #X connect 25 2 24 0; #X connect 26 0 38 0; #X connect 27 0 18 2; #X connect 28 0 18 0; #X connect 29 0 38 0; #X connect 30 0 31 0; #X connect 30 1 32 0; #X connect 30 2 17 0; #X connect 30 3 29 0; #X connect 31 0 38 0; #X connect 32 0 33 0; #X connect 33 0 15 0; #X connect 34 0 10 0; #X connect 34 1 11 0; #X connect 35 0 21 0; #X connect 35 1 13 0; #X connect 36 0 22 1; #X connect 36 1 16 1; #X connect 36 2 15 1; #X connect 37 0 24 1; #X connect 37 1 23 0; #X connect 39 0 40 0; #X coords 0 -1 1 1 160 60 1 100 100; IanniX-0.9.20/Patches/PureData/Iannix-puredata/example_gem/a-inittrig.pd000066400000000000000000000202561317340345000260010ustar00rootroot00000000000000#N canvas 231 61 659 675 10; #X obj 181 459 t b f; #X msg 181 484 1; #X obj 181 505 tabwrite INDEXtrigger; #X obj 105 131 bng 25 250 50 0 empty empty init.tab 0 -7 0 10 -262144 -1 -1; #X obj 105 166 t b b; #X msg 212 190 0; #X obj 212 210 s INITGEN; #N canvas 362 452 450 300 sutab 0; #N canvas 4 50 450 300 (subpatch) 0; #X array INDEXtrigger 3000 float 3; #A 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; #A 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; #A 2000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; #X coords 0 1 3000 -1 50 20 1; #X restore 235 107 graph; #X restore 434 57 pd sutab; #X obj 442 237 + 1; #X obj 410 302 sel 1; #X obj 442 328 + 1; #X obj 164 131 bng 25 250 50 0 empty empty create.object 0 -7 0 10 -262144 -1 -1; #X obj 410 279 tabread INDEXtrigger; #X obj 410 237 f; #X obj 410 329 f; #X msg 480 166 0; #X obj 410 587 pack f f f; #X obj 410 419 mod 10; #X obj 433 464 sel 1; #X obj 410 375 t f f; #X obj 453 505 f; #X obj 481 505 + 50; #X obj 438 562 f; #X obj 410 442 t f f b; #X msg 410 608 obj \$1 \$2 abs-trigger \$3; #X obj 410 484 * 110; #X obj 181 436 r RouteTrigger; #X msg 538 209 clear; #X obj 390 149 t b b b b; #X msg 390 171 loadbang; #X obj 105 210 s INDEXtrigger; #X msg 105 190 const 0; #X obj 410 193 i 3000; #X obj 410 214 until; #X obj 410 257 t f f; #X obj 410 351 t f f; #X obj 453 526 t f f; #X obj 470 186 t a a a; #X obj 390 628 s pd-\$1.Rtrigger; #X obj 442 395 + 0; #X connect 0 0 1 0; #X connect 0 1 2 1; #X connect 1 0 2 0; #X connect 3 0 4 0; #X connect 4 0 31 0; #X connect 4 1 5 0; #X connect 5 0 6 0; #X connect 8 0 13 1; #X connect 9 0 14 0; #X connect 10 0 14 1; #X connect 11 0 28 0; #X connect 12 0 9 0; #X connect 13 0 34 0; #X connect 14 0 35 0; #X connect 15 0 37 0; #X connect 16 0 24 0; #X connect 17 0 23 0; #X connect 18 0 20 0; #X connect 19 0 17 0; #X connect 19 1 39 0; #X connect 20 0 36 0; #X connect 21 0 20 1; #X connect 22 0 16 1; #X connect 23 0 25 0; #X connect 23 1 18 0; #X connect 23 2 22 0; #X connect 24 0 38 0; #X connect 25 0 16 0; #X connect 26 0 0 0; #X connect 27 0 38 0; #X connect 28 0 29 0; #X connect 28 1 32 0; #X connect 28 2 15 0; #X connect 28 3 27 0; #X connect 29 0 38 0; #X connect 31 0 30 0; #X connect 32 0 33 0; #X connect 33 0 13 0; #X connect 34 0 12 0; #X connect 34 1 8 0; #X connect 35 0 19 0; #X connect 35 1 10 0; #X connect 36 0 22 1; #X connect 36 1 21 0; #X connect 37 0 20 1; #X connect 37 1 14 1; #X connect 37 2 13 1; #X connect 39 0 16 2; #X coords 0 -1 1 1 160 60 1 100 100; IanniX-0.9.20/Patches/PureData/Iannix-puredata/example_gem/a-udp.pd000066400000000000000000000042351317340345000247370ustar00rootroot00000000000000#N canvas 245 49 960 669 10; #X obj 317 83 inlet; #X obj 447 83 inlet; #X msg 447 132 /iannix/stop; #X obj 447 107 route 0; #X msg 535 132 /iannix/play \$1; #X obj 647 83 inlet; #X obj 211 75 loadbang; #X obj 141 121 pack s f; #X obj 211 100 f \$2; #X obj 141 100 symbol \$1; #X msg 141 144 connect \$1 \$2; #X obj 307 512 outlet; #X obj 366 512 outlet; #X obj 425 512 outlet; #X obj 484 445 route play stop fastrewind; #X msg 484 465 1; #X msg 535 465 0; #X obj 586 490 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X obj 507 491 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X obj 507 512 outlet; #X obj 586 512 outlet; #X obj 735 492 outlet; #X obj 777 492 outlet; #X obj 819 492 outlet; #X msg 647 132 /iannix/fastrewind; #X msg 484 424 \$1; #X obj 636 512 outlet; #X obj 685 492 outlet; #X obj 484 403 unpack s f s f f f; #X obj 488 298 netsend -u -b; #X obj 488 256 list prepend send; #X obj 488 277 list trim; #X obj 307 305 netreceive -u -b \$3; #X obj 307 327 oscparse; #X obj 307 379 route trigger cursor curve transport; #X obj 448 160 route send; #X obj 448 204 list split 1; #X obj 566 207 symbol; #X obj 488 229 oscformat; #X msg 566 229 set \$1; #X obj 448 182 t a a; #X obj 307 353 list trim; #X connect 0 0 35 0; #X connect 1 0 3 0; #X connect 2 0 35 0; #X connect 3 0 2 0; #X connect 3 1 4 0; #X connect 4 0 35 0; #X connect 5 0 24 0; #X connect 6 0 8 0; #X connect 6 0 9 0; #X connect 7 0 10 0; #X connect 8 0 7 1; #X connect 9 0 7 0; #X connect 10 0 29 0; #X connect 14 0 15 0; #X connect 14 1 16 0; #X connect 14 2 17 0; #X connect 15 0 18 0; #X connect 16 0 18 0; #X connect 17 0 20 0; #X connect 18 0 19 0; #X connect 24 0 35 0; #X connect 25 0 14 0; #X connect 28 0 25 0; #X connect 28 1 26 0; #X connect 28 2 27 0; #X connect 28 3 21 0; #X connect 28 4 22 0; #X connect 28 5 23 0; #X connect 30 0 31 0; #X connect 31 0 29 0; #X connect 32 0 33 0; #X connect 33 0 41 0; #X connect 34 0 11 0; #X connect 34 1 12 0; #X connect 34 2 13 0; #X connect 34 3 28 0; #X connect 35 0 40 0; #X connect 35 1 40 0; #X connect 36 1 38 0; #X connect 37 0 39 0; #X connect 38 0 30 0; #X connect 39 0 38 0; #X connect 40 0 36 0; #X connect 40 1 37 0; #X connect 41 0 34 0; IanniX-0.9.20/Patches/PureData/Iannix-puredata/example_gem/a_range.pd000066400000000000000000000010201317340345000253120ustar00rootroot00000000000000#N canvas 122 49 450 300 10; #X obj 125 27 inlet; #X obj 125 266 outlet; #X obj 125 56 - \$1; #X obj 125 154 /; #X obj 201 119 - \$1; #X obj 125 212 *; #X obj 287 151 - \$3; #X obj 125 242 + \$3; #X obj 201 40 loadbang; #X obj 201 67 t b b; #X obj 201 93 f \$2; #X obj 287 125 f \$4; #X connect 0 0 2 0; #X connect 2 0 3 0; #X connect 3 0 5 0; #X connect 4 0 3 1; #X connect 5 0 7 0; #X connect 6 0 5 1; #X connect 7 0 1 0; #X connect 8 0 9 0; #X connect 9 0 10 0; #X connect 9 1 11 0; #X connect 10 0 4 0; #X connect 11 0 6 0; IanniX-0.9.20/Patches/PureData/Iannix-puredata/example_gem/abs-cursor.pd000066400000000000000000000022441317340345000260070ustar00rootroot00000000000000#N canvas 536 95 574 627 10; #X obj 20 142 outlet; #X obj 48 169 outlet; #X obj 325 327 loadbang; #X obj 104 37 route \$1; #X obj 78 194 outlet; #X obj 104 62 unpack s f f f f; #X obj 127 125 t f f; #X obj 150 104 t f f; #X obj 173 82 t f f; #X obj 104 16 r RouteCursor; #X obj 131 275 translateXYZ; #X obj 131 369 cube 0.1; #X msg 279 352 draw line; #X obj 131 326 rotateXYZ; #X obj 178 300 * 10; #X obj 201 300 * 10; #X obj 224 301 * 10; #X obj 131 247 separator; #X obj 129 227 r GemHeadCube; #X obj 153 147 a_range 0.01 1 -3 3; #X obj 176 170 a_range 0.01 1 -3 3; #X obj 200 190 a_range 0.01 1 -3 3; #X connect 2 0 12 0; #X connect 3 0 5 0; #X connect 5 1 6 0; #X connect 5 2 7 0; #X connect 5 3 8 0; #X connect 6 0 0 0; #X connect 6 1 19 0; #X connect 7 0 1 0; #X connect 7 1 20 0; #X connect 8 0 4 0; #X connect 8 1 21 0; #X connect 9 0 3 0; #X connect 10 0 13 0; #X connect 12 0 11 0; #X connect 13 0 11 0; #X connect 14 0 13 1; #X connect 15 0 13 2; #X connect 16 0 13 3; #X connect 17 0 10 0; #X connect 18 0 17 0; #X connect 19 0 10 1; #X connect 19 0 14 0; #X connect 20 0 10 2; #X connect 20 0 15 0; #X connect 21 0 16 0; #X connect 21 0 10 3; #X coords 0 627 1 626 120 35 0; IanniX-0.9.20/Patches/PureData/Iannix-puredata/example_gem/abs-trigger.pd000066400000000000000000000030221317340345000261300ustar00rootroot00000000000000#N canvas 598 181 574 627 10; #X obj 25 193 outlet; #X obj 73 205 outlet; #X obj 101 38 route \$1; #X obj 120 214 outlet; #X obj 104 16 r RouteTrigger; #X obj 100 60 unpack s f f f f f f f; #X floatatom 228 119 3 0 0 0 - - -; #X floatatom 252 119 3 0 0 0 - - -; #X floatatom 278 119 3 0 0 0 - - -; #X floatatom 332 151 3 0 0 0 - - -; #X obj 54 117 t a a; #X text 41 117 X; #X obj 81 140 t a a; #X text 67 139 Y; #X obj 134 151 t a a; #X text 77 149 Y; #X text 117 157 Z; #X obj 331 128 t a b; #X text 265 153 nbr cursor; #X obj 137 351 translateXYZ; #X obj 136 437 colorRGB 1 0 0 0; #X obj 377 157 t b b; #X msg 363 251 0; #X obj 136 484 circle 0.1; #X obj 361 189 delay 200; #X obj 136 461 alpha; #X msg 396 253 0.3; #X obj 137 303 r GemHeadCircle; #X obj 140 331 separator; #X obj 163 197 a_range 0.01 1 -3 3; #X obj 199 225 a_range 0.01 1 -3 3; #X obj 214 247 a_range 0.01 1 -3 3; #X connect 2 0 5 0; #X connect 4 0 2 0; #X connect 5 1 10 0; #X connect 5 2 12 0; #X connect 5 3 14 0; #X connect 5 4 6 0; #X connect 5 5 7 0; #X connect 5 6 8 0; #X connect 5 7 17 0; #X connect 10 0 0 0; #X connect 10 1 29 0; #X connect 12 0 1 0; #X connect 12 1 30 0; #X connect 14 0 3 0; #X connect 14 1 31 0; #X connect 17 0 9 0; #X connect 17 1 21 0; #X connect 19 0 20 0; #X connect 20 0 25 0; #X connect 21 0 24 0; #X connect 21 1 26 0; #X connect 22 0 20 4; #X connect 24 0 22 0; #X connect 25 0 23 0; #X connect 26 0 20 4; #X connect 27 0 28 0; #X connect 28 0 19 0; #X connect 29 0 19 1; #X connect 30 0 19 2; #X connect 31 0 19 3; #X coords 0 0 1 1 110 35 0; IanniX-0.9.20/Patches/PureData/Iannix-puredata/example_gem/main.pd000066400000000000000000000034751317340345000246620ustar00rootroot00000000000000#N canvas 605 49 757 597 10; #X text 102 39 Set IanniX score speed; #X floatatom 66 38 5 0 0 0 - - -, f 5; #X msg 66 58 /iannix/speed \$1; #X obj 83 194 s RouteCursor; #X obj 100 174 s RouteCurve; #X obj 66 214 s RouteTrigger; #X obj 142 106 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X text 158 105 Play / pause; #X obj 259 70 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X text 274 69 Score played / paused; #X msg 142 85 set \$1; #X floatatom 219 153 5 0 0 0 - - -, f 5; #X floatatom 202 171 5 0 0 0 - - -, f 5; #X floatatom 185 189 5 0 0 0 - - -, f 5; #X obj 66 133 a-udp 127.0.0.1 1234 57120; #X text 66 459 4/ open [pd Rcursor] or [Rtrigger] to see the abstractions or to modify; #X text 65 417 2/ click init tab for cursor and trigger to dump number of elements; #X text 67 444 3/ create object for cursor and trigger.; #X text 69 519 created by philippe boisnard; #X text 63 358 gem example; #X obj 449 217 gemwin; #X msg 506 200 destroy; #X obj 442 276 gemhead; #X obj 442 302 s GemHeadCircle; #X obj 541 279 gemhead; #X obj 541 302 s GemHeadCube; #X text 65 370 this example shows how you can generate in dynamic patching an gem-video; #X msg 448 178 FSAA 4 \, dimen 800 800 \, frame 30 \, create \, 1; #X text 65 402 1/ open a ianniX score and play it (Rosette \, Spin \, Torus).; #N canvas 68 50 1285 596 \$0.Rcursor 0; #X restore 68 335 pd \$0.Rcursor; #N canvas 14 50 1137 239 \$0.Rtrigger 0; #X restore 229 333 pd \$0.Rtrigger; #X obj 64 272 a-initcursor \$0; #X obj 229 271 a-inittrig \$0; #X connect 1 0 2 0; #X connect 2 0 14 0; #X connect 6 0 14 1; #X connect 8 0 10 0; #X connect 10 0 6 0; #X connect 14 0 5 0; #X connect 14 1 3 0; #X connect 14 2 4 0; #X connect 14 7 13 0; #X connect 14 8 12 0; #X connect 14 9 11 0; #X connect 21 0 20 0; #X connect 22 0 23 0; #X connect 24 0 25 0; #X connect 27 0 20 0; IanniX-0.9.20/Patches/PureData/Iannix-puredata/example_sound/000077500000000000000000000000001317340345000237605ustar00rootroot00000000000000IanniX-0.9.20/Patches/PureData/Iannix-puredata/example_sound/a-initcursor.pd000066400000000000000000000433131317340345000267300ustar00rootroot00000000000000#N canvas 313 49 781 656 10; #X obj 115 130 bng 25 250 50 0 empty empty init.tab 0 -7 0 10 -262144 -1 -1; #X obj 169 202 t b b; #X msg 215 219 0; #X obj 215 246 s INITGEN; #X obj 27 441 unpack f; #X obj 29 506 tabwrite INDEXcursor; #X obj 29 461 t b f; #X msg 29 484 1; #N canvas 325 80 450 300 subtab 0; #N canvas 0 50 450 300 (subpatch) 0; #X array INDEXcursor 3000 float 3; #A 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; #A 1000 0 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.749999 0.750312 0.750624 0.750937 0.751249 0.751562 0.751874 0.752187 0.752499 0.752812 0.753124 0.753437 0.753749 0.754062 0.754374 0.754687 0.754999 0.755312 0.755624 0.755937 0.756249 0.756562 0.756874 0.757187 0.757499 0.757812 0.758124 0.758437 0.758749 0.759062 0.759374 0.759687 0.759999 0.760312 0.760624 0.760937 0.761249 0.761562 0.761874 0.762187 0.7625 0.762812 0.763125 0.763437 0.76375 0.764062 0.764375 0.764687 0.765 0.765312 0.765625 0.765937 0.76625 0.766562 0.766875 0.767187 0.7675 0.767812 0.768125 0.768437 0.76875 0.769062 0.769375 0.769687 0.77 0.770312 0.770625 0.770937 0.77125 0.771562 0.771875 0.772187 0.7725 0.772812 0.773125 0.773437 0.77375 0.774062 0.774375 0.774687 0.775 0.775312 0.775625 0.775937 0.77625 0.776562 0.776875 0.777187 0.7775 0.777812 0.778125 0.778437 0.77875 0.779062 0.779375 0.779687 0.78 0.780312 0.780625 0.780937 0.78125 0.781562 0.781875 0.782187 0.7825 0.782812 0.783125 0.783437 0.78375 0.784063 0.784375 0.784688 0.785 0.785313 0.785625 0.785938 0.78625 0.786563 0.786875 0.787188 0.7875 0.787813 0.788125 0.788438 0.78875 0.789063 0.789375 0.789688 0.79 0.790313 0.790625 0.790938 0.79125 0.791563 0.791875 0.792188 0.7925 0.792813 0.793125 0.793438 0.79375 0.794063 0.794375 0.794688 0.795 0.795313 0.795625 0.795938 0.79625 0.796563 0.796875 0.797188 0.7975 0.797813 0.798125 0.798438 0.79875 0.799063 0.799375 0.799688 0.8 0.800313 0.800625 0.800938 0.80125 0.801563 0.801875 0.802188 0.8025 0.802813 0.803125 0.803438 0.80375 0.804063 0.804375 0.804688 0.805 0.805313 0.805625 0.805938 0.806251 0.806563 0.806876 0.807188 0.807501 0.807813 0.808126 0.808438 0.808751 0.809063 0.809376 0.809688 0.810001 0.810313 0.810626 0.810938 0.811251 0.811563 0.811876 0.812188 0.812501 0.812813 0.813126 0.813438 0.813751 0.814063 0.814376 0.814688 0.815001 0.815313 0.815626 0.815938 0.816251 0.816563 0.816876 0.817188 0.817501 0.817813 0.818126 0.818438 0.818751 0.819063 0.819376 0.819688 0.820001 0.820313 0.820626 0.820938 0.821251 0.821563 0.821876 0.822188 0.822501 0.822813 0.823126 0.823438 0.823751 0.824063 0.824376 0.824688 0.825001 0.263439 0.264376 0.265314 0.266251 0.267189 0.268126 0.269064 0.270001 0.270939 0.271876 0.272814 0.273751 0.274689 0.275627 0.276564 0.277502 0.278439 0.279377 0.280314 0.281252 0.282189 0.283127 0.284064 0.285002 0.285939 0.286877 0.287814 0.288752 0.289689 0.290627 0.291564 0.292502 0.293439 0.294377 0.295314 0.296252 0.29719 0.298127 0.299065 0.300002 0.30094 0.301877 0.302815 0.303752 0.30469 0.305627 0.306565 0.307502 0.30844 0.309377 0.310315 0.311252 0.31219 0.313127 0.314065 0.315002 0.31594 0.316877 0.317815 0.318753 0.31969 0.320628 0.321565 0.322503 0.32344 0.324378 0.325315 0.326253 0.32719 0.328128 0.329065 0.330003 0.33094 0.331878 0.332815 0.333753 0.33469 0.335628 0.336565 0.337503 0.33844 0.339378 0.340316 0.341253 0.342191 0.343128 0.344066 0.345003 0.345941 0.346878 0.347816 0.348753 0.349691 0.350628 0.351566 0.352503 0.353441 0.354378 0.355316 0.356253 0.357191 0.358128 0.359066 0.360003 0.360941 0.361879 0.362816 0.363754 0.364691 0.365629 0.366566 0.367504 0.368441 0.369379 0.370316 0.371254 0.372191 0.373129 0.374066 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004; #A 2000 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0.375004 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; #X coords 0 1.5 3000 0 50 20 1; #X restore 244 113 graph; #X restore 467 74 pd subtab; #X obj 27 416 r RouteCursor; #X obj 352 297 tabread INDEXcursor; #X obj 384 257 + 1; #X obj 352 321 sel 1; #X obj 387 341 + 1; #X obj 171 130 bng 25 250 50 0 empty empty create.object 0 -7 0 10 -262144 -1 -1; #X obj 352 257 f; #X obj 352 341 f; #X msg 408 199 0; #X obj 352 556 pack f f f; #X obj 352 422 mod 10; #X obj 395 463 sel 1; #X obj 352 381 t f f; #X obj 395 484 f; #X obj 423 484 + 50; #X obj 385 531 f; #X obj 352 441 t f f b; #X msg 352 577 obj \$1 \$2 abs-cursor \$3; #X obj 384 402 + 0; #X obj 352 483 * 125; #X msg 536 198 clear; #X obj 329 170 t b b b b; #X msg 329 192 loadbang; #X msg 352 215 1000; #X obj 352 237 until; #X obj 352 277 t f f; #X obj 352 361 t f f; #X obj 408 219 t f f f; #X obj 395 504 t f f; #X obj 352 602 s pd-\$1.Rcursor; #X msg 169 269 const 0; #X obj 169 291 s INDEXcursor; #X connect 0 0 1 0; #X connect 1 0 39 0; #X connect 1 1 2 0; #X connect 2 0 3 0; #X connect 4 0 6 0; #X connect 6 0 7 0; #X connect 6 1 5 1; #X connect 7 0 5 0; #X connect 9 0 4 0; #X connect 10 0 12 0; #X connect 11 0 15 1; #X connect 12 0 16 0; #X connect 13 0 16 1; #X connect 14 0 30 0; #X connect 15 0 34 0; #X connect 16 0 35 0; #X connect 17 0 36 0; #X connect 18 0 26 0; #X connect 19 0 25 0; #X connect 20 0 22 0; #X connect 21 0 19 0; #X connect 21 1 27 0; #X connect 22 0 37 0; #X connect 23 0 22 1; #X connect 24 0 18 1; #X connect 25 0 28 0; #X connect 25 1 20 0; #X connect 25 2 24 0; #X connect 26 0 38 0; #X connect 27 0 18 2; #X connect 28 0 18 0; #X connect 29 0 38 0; #X connect 30 0 31 0; #X connect 30 1 32 0; #X connect 30 2 17 0; #X connect 30 3 29 0; #X connect 31 0 38 0; #X connect 32 0 33 0; #X connect 33 0 15 0; #X connect 34 0 10 0; #X connect 34 1 11 0; #X connect 35 0 21 0; #X connect 35 1 13 0; #X connect 36 0 22 1; #X connect 36 1 16 1; #X connect 36 2 15 1; #X connect 37 0 24 1; #X connect 37 1 23 0; #X connect 39 0 40 0; #X coords 0 -1 1 1 160 60 1 100 100; IanniX-0.9.20/Patches/PureData/Iannix-puredata/example_sound/a-inittrig.pd000066400000000000000000000202561317340345000263610ustar00rootroot00000000000000#N canvas 231 61 659 675 10; #X obj 181 459 t b f; #X msg 181 484 1; #X obj 181 505 tabwrite INDEXtrigger; #X obj 105 131 bng 25 250 50 0 empty empty init.tab 0 -7 0 10 -262144 -1 -1; #X obj 105 166 t b b; #X msg 212 190 0; #X obj 212 210 s INITGEN; #N canvas 362 452 450 300 sutab 0; #N canvas 4 50 450 300 (subpatch) 0; #X array INDEXtrigger 3000 float 3; #A 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; #A 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; #A 2000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; #X coords 0 1 3000 -1 50 20 1; #X restore 235 107 graph; #X restore 434 57 pd sutab; #X obj 442 237 + 1; #X obj 410 302 sel 1; #X obj 442 328 + 1; #X obj 164 131 bng 25 250 50 0 empty empty create.object 0 -7 0 10 -262144 -1 -1; #X obj 410 279 tabread INDEXtrigger; #X obj 410 237 f; #X obj 410 329 f; #X msg 480 166 0; #X obj 410 587 pack f f f; #X obj 410 419 mod 10; #X obj 433 464 sel 1; #X obj 410 375 t f f; #X obj 453 505 f; #X obj 481 505 + 50; #X obj 438 562 f; #X obj 410 442 t f f b; #X msg 410 608 obj \$1 \$2 abs-trigger \$3; #X obj 410 484 * 110; #X obj 181 436 r RouteTrigger; #X msg 538 209 clear; #X obj 390 149 t b b b b; #X msg 390 171 loadbang; #X obj 105 210 s INDEXtrigger; #X msg 105 190 const 0; #X obj 410 193 i 3000; #X obj 410 214 until; #X obj 410 257 t f f; #X obj 410 351 t f f; #X obj 453 526 t f f; #X obj 470 186 t a a a; #X obj 390 628 s pd-\$1.Rtrigger; #X obj 442 395 + 0; #X connect 0 0 1 0; #X connect 0 1 2 1; #X connect 1 0 2 0; #X connect 3 0 4 0; #X connect 4 0 31 0; #X connect 4 1 5 0; #X connect 5 0 6 0; #X connect 8 0 13 1; #X connect 9 0 14 0; #X connect 10 0 14 1; #X connect 11 0 28 0; #X connect 12 0 9 0; #X connect 13 0 34 0; #X connect 14 0 35 0; #X connect 15 0 37 0; #X connect 16 0 24 0; #X connect 17 0 23 0; #X connect 18 0 20 0; #X connect 19 0 17 0; #X connect 19 1 39 0; #X connect 20 0 36 0; #X connect 21 0 20 1; #X connect 22 0 16 1; #X connect 23 0 25 0; #X connect 23 1 18 0; #X connect 23 2 22 0; #X connect 24 0 38 0; #X connect 25 0 16 0; #X connect 26 0 0 0; #X connect 27 0 38 0; #X connect 28 0 29 0; #X connect 28 1 32 0; #X connect 28 2 15 0; #X connect 28 3 27 0; #X connect 29 0 38 0; #X connect 31 0 30 0; #X connect 32 0 33 0; #X connect 33 0 13 0; #X connect 34 0 12 0; #X connect 34 1 8 0; #X connect 35 0 19 0; #X connect 35 1 10 0; #X connect 36 0 22 1; #X connect 36 1 21 0; #X connect 37 0 20 1; #X connect 37 1 14 1; #X connect 37 2 13 1; #X connect 39 0 16 2; #X coords 0 -1 1 1 160 60 1 100 100; IanniX-0.9.20/Patches/PureData/Iannix-puredata/example_sound/a-udp.pd000066400000000000000000000042351317340345000253170ustar00rootroot00000000000000#N canvas 245 49 960 669 10; #X obj 317 83 inlet; #X obj 447 83 inlet; #X msg 447 132 /iannix/stop; #X obj 447 107 route 0; #X msg 535 132 /iannix/play \$1; #X obj 647 83 inlet; #X obj 211 75 loadbang; #X obj 141 121 pack s f; #X obj 211 100 f \$2; #X obj 141 100 symbol \$1; #X msg 141 144 connect \$1 \$2; #X obj 307 512 outlet; #X obj 366 512 outlet; #X obj 425 512 outlet; #X obj 484 445 route play stop fastrewind; #X msg 484 465 1; #X msg 535 465 0; #X obj 586 490 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X obj 507 491 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X obj 507 512 outlet; #X obj 586 512 outlet; #X obj 735 492 outlet; #X obj 777 492 outlet; #X obj 819 492 outlet; #X msg 647 132 /iannix/fastrewind; #X msg 484 424 \$1; #X obj 636 512 outlet; #X obj 685 492 outlet; #X obj 484 403 unpack s f s f f f; #X obj 488 298 netsend -u -b; #X obj 488 256 list prepend send; #X obj 488 277 list trim; #X obj 307 305 netreceive -u -b \$3; #X obj 307 327 oscparse; #X obj 307 379 route trigger cursor curve transport; #X obj 448 160 route send; #X obj 448 204 list split 1; #X obj 566 207 symbol; #X obj 488 229 oscformat; #X msg 566 229 set \$1; #X obj 448 182 t a a; #X obj 307 353 list trim; #X connect 0 0 35 0; #X connect 1 0 3 0; #X connect 2 0 35 0; #X connect 3 0 2 0; #X connect 3 1 4 0; #X connect 4 0 35 0; #X connect 5 0 24 0; #X connect 6 0 8 0; #X connect 6 0 9 0; #X connect 7 0 10 0; #X connect 8 0 7 1; #X connect 9 0 7 0; #X connect 10 0 29 0; #X connect 14 0 15 0; #X connect 14 1 16 0; #X connect 14 2 17 0; #X connect 15 0 18 0; #X connect 16 0 18 0; #X connect 17 0 20 0; #X connect 18 0 19 0; #X connect 24 0 35 0; #X connect 25 0 14 0; #X connect 28 0 25 0; #X connect 28 1 26 0; #X connect 28 2 27 0; #X connect 28 3 21 0; #X connect 28 4 22 0; #X connect 28 5 23 0; #X connect 30 0 31 0; #X connect 31 0 29 0; #X connect 32 0 33 0; #X connect 33 0 41 0; #X connect 34 0 11 0; #X connect 34 1 12 0; #X connect 34 2 13 0; #X connect 34 3 28 0; #X connect 35 0 40 0; #X connect 35 1 40 0; #X connect 36 1 38 0; #X connect 37 0 39 0; #X connect 38 0 30 0; #X connect 39 0 38 0; #X connect 40 0 36 0; #X connect 40 1 37 0; #X connect 41 0 34 0; IanniX-0.9.20/Patches/PureData/Iannix-puredata/example_sound/abs-cursor.pd000066400000000000000000000030361317340345000263670ustar00rootroot00000000000000#N canvas 536 95 574 627 10; #X obj 20 142 outlet; #X obj 48 169 outlet; #X obj 383 21 loadbang; #X obj 104 37 route \$1; #X obj 78 194 outlet; #X obj 217 433 *~ 2; #X obj 220 489 -~; #X obj 221 556 vcf~; #X obj 325 457 line~; #X obj 325 433 pack 0 100; #X obj 224 647 throw~ dac1; #X obj 197 329 * 500; #X obj 322 410 random 10; #X obj 221 527 +~; #X obj 257 465 random 3; #X obj 164 517 * -1; #X obj 164 537 + 1; #X obj 224 601 *~; #X obj 259 622 throw~ dac2; #X obj 260 602 *~; #X obj 150 346 * 900; #X obj 177 283 r varPhas; #X obj 104 62 unpack s f f f f; #X obj 127 125 t f f; #X obj 150 104 t f f; #X obj 173 82 t f f; #X obj 104 16 r RouteCursor; #X obj 151 402 osc~; #X obj 266 389 phasor~; #X obj 209 388 osc~; #X obj 256 331 * 2; #X obj 373 41 t a a; #X connect 2 0 31 0; #X connect 3 0 22 0; #X connect 5 0 6 0; #X connect 6 0 13 0; #X connect 7 0 17 0; #X connect 7 0 19 0; #X connect 8 0 7 1; #X connect 9 0 8 0; #X connect 11 0 29 0; #X connect 12 0 9 0; #X connect 13 0 7 0; #X connect 14 0 7 2; #X connect 15 0 16 0; #X connect 16 0 17 1; #X connect 17 0 10 0; #X connect 19 0 18 0; #X connect 20 0 27 0; #X connect 21 0 20 1; #X connect 22 1 23 0; #X connect 22 2 24 0; #X connect 22 3 25 0; #X connect 23 0 0 0; #X connect 23 1 11 0; #X connect 23 1 15 0; #X connect 23 1 19 1; #X connect 24 0 1 0; #X connect 24 1 20 0; #X connect 25 0 4 0; #X connect 25 1 30 0; #X connect 26 0 3 0; #X connect 27 0 13 1; #X connect 28 0 6 1; #X connect 29 0 5 0; #X connect 30 0 28 0; #X connect 31 0 14 0; #X connect 31 1 12 0; #X coords 0 627 1 626 120 35 0; IanniX-0.9.20/Patches/PureData/Iannix-puredata/example_sound/abs-trigger.pd000066400000000000000000000024441317340345000265170ustar00rootroot00000000000000#N canvas 599 137 574 627 10; #X obj 25 193 outlet; #X obj 73 205 outlet; #X obj 101 38 route \$1; #X obj 120 214 outlet; #X obj 104 16 r RouteTrigger; #X obj 280 361 throw~ dac1; #X obj 366 363 throw~ dac2; #X obj 100 60 unpack s f f f f f f f; #X floatatom 228 119 3 0 0 0 - - -, f 3; #X floatatom 252 119 3 0 0 0 - - -, f 3; #X floatatom 278 119 3 0 0 0 - - -, f 3; #X floatatom 332 151 3 0 0 0 - - -, f 3; #X obj 338 263 *~; #X obj 368 166 * 100; #X obj 409 164 * 100; #X obj 292 199 osc~ 1200; #X obj 54 117 t a a; #X text 41 117 X; #X obj 81 140 t a a; #X text 67 139 Y; #X obj 134 151 t a a; #X text 77 149 Y; #X text 117 157 Z; #X obj 331 128 t a b; #X text 265 153 nbr cursor; #X msg 369 213 0 \, \$1 \$2 \, 0 \$3 \$2; #X obj 369 235 vline~; #X obj 369 191 pack 1 0 0; #X connect 2 0 7 0; #X connect 4 0 2 0; #X connect 7 1 16 0; #X connect 7 2 18 0; #X connect 7 3 20 0; #X connect 7 4 8 0; #X connect 7 5 9 0; #X connect 7 6 10 0; #X connect 7 7 23 0; #X connect 12 0 6 0; #X connect 12 0 5 0; #X connect 13 0 27 1; #X connect 14 0 27 2; #X connect 15 0 12 0; #X connect 16 0 0 0; #X connect 16 1 13 0; #X connect 18 0 1 0; #X connect 18 1 14 0; #X connect 20 0 3 0; #X connect 23 0 11 0; #X connect 23 1 27 0; #X connect 25 0 26 0; #X connect 26 0 12 1; #X connect 27 0 25 0; #X coords 0 0 1 1 110 35 0; IanniX-0.9.20/Patches/PureData/Iannix-puredata/example_sound/main.pd000066400000000000000000000042231317340345000252320ustar00rootroot00000000000000#N canvas 732 49 625 541 10; #X obj 379 259 dac~; #X obj 377 141 catch~ dac1; #X obj 409 167 catch~ dac2; #X obj 503 171 s varPhas; #X floatatom 504 147 5 0 0 0 - - -, f 5; #X text 35 340 this example shows how you can generate in dynamic patching an additive synthese; #X text 72 9 Set IanniX score speed; #X floatatom 36 8 5 0 0 0 - - -, f 5; #X msg 36 28 /iannix/speed \$1; #X obj 53 164 s RouteCursor; #X obj 70 144 s RouteCurve; #X obj 36 184 s RouteTrigger; #X obj 112 76 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X text 128 75 Play / pause; #X obj 229 40 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X text 244 39 Score played / paused; #X msg 112 55 set \$1; #X floatatom 189 123 5 0 0 0 - - -, f 5; #X floatatom 172 141 5 0 0 0 - - -, f 5; #X floatatom 155 159 5 0 0 0 - - -, f 5; #X obj 36 103 a-udp 127.0.0.1 1234 57120; #X text 33 328 sound example; #X text 36 429 4/ open [pd Rcursor] or [Rtrigger] to see the abstractions or to modify; #X text 35 372 1/ open a ianniX score and play it.; #X text 35 387 2/ click init tab for cursor and trigger to dump number of elements; #X text 37 414 3/ create object for cursor and trigger.; #X text 39 489 created by philippe boisnard; #X obj 470 204 hsl 128 15 0 127 0 0 empty empty empty -2 -8 0 10 -262144 -1 -1 4400 1; #X obj 467 224 dbtorms; #X obj 467 246 pack 0 50; #X obj 467 268 line~; #X obj 378 230 *~; #X obj 408 230 *~; #X obj 240 83 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #N canvas 68 49 1285 596 \$0.Rcursor 0; #X restore 38 305 pd \$0.Rcursor; #N canvas 14 49 1137 239 \$0.Rtrigger 0; #X restore 199 303 pd \$0.Rtrigger; #X obj 34 242 a-initcursor \$0; #X obj 199 241 a-inittrig \$0; #X connect 1 0 31 0; #X connect 2 0 32 0; #X connect 4 0 3 0; #X connect 7 0 8 0; #X connect 8 0 20 0; #X connect 12 0 20 1; #X connect 14 0 16 0; #X connect 16 0 12 0; #X connect 20 0 11 0; #X connect 20 1 9 0; #X connect 20 2 10 0; #X connect 20 3 14 0; #X connect 20 7 19 0; #X connect 20 8 18 0; #X connect 20 9 17 0; #X connect 27 0 28 0; #X connect 28 0 29 0; #X connect 29 0 30 0; #X connect 30 0 31 1; #X connect 30 0 32 1; #X connect 31 0 0 0; #X connect 32 0 0 1; #X connect 33 0 20 2; IanniX-0.9.20/Patches/PureData/PureData Example.pd000066400000000000000000000072411317340345000214760ustar00rootroot00000000000000#N canvas 267 222 1011 483 10; #X obj 287 34 tgl 15 0 empty empty play/pause 17 7 0 10 -262144 -1 -1 0 1; #X obj 380 33 bng 15 250 50 0 empty empty fast.rewind 17 7 0 10 -262144 -1 -1; #X obj 247 241 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X obj 264 210 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X text 283 209 Score rewinded; #X text 262 240 Score played / paused; #X msg 247 9 set \$1; #X floatatom 338 103 3 0 0 0 - - -, f 3; #X floatatom 366 103 3 0 0 0 - - -, f 3; #X floatatom 394 103 3 0 0 0 - - -, f 3; #X text 421 102 Number of triggers / cursors / curves; #X floatatom 37 27 5 0 0 2 score.speed - -, f 5; #X text 6 325 Triggers fired; #X text 128 326 Cursors coords; #X text 244 319 Curves intersections; #X floatatom 297 165 5 0 0 0 - - -, f 5; #X text 279 182 Transport timecode; #X obj 576 163 gemwin; #X msg 721 142 destroy \, reset; #X msg 576 142 create \, 1 \, frame 25; #X obj 577 189 receive cursors; #X obj 249 404 spigot; #X text 519 143 GEM --->; #X msg 37 47 send /iannix/speed \$1; #X text 576 400 see also:; #X text 391 59 arguments : , f 84; #X obj 194 64 iannix 127.0.0.1 1234 57120; #X obj 299 404 tgl 15 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X obj 249 361 t a a; #X obj 249 382 send curves; #X obj 249 424 print curves; #X obj 357 344 hradio 15 1 0 8 empty empty empty 0 -8 0 10 -262144 -1 -1 0; #X msg 357 368 bang; #N canvas 6 50 645 333 triggers 0; #X obj 359 247 spigot; #X obj 239 173 iannix/filter; #X obj 190 100 tgl 15 0 \$0-triggers \$0-triggers empty 17 7 0 10 -228856 -1 -1 0 1; #X obj 239 143 inlet; #X obj 327 199 t a a; #X floatatom 103 122 5 -1 60 1 filter - -, f 5; #X obj 305 112 select -1; #X obj 305 46 int; #X obj 305 68 t f f; #X msg 337 90 set \$1; #X obj 327 225 send triggers; #X obj 359 267 print triggers; #X obj 428 224 r \$0-triggers; #X connect 0 0 11 0; #X connect 1 10 4 0; #X connect 3 0 1 0; #X connect 4 0 10 0; #X connect 4 1 0 0; #X connect 5 0 7 0; #X connect 6 0 1 1; #X connect 6 1 1 1; #X connect 7 0 8 0; #X connect 8 0 6 0; #X connect 8 1 9 0; #X connect 9 0 5 0; #X connect 12 0 0 1; #X coords 0 -1 1 1 105 40 1 100 100; #X restore 5 343 pd triggers; #N canvas 5 50 645 333 cursors 0; #X obj 359 247 spigot; #X obj 190 100 tgl 15 0 \$0-cursors \$0-cursors empty 17 7 0 10 -228856 -1 -1 0 1; #X obj 239 143 inlet; #X obj 327 199 t a a; #X floatatom 103 122 5 -1 60 1 filter - -, f 5; #X obj 305 112 select -1; #X obj 305 46 int; #X obj 305 68 t f f; #X msg 337 90 set \$1; #X obj 327 225 send cursors; #X obj 359 267 print cursors; #X obj 428 224 r \$0-cursors; #X obj 239 173 iannix/filter; #X connect 0 0 10 0; #X connect 2 0 12 0; #X connect 3 0 9 0; #X connect 3 1 0 0; #X connect 4 0 6 0; #X connect 5 0 12 1; #X connect 5 1 12 1; #X connect 6 0 7 0; #X connect 7 0 5 0; #X connect 7 1 8 0; #X connect 8 0 4 0; #X connect 11 0 0 1; #X connect 12 10 3 0; #X coords 0 -1 1 1 105 40 1 100 100; #X restore 129 343 pd cursors; #X obj 577 212 clone 99 subpatch; #X obj 647 400 iannix/filter; #X obj 249 341 iannix/filter; #X obj 648 428 iannix, f 13; #X symbolatom 318 151 12 0 0 0 - - -, f 12; #X connect 0 0 26 1; #X connect 1 0 26 2; #X connect 2 0 6 0; #X connect 6 0 0 0; #X connect 11 0 23 0; #X connect 18 0 17 0; #X connect 19 0 17 0; #X connect 20 0 35 0; #X connect 21 0 30 0; #X connect 23 0 26 0; #X connect 26 0 33 0; #X connect 26 1 34 0; #X connect 26 2 37 0; #X connect 26 3 2 0; #X connect 26 4 3 0; #X connect 26 5 15 0; #X connect 26 6 39 0; #X connect 26 7 7 0; #X connect 26 8 8 0; #X connect 26 9 9 0; #X connect 27 0 21 1; #X connect 28 0 29 0; #X connect 28 1 21 0; #X connect 31 0 37 1; #X connect 32 0 37 1; #X connect 37 10 28 0; IanniX-0.9.20/Patches/PureData/Readme.txt000066400000000000000000000022421317340345000200220ustar00rootroot00000000000000/* All the files of this directory are part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Copyright (C) 2017 — IOhannes m zmölnig Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) These files were written by Guillaume Jacquemin, Alexandros Drymonitis and IOhannes m zmölnig. IanniX is a 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 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 . */ Pure Data ---------- - Open any IanniX score - Play and have a look with GEM or print messages IanniX-0.9.20/Patches/PureData/iannix/000077500000000000000000000000001317340345000173525ustar00rootroot00000000000000IanniX-0.9.20/Patches/PureData/iannix/filter-help.pd000066400000000000000000000012741317340345000221160ustar00rootroot00000000000000#N canvas 5 49 724 363 10; #X declare -path ..; #X text 229 174 - no argument : outputs all objects (no filtering) ; #X text 148 217 Inlet #2 : desired ID (see arguments); #X text 148 247 Outlets : (1) unique ID \, (2) group ID \,; #X text 218 259 (3-4-5) mapped X coord \, Y coord \, Z coord \,; #X text 218 271 (6-7-8) absolute X coord \, Y coord \, Z coord \,; #X text 218 284 (9-10) (triggers only) curve Unique ID \, curve group ID \,; #X text 218 297 (11) packed data as a list; #X obj 116 91 iannix/filter; #X text 228 188 - one argument : only outputs object with desired ID ; #X text 99 4 [iannix/filter] filter data from IanniX; #X text 148 154 Arguments :; #X obj 495 24 declare -path ..; IanniX-0.9.20/Patches/PureData/iannix/filter.pd000066400000000000000000000041261317340345000211670ustar00rootroot00000000000000#N canvas 647 70 601 470 10; #X obj 56 105 inlet; #X obj 88 381 outlet; #X obj 105 401 outlet; #X obj 122 320 outlet; #X obj 139 340 outlet; #X obj 156 360 outlet; #X obj 173 320 outlet; #X obj 190 340 outlet; #X obj 207 360 outlet; #X obj 224 381 outlet; #X obj 241 401 outlet; #X obj 436 361 outlet; #X obj 56 224 t l l; #X obj 88 297 unpack f s f f f f f f f s; #X obj 56 178 route \$1; #X obj 56 200 list prepend \$1; #N canvas 5 50 450 300 have-arg 0; #X obj 55 40 inlet; #X obj 55 248 outlet; #X obj 55 135 symbol \$1-; #X obj 55 62 t b b; #X msg 110 35 bang; #X obj 55 157 select symbol; #X obj 143 136 makefilename $%d-; #X msg 143 115 1; #X msg 55 179 0; #X msg 143 180 1; #X obj 55 201 t f; #X connect 0 0 3 0; #X connect 2 0 5 0; #X connect 3 0 2 0; #X connect 3 1 7 0; #X connect 4 0 3 0; #X connect 5 0 8 0; #X connect 5 1 9 0; #X connect 6 0 5 1; #X connect 7 0 6 0; #X connect 8 0 10 0; #X connect 9 0 10 0; #X connect 10 0 1 0; #X restore 138 81 pd have-arg; #X obj 56 127 t a a; #X obj 56 149 spigot 0; #X obj 126 149 spigot 1; #X obj 138 103 t f f; #X obj 179 126 == 0; #X obj 138 58 loadbang; #X msg 208 60 bang; #X obj 404 64 inlet ID; #X msg 404 130 1; #X obj 404 152 t f; #X obj 358 108 t b; #X msg 358 130 0; #X text 44 11 [iannix/filter] filter IanniX data; #X obj 404 86 route bang; #X obj 404 108 t b a; #X obj 126 178 t a a; #X connect 0 0 17 0; #X connect 12 0 11 0; #X connect 12 1 13 0; #X connect 13 0 1 0; #X connect 13 1 2 0; #X connect 13 2 3 0; #X connect 13 3 4 0; #X connect 13 4 5 0; #X connect 13 5 6 0; #X connect 13 6 7 0; #X connect 13 7 8 0; #X connect 13 8 9 0; #X connect 13 9 10 0; #X connect 14 0 15 0; #X connect 15 0 12 0; #X connect 16 0 20 0; #X connect 17 0 18 0; #X connect 17 1 19 0; #X connect 18 0 14 0; #X connect 19 0 12 0; #X connect 20 0 18 1; #X connect 20 1 21 0; #X connect 21 0 19 1; #X connect 22 0 16 0; #X connect 23 0 16 0; #X connect 24 0 30 0; #X connect 25 0 26 0; #X connect 26 0 20 0; #X connect 27 0 28 0; #X connect 28 0 26 0; #X connect 30 0 27 0; #X connect 30 1 31 0; #X connect 31 0 25 0; #X connect 31 1 32 0; #X connect 32 0 14 1; #X connect 32 1 15 1; IanniX-0.9.20/Patches/PureData/iannix/iannix-help.pd000066400000000000000000000023731317340345000221200ustar00rootroot00000000000000#N canvas 159 140 901 429 10; #X declare -path ..; #X obj 287 134 tgl 15 0 empty empty play/pause -17 -7 0 10 -262144 -1 -1 0 1; #X obj 380 133 bng 15 250 50 0 empty empty fastrewind -17 -7 0 10 -262144 -1 -1; #X obj 256 341 tgl 15 0 empty empty score.playing/paused 17 7 0 10 -262144 -1 -1 0 1; #X obj 276 310 bng 15 250 50 0 empty empty score.rewound 17 7 0 10 -262144 -1 -1; #X floatatom 338 213 3 0 0 0 - - -, f 3; #X floatatom 361 213 3 0 0 0 - - -, f 3; #X floatatom 384 213 3 0 0 0 - - -, f 3; #X text 411 212 Number of triggers / cursors / curves; #X floatatom 37 117 5 0 0 2 score.speed - -, f 5; #X floatatom 297 286 5 0 0 1 transport.timecode - -, f 5; #X obj 194 164 iannix 127.0.0.1 1234 57120; #X msg 37 137 send /iannix/speed \$1; #X text 108 62 arguments : , f 84; #X text 167 39 [iannix] interfacing with IanniX via OSC; #X obj 670 18 declare -path ..; #X obj 211 385 iannix/filter; #X text 142 387 see also:; #X symbolatom 318 267 12 0 0 0 - - -, f 12; #X connect 0 0 10 1; #X connect 1 0 10 2; #X connect 8 0 11 0; #X connect 10 3 2 0; #X connect 10 4 3 0; #X connect 10 5 9 0; #X connect 10 6 17 0; #X connect 10 7 4 0; #X connect 10 8 5 0; #X connect 10 9 6 0; #X connect 11 0 10 0; IanniX-0.9.20/Patches/PureData/iannix/iannix.pd000066400000000000000000000044041317340345000211670ustar00rootroot00000000000000#N canvas 297 108 840 599 10; #X obj 95 14 inlet; #X obj 188 14 inlet; #X obj 188 38 route 0; #X obj 468 14 inlet; #X obj 19 6 loadbang; #X obj 19 82 pack s f; #X obj 89 61 f \$2; #X obj 19 61 symbol \$1; #X msg 19 105 connect \$1 \$2; #X obj 301 376 route play stop fastrewind; #X msg 301 396 1; #X msg 352 396 0; #X msg 301 355 \$1; #X obj 301 334 unpack s f s f f f; #X msg 188 63 send /iannix/stop; #X msg 316 63 send /iannix/play \$1; #X msg 468 63 send /iannix/fastrewind; #X obj 64 252 oscparse; #X obj 64 280 list trim; #X obj 301 420 t f; #X obj 330 489 t b; #X obj 19 33 t b b; #X obj 65 206 netsend -u -b; #X obj 65 168 list prepend send; #X obj 65 187 list trim; #X obj 316 118 t a; #X obj 316 140 route send; #X obj 316 162 t a a; #X obj 409 186 symbol; #X msg 409 208 set \$1; #X obj 316 227 oscformat; #X obj 316 184 list split 1; #X obj 316 206 t a; #X obj 64 233 netreceive -u -b \$3; #X obj 64 300 route trigger cursor curve transport; #X obj 64 453 outlet triggers; #X obj 126 433 outlet cursors; #X obj 188 413 outlet curves; #X obj 301 463 outlet play_state; #X obj 330 513 outlet score_rewound; #X obj 480 463 outlet score:timecode; #X obj 530 443 outlet num.triggers; #X obj 572 423 outlet num.cursors; #X obj 614 403 outlet num.curves; #X obj 450 483 outlet score.time; #X connect 0 0 25 0; #X connect 1 0 2 0; #X connect 2 0 14 0; #X connect 2 1 15 0; #X connect 3 0 16 0; #X connect 4 0 21 0; #X connect 5 0 8 0; #X connect 6 0 5 1; #X connect 7 0 5 0; #X connect 8 0 22 0; #X connect 9 0 10 0; #X connect 9 1 11 0; #X connect 9 2 20 0; #X connect 10 0 19 0; #X connect 11 0 19 0; #X connect 12 0 9 0; #X connect 13 0 12 0; #X connect 13 1 44 0; #X connect 13 2 40 0; #X connect 13 3 41 0; #X connect 13 4 42 0; #X connect 13 5 43 0; #X connect 14 0 25 0; #X connect 15 0 25 0; #X connect 16 0 25 0; #X connect 17 0 18 0; #X connect 18 0 34 0; #X connect 19 0 38 0; #X connect 20 0 39 0; #X connect 21 0 7 0; #X connect 21 1 6 0; #X connect 23 0 24 0; #X connect 24 0 22 0; #X connect 25 0 26 0; #X connect 26 0 27 0; #X connect 27 0 31 0; #X connect 27 1 28 0; #X connect 28 0 29 0; #X connect 29 0 32 0; #X connect 30 0 23 0; #X connect 31 1 32 0; #X connect 32 0 30 0; #X connect 33 0 17 0; #X connect 34 0 35 0; #X connect 34 1 36 0; #X connect 34 2 37 0; #X connect 34 3 13 0; IanniX-0.9.20/Patches/PureData/subpatch.pd000066400000000000000000000014341317340345000202240ustar00rootroot00000000000000#N canvas 810 49 420 318 10; #X obj 30 54 inlet; #X obj 24 101 gemhead; #X obj 24 223 cube; #X msg 108 206 draw line; #X obj 108 166 loadbang; #X obj 108 187 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X msg 178 206 0.03; #X obj 24 143 translateXYZ -0.5 -0.5 0; #X obj 24 123 scaleXYZ 6 6 6; #X obj 24 201 translateXYZ; #X obj 12 179 unpack f f; #X obj 168 166 r reset; #X msg 218 206 -5 -5; #X obj 30 77 unpack s f f f f f f f s; #X connect 0 0 13 0; #X connect 1 0 8 0; #X connect 3 0 2 0; #X connect 4 0 5 0; #X connect 5 0 3 0; #X connect 5 0 6 0; #X connect 5 0 12 0; #X connect 6 0 2 1; #X connect 7 0 9 0; #X connect 8 0 7 0; #X connect 9 0 2 0; #X connect 10 0 9 1; #X connect 10 1 9 2; #X connect 11 0 5 0; #X connect 12 0 10 0; #X connect 13 1 9 1; #X connect 13 2 9 2; IanniX-0.9.20/Readme.md000066400000000000000000000016411317340345000145110ustar00rootroot00000000000000About IanniX ============ IanniX is a graphical open-source sequencer, based on Iannis Xenakis works, for digital art. IanniX syncs via Open Sound Control (OSC) events and curves to your real-time environment. Build IanniX ============ All platforms ------------- - Download Qt 4.8 for your plateform (http://qt-project.org/downloads) (4.7 is also compatible) - Download Qt Creator (http://qt-project.org/downloads) - Open IanniX.pro and build! Mac OS X specific ----------------- - Download Syphon Framework (http://syphon-framework.googlecode.com/) and add it to /Library/Frameworks folder - If you want to build IanniX with Kinect support, you'll need libfreenect (http://openkinect.org/wiki/Getting_Started) Linux ----- - You'll need to build Qt before building IanniX - If your distribution supports it, you can also install Qt via the package manager, e.g.: aptitude install libqt4-dev libqt4-opengl-dev IanniX-0.9.20/Tools/000077500000000000000000000000001317340345000140705ustar00rootroot00000000000000IanniX-0.9.20/Tools/HTML Template.html000066400000000000000000010060331317340345000172610ustar00rootroot00000000000000 IanniX Web Remote

IanniX-0.9.20/Tools/JavaScript Library.js000066400000000000000000000115151317340345000200640ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ //Shortcut to IanniX Object function run(_command) { return iannix.execute(_command); } function ask(_category, _label, _variable, _defaultValue) { return iannix.ask(_category, _label, _variable, _defaultValue); } function title(_title) { return iannix.meta(_title); } function console(_log) { return iannix.execute("log " + JSON.stringify(_log, null, 4)); } function load(_filename) { return iannix.load(_filename); } function loadJSON(_filename) { return JSON.parse(load(_filename)); } //Prototypes for Strings String.prototype.trim = function() { return (this.replace(/^[\s\xA0]+/, "").replace(/[\s\xA0]+$/, "")) } String.prototype.startsWith = function(str) { return (this.match("^"+str)==str) } String.prototype.endsWith = function(str) { return (this.match(str+"$")==str) } String.prototype.replaceAll = function(str, str2) { return (this.replace(new RegExp(str, 'g'), str2)) } String.prototype.pad = function(length) { var str = '' + this; while (str.length < length) { str = '0' + str; } return str; } //Constants var E = Math.E; var LN2 = Math.LN2; var LN10 = Math.LN10; var LOG2E = Math.LOG2E; var LOG10E = Math.LOG10E; var PI = Math.PI; var TWO_PI = 2 * Math.PI; var THIRD_PI = Math.PI / 3; var QUARTER_PI = Math.PI / 4; var HALF_PI = Math.PI / 2; var SQRT1_2 = Math.SQRT1_2; var SQRT2 = Math.SQRT2; //Math functions function abs(x) { return Math.abs(x); } function acos(x) { return Math.acos(x); } function asin(x) { return Math.asin(x); } function atan(x) { return Math.atan(x); } function atan2(x,y) { return Math.atan2(x,y); } function ceil(x) { return Math.ceil(x); } function cos(x) { return Math.cos(x); } function exp(x) { return Math.exp(x); } function floor(x) { return Math.floor(x); } function log(x) { return Math.log(x); } function min(x,y) { return Math.min(x,y); } function max(x,y) { return Math.max(x,y); } function pow(x,y) { return Math.pow(x,y); } function sin(x) { return Math.sin(x); } function sqrt(x) { return Math.sqrt(x); } function sq(x) { return x*x; } function tan(x) { return Math.tan(x); } function degrees(value) { return value * 180. / pi; } function radians(value) { return value * pi / 180.; } function round(x, y) { if(y == undefined) return Math.round(x); else return Math.round(x*Math.pow(10, y)) / Math.pow(10, y); } function random(low, high) { if((low == undefined) || (high == undefined)) return Math.random(); else return range(Math.random(), low, high); } //Useful functions function constrain(value, min, max) { return Math.min(max, Math.max(min, value)); } function dist(x1, y1, z1, x2, y2, z2) { var dx = x2 - x1, dy = y2 - y1, dz = z2 - z1; return Math.sqrt(sq(dx) + sq(dy) + sq(dz)); } function angle(x1, y1, x2, y2) { var dx = x2 - x1, dy = y2 - y1, angle = 0; if((dx > 0) && (dy >= 0)) angle = (Math.atan(dy / dx)) * 180.0 / PI; else if((dx <= 0) && (dy > 0)) angle = (-Math.atan(dx / dy) + HALF_PI) * 180.0 / PI; else if((dx < 0) && (dy <= 0)) angle = (Math.atan(dy / dx) + PI) * 180.0 / PI; else if((dx >= 0) && (dy < 0)) angle = (-Math.atan(dx / dy) + 3 * HALF_PI) * 180.0 / PI; return angle; } function norm(value, low, high, exp) { if((high - low) == 0) return 0; else return linexp((value - low) / (high - low), exp); } function range(value, low, high, exp) { value = linexp(value, exp); return value * (high - low) + low; } function rangeMid(value, low, mid, high, exp) { value = linexp(value, exp); if(value < 0.5) return (value * 2) * (mid - low) + low; else return (value - .5) * 2 * (high - mid) + mid; } function map(value, low1, high1, low2, high2, exp) { return range(norm(value, low1, high1, exp), low2, high2); } function linexp(value, factor) { if((factor == undefined) || (factor == 0)) return value; else return (exp(factor * value - factor) - exp(-factor)) / (1 - exp(-factor)); } IanniX-0.9.20/Tools/Museo.ttf000066400000000000000000001420401317340345000157000ustar00rootroot000000000000000FFTMZ<GDEFX&GPOSPBDGSUBTِhOS/2q <`cmap cvt e "p2fpgmS/"egasp% glyfm|%headD6hhea$hmtxɾZ+(\locawmaxp4 nameSTxpost?3prepowebfOɉo1< Ni ,latnkern ^7x(2<Rhnt~"4jj$:H^p9M)) 09Y9Y  uw9;fS[vf9=;99+' "0@%S`%7%@ Y39%; 3%7=89:<7^9:<7X9:< "$-7-9+<%@%`#17?89:<-7o89<8:<v{7N9:;<=$-7s;<=7`9:<7<7=89:<$7{;=$7m;<=7m<$-7{;=7`9:<9%M31O{Mb9; +"@5`5"  +"/@)`5[)7 %)/03479;<>DFHIJNORTUVWXYZ[\]^v~(6,Ld d`hZ;Z5/m3mf{?VD+RLN!?)3+ /'+%%y)%R ? )% !    !#"##$%&'()*+,   -. /#$$$$$$)) 1212' !(      "%#%$%)#  *   %%%%%&%%%%%% %  $>DF!II$KK%NN&PS'UU+Y^,vv23JXY`aefik "`latnfracliga2sups8   (08@HPX`hpxx:fR.  IOILOLI  $"&* $(,0"&*.26$(,048<&*.26:>B (,048<@DH *.26:>BFJN  xrs33f@Jxljb@    ( ~Sx    " & : !" Rx    " & 9 !"mI$߯   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`apdegunithqfjy~clkzbǶvow ,KLPXJvY#?+X=YKLPX}Y ԰.-, ڰ +-,KRXE#Y!-,i @PX!@Y-,+X!#!zXYKRXXY#!+XFvYXYYY-, \Z-,"PX \\Y-,$PX@\\Y-, 9/- , }+XY %I# &JPXea PX8!!Ya RX8!!YY- ,+X!!Y- , Ұ +- , /+\X G#Faj X db8!!Y!Y- , 9/ GFa# #JPX#RX@8!Y#PX@e8!YY-,+X=!! ֊KRX #I UX8!!Y!!YY-,# /+\X# XKS!YX&I## I#a8!!!!Y!!!!!Y-, ڰ+-, Ұ+-, /+\X G#Faj G#F#aj` X db8!!Y!!Y-, %Jd# PX<Y-,@@BBKcKc UX RX#b #Bb #BY @RX CcB CcB ce!Y!!Y-,Cc#Cc#-@++/ְ2 2 2/ +9013#53 s=;B+3 +2+ +/ִ+++ +01333=Zj9+333+ 333+ $3 $2 +$3 $2 /ֱ++ + !+6?.+ ? + +++ +  +  + + + + ++++ + ++@ ................@017!!7!3!3!!!!#!#7!!Z ; HH=HH > FDCC=>XffyyXo/y?:+73 : +@:9 ++3' ' +@ +@/ֱ* *9+28+28 +4 A+*9998'99 /94 !99'!4$9 901?32654.546753.#"#5.'orLQz[3  vg9?.Űk=)+ +/ִ+++013==1  /ֱ +013#&p}yV*]9=  /ֱ +0139}qR4Ju%+/ֱ+ $90173%'#'75J58紑=f#fKjj L +/32 +@ + / ְ2 2 +@  + +@ + +015!3!!#ʨ7 71 / +/ִ ++0137ˬZ"//+++015!Vm)++/ֱ+01353JM/ֱ++62".732>54.#" JstJ JtsJ CyVFjD,,DjFEjD+ՁٿLLفMMڂ}ŸU:bcbb99bhB+2+/ֱ +@ + +@ ++9013!!5!7#h[;?5VP Z!3q+f*+'+ ,/ְ2'' + +@( +-+'*99  $$9'*9 $90174>54&#"'>32!!&q0RkuukR0s5dB3  (/OXzCLz{M\ oSqfVQPSd6k&66d94?.`znbbxCAR.E'+ +// ֱ" 0+" 99"$99901?32654&+'>?5#!5!#".'RoGMt;|Že/<- +Pav32#".'bq=Dm9?ztG" !b/SbK6)"$+Ͱ& );<yf -m+% + + +./ֱ!!(+ /+(!$9 99+%999 9 9014>32.#"3>32#"732654&#"y0iۂL !B %m3`h@ -`TXzyrբbS^=Ly^y{H $++/+ 99015!#>?5#Hs3* Js$Cu\+@m+ +> A/ֱ,  /, ;+#2B+; )$99> *6$9014>7&54>32#"$732654.'>54&#"u*6L'#IhY]gxϱxv$2]G|#? 5'G+R2st>yPMu;maG*ұ9iqwxm&C/6!7z/)"#!" 'Lf5cvrdR"/m+ +- & + 0/ֱ# #)+1+#99) $99 9&9-9901432#"&/732>7##"732654.#"drǑS0iۂL B %l3`hA ,aɠxUX{brբbS^=J̇}N^y /++/ְ22 +01353539`1 *+/ְ22 +9013 53`m͚1ZDZ55D#ʶ5X/// +015!5!/5yZ357555y%Z65VBT#'X$+%/ (/$ְ2' 2'+ )+'$9999% #999901>32#54>54&#"53BGMz>(@MN@(&>JJ>&e9us?."ѦEuTKDEW2Ta?nOIBCU0Wt+Ny '0l#/"/+ 2./ /1/ֱ +@# ++( (,+2 2+,(99.+9990146$323!"&54>;.#"3"$&%;#"yusyP"ѻg} tgiw-MkwCfk[wue,+3+ +/+90133#!!./# Ӓ  Z`H!f##J"g++" +#/ֱ 2+  $+ 99 9 99"9013!2#%!2654&#!5!264&#!`Tp~J`Ftq/atrgƫi+!}ce5poztbw*3'+ + +/ֱ,+ !$90146$32.#"32>?#"$bqavZdU\FLfQmlxeۛr'886*"'77 P<2Y 8+ +/ֱ ++ 9013!2!%!2#!Js!/ J+ + + /ֱ 2 +@ +@  +@  + +013!!!!!G;/ @++ + /ֱ 2 +@  +@  + +013!!!!%d3{&+/+ + "#/ +"4/ֱ&+ 2%&% +@&" +5+&)/$9% 99#/(99 99 90146$32.#"32>?5#5!#57##"$&dqau[fSYEF^IU_Pq՛t$330&%55Ѱ)Z>=/&oH ?+3+3  +  /ֱ 2 +2 +0133!3#!{Z{!++/ֱ  +0133Z=P+  +@ ++ /ֱ  +  +@ ++ 9901533265!5!".='CO-_81SpzyoR1G=Gj;|T[dEFd ;+ 3+3  +/ֱ 2+ 99013333##m\`R h,++/ֱ  +@ ++0133! V&t+ 33+ 3'/ֱ& &+ (+62+   . ..@&9 999 9901333673#&5454?##./#tL$ '!KuG*#ߴ' F$asPZ'6"Pu#l%% YBqJP+ 3+ 3/ֱ  + +999 9999901333&53#./#<{<T#h##PZ$i##RVb/!D + + "/ֱ+ #+ 99 990146$32#"$&732>54. btTΚtѐmŎTݙrvXx D++  +/ֱ 2 ++ 99013!2#!!2654&#!%hǗd3+[+ +' ,/ֱ#+  2-+#999  99 99' 9990146$32'!".73267'7654&#"dsUZPw{䶈IэS>wjoŎSۚr΅bL}82T_+3+ +/ֱ 2++  9999 999013!2#!!2654'&+[pv3#ws@!*Ѝ&/?y@!V9a4+ +$ :/ֱ' ' +1 ;+'9 $,4$9199$1$9901?32654.54$32.#"#".'VsLQz?5#!5!63!T5'FqG4&F$C$A=!5/ / /ִ +2 +2 +01!#3R9M/ֱ++6L+ ......@013#9 H=>/ / /ְ2 +/ +/ +013#5!!HT+w\?+/+013# T/9`++/+013!!9NJ  /+/ִ ++013#JՕH%+<}+)+/+ 5) + =/ֱ, ,3+ 2/>+,993 )999!#99) 9 99014>;54#"'>32#57##"&732>=#"H5OwkS1--\D8RMTCո!9@[3g\PB3'@[FK1 #FrI5 * qbR+&0"DbfO! )>u(_++ + +&)/ֱ22#+ *+99# 99& $901333>32#"./#32654&#"9ExDArH5 >^'X=.&%45!-L`nȫ̻R%$="++%/ֱ &+"9 999 901432.#"32>?#"R9IWB^9>a1Π6jI;POYL7--)))9,$4X3*c++ ++(+/ֱ $+ 22,+$999(999 99014323&53#57##"732>54.#"XCtD2 Ƽ8G{Hˣ^*"00'ZbFB3*++W_`nT%#h+ +!  + $/ֱ 2 + %+  999999 9 9901432!32>?#".!.#"T%d ˒2dG9ROWE)iu+وV$# 3' RN+ + +32/ְ22 +@ + +@ ++015354>32&#"3##R9SqY/& 2?.^1aO1 ,S7-^XR#%&1r ++//#/*2/ֱ' '-+ 223+'99-#$9 9#9/ 99  9014323&=3#"'7326=7##".73265!"XFvE2 XfB3Eaҍmɣxۆ" --`{m5V'LAȩ\FO+ 3++ /ֱ2 + +9 99901333>32#4.#"(ʍ(Q53#'53q63B/!1FFQ> F .W:#GvO;!} =+ 3++  +/ֱ 2+ 99013333##ƒɖ}8! ++/ֱ+01337#".:5"#(BP7&V= $3 3>32#4.#"#4.#"'u5-y&L8h&D.m  L`chm32#4.#"=]P(Q2 $&732654&#"PX͗XДΖsʎRRsԡfu%(l+ + +&/)/ֱ2#+ *+99#  &$9 99&9990133>32#"./#32654&#":H~I@pE4 A[fXLA2)#22%5/_mȫ̻Xf3%*a+ ++(/+/ֱ + $222,+($9 9( $9014323&=3#7##"732>54.#"XCuG4 8ExEˣ^*$33)NZ[>/'++W_`n;++3 /ֱ2+99 9901333>3&#"%t3a# NwrRhXHH%5f0++"6/ֱ% % +- 7+%9 ")0$9-9909"-$9901?32654.54632.#"#".'H`;Ad2Eg;^rq^;֡@sJ8 P27W.Gc;^qr^;ϨGYD* E<&=-,7EmE!"  @?%<++8EmE--?)P+/32 +@ +/ְ2 2  +@  + +@ ++015333#37#".5? /@30)0ZtT;^+ՠ3;Y0 0Oc- Q++ + 3/ֱ +2 + 9 999901332653#57##"&(P<&̋u;UK'LZ !++ 3/+9013;2>73#     DG--G#` +33+ $3/ֱ++6¡+ /+ .  =T+ »+  ++ #99 ......@  ..........@9013;6733673#'###    )895+n95p;5f- &+ 3+ 3/+99013 33673 #'#-`#`>#;Z9 R ++ 3//+9990133673#"&/7326? .o4dF:?;a3 Z>F5:v~ +QGvP 4+ + /+99 9  90135>?5#!5!63!P + DV, #Ds0 rn/ d7<R0/,/ =/6ְ2&2&6 +@&. +26& +@6 +>+&69,699015>=4>3#";#".=4.'d<-&4HcH%/%5&"119,$&5%%HcH4$33B,Z<\H+ ,S89_7' (4b;8S, ,I];Y+yV/ֱ+013ˮd?7h>G>/ / ?/ְ27(27 +@> +2@+79(7990132>=4>?5.=4.+5632#'?%5&"119,$&5%1D;=*$33<-&4HbH%0-,S8;a6% *5`98S,6ImC53#".#";`@:H*'8 ;a?:I+&8);<)#;@#)::)#:?"f 4+ //ְ2 2 2 +901353 fm/ e+  +/ +!/ֱ +2+2"+ 9999  $999014>753&#"3267#5.mfƄ6Z_)7ÇfӕFܫn]H~sVo+2 +  +3 2 /ְ2 2 +@ +@ + +@ +@ +!+9 901353#534632.#"!!!s}ZZ:qO>u 'u8oyݐ'& 1}^#9~++ 3 +3 +2 +3 + 2 /ְ2 2 +@ + 2 +@ +2!+999901336733!!!#!5!5'!539, +-7LN7=+hq`cKhKcb%1+(/2/ְ02+-2/++.+ + 22 + $+ /$+3+6+ 0...0-./+ ..   -./0........@./99 (999($$9#901732654'3#".'4632.#"#&bZ *+B _z б2`B4 Ѳ1`B5 ^ "f2az  pg(47%  'kd$..?//32/ֱ+ +0153353?o#!I+ + G: +G '4 +' J/ִ+"+7+7+ +K+7'-AG$94:@  -".@A$9016$32#"$&32$$#"4>32.#"32>?#"&os Qs"Zx xיc9fZBvI6 } &,F%ux&E."};FwB:2u͙vv-^R^QqC*;;D,"or&% DF5,$.+ +/ +"/( +-/ +//ְ2%+%++22+0+%99+ "9999("99-9 9015!4!354#"'>32#5##"&7326=#"3'U;05T, "'C%X71CWtt e }e^&kf%3qEZ  3 #3 #ZPPLPPB[\[\{5LX0/ +@ +/ֱ +@ ++015!#{Ѧ"//+++015!Vo#!2;+ + 13 +1 +13 +@1" +.2#; +# +54&#"'>32!!.`0L]]L0S@,Vd466D'RN'I"/ / (/ ִ+)+ 99"9$99901732654&+'7>?5#!5!#".'RV (-G&CglJF! '#+f:iB2 m$ZBCNN bsz('J  /+/ִ ++013J Xh S+ +@ + 2/ ִ+ +@ ++/ +++01>3!!#"&3Xނ-ozH|T}/"//ֱ  +0153^X/A/ +/ִ+ + + / ++  990132654&#7#"&/^)-+8<1%+ 99%+36$963999$%.999+ 9901733!537# 3%4>54&#"'>32!!.mًGPP0L]]L0S@8(!d466D'Rf'+6>(+43+)3 ,7( +03, +227, +@7/ +"( +" ?/ ִ+5+824+/245 +@42 +54 +@5, +@+ (9995)*+.7>$94;97,-9(>99:;$99901732654&+'7>?5#!5!#".' 3%533##5%!57#RV (-G&CglJF! '#+f:iB2 P}}l#YBCON bsz((tZg=ۇw7+PR` $(X&+% !/ )/ֱ%+2( 2*+%99(!99!9% 999014>=3326?#".53P(@MM@(&=JJ=&e9ulFMy>tvf9EuTKDEX2LX?nPICCU/Wv,-#Z ,+3+  +/+ 90133#!3#!./# ӒՕ  Z`>!f##J,+3+ +/+90133#!!./#3 Ӓ  Z`H!f##J,+3+ +/+90133#!3#'#!./# Ӓεmkn  Z` >!f##J)+3+  +/3 +/ +2*/ִ+++++ 99 &'$9!99 &990133#!3232653#".#"!./# ӒJ&A-(.*&&A-(.*&  Z` )(P5)(O6<!f##J e+3+  +/3 2/ֱ  ++  9999 99 90133#!53!./#53 Ӓ  Z`? !f##J-#){+3+ +/! +'/ +*/ִ+$++++9$$999'!990133#!!./#4632#"&732654&#" Ӓ  sfHGggGHfj%'&%Z`H!f##JwFTUEDSSD&& ((Y +3 +2  + 32/ ְ2 2 +@  +@  +@ ++013!!!!!!! !#V!F^;/}+fX{>q'+<3 + ./5 +?/ֱ7+++@+7(.2;<$9+'9'5+:;999 !$90146$32.#"32>?#"&/53254&#7$fqavZdU\FLfQmfr`BRyX9 )-b;1%)ۛr'886*"'77 L<4MN@XTw?!/ R+ + +/ֱ 2 +@ +@  +@  ++  9013!!!!!3#G>Օ;// J+ + +/ֱ 2 +@ +@  +@  ++013!!!!!3G;/ / R+ + +/ֱ 2 +@ +@  +@  ++  9013!!!!!3#'#G5εmk;/ / l+ + + /3 2/ֱ 2 +@ +@  +@  + + ++013!!!!!53353GT;/?)++/ֱ +999013#3ՕZ=)++/ֱ +99901333ʼZ F '+ + /ֱ + 99013#'#3εmk  Z/) E++/3 2 /ֱ +/+  +0153353/ ?Z?s g ++  +32/ ְ2 2 +@ +  +@ +++990153!2)!2#!!!syJs!"111J/+ 3+ 3&/3 +,/ +#20/ֱ +/+/#+$+$ + 1+#/&9999 &*9,901333&53#./#3232653#".#"<{<&A-(.*&&A-(.*&T#h##PZ$i##RV )(P5)(O6b/!%G + + &/ֱ+ '+ "$$9 990146$32#"$&732>54. 3#btTΚtѐmŎTՖݙrvXxb/!%G + + &/ֱ+ '+ "$$9 990146$32#"$&732>54. 3btTΚtѐmŎTݙrvXxb/!)G + + */ֱ+ ++ "%$9 990146$32#"$&732>54. 3#'#btTΚtѐmŎTϴlkݙrvXxb/!9 + + 0/"3* +6/$ +-2:/ֱ"+9+9-+.+.+ ;+-9 $0$9 99*0490146$32#"$&732>54. 3232653#".#"btTΚtѐmŎT&A-(.*%&A-(.*&ݙrvXx)(P5)(O6b/!%)u + + "/&3#'2*/ֱ"+%%&+))+ ++%"9& 999)9 990146$32#"$&732>54. 53353btTΚtѐmŎTݙrvXx  + 3 / +017 7   ZqqXq\_qp-p))q/f3!,n+$ + -/ֱ)+ .+9) "$9  9$999 ,$9 9990146$327#"''7&7&#"32>54&'ft˰^d^|ٰafdwѠ{}mŎTYOݙrdEe۫mEi(zJ{PXxyK#<+ + 3/ֱ  + + $901332653 3#ŧ'ՖZZ(#<+ + 3/ֱ  + + $901332653 3ŧߖZZ(#<+ + 3/ֱ  + + $901332653 3#'#ŧϴmjZZ(#n+ + 3/32/ֱ +$++$+ + +99901332653 53353ŧ>ZZ(06++ 3/ֱ + $990133673#3 , +- %$[eRd M++  +  +/ֱ  22 + + 990133!2#!!2654&#!H'hј}9q+3"+5:/ֱ99,+ 2 + %2+ ;+,999% $9"959990134>32#"&/532654.54>54&#"s.5.6R_R6͑T .DJb6R^R6*==*f\b=yU/T:<.:?5IJm=#JI'J9EB]3/VCAO)A^vmH+/@+)+3,++ 9) + A/ֱ0 07+ 2/B+0,9997 )-./$9!#999 #999 99014>;54#"'>32#57##"&3#32>=#"H5OwkS1--\D8RMTCո!9@[3Ֆg\PB3'@[FK1 #FrI5 * qbR+&0"DbfO! )>H+<@+)+/>++ 5) + A/ֱ, ,3+ 2/B+,993 )=>@$9!#99?95 #999 99014>;54#"'>32#57##"&732>=#"3H5OwkS1--\D8RMTCո!9@[3g\PB3'@[FK1 #FrI5 * qbR+&0"DbfO! )>OH+3D+)+7-++ =) + E/ֱ4 4;+ 2/F+4,999; )-.03$9!#99/9= #999 99014>;54#"'>32#57##"&3#'#32>=#"H5OwkS1--\D8RMTCո!9@[3Ѵϴljg\PB3'@[FK1 #FrI5 * qbR+&0"DbfO! )>H+CT+)+G.+73@ ++ M) + 4: . +,34 +U/ֱD DC ,+,/C+D+7  K338+V+C,97 ).:G$98#9M #999 994:>9014>;54#"'>32#57##"&3232653#".#"32>=#"H5OwkS1--\D8RMTCո!9@[3y&A-(.*&&A-(.*&@g\PB3'@[FK1 #FrI5 * qbR+&0")(P5)(O6DbfO! )>H+<@D+)+/>+B3=A2+ 5) + E/ֱ, ,=+@@3+ 2D3+AA/D/F+@=)9A /999D95 #999 99014>;54#"'>32#57##"&732>=#"53353H5OwkS1--\D8RMTCո!9@[3g\PB3'@[FK1 #FrI5 * qbR+&0"DbfO! )>H+<HT+)+/@+R ++ 5) + LF @ +L +U/ֱ, ,=+I+IO+C+C3+ 2/V+I=/)99O F@$995 #999 99RLC=99014>;54#"'>32#57##"&732>=#"4632#"&732654&#"H5OwkS1--\D8RMTCո!9@[3g\PB3'@[FK1 ZgHGggGHgk&&%%#FrI5 * qbR+&0"DbfO! )>ETTEDTTD&' ''J%>NU<+23B%2+3 S2H< +!3 O2V/ֱ? ?F+ 2"O2"P+ W+?99F <999"56$9P%2999 !+,999B<,9H+56$9 9999014>;54#"'>3 36!2!32>?#"&'##"&732>=#"!.#"J/Kmka53E$%PKRBT{b2dG9ROWE?ASLf]Q@`+NYG;!fu#CmI62* ;"# 3' |6O>-EagO*@1}TX%9y"+73+)/0 +:/ֱ 2+&+;+2#)-67$9&"9"0&569999 999 901432.#"32>?#"&/53254&#7&T9IWB^9>a1Π6jI;PJSGBRyX9 )-b;1%)7--)))6+&MN@XTw?!'T#'s+ $++!  + (/ֱ 2 + )+  $&$9999 9!9$&901432!32>?#".!.#"3#T%d ˒2dG9ROWE)iuՕ+وV$# 3' T#'u+ %++!  + (/ֱ 2 + )+  $%'$9&$9 9!9%$901432!32>?#".!.#"3T%d ˒2dG9ROWE)iuƖ+وV$# 3' T#+u+ %++!  + ,/ֱ 2 + -+  $&($9'$9 9!9%$901432!32>?#".!.#"3#'#T%d ˒2dG9ROWE)iuϴmj+وV$# 3' T#'+}+ %+)3$(2+!  + ,/ֱ 2 $+''(+++(+ -+(' !$9 9901432!32>?#".!.#"53353T%d ˒2dG9ROWE)iu"+وV$# 3' b6+++/ֱ +9999013#3Օ^ 6+++/ֱ +999901333ƺ  4++ + /ֱ  + 99 9013#'#3εmk ^  G++ 32+ /ֱ+/+  +0153353 ) XF&4|"+*2//5/ֱ' '/+ 6+'$9/ "$9992*99 99$99014>323&''7&'7%#".732>54&#"X@wr.V8, =7$QvlqxAɚP}H$\O nq@7m}}VrVsFV]EpEuF3+3+'30 ++ + $* +3$ +4/ֱ2+3++' (+5+399' *$9$*.901333>32#4.#"3232653#".#"=]P(Q2 $&732654&#"3#PX͗XДΖRՕsʎRRsԡPV +++ /ֱ + !+ $9 999014>2 $&732654&#"3PX͗XДΖ sʎRRsԡP#V +++$/ֱ + %+ $9 999014>2 $&732654&#"3#'#PX͗XДΖIεmksʎRRsԡP3 ++'30 ++$* +3$ +4/ֱ +3+3'+(+(+ 5+'3 *$9 99$*.9014>2 $&732654&#"3232653#".#"PX͗XДΖ &A-(.*&&A-(.*&sʎRRsԡ)(P5)(O6P#y ++!3 2+$/ֱ + +##+ %+ 99 99# 99 99014>2 $&732654&#"53353PX͗XДΖhsʎRRsԡ0Z5 ./ //  /ְ2 2 +015!5353 b!PR't+"++ +(/ֱ %+ )+99% $9 9"99 '$9 99014>327#"''7.&#"32654'PXsRaPVb~PbK[gfQ[HT\sʎRDqFnIzF5:v~ +QGvfw*e+!+ +&/+/ֱ22$+ ,+9$ !&$9!99&9990133>32#"./#326&#" :=\4oCsE3 =jU1f@)V( -#22%5/J*WR"\+ 32+ 3/#/ֱ+"$+9999990133673#"&/7326?53353 .o4dF:?;a3 Z>F5:v~ +QGvbL'+++ +$  + (/ֱ!+ 2! +@ +@ +@ +)+!99!9 99 "9014$323!!!!!!"#"$7326?&#"bW6  6ш$I?RS;/UΞNR%*4;!+(3-2+ 33925! +5 323>32!326?#"&'##"& 654&#"!.#"RF?ؓd >byEO%&RPWEAD癗4*ѓ)ivd@tvوVSS+=3' vw>ϨZ++ 3/32/ֱ  +/ ++9990133673#53353 , +-˞%$[eRd +/3+/ִ+ +9013#'#εmk XX/3 +/ + 2/ִ+ + ++ 9999013232653#".#"&A-(.*&&A-(.*& )(P5)(O6//+015!6//+015!d-}"+ +/ִ++013dX-qh/"+ +/ִ++013hY/qVHh / +/ִ++013VXqd-2+3 +2/ִ+ +9901333dX^X-qqh/2+3 +2/ִ+ +9901333hY‡XÅ/qqVH0/3 +2/ִ+ +9901333VXXqqh ./++ /ִ++ +01632#"h E+33 22+ /ֱ + + +01353!53!53HHZq /ִ++99013 #ZPPB[\f}!/ְ2++9017 3 fPP[\Nq)p&+ + + & +3 +2& +3 +2*/)ְ22++)999#90153&7#53632&#"!!!!326?# 'Np p>{3h1LV4@ )0-^'c:RB* DP#2/! + 33 2 +@ +22 /ִ+ +@ + +@ +++++!+ 9 999015!!#33673#7###/ ɜH ՐE+}+)+ 1%{>N>  5++++/ִ+++011!  R#h+3 +!+ +32$/ְ22 +@ ++ 2"2%+ 99015354>32&#"!#!#53R9SqY/& 2?.zLwm#aO1 ,S7mmnR-m(+3$ +3( +32./ְ22 +@ + +@ ++!/+ 99015354>32&#"3##337#".R9SqY/& 2?.l:5##(BP7&^1aO1 ,S7-^V= $/8ְ27287 +@8 +74+23,230+:2/<2?+47 9903#99015354>32&#"!54>32&#"!#!#!#53R9SqY/& 2?.9SqY/& 2?.{L'm#aO1 ,S7#aO1 ,S7mmmnRH7GB+1533> +933$2+-33/322H/6ְ25265 +@6 +52+21,212 +@1/ +18+;I+25 9981#99015354>32&#"!54>32&#"3##!#337#".R9SqY/& 2?.9SqY/& 2?.:5##(BP7%m#aO1 ,S7#aO1 ,S7mmV= $|Hf,6  !!6!^!|"<"Z""#J##$$2$z$% %B%&'`'((L())~**T*+0+v+,,H,r,,-B-.4.//0 0L011Z122L2334^5567^8089<9::::;;R;<<= =n=>h>???@J@AApABLBC|CDDPDhDDDDE E:EhEEEFFG G2GHHI\V9 p p  " ,    T  ` x : > > F Z ` 0vCopyright (c) 2008 by Jos Buivenga. All rights reserved.Museo Sans 500RegularFONTLAB:OTFEXPORTMuseo Sans 500 Regular1.000MuseoSans-500Museo Sans is a trademark of Jos Buivenga.Jos BuivengaJos BuivengaSpaced and kerned with iKern.http://www.josbuivenga.demon.nlhttp://www.josbuivenga.demon.nlMuseo Sans500Webfont 1.0Sun Jun 24 19:08:25 2012gf  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghjikmlnoqprsutvwxzy{}|~     glyph1glyph2uni00A0uni00ADuni00B2uni00B3uni00B9EurouniE000uniFB01uniFB02uniFB03uniFB04KPXYF+X!YKRX!Y+\X E+D E3++D E3++D E++D El++D E9++D E3++D E 7++D E 5++D E )++D E+D E  +Fv+D Eu+Fv+D E8+Fv+D E +Fv+D E+Fv+D E+Fv+DY+OIanniX-0.9.20/Tools/Score template.iannix000066400000000000000000000123351317340345000201530ustar00rootroot00000000000000/* * IanniX Score File */ /* * This method is called first. * It is the good section for asking user for script global variables (parameters). * * This section is never overwritten by IanniX when saving. */ function askUserForParameters() { //title("The title of the parameter box"); //ask("Group name of the parameter (only for display purposes)", "Parameter label", "myGlobalVar", "theDefaultValue"); } /* * This method stores all the operations made through IanniX scripts. * You can add some commands here to make your own scripts! * Scripts are written in Javascript but even with a limited knowledge of Javascript, many types of useful scripts can be created. * * Beyond the standard javascript commands, the run() function is used to send commands to IanniX. * Commands must be provided to run() as a single string. * For example, run("zoom 100"); sets the display zoom to 100%. * * To combine numeric parameters with text commands to produce a string, use the concatenation operator. * In the following example center_x and center_y are in numeric variables and must be concatenated to the command string. * Example: run("setPos current " + center_x + " " + center_y + " 0"); * * To learn IanniX commands, perform an manipulation in IanniX graphical user interface, and see the Helper window. * You'll see the syntax of the command-equivalent action. * * And finally, remember that most of commands must target an object. * Global syntax is always run(" "); * Targets can be an ID (number) or a Group ID (string name of group) (please see "Info" tab in Inspector panel). * Special targets are "current" (last used ID), "all" (all the objects) and "lastCurve" (last used curve). * * This section is never overwritten by IanniX when saving. */ function makeWithScript() { //Clears the score run("clear"); //Resets rotation run("rotate 0 0 0"); //Resets score viewport center run("center 0 0"); //Resets score zoom run("zoom 100"); } /* * When an incoming message is received, this method is called. * - tells information about the nature of message ("osc", "midi", "direct…) * - and gives the origin of message, specially for IP protocols (for OpenSoundControl, UDP or TCP, it is the IP and port of the application that sends the message) * - is the supposed destination of message (for OpenSoundControl it is the path, for MIDI it is Control Change or Note on/off…) * - are an array of arguments contained in the message * * This section is never overwritten by IanniX when saving. */ function onIncomingMessage(protocol, host, port, destination, values) { //Logs a message in the console (open "Config" tab from Inspector panel and see "Message log") console("Received on '" + protocol + "' (" + host + ":" + port + ") to '" + destination + "', " + values.length + " values : "); //Browses all the arguments and displays them in log window for(var valueIndex = 0 ; valueIndex < values.length ; valueIndex++) console("- arg " + valueIndex + " = " + values[valueIndex]); } /* * This method stores all the operations made through the graphical user interface. * You are not supposed to modify this section, but it can be useful to remove some stuff that you added accidentaly. * * Be very careful! This section is automaticaly overwritten when saving a score. */ function madeThroughGUI() { //GUI: NEVER EVER REMOVE THIS LINE //GUI: NEVER EVER REMOVE THIS LINE } /* * This method stores all the operations made by other softwares through one of the IanniX interfaces. * You are not supposed to modify this section, but it can be useful to remove some stuff that you or a third party software added accidentaly. * * Be very careful! This section is automaticaly overwritten when saving a score. */ function madeThroughInterfaces() { //INTERFACES: NEVER EVER REMOVE THIS LINE //INTERFACES: NEVER EVER REMOVE THIS LINE } /* * This method is called last. * It allows you to modify your hand-drawn score (made through graphical user interface). * * This section is never overwritten by IanniX when saving. */ function alterateWithScript() { } /* * //APP VERSION: NEVER EVER REMOVE THIS LINE * Made with IanniX appversion: "" * //APP VERSION: NEVER EVER REMOVE THIS LINE */ /* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ IanniX-0.9.20/Tools/Templates/000077500000000000000000000000001317340345000160265ustar00rootroot00000000000000IanniX-0.9.20/Tools/Templates/Cosmosf.txt000066400000000000000000000402121317340345000201770ustar00rootroot00000000000000[General] name=Cosmosƒ interface=:7001 | control of instance #1 interface=:7002 | control of instance #2 interface=:7003 | control of instance #3 [Messages] osc://ip_out:port_out/Cosmos /macroEVL cursor_value_x | value between 0-10000 osc://ip_out:port_out/Cosmos /CellLMod cursor_value_x | value between 0-2 osc://ip_out:port_out/Cosmos /LoopAcc cursor_value_x | value between 0-10 osc://ip_out:port_out/Cosmos /CellFeedback cursor_value_x | value between 0-8 osc://ip_out:port_out/Cosmos /mesoDensity cursor_value_x | value between 0-6 osc://ip_out:port_out/Cosmos /mesoDensityMod cursor_value_x | value between 0-3 osc://ip_out:port_out/Cosmos /mesoCellScale cursor_value_x | value between 0-6 osc://ip_out:port_out/Cosmos /mesoOnsetDist cursor_value_x | value between 0-8 osc://ip_out:port_out/Cosmos /mesoDurDist cursor_value_x | value between 0-8 osc://ip_out:port_out/Cosmos /microDensity cursor_value_x | value between 0-6 osc://ip_out:port_out/Cosmos /microDensityMod cursor_value_x | value between 0-3 osc://ip_out:port_out/Cosmos /microOnsetDist cursor_value_x | value between 0-8 osc://ip_out:port_out/Cosmos /microDurDist cursor_value_x | value between 0-8 osc://ip_out:port_out/Cosmos /microCellScale cursor_value_x | value between 0-6 -- osc://ip_out:port_out/Cosmos /mesOnset /regular cursor_value_x | value between 0 osc://ip_out:port_out/Cosmos /mesOnset /uniform cursor_value_x | value between 0 osc://ip_out:port_out/Cosmos /mesOnset /gaussian cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesOnset /cauchy cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesOnset /exponential cursor_value_x | value between 0-10 osc://ip_out:port_out/Cosmos /mesOnset /arcsine cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesOnset /weibull cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesOnset /lognormal cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesOnset /triangular cursor_value_x cursor_value_y cursor_value_z | 3 values between 0-1 0-1 0-1 -- osc://ip_out:port_out/Cosmos /micOnset /regular cursor_value_x | value between 0 osc://ip_out:port_out/Cosmos /micOnset /uniform cursor_value_x | value between 0 osc://ip_out:port_out/Cosmos /micOnset /gaussian cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /micOnset /cauchy cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /micOnset /exponential cursor_value_x | value between 0-10 osc://ip_out:port_out/Cosmos /micOnset /arcsine cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /micOnset /weibull cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /micOnset /lognormal cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /micOnset /triangular cursor_value_x cursor_value_y cursor_value_z | 3 values between 0-1 0-1 0-1 -- osc://ip_out:port_out/Cosmos /mesDur /regular cursor_value_x | value between 0 osc://ip_out:port_out/Cosmos /mesDur /uniform cursor_value_x | value between 0 osc://ip_out:port_out/Cosmos /mesDur /gaussian cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesDur /cauchy cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesDur /exponential cursor_value_x | value between 0-10 osc://ip_out:port_out/Cosmos /mesDur /arcsine cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesDur /weibull cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesDur /lognormal cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesDur /triangular cursor_value_x cursor_value_y cursor_value_z | 3 values between 0-1 0-1 0-1 -- osc://ip_out:port_out/Cosmos /micDur /regular cursor_value_x | value between 0 osc://ip_out:port_out/Cosmos /micDur /uniform cursor_value_x | value between 0 osc://ip_out:port_out/Cosmos /micDur /gaussian cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /micDur /cauchy cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /micDur /exponential cursor_value_x | value between 0-10 osc://ip_out:port_out/Cosmos /micDur /arcsine cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /micDur /weibull cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /micDur /lognormal cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /micDur /triangular cursor_value_x cursor_value_y cursor_value_z | 3 values between 0-1 0-1 0-1 -- osc://ip_out:port_out/Cosmos /microAmpGainP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesoAmpGainP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /microAmpModP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesoAmpModP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /microPBModP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesoPBModP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /sampStartP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /pbDirectionP cursor_value_x | value between 0-2 osc://ip_out:port_out/Cosmos /pulseDutyP cursor_value_x | value between 0-100 osc://ip_out:port_out/Cosmos /microWindowP cursor_value_x | value between 0-4 osc://ip_out:port_out/Cosmos /mesoWindowP cursor_value_x | value between 0-4 osc://ip_out:port_out/Cosmos /microPBrateP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesoPBrateP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /engTypeP cursor_value_x | value between 0-6 -- osc://ip_out:port_out/Cosmos /microCutOffP cursor_value_x | value between 0-15000 osc://ip_out:port_out/Cosmos /mesoCutOffP cursor_value_x | value between 0-15000 osc://ip_out:port_out/Cosmos /microFiltModP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesoFiltModP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /microFiltTypeP cursor_value_x | value between 0-3 osc://ip_out:port_out/Cosmos /mesoFiltTypeP cursor_value_x | value between 0-3 osc://ip_out:port_out/Cosmos /microFiltResP cursor_value_x | value between 0-10 osc://ip_out:port_out/Cosmos /mesoFiltResP cursor_value_x | value between 0-10 -- osc://ip_out:port_out/Cosmos /GrnModP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /GrnPBSpeedP cursor_value_x | value between 0-10 osc://ip_out:port_out/Cosmos /GrnSizeP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /GrnInputP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /GrnFeedbackP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /GrnPosMovP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /RingModP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /RingModFreqP cursor_value_x | value between 0-2000 osc://ip_out:port_out/Cosmos /RingModMP cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /RingModFreqMP cursor_value_x | value between 0-2000 -- osc://ip_out:port_out/Cosmos /microAmpGain cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesoAmpGain cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /microAmpMod cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesoAmpMod cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /microPBMod cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesoPBMod cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /sampStart cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /pbDirection cursor_value_x | value between 0-2 osc://ip_out:port_out/Cosmos /pulseDuty cursor_value_x | value between 0-100 osc://ip_out:port_out/Cosmos /microWindow cursor_value_x | value between 0-4 osc://ip_out:port_out/Cosmos /mesoWindow cursor_value_x | value between 0-4 osc://ip_out:port_out/Cosmos /microPBrate cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesoPBrate cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /engType cursor_value_x | value between 0-6 -- osc://ip_out:port_out/Cosmos /microCutOff cursor_value_x | value between 0-15000 osc://ip_out:port_out/Cosmos /mesoCutOff cursor_value_x | value between 0-15000 osc://ip_out:port_out/Cosmos /microFiltMod cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesoFiltMod cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /microFiltType cursor_value_x | value between 0-3 osc://ip_out:port_out/Cosmos /mesoFiltType cursor_value_x | value between 0-3 osc://ip_out:port_out/Cosmos /microFiltRes cursor_value_x | value between 0-10 osc://ip_out:port_out/Cosmos /mesoFiltRes cursor_value_x | value between 0-10 -- osc://ip_out:port_out/Cosmos /GrnMod cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /GrnPBSpeed cursor_value_x | value between 0-10 osc://ip_out:port_out/Cosmos /GrnSize cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /GrnInput cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /GrnFeedback cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /GrnPosMov cursor_value_x | value between 0-1 -- osc://ip_out:port_out/Cosmos /RingMod cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /RingModFreq cursor_value_x | value between 0-2000 osc://ip_out:port_out/Cosmos /RingModM cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /RingModFreqM cursor_value_x | value between 0-2000 -- osc://ip_out:port_out/Cosmos /LFO(number) cursor_value_x | value between on-off osc://ip_out:port_out/Cosmos /LFO(number) /modamt cursor_value_x | value between (-1)-1 osc://ip_out:port_out/Cosmos /LFO(number) /modrate cursor_value_x | value between 0-20 osc://ip_out:port_out/Cosmos /LFO(number) /stochmod cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LFO(number) /LFOcateg cursor_value_x cursor_value_y | 2 values between 0-6 0-6 osc://ip_out:port_out/Cosmos /LFO(number) /arcsine cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LFO(number) /weibull cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LFO(number) /stochdistrate cursor_value_x | value between 0-200 osc://ip_out:port_out/Cosmos /LFO(number) /regular cursor_value_x | value between 0 osc://ip_out:port_out/Cosmos /LFO(number) /uniform cursor_value_x | value between 0 osc://ip_out:port_out/Cosmos /LFO(number) /gaussian cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LFO(number) /cauchy cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LFO(number) /exponential cursor_value_x | value between 0-10 osc://ip_out:port_out/Cosmos /LFO(number) /arcsine cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LFO(number) /weibull cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LFO(number) /lognormal cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LFO(number) /triangular cursor_value_x cursor_value_y cursor_value_z | 3 values between 0-1 0-1 0-1 -- osc://ip_out:port_out/Cosmos /LFOm(number) on-off cursor_value_x | value between osc://ip_out:port_out/Cosmos /LFOm(number) /modamt cursor_value_x | value between (-1)-1 osc://ip_out:port_out/Cosmos /LFOm(number) /modrate cursor_value_x | value between 0-20 osc://ip_out:port_out/Cosmos /LFOm(number) /stochmod cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LFOm(number) /LFOcateg cursor_value_x cursor_value_y | 2 values between 0-6 0-6 osc://ip_out:port_out/Cosmos /LFOm(number) /LFOwave cursor_value_x | value between 0-6 osc://ip_out:port_out/Cosmos /LFOm(number) /regular cursor_value_x | value between 0 osc://ip_out:port_out/Cosmos /LFOm(number) /uniform cursor_value_x | value between 0 osc://ip_out:port_out/Cosmos /LFOm(number) /gaussian cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LFOm(number) /cauchy cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LFOm(number) /exponential cursor_value_x | value between 0-10 osc://ip_out:port_out/Cosmos /LFOm(number) /arcsine cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LFOm(number) /weibull cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LFOm(number) /lognormal cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LFOm(number) /triangular cursor_value_x cursor_value_y cursor_value_z | 3 values between 0-1 0-1 0-1 -- osc://ip_out:port_out/Cosmos /LinG(number) cursor_value_x | value between on-off osc://ip_out:port_out/Cosmos /LinG(number) /offsetModType cursor_value_x | value between 0-8 osc://ip_out:port_out/Cosmos /LinG(number) /speedModType cursor_value_x | value between 0-8 osc://ip_out:port_out/Cosmos /LinG(number) /offsetMod cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LinG(number) /speedMod cursor_value_x | value between 0-10 osc://ip_out:port_out/Cosmos /LinG(number) /stochdistrate cursor_value_x | value between 0-20 osc://ip_out:port_out/Cosmos /LinG(number) /regular cursor_value_x | value between 0 osc://ip_out:port_out/Cosmos /LinG(number) /uniform cursor_value_x | value between 0 osc://ip_out:port_out/Cosmos /LinG(number) /gaussian cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LinG(number) /cauchy cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LinG(number) /exponential cursor_value_x | value between 0-10 osc://ip_out:port_out/Cosmos /LinG(number) /arcsine cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LinG(number) /weibull cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LinG(number) /lognormal cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LinG(number) /triangular cursor_value_x cursor_value_y cursor_value_z | 3 values between 0-1 0-1 0-1 -- osc://ip_out:port_out/Cosmos /LinGm(number) cursor_value_x | value between on-off osc://ip_out:port_out/Cosmos /LinGm(number) /offsetModType cursor_value_x | value between 0-8 osc://ip_out:port_out/Cosmos /LinGm(number) /speedModType cursor_value_x | value between 0-8 osc://ip_out:port_out/Cosmos /LinGm(number) /offsetMod cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LinGm(number) /speedMod cursor_value_x | value between 0-10 osc://ip_out:port_out/Cosmos /LinGm(number) /stochdistrate cursor_value_x | value between 0-20 osc://ip_out:port_out/Cosmos /LinGm(number) /regular cursor_value_x | value between 0 osc://ip_out:port_out/Cosmos /LinGm(number) /uniform cursor_value_x | value between 0 osc://ip_out:port_out/Cosmos /LinGm(number) /gaussian cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LinGm(number) /cauchy cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LinGm(number) /exponential cursor_value_x | value between 0-10 osc://ip_out:port_out/Cosmos /LinGm(number) /arcsine cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LinGm(number) /weibull cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LinGm(number) /lognormal cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LinGm(number) /triangular cursor_value_x cursor_value_y cursor_value_z | 3 values between 0-1 0-1 0-1 -- osc://ip_out:port_out/Cosmos /mesOnsetFreeze cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /mesDurFreeze cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /micOnsetFreeze cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /micDurFreeze cursor_value_x | value between 0-1 -- osc://ip_out:port_out/Cosmos /mesoMute cursor_value_x cursor_value_y | 2 values between 0-6 0-1 osc://ip_out:port_out/Cosmos /microMute cursor_value_x cursor_value_y | 2 values between 0-6 0-1 -- osc://ip_out:port_out/Cosmos /morph1 cursor_value_x cursor_value_y | 2 values between 0-1 0-1 osc://ip_out:port_out/Cosmos /morph2 cursor_value_x cursor_value_y | 2 values between 0-1 0-1 osc://ip_out:port_out/Cosmos /morphrandspeed cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /morphinterp cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /ellipse1 cursor_value_x cursor_value_y | 2 values between 0-200 0-155 osc://ip_out:port_out/Cosmos /ellipse2 cursor_value_x cursor_value_y | 2 values between 0-200 0-155 osc://ip_out:port_out/Cosmos /Running cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /LiveIPlay cursor_value_x | value between 0-1 osc://ip_out:port_out/Cosmos /BufSelect cursor_value_x | value between 0-1-2IanniX-0.9.20/Tools/Templates/_IanniX.txt000066400000000000000000000065351317340345000201250ustar00rootroot00000000000000[General] name=IanniX interface=:57120 | standart output interface=:1234 | standart input [Messages] osc://ip_out:port_out/trigger trigger_id trigger_group_id trigger_value_x trigger_value_y trigger_value_z trigger_xPos trigger_yPos trigger_zPos cursor_id cursor_group_id | Default OSC message for triggers osc://ip_out:port_out/cursor cursor_id cursor_group_id cursor_value_x cursor_value_y cursor_value_z cursor_xPos cursor_yPos cursor_zPos | Default OSC message for cursors in XYZ osc://ip_out:port_out/cursor cursor_id cursor_group_id cursor_value_a cursor_value_e cursor_value_d cursor_aPos cursor_ePos cursor_dPos | Default OSC message for cursors in AED osc://ip_out:port_out/curve collision_curve_id collision_curve_group_id collision_value_x collision_value_y 0 collision_xPos collision_yPos 0 | Default OSC message for classical playhead midi://midi_out/notef 1 trigger_value_y trigger_value_x 3 | Default MIDI message for triggers midi://midi_out/note 1 69 127 5 | Play a MIDI note #69 (A | 440Hz) during 5 seconds on channel #1 with maximum velocity midi://midi_out/ccf 1 0 cursor_value_y | Send a MIDI control change on controler #0 on channel #1 depending on cursor position (as float value between 0 and 1) direct:// goto 2 | Make score go back to timecode 000:02.000 direct:// setSpeedF 10 1 | Make the cursor #10 start (please set its Master Speed to 0 before) [Equations] cartesian 3*param1*cos(param3*4*PI*t) , 3*param2*sin(param4*4*PI*t) , cos(param5*4*PI*t) | 3D circle cartesian 5*cos(4*param4*param1*2*PI*t) , 3*sin(4*param4*param2*10*t*PI) , param5*sin(4*param4*param3*6*t*PI) | Super-8 cartesian 10*param1*t , sin(param2*20*t*PI) * exp(1-4*param3*t) , 2*param5*cos(8*param4*t*PI) | 3D Damped sine cartesian 2*param1*(8-16*(1-t)) , param2*2*sin(3*param3*(8-16*(1-t))*4)/(8-16*(1-t))-3 , param5*sin((8-16*(1-t))*4*param4) | Coiled sinus cardinalis polar 6*cos(20*param1*param4*PI*t) , cos(40*param2*param4*PI*t) , 2*param3*param4*t | Super-S polar 5*cos(80*param1*param4*PI*t) , 4*sin(4*param2*param4*PI*t) , param5*sin(10*param3*param4*PI*t) | Flower cartesian 2*cos(2*param1*t*PI)+2*cos(6*param2*t*PI) , 2*sin(2*param3*t*PI)-2*sin(6*param4*t*PI) , 3*sin(4*param5*t*PI) | Lasso cartesian 6*cos(8*param1*param4*t*PI) , 6*sin(24*param2*param4*t*PI) , 12*param5*sin(56*param3*param4*t*PI) | 3D Lissajoussche curve cartesian 5*sin(80*param1*param5*t*PI)*cos(8*param2*param5*t*PI) , 5*sin(80*param3*param5*t*PI)*sin(8*param4*param5*t*PI) , 5*cos(40*param5*t*PI) | 2D rosette or 3D sphere? cartesian 10*param2*t*cos(40*param4*param1*t*PI) , 10*param2*t*sin(40*param4*param1*t*PI) , 20*param3*param4*t-5*param5 | Conical spiral of Pappus cartesian (2+4*cos(48*param1*param4*t*PI))*cos(8*param2*param4*t*PI) , (2+4*cos(48*param1*param4*t*PI))*sin(8*param2*param4*t*PI) , 4*param5*sin(48*param3*param4*t*PI) | An other 3D flower cartesian (5*param1+5*param2)*cos(50*param4*t*2*PI) + (5*param3)*cos((5*param1+5*param2)*50*param4*t*2*PI/(5*param2)), (5*param1+5*param2)*sin(50*param4*t*2*PI) + (5*param3)*sin((5*param1+5*param2)*50*param4*t*2*PI/(5*param2)), 0 | Base for 2D spirography cartesian (5*param1+5*param2)*cos(50*param4*t*2*PI) + (5*param3)*cos((5*param1+5*param2)*50*param4*t*2*PI/(5*param2)), (5*param1+5*param2)*sin(50*param4*t*2*PI) + (5*param3)*sin((5*param1+5*param2)*50*param4*t*2*PI/(5*param2)), (5*param1+5*param2)*cos(500*param5*t*2*PI)*sin(50*param4*t*2*PI) | Base for 3D spirographyIanniX-0.9.20/Tools/Translation_fr_FR.qm000066400000000000000000003511621317340345000200130ustar00rootroot00000000000000of.@4E/0į=@R]@QE$ ,&#w0dHJ62JLtN+CNPJ1PVbP3SRJu ZRVQS#$OVatVX5YD1VZa&Za\Zgo_D @~din!Pm~r#qG8ݣ8Q8bEl(>,͛]jtʚ 6̾ NiNJwy QnσXA1hD?AhDM5.Vm/Kefi>rP&U`р[tSvi9'U's1i&.k E7G̃b[[,' JpE]cNt" c tZ7%/ 2/18?U3K L:daeh`pw'yg]N>N2N-k)OIj;!C4ZG' tFRbLXY"8ٹ O-S}&VвITw1.  ՃF,T9@%nPsc?_t *_$c2bd&eln"06OWs8:>F$*1U%dzaHšDƥXZʳL^ݻ5 #ET-4Oe E T$+-ye%I&-E &VE'&4-(M-3:ViXrǿ4rwՄx#%,Nsf4.xBzPpSU@Z˹<]~`#ރ  't,,KӉ\*GJSDžؚ5CzO TTT"T,TަTCTPMYeK0}} |ei4 K+$ 416/DAC#-C[(HFمMF3t:KR%W\T$]_i,$jk?Luk^[l*l]GxF&1ZYF0H50C|8huZ|A*BC>f+o^]'cέT5ϱP pUQ֤R YsNKYw!_6B"u:rF!KUS)UN_pd\eh}#mTmoP$Xpzҥ,}#07t/(7WT3JFXT1^is#"Q ] jۿ.<uAZ CKb-QkeI^It#/e(/e6&47)=28@J R`V5^t%h`sS1e a6e/ae`)e`|߅Qpslt_o.|b<FpMnu\Xy^1UoV$VV$D+FE+=s[#ZX{C] QSqs[%}sq(s/*&t#Vk-o;.T/)c6CQ7_M;1<.F|OT-GU+tmZMe`Pqhr0{$=|u!r :c>S#3 "99d2#onuPYc^.i'~f^+. pu  s+1  ( ) " ,y IT, Lc W` m.s xN!R y0 yE.4 yE }_0_ gU. /\ p A< (N b *14 % E6 &_ Wt? < w ֧ ֨ |hR |h~ $T  !_ {9 I}C */g 1v1 3q 6i Gf Mj) T G VbBG ` ! aa ab ac ad^ ae af fI k2 ^ q K %E߹ } *-F 4 C+ l4A ?W r~ %G @' 8 =9 @] CTCR LN VbB a1 f( kfM ox"K U  M 9 :y 14 =N:  C&k ٹ :S S! Lg > W| g" $)s nI (( )0T +.e /.y 1 :3% >4 I VbC Z3 ^ ` bT)/ cX c nru#r ny# ujsL z23 #b ^+Y xs6 U " ƞ$PD %~ ɠ. ɠ.Q! 7c ;\ S p _V; $h LD 4 Su 5o z .e : Rk g ^f G< $>' '6R$ 2 QE DYD DYk DY DY DY DZ DZ. DZU DZ| QSu ` e3@ k& rmuq uD'y u rC- QQ d}&  o "S ׿ U"# z)b$d5u o% U?)E}+f,IJ1.B2.4Y6x|D`% QA4#_bi+:-kvl[3tsU'u3~QPvJWDZb6`haum6?oe)b/l^Vy9_%Cs2W9$>dn2$,X)lXcww-w#*^V~")VsA !ۀ^дgT3@e 5^kTX{iIIanniXExtKinectManagerKinectExtKinectManager<MIDI %1 sur ch. %2, CC (%3)=%4!MIDI %1 on ch. %2, send CC(%3)=%4ExtMidiManager4MIDI %1 sur ch. %2, PGM=%3MIDI %1 on ch. %2, send PGM=%3ExtMidiManager6MIDI %1 sur ch. %2, bend=%3MIDI %1 on ch. %2, send bend=%3ExtMidiManager>MIDI %1 sur ch. %2, note(%3)=%4#MIDI %1 on ch. %2, send note(%3)=%4ExtMidiManager4AJOUTER UN NOUVEAU MESSAGEADD A NEW MESSAGEExtOscPatternAskFRENExtOscPatternAsk8IanniX  diteur de messagesIanniX — Message editorExtOscPatternAsk Message %1ExtOscPatternAsk(SUPPRIMER LE MESSAGEREMOVE CURRENT MESSAGEExtOscPatternAskCOMMANDE %1 COMMAND %1ExtOscPatternEditorID CONTRLLEUR CONTROLLER IDExtOscPatternEditor$Effacer le messageClear the messageExtOscPatternEditor"Effacer la valeurClear the valueExtOscPatternEditorFCliquer ici pour effacer le messageClick here to clear the messageExtOscPatternEditorDCliquer ici pour effacer la valeurClick here to clear the valueExtOscPatternEditor DUREDURATIONExtOscPatternEditorIanniXExtOscPatternEditorCANAL MIDI MIDI CHANNELExtOscPatternEditor,Apprentissage MIDI/OSCMIDI/OSC learnExtOscPatternEditorNUMRO NOTE NOTE NUMBERExtOscPatternEditorSUR LE PORTON PORTExtOscPatternEditorID PROGRAMME PROGRAM IDExtOscPatternEditorVeuillez envoyer un vnement IanniX Bougez un slider sur votre interface de contrle ou appuyez sur une note MIDI]Please send an event to IanniX Move a slider on your surface control or press a MIDI note…ExtOscPatternEditor QUERY ARG. %1ExtOscPatternEditorENVOYER SUR SEND THROUGHExtOscPatternEditorBSelectionner ici un contrle MIDISelect here a MIDI controlExtOscPatternEditorlSlectionnez ici un protocole pour envoyer le messager1Select here the protocol used to transmit messageExtOscPatternEditorlSelectionner ou taper le priphrique MIDI atteindre%Select or type a MIDI device to reachExtOscPatternEditor^Selectionner ou taper l'adresse OSC atteindre&Select or type an OSC address to reachExtOscPatternEditornSelectionner ou taper l'application ou l'IP destination2Select or type the destination application/host IPExtOscPatternEditorSelectionner ou taper l'application/numro de port de destination;Select or type the destination application/host port numberExtOscPatternEditorVERS L'ADRESSE TO ADDRESSExtOscPatternEditorCONTRLE TO CONTROLExtOscPatternEditorVERS L'HOTETO HOSTExtOscPatternEditorVERSTO MIDI DEVICEExtOscPatternEditorModles TemplatesExtOscPatternEditor0Type here a IanniX variable or your custom valueExtOscPatternEditor VALEURVALUEExtOscPatternEditorVALEUR %1VALUE %1ExtOscPatternEditorVALEUR 1VALUE 1ExtOscPatternEditorVALEUR 2VALUE 2ExtOscPatternEditorVALEUR 3VALUE 3ExtOscPatternEditorVALEUR 4VALUE 4ExtOscPatternEditorVALEUR 5VALUE 5ExtOscPatternEditorVALEUR 6VALUE 6ExtOscPatternEditorVELOCITVELOCITYExtOscPatternEditorXXExtOscPatternEditorNOEUD XML %1 XML NODE %1ExtOscPatternEditordirect:// goto 2 - Fait revenir le playback au timecode 000:02.000Les curseurs</b> gnrent par dfaut des messages toutes les 20&nbsp;ms (mais vous pouvez modifier cette priode).^Cursors, by default, generate messages every 20 ms (but you can change this time). IanniXApp0<b>Les triggers</b> n'envoient gnralement qu'un seul message au passage du curseur et IanniX limite l'envoi 1 message par milliseconde maximum.<br/>Triggers usually send one only message when a cursor goes past them. IanniX is limited to sending one message per millisecond maximum.
 IanniXApp<li><b>un trigger</b> est un vnement ponctuel positionn dans l'espace ; il est dclench lors du passage d'<b>un curseur</b>&nbsp;;</li><li><b>une courbe</b> est une suite de points dans l'espace ; elle dfinit une trajectoire&nbsp;;</li><li><b>un curseur</b> est une tte de lecture. Il dclenche des vnements discrets (<b>triggers</b>) ou continus (valeurs). Il peut suivre <b>une courbe</b> ou tre compltement libre (contrl par la souris, une tablette ou par un autre logiciel).</li>
  • a trigger is a momentary event set in space; it is activated when a cursor goes past it;
  • a curve is a series of points set in space; it defines a trajectory ;
  • a cursor is similar to a tape head. It triggers discrete events (triggers) or continuous (values). It can follow a curve or be completely free (controlled by the mouse, a graphic tablet or by another software).
  •  IanniXApp<li><b>l'interface graphique</b> l'aide de la <a href='overview.html'>barre d'outils</a>&nbsp;;</li><li><b>les interfaces logicielles</b> contrlant IanniX en Open Sound Control par exemple, grce au systme de <a href='reference.html'>commandes IanniX</a>&nbsp;;</li><li><b>les scripts</b> qui cr des partitions gnratives via <a href='script.html'>des commandes scriptes</a>.</li>2
  • the graphic interface thanks to the toolbar;
  • scripts that create generative scores via scripted commands.
  •  IanniXApp<li><b>l'identifiant (ID)</b> : chaque objet (trigger, courbe ou curseur) possde un identifiant unique&nbsp;;</li><li><b>le groupe</b> : les objets peuvent tre regroups sous un nom de groupe, permettant le contrle de plusieurs objets d'un coup.</li>
  • the identifier (ID): each object (trigger, curve or cursor) has an unique identifier;
  • the group: objects can be grouped under a group name, allowing control of multiple objects at once.
  •  IanniXApp><li><code class='target'>id</code> dsigne un objet prcis.<br/>Exemple : <span class='api'><code>remove <span class='target'>2</span></code></span></li> <li><code class='target'>group_id</code> dsigne le groupe entier qui peut tre un mot.<br /> Exemple : <span class='api'><code>remove <span class='target'>toto</span></code></span></li><li><code class='target'>all</code> dsigne tous les objets.<br /> Exemple : <span class='api'><code>remove <span class='target'>all</span></code></span></li> <li><code class='target'>current</code> dsigne le dernier objet cr.<br /> Exemple : <span class='api'><code>remove <span class='target'>current</span></code></span></li>
  • id refers to a specific object.
    Example: remove 2
  • group_id refers to the entire group that can be a word.
    Example: remove toto
  • all refers to all objects.
    Example: remove all
  • current refers to the last created object.
    Example: remove current
  •  IanniXAppUne partition IanniX se compose de trois objets fondamentaux&nbsp;:2A IanniX score is composed of three main elements: IanniXAppQuelques notions trs simples vous permettront de comprendre les mcanismes de IanniX :MA few simple concepts will enable you to understand the mechanisms of IanniX: IanniXApp$Ajouter des objets Add objects IanniXApp.Vocabulaire fondamentalBasic vocabulary IanniXAppBugsBugs IanniXAppCopier/coller cet exemple dans IanniX pour voir son fonctionnement !ECopy / paste this example in IanniX to understand how the code works! IanniXAppCopier/coller cet exemple dans IanniX pour voir son fonctionnement !ECopy / paste this example in Iannix to understand how the code works! IanniXApp>Adresse par dfaut des curseurs Default address used for cursors IanniXApp>Adresse par dfaut du transport+Default address used for transport messages IanniXApp>Adresse par dfaut des triggers!Default address used for triggers IanniXApp8Adresse par dfaut de IanniX$Default address used to reach IanniX IanniXAppPort par dfautDefault port used by IanniX IanniXApp\IP par dfaut (saisie dans l'onglet "Network")2Destination is the default IP set in "Network" tab IanniXApp^MIDI par dfaut (saisi dans l'onglet "Network");Destination is the default MIDI device set in "Network" tab IanniXApp4Cet ordinateur (IP locale) Destination is your own computer IanniXAppDocumentation Documentation IanniXAppFREN IanniXAppExemple :Example: IanniXAppfN hsitez pas vous inscrire sur notre <a href='http://iannix.org/en/community.php' target='_blank'>forum</a>. Poster vos problmes ou astuces pour faire vivre notre communaut !Feel free to suscribe to our forum. Post your problems or tips to make live our community! IanniXAppTRequte vers une page web/webservice (GET)*HTTP request to a webpage/webservice (GET) IanniXApp4Port OSC entrant de IanniXIanniX OSC default input IanniXAppIanniX peut tre contrl par IanniX lui-mme (!). Vous pouvez utiliser tous les protocoles dcrits prcdemment mais nous vous recommandons d'utiliser l'OSC pour communiquer entre deux IanniX sur des ordinateurs en rseau et d'utiliser la commande <code>direct</code> pour envoyer des messages l'intrieur mme de IanniX.<br/><br /><span class='titre'>Exemple :&nbsp;</span>HIanniX can be controlled by IanniX itself (!). You can use all the protocols described above, but we recommend using OSC to communicate between two IanniX applications on network computers and use the direct command to send messages inside one IanniX application.

    Example:  IanniXAppLes commandes IanniX doivent spcifier une cible chaque excution :8IanniX commands must specify a target at each execution: IanniXApprIanniX est un squenceur graphique open-source, inspir des travaux de Iannis Xenakis, destin la cration numrique. IanniX synchronise via Open Sound Control (OSC) des vnements et courbes vers votre environnement temps-rel (PureData, C-Sound, SuperCollider, openFramework, Processing, vvvv, Live, Max/MSP/Jitter & et beaucoup d autres dans notre section <a href='http://www.iannix.org/en/links.php' target='_blank'>links</a> section) !|IanniX is a graphical open-source sequencer, based on Iannis Xenakis works, for digital art. IanniX syncs via Open Sound Control (OSC) events and curves to your real-time environment (PureData, C-Sound, SuperCollider, openFramework, Processing, vvvv, Live, Max/MSP/Jitter… and many others from our links section)! IanniXApp~IanniX est compatible avec Linux, Mac OS X 10.6+ et Windows et ne ncessite pas d installation particulire.<br /> Pour les utilisateurs de IanniX sous Linux qui ne souhaitent pas compiler depuis les sources, nous avons inclus une version compile que vous pourrez excuter en lanant le fichier <code>IanniX.sh</code>. IanniX is compatible with Linux, Mac OS X 10.6+ and Windows and does not require any particular installation.
    For Linux users of IanniX who do not build from source, we have included a compiled version that you can run by launching the file IanniX.sh. IanniXApp IanniX est toujours en beta-testing, quelques bugs sont donc encore prsents mais la plupart des fonctionnalits peuvent tre employes correctement. Vous pouvez signaler les erreurs dans la section Bugs de notre <a href='http://iannix.org/fr/community.php'>forum</a>.IanniX is still on beta-testing, some bugs are still present but most features can be used properly. You can report errors in the 'Bugs' section of our forum. IanniXApprAfin de rester compatible avec les stations MIDI, nous avons intgr nativement le protocole MIDI.<br /> Pour les utilisateurs de Windows qui ne possdent pas de priphriques MIDI matriels, vous devez installer un priphrique MIDI virtuel tel que <a href='http://www.nerds.de/data/setuploopbe1.exe'>LoopBe</a>.In order to remain compatible with the MIDI stations, we have integrated the MIDI protocol natively.
    For Windows users who do not have MIDI hardware devices, you must install a virtual MIDI device such as LoopBe. IanniXApp Installation IanniXAppIntroduction Introduction IanniXAppMIDI IanniXApp^Priphrique MIDI cr par IanniX (Mac & Linux)0MIDI device created by IanniX (Mac & Linux only) IanniXAppxMessage MIDI (control change, note on/off ou program change)principauxMain
    elements IanniXApp La gestion des messages est la fonction principale de IanniX. Ils peuvent tre envoys par <b>les curseurs</b> et <b>les triggers</b>.hMessage handling is the main function of IanniX. They can be sent by cursors and triggers. IanniXAppMessagesMessages IanniXAppMessages IP Messages IP IanniXAppPorts IPMessages IP ports IanniXAppContrles MIDIMessages MIDI controls IanniXApp$Priphriques MIDIMessages MIDI devices IanniXAppAdresse OSCMessages OSC addresses IanniXAppProtocolesMessages protocols IanniXAppValeursMessages values IanniXApp ObjetsObjects IanniXAppOpen Sound Control IanniXAppL Open Sound Control est un protocole de communication qui fonctionne sur le rseau IP (donc sur Ethernet, Wi-Fi, sur Internet &). Il est reconnu par tous les systmes d exploitation et ne ncessite pas de drivers ou de configuration rseau. Quelques connaissances en rseau sont toutefois ncessaires pour des usages plus pousss.<br/><br/> La rgle d'or pour l'OSC est de faire correspondre les adresses IP et les ports : un message envoy par IanniX au <code>127.0.0.1:57120</code> signifie qu'il est envoy la machine local sur le port&nbsp;57120. L'application qui veut recevoir ce message devra donc ouvrir le port 57120.Open Sound Control is a communication protocol that operates over the IP network (i.e. Ethernet, Wi-Fi, Internet). It is recognized by all operating systems and requires no drivers or network configuration. Some knowledge of networking is needed to more advanced uses.

    The golden rule about OSC is to match IP addresses and ports: a message sent by IanniX to 127.0.0.1:57120 means that it is sent to the local machine on port  57120. The software that has to receive this message will have to open port 57120. IanniXApp0Message OpenSoundControlOpenSoundControl message IanniXAppZMessage en raw UDP (compatible avec PureData)*Raw UDP message (compatible with PureData) IanniXAppRcursivit Recursion IanniXAppxMessage rcursif/boucle locale (envoy directement IanniX)4Recursive/loopback message (sent directly to IanniX) IanniXAppRfrence Reference IanniXAppScriptsScripts IanniXAppEnvoi d'un bend Send a bend IanniXApp2Envoi d'un control changeSend a control change IanniXApp Envoi d'une note Send a note IanniXApp2Envoi d'un program changeSend a program change IanniXApp4Message srie (UART/RS232)Serial message (UART/RS232) IanniXApp4Interfaces &amp; logicielsSoftware & interfaces IanniXApp|Pour diter le message qu'un objet doit envoyer, cliquez sur 'Edit' dans l'inspecteur aprs avoir slectionn l objet ou double-cliquez sur l objet lui-mme pour faire apparatre la fentre:To edit the message that a element has to send, click on 'Edit' in the inspector after having selected the object or double-click on the object itself to display this window: IanniXAppPour savoir si les messages sont effectivement reus ou envoys, IanniX en affiche une trace dans la section Messages de l'inspecteur.uTo see if the messages are actually sent or received, IanniX displays a trace in the 'Messages' section of inspector. IanniXAppPour positionner un objet dans l'espace, vous disposez de trois mthodes :2To set an object in space, you have three methods: IanniXApp"Suivi de versionsVersion tracking IanniXApp.Nous avons mis votre disposition des patches/interfaces pour les logiciels couramment utiliss que nous avons tests. Cliquez sur le bouton 'Open Patches Folder' de la barre d'outils depuis IanniX pour les dcouvrir.<br/> Il s'agit d'exemples trs simples qui illustrent le principe de communication entre IanniX et les logiciels ; nous vous invitons les modifier et vous en inspirer pour vos projets.WWe have made available patches/interfaces for commonly used software that we have tested. Click on 'Open Patches Folder' from the IanniX toolbar to discover them.
    This is very simple examples that illustrate the principle of communication between IanniX and other software; we invite you to modify them and get inspired for your projects. IanniXApp\Bienvenue et merci d'avoir tlcharg IanniX !-Welcome and thank you for downloading IanniX! IanniXApphMessage XML sur TCP (compatible avec Flash/Director)5XML over TCP message (compatible with Flash/Director) IanniXApp GroupeGroupNxGroup-F<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Arial'; font-weight:400; font-style:normal;"> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">IDATION</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thierry Coduys</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Adrien Lefevre</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gerard Pape (CCMIX)</p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">CONTRIBUTEURS</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Christopher Graham</p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">WEB &amp; IDENTIT</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Matthieu Ranc</p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">DVELOPPEURS IANNIX </span><span style=" font-weight:600; font-style:italic;">(ANCIENNES VERSIONS)</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Adrien Lefevre <span style=" font-style:italic;">(v0.54)</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Guillaume Ferry <span style=" font-style:italic;">(v0.6xx)</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pierre Jullian de la Fuente &amp; Cyrill Duneau <span style=" font-style:italic;">(v0.6xx)</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Matthieu Ranc &amp; Guillaume Jacquemin <span style=" font-style:italic;">(v0.66)</span></p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TESTEURS &amp; CONTRIBUTEURS EXTERNES</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jean Bresson (OpenMusic)</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Paul Crabbe (SuperCollider)</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Francesco (C-Sound)</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cyrille Henry</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thomas Thiery (PureData)</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Romain Vuillet</p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">MERCI </span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Etienne Math (documentation), Joachim Montessuis et tous les utilisateurs pour leur observations et suggestions et l'AFIM (Association Franaise d'Informatique Musicale).</p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Visitez <a href="http://www.iannix.org"><span style=" text-decoration: underline; color:#000000;">http://www.iannix.org</span></a> pour plus d'informations !</p></body></html>

    IDEATION

    Thierry Coduys

    Adrien Lefevre

    Gerard Pape (CCMIX)

    CONTRIBUTORS

    Christopher Graham

    WEB & IDENTITY

    Matthieu Ranc

    IANNIX DEVELOPERS (FORMER VERSIONS)

    Adrien Lefevre (v0.54)

    Guillaume Ferry (v0.6xx)

    Pierre Jullian de la Fuente & Cyrill Duneau (v0.6xx)

    Matthieu Ranc & Guillaume Jacquemin (v0.66)

    TESTERS & EXTERNAL CONTRIBUTORS

    Jean Bresson (OpenMusic)

    Paul Crabbe (SuperCollider)

    Francesco (C-Sound)

    Cyrille Henry

    Thomas Thiery (PureData)

    Romain Vuillet

    THANKS TO

    Etienne Mathé (documentation), Joachim Montessuis and all users for their observations and suggestions and AFIM (Association Française d'Informatique Musicale).

    Visit http://www.iannix.org for more information !

    UiAboutz<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Arial'; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">CHEF DE PROJET</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thierry Coduys</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">DVELOPPEMENT</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Guillaume Jacquemin</p></body></html>>

    PROJECT MANAGER

    Thierry Coduys

    DEVELOPPEMENT

    Guillaume Jacquemin

    UiAbout$ propos de IanniX About IanniXUiAboutbetaUiAboutversionUiAbout FermerCloseUiEditorCtrl+SUiEditorCtrl+WUiEditorIanniXUiEditor6IanniX  diteur de scriptsIanniX — Script EditorUiEditorSauvegarderSaveUiEditor$diteur de scripts Script EditorUiEditorEXEMPLEEXAMPLEUiHelp4IMPLMENTER DANS LE SCRIPTIMPLEMENT IN SCRIPTUiHelpAide de IanniX IanniX HelperUiHelpSNIPPETSNIPPETUiHelpSYNTAXESYNTAXUiHelp$%1 client connect%1 clients connected UiInspector01 - Boucle sur la courbe1 - Loop on curve UiInspectorV1 -1 - Aller/retour sur la courbe en boucle1 -1 - Loop roundtrip on curve  UiInspectorF1 -1 0 - Aller/retour sur la courbe#1 -1 0 - Single roundtrip on curve  UiInspectorN1 0 - Une seule itration sur la courbe1 0 - One run on curve UiInspector|1 2 0 - Une itration normale, puis une autre vitesse double/1 2 0 - One normal run, another at double speed UiInspector"1 client connect1 client connected UiInspector=> UiInspector ACTIFACTIVE UiInspectorUn autre objet possde dj cet ID. Essayez de supprimer cet objet ou changez son ID.GAnother object has this ID. Try deleting that object, or change its ID. UiInspectorDBUTE  BEGINS FROM UiInspector&CAMRA SUIT L'OBJETCAMERA FOLLOWS OBJECT ID UiInspectorCOULEURSCOLORS UiInspectorCURSEURCURSOR UiInspector*RPTITION DU CURSEURCURSOR LOOP PATTERN UiInspector VITESSE GNRALECURSOR MASTER SPEED UiInspector(OFFSETS DES CURSEURSCURSOR OFFSETS UiInspector2TAILLE (L / P) DU CURSEURCURSOR WIDTH / DEPTH UiInspector$VITESSE DU CURVEURCURSOR SPEED or LENGTH UiInspectorCURSEURSCURSORS UiInspector COURBECURVE UiInspector&POINTS DE LA COURBE CURVE POINTS UiInspectorCOURBESCURVES UiInspectorDID l'objet suivre avec la camraCamera Follow ID UiInspector8Impossible de modifier l'ID.Can't change ID. UiInspectorzModifier ici les coordonnes absolues des objets slectionns8Change here the absolute coordinates of selected objects UiInspectorModifier ici la couleur des objets ACTIFS qui N'ENVOIENT PAS de messagesOChange here the color of objects that are ACTIVE and that DOESN'T SEND messages UiInspectorModifier ici la couleur des objets ACTIFS qui ENVOIENT des messagesGChange here the color of objects that are ACTIVE and that SEND messages UiInspectorModifier ici la couleur des objets INACTIFS qui N'ENVOIENT PAS de messagesQChange here the color of objects that are INACTIVE and that DOESN'T SEND messages UiInspectorModifier ici la couleur des objets INACTIFS qui ENVOIENT de messagesIChange here the color of objects that are INACTIVE and that SEND messages UiInspectorJModifier ici la profondeur du curseurChange here the cursor depth UiInspectorModifier ici la vitesse gnrale du curseur (1.00 = vitesse nominale) (vitesse total = vitesse gnrale x vitesse du curseur)fChange here the cursor master speed factor (1.00 = nominal speed) (total speed = master speed x speed) UiInspector|Modifier ici la dure d'une itration du curseur sur la courbe0Change here the cursor run duration on the curve UiInspectorxModifier ici la vitesse du curseur (1.00 = vitesse nominale):Change here the cursor speed factor (1.00 = nominal speed) UiInspectorBModifier ici la taille du curseurChange here the cursor width UiInspectorJModifier ici la dure d'une note MIDI'Change here the duration of a MIDI note UiInspectorModifier ici l'offset initial (premire itration du curseur sur la courbe). Un offset initial positif signifie que le curseur dmarre sur la courbe une position donnes ; un offset initial ngatif signifie que le curseur dmarre avec un retard.Change here the initial offset (first iteration of a cursor on a curve). Positive initial offset means that cursor will start from a position on the curve whereas negative initial offset means that cursor start will be delayed. UiInspectorModificer ici le Z maximum afficher. Les objets avec un Z suprieurs ne seront pas visibles.bChange here the maximum displayable Z-value. Objects with a higher Z values will not be displayed. UiInspectorModificer ici le Z minimum afficher. Les objets avec un Z infrieur ne seront pas visibles.aChange here the minimum displayable Z-value. Objects with a lower Z values will not be displayed. UiInspector`Modifier ici la priodicit des messages envoys/Change here the periodicity of emitted messages UiInspector\Modifier ici la taille des objets slectionns(Change here the size of selected objects UiInspectorModifier ici l'offset de fin dfinissant le point de fin de boucle sur la courbeOChange here the start offset of a cursor defining the loop end point on a curve UiInspectorModifier ici l'offset de dmarrage dfinissant le point de dpart d'une boucle sur la courbeQChange here the start offset of a cursor defining the loop start point on a curve UiInspector`Modofier ici l'paisseur des objets slectionns,Change here the tickness of selected objects UiInspectorModifier ici les valeurs pour le mapping des les coordonnes graphiquesDChange here the values for the graphical mapping of cursors position UiInspectorCocher cette case si vous souhaitez synchroniser l'horloge avec un autre squenceurBCheck this option if you want to sync clock from another sequencer UiInspector Cocher cette case si vous souhaitez synchroniser le transport (play, pause, stop, retour zro, position temporelle) depuis un autre squenceurvCheck this option if you want to sync transport (play, pause, stop, fast rewind, song position) from another sequencer UiInspector`Cliquer ici pout modifier le group ID de l'objet/Click here to change the group ID of the object UiInspector`Cliquer ici pour modifier l'ID unique de l'objet0Click here to change the unique ID of the object UiInspectorCliquer ici pour dsactiver le solo de tous les groups de la partition=Click here to disable solo of all groups of the current score UiInspectorCliquer ici pour dsactiver le solo de tous les objets de la partition>Click here to disable solo of all objects of the current score UiInspectorCliquer ici pour diter le(s) message(s) envoy(s) par les objets slectionns;Click here to edit the message send by the selected objects UiInspectorzCliquer ici pour activer/dsactiver l'objet dans la partition4Click here to enable/disable the object on the score UiInspector|Cliquer ici estomper les courbes non parcourues par un curseur@Click here to light on/off curves on which no cursor are running UiInspectorCliquer ici pour afficher/cacher les curseurs de la partition courante4Click here to show/hide cursors of the current score UiInspectorCliquer ici pour afficher/cacher les courbes de la partition courante3Click here to show/hide curves of the current score UiInspectorCliquer ici pour afficher/cacher les triggers de la partition courante5Click here to show/hide triggers of the current score UiInspectorpCliquer ici pour activer tous les objets de la partition8Click here to switch on all objects of the current score UiInspectorvCliquer ici pour dsactiver tous les objets de la partition;Click here to switch on of all objects of the current score UiInspector.Cliquer sur une ligne pour slectionner un groupe de la partition. Cocher les cases pour activer/dsactiver ou mettre en solo un groupe de la partitionClick on a row to highlight and select groups in score. Click on checkboxes to switch on/off and solo groups of the current score UiInspector*Cliquer sur une ligne pour slectionner un objet de la partition. Cocher les cases pour activer/dsactiver ou mettre en solo un objet de la partitionClick on a row to highlight and select object in score. Click on checkboxes to switch on/off and solo objects of the current score UiInspector8IP PAR DFAUT (ALIAS IP_OUT)DEFAULT IP (ALIAS IP_OUT) UiInspector@MIDI PAR DFAUT (ALIAS MIDI_OUT)!DEFAULT MIDI OUT (ALIAS MIDI_OUT) UiInspector*Adresse IP par dfautDefault IP address UiInspector8Priphrique MIDI par dfautDefault MIDI device UiInspectorFDsactiver le solo pour les groupesDisable solo for all groups UiInspectorDDsactiver le solo pour les objetsDisable solo for all objects UiInspector8Afficher/cacher les curseursDisplay/hide cursors UiInspector6Afficher/cacher les courbesDisplay/hide curves UiInspector8Afficher/cacher les triggersDisplay/hide triggers UiInspector DITEREDIT UiInspectorAccleration Easing UiInspector2Entrez le nom du groupe :(Enter the name of the destination group: UiInspector>Entez le nouvel ID de l'objet :Enter the new ID: UiInspectorFICHIERSFILES UiInspectorVOLUE DE GOES FROM UiInspector GROUPEGROUP UiInspectorGROUP ID UiInspectorGROUPESGROUPS UiInspectorPORT HTTP IN HTTP IN PORT UiInspector"Port entrant HTTP HTTP in port UiInspectorIDID UiInspector ID / GROUP ID UiInspector INFOSINFOS UiInspector,Inspecteur de couleursIanniX Color Inspector UiInspector"Inspecteur IanniXIanniX Inspector UiInspector&IanniX  InspecteurIanniX — Inspector UiInspector NumroIndex UiInspectorTIQUETTELABEL UiInspectorDESTOMPER LES COURBES NON UTILISESLIGHT OFF UNUSED CURVES UiInspectorBAttnue les courbes non utilisesLight off unused curves UiInspectorLList de toutes les partitions (depuis le projet et depuis les dossiers IanniX). Double-cliquer pour ouvrir une partition. Clic-droit pour afficher le menu contextuel.List of available scores (from your project folder and from IanniX folders). Double-click to open a score. Right-click to show contextual menu. UiInspector@Liste de tous les scripts (depuis le projet et depuis les dossiers IanniX). Double-cliquer pour excuter un script. Clic-droit pour afficher le menu contextuel.List of available scripts (from your project folder and from IanniX folders). Double-click to launch a script. Right-click to show contextual menu. UiInspector Liste des objetsList of objects UiInspector"Liste des groupesList of objects group name UiInspectorAffiche les messages reus (ralentit IanniX si affich en permanence)HLogs all the received messages (will slow down IanniX if kept on-screen) UiInspectorAffiche les messages envoys (ralentit IanniX si affich en permanence)DLogs all the sent messages (will slow down IanniX if kept on-screen) UiInspector2BUNDLE OSC POUR L'IP/PORTMAKE OSC BUNDLE ON UiInspector=> VALEURS DE MAPPED RANGE UiInspectorMESSAGESMESSAGES UiInspector2TEMPO MIDI (HORLOGE MIDI)MIDI TEMPO (FOR CLOCK SYNC.) UiInspector SOURISMOUSE UiInspectorSOURIS : MOUSE: UiInspectorNPosition de la souris dans la partitionMouse current position on score UiInspector*Position de la sourisMouse position UiInspector RSEAUNETWORK UiInspector(CONFIGURATION RSEAUNETWORK CONFIGURATION UiInspector2AUCUN LMENT SLECTIONNNO ITEMS SELECTED UiInspector,Aucune client connectNo client connected UiInspector OBJETSOBJECTS UiInspector ON/OFFON/OFF UiInspectorPORT OSC IN OSC IN PORT UiInspector*Adresse du bundle OSCOSC bundle address UiInspector$Port du bundle OSCOSC bundle port UiInspector Port entrant OSC OSC in port UiInspectorPOSITION (X / Y / Z) UiInspectorPORT RAW UDP INRAW UDP IN PORT UiInspectorMESSAGES REUSRECEIVED MESSAGES UiInspector*Port entrant UDP brutRaw UDP in port UiInspectorMessages reusReceived messages UiInspectorSS UiInspectorPARTITIONSSCORES UiInspector8SCRIPTS && FEUILLES DE STYLESCRIPTS & STYLES UiInspectorENVOY CHAQUE SENT EACH UiInspector MESSAGES ENVOYS SENT MESSAGES UiInspectorPORT SRIE SERIAL PORT UiInspectorTAILLE (L / H) SIZE (W / H) UiInspector2MESSAGE DE SYCHRONISATION SYNC MESSAGE UiInspectorSYNC HORLOGE SYNC CLOCK UiInspectorSYNC TRANSPORT UiInspector&BPM de la partition Score BPM UiInspector:Zoom actuel dans la partitionScore current zoom UiInspector(Liste des partitions Scores list UiInspector"Liste des scripts Scripts list UiInspectorSlectionner ici le courbe d'acclration du curseur du la courbe.Select here the cursor acceleration on a curve UiInspector Messages envoys Sent messages UiInspector*Adresse du port srieSerial port address UiInspectorLissageSmooth UiInspector.Active tous les groupesSwitch on all groups UiInspector,Active tous les objetsSwitch on all objects UiInspector4Message de synchronisation Sync message UiInspector,PORT TCP/XML SERVER INTCP/XML SERVER IN PORT UiInspector>Port entrant du serveur TCP/XMLTCP/XML Server in port UiInspectorPAISSEUR THICKNESS UiInspectorTO UiInspector(MESSAGE DE TRANSPORTTRANSPORT MESSAGE UiInspectorTRIGGERTRIGGER UiInspector TEMPS DE RELCHETRIGGER OFF-TIME UiInspectorTRIGGERSTRIGGERS UiInspectorTYPETYPE UiInspector(Message de transportTransport message UiInspectordTaper ici l'tiquette pour les objets slectionns&Type here a label for selected objects UiInspectorTaper ici le BPM utilis pour la synchronisation des horologes MIDI/Type here the BPM (used by MIDI clock for sync) UiInspectorPTaper ici le numro du port entrant HTTP!Type here the HTTP in port number UiInspectorbTaper ici l'ID de l'objet suivre avec la camra:Type here the ID of the object that the camera will follow UiInspectorTaper ici l'adresse IP sortante des messages OSC mettre en bundles.tType here the IP address number associated to bundled messages. All OSC messages using this IP/port will be bundled. UiInspectorNTaper ici le numro du port entrant OSC Type here the OSC in port number UiInspectorVTape ici le port entrant du serveur TCP/XML+Type here the TCP/XML Server in port number UiInspectorTaper ici la configration du port srie (syntaxe : port name:baud rate:data bits:parity:stop bits:flow control)vType here the configuration of your serial port (syntax : port name:baud rate:data bits:parity:stop bits:flow control) UiInspectorTaper ici l'adresse IP par dfaut utilise pour les messages contenant le mot-clef ip_outOType here the default IP address used by messages containing the keyword ip_out UiInspectorTaper ici le priphrique MIDI par dfaut utilis pour les messages contenant le mot-clef midi_outRType here the default MIDI device used by messages containing the keyword midi_out UiInspectorlTaper ici le message envoyer pour la synchronisation?Type here the message that will be sent when clicking on "Sync" UiInspectorTaper ici le message envoyer quand le playback change d'tat (play, pause, retour zro)_Type here the message that will be sent when playback status changed (play, pause, fast rewind) UiInspectorzTaper ici les coordonnes des points (x, y, z) et les points de contrle de Bzier (c1x, c1y, c1z, c2x, c2y, c2z). Les cases cocher permette d'activer un lissage automatique de la courbe.Type here the points coordinates (x, y, z) and the Bezier control points (c1x, c1y, c1z, c2x, c2y, c2z). Checkboxes allow you to activate automatic smoothing or not. UiInspectorTaper ici le numro du port sortant des messages OSC mettre en bundles.nType here the port number associated to bundled messages. All OSC messages using this IP/port will be bundled. UiInspectorVTaper ici le numro du port entrant raw UDP$Type here the raw UDP in port number UiInspectorvTaper ici des vitesses de curseurs spares par des espaces/Type here the speed pattern separated by spaces UiInspector$MAPPING DE VALEURS VALUE MAPPING UiInspector$AFFICHAGE DES Z DE Z-RANGE FROM UiInspector,Borne des Z afficherZ-range values UiInspectorZOOMZOOM UiInspectorZOOM : ZOOM: UiInspectorZoomZoom UiInspectorc1x UiInspectorc1y UiInspectorc1z UiInspectorc2x UiInspectorc2y UiInspectorc2z UiInspectorpas d'objets no objects UiInspector la finthe end UiInspectorxx UiInspectorx VOLUE DEx RANGE UiInspectoryy UiInspectory VOLUE DEy RANGE UiInspectorzz UiInspectorz VOLUEz RANGE UiInspector,ENTRER UNE VALEUR POURENTER A VALUE FOR UiMessageBox IanniXIanniX UiMessageBox IMAGEPICTURE UiMessageBox.Cliquer pour ajouter des points. Double-click ou ESC pour finir une courbe. Ensuite, Double-clic sur la courbe pour ajouter un point, Command+click pour le supprimer, Double-click sur un point pour activer/dsactiver le lissage. Shift+double-click pour rchantilloner la courbe.Click on score to add points. Double-click or press ESC to end your curve. After, Double-click on a curve to add a point, Command+click to remove it, Double-click on a point to enable/disable smoothing. Shift+double-click to resample curve.UiRender.Cliquer pour ajouter des points. Double-click ou ESC pour finir une courbe. Ensuite, Double-clic sur la courbe pour ajouter un point, Control+click pour le supprimer, Double-click sur un point pour activer/dsactiver le lissage. Shift+double-click pour rchantilloner la courbe.Click on score to add points. Double-click or press ESC to end your curve. After, Double-click on a curve to add a point, Control+click to remove it, Double-click on a point to enable/disable smoothing. Shift+double-click to resample curve.UiRenderCliquer-dplacer/mollette pour naviguer/zoomer dans la partition. En 3D, Alt+dplacer/Alt+molette et Alt+double-click pour dplacer la camra. Double-clic sur un objet pour diter ses messages. Shift+double-click sur un objet pour forcer un envoi de message.Click+move and mouse wheel to navigate/zoom in score. In 3D, Alt+move, Alt+mouse wheel and Alt+double-click to change camera position. Double-clic on an object to edit messages. Shift+double-clic on an object to force its messages to be sent.UiRender4Rchantionnage de courbesIanniX Curve ResampleUiRenderIanniX  RenduIanniX — RenderUiRender.Glisser-dposer d'image Image drop…UiRender Image_%1.pngUiRender$Nombre de points :Number of points:UiRenderZVeuillez slectionner une action raliser :!Please select the desired action:UiRenderZEssayer de vectoriser automatiquement l'image(Try to vectorize this image automaticalyUiRender^Utiliser cette image comme fond de la partitionUse this image as a backgroundUiRenderIanniXUiSplashbetaUiSplashversionUiSplash 000:00.000UiTimerIanniX - TimerUiTimer$ propos de IanniX About IanniX UiTransportUsage CPU CPU usage UiTransport|Modifier ce champ pour ajuster la vitesse gnrale du playback7Change this spinbox to adjust the global playback speed UiTransportzCliquer ici pour afficher les informations relatives IanniX.Click here to display information about IanniX UiTransportCliquer ici pour activer ou dsactiver la sortie vido dans Syphon (protocole d'change d'image entre applications Mac OS)XClick here to enable or disable Syphon output (video frame exchange between Mac OS apps) UiTransportAffiche le nombre d'images par secondes. Vous pouvez aussi changer la valeur directement dans le champ`Displays of the number of frames per seconds or type directly in this box to change it manually  UiTransportTemps coul Elapsed time UiTransportRetour zro Fast rewind UiTransport&Images par secondesFrames per seconds UiTransportIanniX — Transport UiTransport~Dplacer le slider pour ajuster la vitesse gnrale du plauback4Move this slider to adjust the global playback speed UiTransportPas de message No message UiTransport Play/pause UiTransport&Vitesse du playbackPlayback speed UiTransportRAppuyer sur ce bouton pour revenir zro-Press this button to fast rewind the playback UiTransportAppuyer sur ce bouton pour dmarrer ou mettre en pause le playback0Press this button to start or pause the playback UiTransportFAffiche l'utilisation CPU de IanniXReport of the CPU usage UiTransportbAffiche le temps coul entre deux calculs de la partition (positions des curseurs et dclenchements des triggers). Vous pouvez aussi changer la valeur directement dans le champ_Report of the time between two calculations or type directly in this box to change it manually  UiTransport(Priode du schedulerScheduler period UiTransport Messages envoys Sent messages UiTransportSyphon UiTransport|Cette zone affiche le temps coul depuis le dbut du playbackEThis area display the elapsed time from the beginning of the playback UiTransportdCette zone affiche les messages envoys par IanniX.This area displays the sent messages by IanniX UiTransport%1 x %2UiView1 seconde1 secondUiView 10 millisecondes10 millisecondsUiView10 secondes 10 secondsUiView10% d'opacit 10% opaqueUiView"100 millisecondes100 millisecondsUiView100% d'opacit 100% opaqueUiView25% d'opacit 25% opaqueUiView50% d'opacit 50% opaqueUiView"500 millisecondes500 millisecondsUiView75% d'opacit 75% opaqueUiView$ propos de IanniX About IanniXUiView$Ajouter un curseur Add a cursorUiView:Ajouter une courbe circulaireAdd circular curvesUiView(Ajouter des triggers Add triggersUiViewAligner en bas Align bottomUiView"Aligner au centre Align centerUiView.Aligner horizontalementAlign horizontallyUiView Aligner gauche Align leftUiView"Aligner au milieu Align middleUiView Aligner droite Align rightUiViewAligner en haut Align topUiView*Aligner verticalementAlign verticallyUiViewFAutoriser la slection des curseursAllow cursors selectionUiViewDAutoriser la slection des courbesAllow curves selectionUiViewFAutoriser la slection des triggersAllow triggers selectionUiView$Aligner les objetsArrange objectsUiViewPRedimensionnement automatique des objetsAutoresize objectUiView BackspaceUiViewCliquer ici pour ajouter et dessiner une courbe lisse dans la partition. Appuyer sur ESC ou recliquer ici pour finir la courbe.dClick here to add and draw a smooth curve in your score. Press ESC or click again to end your curve.UiViewCliquer ici pour ajouter et dessiner une courbe dans la partition. Appuyer sur ESC ou recliquer ici pour finir la courbe.fClick here to add and draw a straight curve in your score. Press ESC or click again to end your curve.UiViewCliquer ici pour ajouter une courbe circlaire dans la partition. Appuyer sur ESC ou recliquer ici pour finir la courbe.iClick here to add circular curves in your score. Press ESC or click again to stop adding circular cuvers.UiViewVCliquer ici pour ajouter des curseurs sur la courbe slectionne. Si aucune courbe est slectionne, le curseur sera libre (contrl par exemple depuis une source externe)Click here to add cursors on the selected curve. If no curve is selected, cursor will be free (controlled by an external source)UiViewCliquer ici pour ajouter des triggers dans la partition. Appuyer sur ESC ou recliquer ici pour terminer l'ajout.[Click here to add triggers in your score. Press ESC or click again to stop adding triggers.UiViewlCliquer ici pour aligner les objets en forme de cercle'Click here to align objects as a circleUiViewlCliquer ici pour aligner les objets en forme d'ellipse)Click here to align objects as an ellipseUiViewvCliquer ici pour aligner les objets sur l'objet le plus bas4Click here to align objects on the bottommost objectUiViewCliquer ici pour aligner les objets sur le centre de la slectionEClick here to align objects on the horizontal center of the selectionUiViewCliquer ici pour aligner les objets sur l'objet le plus gauche2Click here to align objects on the leftmost objectUiViewCliquer ici pour aligner les objets sur l'objet le plus droite3Click here to align objects on the rightmost objectUiViewxCliquer ici pour aligner les objets sur l'objet le plus haut1Click here to align objects on the topmost objectUiViewCliquer ici pour aligner les objets sur le milieu de la slectionCClick here to align objects on the vertical center of the selectionUiViewCliquer ici pour autoriser/interdire la slection des curseurs (sur toutes les actions de slection)kClick here to allow/forbid the selection of cursors (on hover, on marquee selection, on select all actions)UiViewCliquer ici pour autoriser/interdire la slection des courbes (sur toutes les actions de slection)jClick here to allow/forbid the selection of curves (on hover, on marquee selection, on select all actions)UiViewCliquer ici pour autoriser/interdire la slection des triggers (sur toutes les actions de slection)lClick here to allow/forbid the selection of triggers (on hover, on marquee selection, on select all actions)UiViewnCliquer ici pour changer le thme de couleurs de IanniX.Click here to change the color theme of IanniXUiViewxCliquer ici pour copier et supprimer les objets slectionns.Click here to copy and remove selected objectsUiViewCliquer ici pour copier les objets slectionns dans le presse-papier0Click here to copy selected objects in clipboardUiViewCliquer ici pour copier le script gnrant les objets slectionns dans le presse-papierCClick here to copy selected objects in clipboard as script commandsUiViewfCliquer ici pour crer un nouvelle partition vierge&Click here to create a new empty scoreUiViewzCliquer ici pour afficher l'aide de IanniX dans le navigateur1Click here to display IanniX help in your browserUiViewjCliquer ici pour afficher des informations sur IanniX.Click here to display information about IanniXUiViewCliquer ici pour rpartir les objets horizontalement, de l'objet le plus gauche l'objet le plus droite^Click here to distribute objects horizontally from the leftmost object to the rightmost objectUiViewCliquer ici pour rpartir les objets verticalement, de l'objet le plus haut l'objet le plus bas\Click here to distribute objects vertically from the topmost object to the bottommost objectUiViewdCliquer ici pour dupliquer les objets slectionns(Click here to duplicate selected objectsUiViewNCliquer ici pour dupliquer la partition9Click here to duplicate your score in your project folderUiViewXCliquer ici pour remettre zro le playback&Click here to fast rewind the playbackUiViewZCliquer ici pour afficher/cacher l'inspecteur'Click here to hide/show inspector panelUiViewlCliquer ici pour afficher/cacher la barre de transport'Click here to hide/show transport panelUiView|Cliquer ici pour importer une courbe partir d'un fichier SVG8Click here to import a SVG file as a curve in your scoreUiViewVCliquer ici pour importer une image de fond5Click here to import a background image in your scoreUiViewrCliquer ici pour importer une courbe partir d'un glyphe5Click here to import a glyph as a curve in your scoreUiViewCliquer ici pour importer une courbe partir d'une image vectorise automatiquement9Click here to import image to be vectorized in your scoreUiViewCliquer ici vrouiller/dvrouiller la position des objets (pour viter de dplacer les objets en naviguant dans la partition)iClick here to lock/unlock the position of objects (to avoid moving objects while navigating in the score)UiViewbCliquer ici pour ouvrir le dossier des partitions%Click here to open a folder of scoresUiViewCliquer ici pour le dossier des patches (objets pour les logiciels htes) fourni avec IanniX`Click here to open the patches folder (external objects for hosts software) provided with IanniXUiViewfCliquer ici pour coller les objets du presse-papier1Click here to paste copied objects from clipboardUiViewxCliquer ici pour coller du script provenant du presse-papierTClick here to paste scripts commands from clipboard (a script must be loaded before)UiViewpCliquer ici pour dmarrer ou mettre en pause le playback(Click here to play or pause the playbackUiView>Cliquer ici pour quitter IanniXClick here to quit IanniXUiViewVCliquer ici pour rpter la dernire actionClick here to redo last actionUiViewHCliquer ici pour recharger le script'Click here to reload the current scriptUiViewdCliquer ici pour supprimer les objets slectionns%Click here to remove selected objectsUiViewbCliquer ici pour supprimer la partition du projet8Click here to remove this score from your project folderUiViewLCliquer ici pour renommer la partitionClick here to rename your scoreUiViewCliquer ici pour redimensionner automatiquement les objets en fonction du zoom/Click here to rescale objects according to zoomUiViewJCliquer ici pour redimensionner la partition (zone de rendu). Il est recommend de cacher l'inspecteur ainsi que la barre de transport pour obtenir la taille exacte.Click here to resize the viewport (the rendering area). Note that it is recommended to hide Transport bar and Inspector bar to get the exact desired size.UiViewVCliquer ici pour restaurer le zoome initial"Click here to restore initial zoomUiViewvCliquer ici pour sauvegarder toutes les partitions ouvertes(Click here to save all the opened scoresUiViewdCliquer ici pour sauvegarder la partition courante$Click here to save the current scoreUiViewCliquer ici pour exporter la vue courant dans un PNG haute-rsolution (le fichier sera plac sur le bureau)gClick here to save the current view in a high resolution PNG file (file will be placed on your desktop)UiViewCliquer ici pour slectionner tous les objetsn slectionnables de la partition ExtKinectManager IanniX Kinect ExtMidiManager MIDI %1 on ch. %2, send note(%3)=%4 MIDI %1 sur ch. %2, note(%3)=%4 MIDI %1 on ch. %2, send CC(%3)=%4 MIDI %1 sur ch. %2, CC (%3)=%4 MIDI %1 on ch. %2, send PGM=%3 MIDI %1 sur ch. %2, PGM=%3 MIDI %1 on ch. %2, send bend=%3 MIDI %1 sur ch. %2, bend=%3 ExtOscPatternAsk IanniX — Message editor IanniX — Éditeur de messages ADD A NEW MESSAGE AJOUTER UN NOUVEAU MESSAGE REMOVE CURRENT MESSAGE SUPPRIMER LE MESSAGE Message %1 EN FR ExtOscPatternEditor IanniX osc://ip_out:57120/cursor cursor_id cursor_value_x cursor_value_y cursor_xPos cursor_yPos cursor_zPos - Default OSC message for cursors osc://ip_out:57120/cursor cursor_id cursor_value_x cursor_value_y cursor_xPos cursor_yPos cursor_zPos - Message OSC par défaut pour les curseurs midi://midi_out/note 0 69 127 5 - Play a MIDI note (A - 440Hz) during 5 seconds on channel #0 midi://midi_out/note 0 69 127 5 - Joue une note MIDI (LA - 440Hz) pendant 5 secondes sur le canal #0 midi://midi_out/cc 1 0 cursor_value_y - Send a MIDI control change on controler #0 on channel #1 depending on cursor position midi://midi_out/cc 1 0 cursor_value_y - Envoie un control change MIDI depuis le contrôleur #0 sur le canal #1, suivant la valeur du curseur direct:// setSpeedF 10 1 - Make the cursor #10 start (please set its Master Speed to 0 before) direct:// setSpeedF 10 1 - Démarre le curseur #10 (il faut mettre au préalable la vitesse générale du curseur à 0) Clear the message Effacer le message Click here to clear the message Cliquer ici pour effacer le message X X learn learn SEND THROUGH ENVOYER SUR Select here the protocol used to transmit message Sélectionnez ici un protocole pour envoyer le messager Templates Modèles direct:// goto 2 - Make score go back to timecode 000:02.000 direct:// goto 2 - Fait revenir le playback au timecode 000:02.000 osc://ip_out:57120/trigger trigger_id trigger_xPos trigger_yPos trigger_zPos cursor_id - Default OSC message for triggers osc://ip_out:57120/trigger trigger_id trigger_xPos trigger_yPos trigger_zPos cursor_id - Message OSC par défaut pour les triggers osc://ip_out:57120/cursor cursor_id cursor_value_x cursor_value_y cursor_xPos cursor_yPos cursor_zPos - Default OSC message for curves osc://ip_out:57120/cursor cursor_id cursor_value_x cursor_value_y cursor_xPos cursor_yPos cursor_zPos - Message OSC par défaut pour les curseurs midi://midi_out/note 0 69 127 5 - Play a MIDI note (A - 440Hz) during 5 seconds midi://midi_out/note 0 69 127 5 - Joue une note MIDI (LA - 440Hz) pendant 5 secondes midi://midi_out/cc 0 20 cursor_value_y - Send a MIDI control change on controler #20 depending on cursor position midi://midi_out/cc 0 20 cursor_value_y - Envoie un control change MIDI depuis le contrôleur #20, suivant la valeur du curseur direct:// setSpeedF 10 1 - Make the cursor #10 start (please set its speedF parameter to 0 before) direct:// setSpeedF 10 1 - Démarre le curseur #10 (il faut mettre au préalable le Master Speed du curseur à 0) TO HOST VERS L'HOTE Select or type the destination application/host IP Selectionner ou taper l'application ou l'IP destination ON PORT SUR LE PORT Select or type the destination application/host port number Selectionner ou taper l'application/numéro de port de destination TO ADDRESS VERS L'ADRESSE Select or type an OSC address to reach Selectionner ou taper l'adresse OSC à atteindre TO MIDI DEVICE VERS Select or type a MIDI device to reach Selectionner ou taper le périphérique MIDI à atteindre TO CONTROL CONTRÔLE Select here a MIDI control Selectionner ici un contrôle MIDI VALUE 1 VALEUR 1 Type here a IanniX variable or your custom value Clear the value Effacer la valeur Click here to clear the value Cliquer ici pour effacer la valeur VALUE 2 VALEUR 2 VALUE 3 VALEUR 3 VALUE 4 VALEUR 4 VALUE 5 VALEUR 5 VALUE 6 VALEUR 6 VALUE %1 VALEUR %1 QUERY ARG. %1 MIDI CHANNEL CANAL MIDI NOTE NUMBER NUMÉRO NOTE VELOCITY VELOCITÉ DURATION DURÉE PROGRAM ID ID PROGRAMME CONTROLLER ID ID CONTRÔLLEUR VALUE VALEUR COMMAND %1 COMMANDE %1 XML NODE %1 NOEUD XML %1 MIDI/OSC learn Apprentissage MIDI/OSC Please send an event to IanniX Move a slider on your surface control or press a MIDI note… Veuillez envoyer un événement à IanniX Bougez un slider sur votre interface de contrôle ou appuyez sur une note MIDI ExtScriptManager Filename conflict Conflit de nom de fichiers The file can't be renamed! A file with this name exists in your project. Ce fichier ne peut pas être renommé ! Un fichier avec le même nom existe déjà dans votre projet. ExtScriptVariableAsk IanniX PLEASE ENTER VALUES TO LAUNCH SCRIPT: SAISIE DES VARIABLES DE SCRIPT : List of script variables Liste des variables de scripts Double-click on a column to change a value Double-cliquer sur une case pour changer sa valeur VARIABLE VARIABLE VALUE VALEUR ExtTcpManager New TCP client connected Nouveau clien TCP connecté IanniX CURRENT PROJECT PROJET COURANT TOOLS OUTILS EXAMPLES EXEMPLES SVG Import Import SVG Coordinates systems are different. Please enter a scale factor: Les systèmes de coordonnées sont différents. Merci de saisir un facteur de taille : Image import Import d'image Text import Import de texte IanniX Update Center Mises à jour de IanniX A new version of IanniX is available Une nouvelle version de IanniX est disponible Would you like to update IanniX with the new version ? Voulez-vous mettre à jour IanniX avec la nouvelle version ? New score Nouvelle partition Enter the name of your new score: Veuillez entrer un nom pour la nouvelle partition : Filename conflict Conflit de nom de fichiers The file can't be created! A file with this name exists in your project. Ce fichier ne peut pas être créé ! Un fichier avec le même nom existe déjà dans votre projet. New script Nouveau script Enter the name of your new script: Veuillez entrer un nom du nouveau script : Open IanniX Project Folder Ouvrir un projet IanniX File rename Renommage de fichier New name of script: Nouveau nom du script : The file can't be renamed! A file with this name exists in your project. Ce fichier ne peut pas être renommé ! Un fichier avec le même nom existe déjà dans votre projet. File remove Suppression de fichier The file will be removed from your disk. Are you sure? Le fichier va être supprimé de votre disque. Êtes-vous sûr ? File duplication Dupplication de fichier Enter the desired name of the duplicated score Entrer le nom de la partition duppliquée IanniX Open a project Ouvrir un projet New Nouveau Duplicate Dupliquer Rename Renommer Remove Supprimer Click here to open a project folder Cliquez ici pour ouvrir un projet Click here to create a new score Cliquer ici pour créer une nouvelle partition Click here to duplicate the score to a new one Cliquer ici pour dupliquer la partition Click here to rename the score Cliquer ici pour renommer la partition Click here to remove the score from project folder Cliquer ici pour supprimer la partition du projet Name of duplicate script: Nom du script duppliqué : Run Exécuter Open Ouvrir Open with default external editor Ouvrir avec l'éditeur par défaut Click here to run this script Cliquer ici pour exécuter le script Click here to create a new script Cliquer ici pour créer un nouveau script Click here to duplicate the script to a new one Cliquer ifi pour dupliquer le script Click here to rename the script Cliquer ici pour renommer le script Click here to remove the script from project folder Cliquer icc pour supprimer le script du projet Script: has a s have s ont Score save Enregistrer des partitions %1 document%2 been changed without saving. Do you want to save modifications? %1 document%2 été modifié(s) sans être sauvegardé(s). Voulez-vous enregistrer les modifications ? IanniXApp Messages protocols Protocoles OpenSoundControl message Message OpenSoundControl Recursive/loopback message (sent directly to IanniX) Message récursif/boucle locale (envoyé directement à IanniX) MIDI message (control change, note on/off or program change) Message MIDI (control change, note on/off ou program change) Serial message (UART/RS232) Message série (UART/RS232) HTTP request to a webpage/webservice (GET) Requête vers une page web/webservice (GET) Raw UDP message (compatible with PureData) Message en raw UDP (compatible avec PureData) XML over TCP message (compatible with Flash/Director) Message XML sur TCP (compatible avec Flash/Director) Messages IP Messages IP Destination is the default IP set in "Network" tab IP par défaut (saisie dans l'onglet "Network") Destination is your own computer Cet ordinateur (IP locale) Messages MIDI devices Périphériques MIDI Destination is the default MIDI device set in "Network" tab MIDI par défaut (saisi dans l'onglet "Network") MIDI device created by IanniX (Mac & Linux only) Périphérique MIDI créé par IanniX (Mac & Linux) Messages IP ports Ports IP Default port used by IanniX Port par défaut IanniX OSC default input Port OSC entrant de IanniX Messages OSC addresses Adresse OSC Default address used for triggers Adresse par défaut des triggers Default address used for cursors Adresse par défaut des curseurs Default address used for transport messages Adresse par défaut du transport Default address used to reach IanniX Adresse par défaut de IanniX Messages MIDI controls Contrôles MIDI Send a control change Envoi d'un control change Send a bend Envoi d'un bend Send a program change Envoi d'un program change Send a note Envoi d'une note Messages values Valeurs ID of the triggered trigger Group name of the triggered trigger Document name of the triggered trigger Label of the triggered trigger x coordinate of the triggered trigger y coordinate of the triggered trigger z coordinate of the triggered trigger x mapped coordinate of the triggered trigger y mapped coordinate of the triggered trigger z mapped coordinate of the triggered trigger When trigger off-time is set, returns 127 when the trigger is trigged and 0 when the trigger is released Distance between the triggered trigger and the cursor that triggers the trigger 0 if trigger is triggered from left to right and 1 for the other side ID of the message (each message generates an ascending ID) ID of the running cursor Group name of the running cursor Document name of the running cursor Label of the running cursor x coordinate of the running cursor y coordinate of the running cursor z coordinate of the running cursor x mapped coordinate of the running cursor y mapped coordinate of the running cursor z mapped coordinate of the running cursor Current progression of the cursor on the curve (in seconds) Current progression of the cursor on the curve (in percentages, from 0.0 to 1.0) Angle of the cursor Variation of x coordinate of the running cursor Variation of y coordinate of the running cursor Variation of z coordinate of the running cursor Variation of x mapped coordinate of the running cursor Variation of y mapped coordinate of the running cursor Variation of z mapped coordinate of the running cursor Variation of current progression of the cursor on the curve (in seconds) Variation of current progression of the cursor on the curve (in percentages, from 0.0 to 1.0) Variation of angle of the cursor Number of loops done by the cursor on the curve ID of curve where the cursor runs on Group name of curve where the cursor runs on Document name of curve where the cursor runs on Label of curve where the cursor runs on x coordinate of curve where the cursor runs on y coordinate of curve where the cursor runs on z coordinate of curve where the cursor runs on ID of the collided curve Group name of the collided curve Document name of the collided curve Label of the collided curve x coordinate of the collided curve y coordinate of the collided curve z coordinate of the collided curve x coordinate of the collision between the cursor and the curve y coordinate of the collision between the cursor and the curve x mapped coordinate of the collision between the cursor and the curve y mapped coordinate of the collision between the cursor and the curve Distance between the collision and the cursor Set an OSC Timetag (compliant with Internet NTP timestamps) to message Playback status of score ("play"), "stop" or "fastrewind") Number of triggers in the current score Number of cursors in the current score Number of curves in the current score Elapsed time in seconds Elapsed time as displayed in Transport bar JavaScript useful functions Absolute value of x Arccosine of x Arcsine of x Arctangent of x Arctangent of x divided by y Next higher integer above x Cosine of x e to the power x Next lower integer below x Logarithm to the base 2 of x Minimum of x and y Maximum of x and y x raised to the power y x rounded nearest integer, higher or lower Sine of x Square root of x x squared Tangent of x Radian angle x converted into degrees Degree angle x converted into radians Random number between low and high Values of x below min and above max are discarded Distance between the points (x1, y1, z1) and (x2, y2, z2) Angle between the points (x1, y1) and (x2, y2) Scale x to cover the range from low to high, assuming x ranges between 0.0 and 1.0: Scale x to cover the range from low to high, assuming x ranges between 0.0 and 1.0, with mid being returned as the value for x=0.5 Scale x to cover the range from low2 to high2, assuming x ranges between low1 and high1 Mathematical constant e Natural logarithm of 2 Natural logarithm of 10 Base 2 logarithm of e Logarithm to the base 10 of e Constant PI Two times PI PI over 3 PI over 4 PI over 2 One over the square root of two Square root of two IanniX Commands Add an object Adds an object on the score. The keyword auto automatically assigns an ID to your object. add <trigger|curve|cursor> <id> add <trigger|curve|cursor> auto Remove an object Removes an object in the score thanks to its ID. remove <id> Force object to send its message(s) Forces an object to send its message(s). trig <target> Erase a score Erase all objects into the score clear Defining a group Groups are identified by a word you are free to choose. Objects are not required to be part of a group. setGroup <target> <group name> Enable/disable an object An object is enable by default, but you can disable it. Disabled objects will not send messages. setActive <target> <0|1> Time before release (note off) of a trigger When a note is played thanks to a trigger, you can configure it to turn the note off automatically after a configurable delay. The time before release should normally be set to zero when note-off time is not being sent in the messages of this trigger. setTriggerOff <target> <delay> Assign a cursor to a curve After creating your cursor, make sure you have assigned the curve you want it to follow. You can use the keyword lastCurve to designate the last curve added. setCurve <cursor target> <curve target> Width of the cursor play head You can edit in real time the width of a cursor in order to enable or disable triggers nearby. setWidth <target> <width> Depth of the cursor play head You can edit in real time the depth of a cursor in order to enable or disable triggers nearby. setDepth <target> <depth> Cursor loop pattern This parameter refers to the direction and the number of cycles. For example, with 1 1 0, the cursor will perform two cycles in the positive direction before stopping. setPattern <target> <easing> 0 <pattern> Speed of a cursor Cursors have a speed factor independent of each other. The travel time of a curve is also configurable. The cursor will evolve in the negative direction if the speed is negative, but time will continue to flow naturally. setSpeed <target> auto <duration> setSpeed <target> <speed factor> Instantaneous speed of a cursor Cursors have an instantaneous speed factor independent, very useful for real-time performances. As setSpeed, a negative speed is possible without affecting the global speed of the score. setSpeedF <target> <speed factor> Cursor offsets You can choose to start your cursor at a certain point of the curve (marked in seconds) and limit it between certain values (also in seconds). For example, the 2 4 6 offset means that your cursor will start your curve at the position t=2s then will travel to point t=6s to start again at the point t=4s. setOffset <target> <initial> <start> <end> Instantaneous position (in seconds) The position of a cursor can be modified in real time. This instruction does not work if you include it directly in your script, because at each execution, IanniX does a fastrewind. setTime <target> <time> Instantaneous position (in percentages) setTimePercent <target> <time> Mapping values You can set your cursor to send values within a chosen interval. For example, if it is operating in a 3x3 square, it can still send coordinates as values between 0 and 1. Use setBoundsSource to indicate to IanniX the interval in which your cursor is located and setBoundsTarget to set the range of your sent values. Generally BoundsSource is correctly set by default. You must use the variables cursor_value_x, cursor_value_y, trigger_value_x, trigger_value_y, collison_value_x or collison_value_y that values sent are those of boundsTarget. setBoundsSource <target> <x-top-left-corner> <y-top-left-corner> <x-bottom-right-corner> <y-bottom-right-corner> setBoundsTarget <target> <x-top-left-value> <y-top-left-value> <x-bottom-right-value> <y-bottom-right-value> Shifting points of a curve Shfit points from left to right or right to left shiftPoints <target> <start point index> <-1|1> Translating a curve Translates a curve translatePoints <target> <dX> <dY> <dZ> Translating a point of a curve Translates a point of a curve translatePoint <target> <point index> <dX> <dY> <dZ> Setting or modifying points of a curve (straight or Bezier) A curve must be defined by a sequence of points. The points index starts at 0. setPointAt <target> <point index> <x> <y> setPointAt <target> <point index> <x> <y> <c1x> <c1y> <c2x> <c2y> setPointAt <target> <point index> <x> <y> <z> setPointAt <target> <point index> <x> <y> <z> <c1x> <c1y> <c1z> <c2x> <c2y> <c2z> Setting or modifying points of a curve (with automatic smoothing) setSmoothPointAt <target> <point index> <x> <y> setSmoothPointAt <target> <point index> <x> <y> <z> Modifying x-coordinate of a point of a curve Description setPointXAt <target> <point index> <x> Modifying y-coordinate of a point of a curve setPointYAt <target> <point index> <y> Modifying z-coordinate of a point of a curve setPointZAt <target> <point index> <z> Removing a point of a curve removePointAt <point index> Text curves A character can also be played like a curve. setPointsTxt <target> <scaling> <font> <text> Manual SVG curve — cubic path A SVG curve is defined by a path that you can directly import from another software by copy / paste. setPointsPath <target> <scale> <svg path> Manual SVG curve — polylines The SVG path of these curves is simply a set of points . setPointsLines <target> <scale> <svg polyline> Automatic vectorization A curve can be directly constructed from an image by an automatic vectorization. setPointsImg <target> <scaling> <filename> Elliptical or circular curves Ellipses are defined by a major axis and a minor axis. To construct circles, the two axes must have the same value. setPointsEllipse <target> <width> <height> Size of objects This function modifies the thickness of a curve or a cursor and the size of a trigger. setSize <target> <size> Curve size (width/height) The size of objects can be changed directly. setResize <target> <width> <height> Curve size (scale factor) setResizeF <target> <scale factor> Paths format Sets a style dotted with dash pattern which must be a sequence of 0 and 1, dash style defines the space between each dot. setLine <target> <dash style> <dash pattern> Space position Sets an object on the score via the coordinates (x, y, z). setPos <target> <x> <y> <z> Adding text You can add a text description of your items on the score. setLabel <target> <label> Assigning a message This command sets the message that an object must send (please refer to Messages Syntax help). setMessage <target> <period>, <message1> <variables>, <message2>,message2, message3, … Send a message You can send manually a message (please refer to Messages Syntax help). sendOsc <message> Solo/un-solo Solo/un-solo an object or a group (exactly like in Objects of inspector tab) solo <target> <0|1> Mute/un-mute Mute/un-mute an object or a group (exactly like in Objects of inspector tab) mute <target> <1|0> Creating a variable texture Save your texture as a variable. If you are using the following variables, the display is directly modified because native textures are saved under those variables. Use the tool "restore triggers original shapes" from the inspector "scripts & styles" to find the original textures. registerTexture <variable> <x-top-left-corner> <y-top-left-corner> <x-bottom-right-corner> <y-bottom-right-corner> <file name> Texture of an object Modify the texture of an object or a group with a preloaded texture (refer to registerTexture). setTexture <target> <variable> Texture of an active object that does not send any messages setTextureActive <target> <variable> Texture of an inactive object that does not send any messages setTextureInactive <target> <variable> Texture of an active object that send messages setTextureActiveMessage <target> <variable> Texture of an inactive object that send messages setTextureInactiveMessage <target> <variable> Creating a variable color (RGB) IanniX can also save a color as a variable for reusing it more easily. registerColor <variable> <r> <g> <b> <a> Creating a variable color (HSB) registerColor <variable> <h> <s> <b> <a> Color of an object (RGB) Modify the color of an object or a group with a specific color or a preloaded color (refer to registerColor or registerColorHur). setColor <target> <r> <g> <b> <a> setColor <target> <variable> Color of an object (HSB) setColorHue <target> <h> <s> <b> <a> setColorHue <target> <variable> Color of an active object that does not send any messages (RGB) setColorActive <target> <r> <g> <b> <a> setColorActive <target> <variable> Color of an inactive object that does not send any messages (RGB) setColorInactive <target> <r> <g> <b> <a> setColorInactive <target> <variable> Color of an active object that send messages (RGB) setColorActiveMessage <target> <r> <g> <b> <a> setColorActiveMessage <target> <variable> Color of an inactive object that send messages (RGB) setColorInactiveMessage <target> <r> <g> <b> <a> setColorInactiveMessage <target> <variable> Color of an active object that does not send any messages (HSB) setColorActiveHue <target> <h> <s> <b> <a> setColorActiveHue <target> <variable> Color of an inactive object that send messages (HSB) setColorInactiveHue <target> <h> <s> <b> <a> setColorInactiveHue <target> <variable> Color of an inactive object that does not send any messages (HSB) setColorActiveMessageHue <target> <h> <s> <b> <a> setColorActiveMessageHue <target> <variable> setColorInactiveMessageHue <target> <h> <s> <b> <a> setColorInactiveMessageHue <target> <variable> Resizing objects regardless of zoom Enabled by default, can automatically increase or decrease the size of the triggers and cursors when you zoom in / out the score in order to facilitate reading. Only the visual aspect is affected, the actual size of the objects is not changed. autoSize <0|1> Zoom in score Adjust the zoom using the script. The factor is in percent. e.g. A factor of 200 doubles the size of the display area. zoom <zoom factor> Center score Placing the point (x,y) in the center of the workspace center <x> <y> Resize the viewport viewport <width> <height> Export as an image snapshot Make a snapshot of current score snapshot <scale> <filename,optional> Rotate score Rotate the view about the x, y and z axes rotate <x-axis> <y-axis> <z-axis> Playing the score Enabling the playback play <score speed> Stopping the score Disabling the playback stop Fastrewinding the score Go back to the begging of score fastrewind Speed of the score You can set the global speed of the score. A negative speed will evolve over time in the negative direction. speed <speed> Load a score or a script Load a score or a script of the current project folder load <score name> Log information to console Log information to IanniX console (network tab) log <text> Go to a specific timecode Go to a specific timecode in seconds goto <time in seconds> Control mouse Enable to move cursor of the mouse mouse <x> <y> Get IanniX window title Returns IanniX window title (scripts only) title Make IanniX script sleeping (scripts only) Set a sleep time. BE CAREFUL, IanniX will not respond during sleeping sleep <duration> EN FR Introduction Introduction Main<br/>elements Éléments<br/>principaux Scripts Scripts Reference Référence Documentation Documentation IanniX commands must specify a target at each execution: Les commandes IanniX doivent spécifier une cible à chaque exécution : <li><code class='target'>id</code> refers to a specific object.<br/>Example: <span class='api'><code>remove <span class= 'target'>2</span></code></span></li><li><code class='target'>group_id</code> refers to the entire group that can be a word.<br/>Example: <span class='api'><code>remove <span class= 'target'>toto</span></code></span></li><li><code class='target'>all</code> refers to all objects.<br/>Example: <span class='api'><code>remove <span class= 'target'>all</span></code></span></li><li><code class='target'>current</code> refers to the last created object.<br/>Example: <span class='api'><code>remove <span class= 'target'>current</span></code></span></li> <li><code class='target'>id</code> désigne un objet précis.<br/>Exemple : <span class='api'><code>remove <span class='target'>2</span></code></span></li> <li><code class='target'>group_id</code> désigne le groupe entier qui peut être un mot.<br /> Exemple : <span class='api'><code>remove <span class='target'>toto</span></code></span></li><li><code class='target'>all</code> désigne tous les objets.<br /> Exemple : <span class='api'><code>remove <span class='target'>all</span></code></span></li> <li><code class='target'>current</code> désigne le dernier objet créé.<br /> Exemple : <span class='api'><code>remove <span class='target'>current</span></code></span></li> Example: Exemple : Copy / paste this example in IanniX to understand how the code works! Copier/coller cet exemple dans IanniX pour voir son fonctionnement ! Welcome and thank you for downloading IanniX! Bienvenue et merci d'avoir téléchargé IanniX ! IanniX is a graphical open-source sequencer, based on Iannis Xenakis works, for digital art. IanniX syncs via Open Sound Control (OSC) events and curves to your real-time environment (PureData, C-Sound, SuperCollider, openFramework, Processing, vvvv, Live, Max/MSP/Jitter… and many others from our <a href='http://www.iannix.org/EN/links.php' target='_blank'>links</a> section)! IanniX est un séquenceur graphique open-source, inspiré des travaux de Iannis Xenakis, destiné à la création numérique. IanniX synchronise via Open Sound Control (OSC) des événements et courbes vers votre environnement temps-réel (PureData, C-Sound, SuperCollider, openFramework, Processing, vvvv, Live, Max/MSP/Jitter… et beaucoup d’autres dans notre section <a href='http://www.iannix.org/en/links.php' target='_blank'>links</a> section) ! Feel free to suscribe to our <a href='http://iannix.org/EN/community.php' target='_blank'>forum</a>. Post your problems or tips to make live our community! N’hésitez pas à vous inscrire sur notre <a href='http://iannix.org/en/community.php' target='_blank'>forum</a>. Poster vos problèmes ou astuces pour faire vivre notre communauté ! Installation IanniX is compatible with Linux, Mac OS X 10.6+ and Windows and does not require any particular installation.<br/>For Linux users of IanniX who do not build from source, we have included a compiled version that you can run by launching the file <code>IanniX.sh</code>. IanniX est compatible avec Linux, Mac OS X 10.6+ et Windows et ne nécessite pas d’installation particulière.<br /> Pour les utilisateurs de IanniX sous Linux qui ne souhaitent pas compiler depuis les sources, nous avons inclus une version compilée que vous pourrez exécuter en lançant le fichier <code>IanniX.sh</code>. Open Sound Control Open Sound Control is a communication protocol that operates over the IP network (i.e. Ethernet, Wi-Fi, Internet). It is recognized by all operating systems and requires no drivers or network configuration. Some knowledge of networking is needed to more advanced uses.<br /> <br /> The golden rule about OSC is to match IP addresses and ports: a message sent by IanniX to <code>127.0.0.1:57120</code> means that it is sent to the local machine on port &nbsp;57120. The software that has to receive this message will have to open port 57120. L’Open Sound Control est un protocole de communication qui fonctionne sur le réseau IP (donc sur Ethernet, Wi-Fi, sur Internet…). Il est reconnu par tous les systèmes d’exploitation et ne nécessite pas de drivers ou de configuration réseau. Quelques connaissances en réseau sont toutefois nécessaires pour des usages plus poussés.<br/><br/> La règle d'or pour l'OSC est de faire correspondre les adresses IP et les ports : un message envoyé par IanniX au <code>127.0.0.1:57120</code> signifie qu'il est envoyé à la machine local sur le port&nbsp;57120. L'application qui veut recevoir ce message devra donc ouvrir le port 57120. MIDI In order to remain compatible with the MIDI stations, we have integrated the MIDI protocol natively.<br/> For Windows users who do not have MIDI hardware devices, you must install a virtual MIDI device such as <a href='http://www.nerds.de/data/setuploopbe1.exe'>LoopBe</a>. Afin de rester compatible avec les stations MIDI, nous avons intégré nativement le protocole MIDI.<br /> Pour les utilisateurs de Windows qui ne possèdent pas de périphériques MIDI matériels, vous devez installer un périphérique MIDI virtuel tel que <a href='http://www.nerds.de/data/setuploopbe1.exe'>LoopBe</a>. Software &amp; interfaces Interfaces &amp; logiciels We have made available patches/interfaces for commonly used software that we have tested. Click on 'Open Patches Folder' from the IanniX toolbar to discover them.<br/> This is very simple examples that illustrate the principle of communication between IanniX and other software; we invite you to modify them and get inspired for your projects. Nous avons mis à votre disposition des patches/interfaces pour les logiciels couramment utilisés que nous avons testés. Cliquez sur le bouton 'Open Patches Folder' de la barre d'outils depuis IanniX pour les découvrir.<br/> Il s'agit d'exemples très simples qui illustrent le principe de communication entre IanniX et les logiciels ; nous vous invitons à les modifier et à vous en inspirer pour vos projets. Bugs Bugs IanniX is still on beta-testing, some bugs are still present but most features can be used properly. You can report errors in the 'Bugs' section of our <a href='http://iannix.org/EN/community.php'>forum</a>. IanniX est toujours en beta-testing, quelques bugs sont donc encore présents mais la plupart des fonctionnalités peuvent être employées correctement. Vous pouvez signaler les erreurs dans la section « Bugs » de notre <a href='http://iannix.org/fr/community.php'>forum</a>. Version tracking Suivi de versions Known bugs Bugs connus Objects Objets A IanniX score is composed of three main elements: Une partition IanniX se compose de trois objets fondamentaux&nbsp;: <li><b>a trigger</b> is a momentary event set in space; it is activated when <b>a cursor</b> goes past it;</li><li><b>a curve</b> is a series of points set in space; it defines a trajectory&nbsp;;</li><li><b>a cursor</b> is similar to a tape head. It triggers discrete events (<b>triggers</b>) or continuous (values). It can follow <b>a curve</b> or be completely free (controlled by the mouse, a graphic tablet or by another software).</li> <li><b>un trigger</b> est un événement ponctuel positionné dans l'espace ; il est déclenché lors du passage d'<b>un curseur</b>&nbsp;;</li><li><b>une courbe</b> est une suite de points dans l'espace ; elle définit une trajectoire&nbsp;;</li><li><b>un curseur</b> est une tête de lecture. Il déclenche des événements discrets (<b>triggers</b>) ou continus (valeurs). Il peut suivre <b>une courbe</b> ou être complètement libre (contrôlé par la souris, une tablette ou par un autre logiciel).</li> Add objects Ajouter des objets To set an object in space, you have three methods: Pour positionner un objet dans l'espace, vous disposez de trois méthodes : <li><b>the graphic interface</b> thanks to the toolbar;</li><li><b>software interfaces</b> controlling IanniX via Open Sound Control for example, through <a href='reference.html'>IanniX commands</a>;</li><li><b>scripts</b> that create generative scores via <a href='script.html'>scripted commands</a>.</li> <li><b>l'interface graphique</b> à l'aide de la <a href='overview.html'>barre d'outils</a>&nbsp;;</li><li><b>les interfaces logicielles</b> contrôlant IanniX en Open Sound Control par exemple, grâce au système de <a href='reference.html'>commandes IanniX</a>&nbsp;;</li><li><b>les scripts</b> qui créé des partitions génératives via <a href='script.html'>des commandes scriptées</a>.</li> Basic vocabulary Vocabulaire fondamental A few simple concepts will enable you to understand the mechanisms of IanniX: Quelques notions très simples vous permettront de comprendre les mécanismes de IanniX : <li><b>the identifier (ID)</b>: each object (trigger, curve or cursor) has an unique identifier;</li><li><b>the group</b>: objects can be grouped under a group name, allowing control of multiple objects at once.</li> <li><b>l'identifiant (ID)</b> : chaque objet (trigger, courbe ou curseur) possède un identifiant unique&nbsp;;</li><li><b>le groupe</b> : les objets peuvent être regroupés sous un nom de groupe, permettant le contrôle de plusieurs objets d'un coup.</li> Messages Messages Message handling is the main function of IanniX. They can be sent by <b>cursors</b> and <b>triggers</b>. La gestion des messages est la fonction principale de IanniX. Ils peuvent être envoyés par <b>les curseurs</b> et <b>les triggers</b>. To see if the messages are actually sent or received, IanniX displays a trace in the 'Messages' section of inspector. Pour savoir si les messages sont effectivement reçus ou envoyés, IanniX en affiche une trace dans la section « Messages » de l'inspecteur. <b>Triggers</b> usually send one only message when a cursor goes past them. IanniX is limited to sending one message per millisecond maximum.<br/> <b>Les triggers</b> n'envoient généralement qu'un seul message au passage du curseur et IanniX limite l'envoi à 1 message par milliseconde maximum.<br/> <b>Cursors</b>, by default, generate messages every 20&nbsp;ms (but you can change this time). <b>Les curseurs</b> génèrent par défaut des messages toutes les 20&nbsp;ms (mais vous pouvez modifier cette période). To edit the message that a element has to send, click on 'Edit' in the inspector after having selected the object or double-click on the object itself to display this window: Pour éditer le message qu'un objet doit envoyer, cliquez sur 'Edit' dans l'inspecteur après avoir sélectionné l’objet ou double-cliquez sur l’objet lui-même pour faire apparaître la fenêtre: Recursion Récursivité IanniX can be controlled by IanniX itself (!). You can use all the protocols described above, but we recommend using OSC to communicate between two IanniX applications on network computers and use the <code>direct</code> command to send messages inside one IanniX application.<br/><br /><span class='titre'>Example:&nbsp;</span> IanniX peut être contrôlé par IanniX lui-même (!). Vous pouvez utiliser tous les protocoles décrits précédemment mais nous vous recommandons d'utiliser l'OSC pour communiquer entre deux IanniX sur des ordinateurs en réseau et d'utiliser la commande <code>direct</code> pour envoyer des messages à l'intérieur même de IanniX.<br/><br /><span class='titre'>Exemple :&nbsp;</span> Copy / paste this example in Iannix to understand how the code works! Copier/coller cet exemple dans IanniX pour voir son fonctionnement ! NxGroup Group Groupe UiAbout About IanniX À propos de IanniX <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Arial'; font-weight:400; font-style:normal;"> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">IDEATION</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thierry Coduys</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Adrien Lefevre</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gerard Pape (CCMIX)</p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">CONTRIBUTORS</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Christopher Graham</p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">WEB &amp; IDENTITY</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Matthieu Ranc</p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">IANNIX DEVELOPERS </span><span style=" font-weight:600; font-style:italic;">(FORMER VERSIONS)</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Adrien Lefevre <span style=" font-style:italic;">(v0.54)</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Guillaume Ferry <span style=" font-style:italic;">(v0.6xx)</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pierre Jullian de la Fuente &amp; Cyrill Duneau <span style=" font-style:italic;">(v0.6xx)</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Matthieu Ranc &amp; Guillaume Jacquemin <span style=" font-style:italic;">(v0.66)</span></p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TESTERS &amp; EXTERNAL CONTRIBUTORS</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jean Bresson (OpenMusic)</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Paul Crabbe (SuperCollider)</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Francesco (C-Sound)</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cyrille Henry</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thomas Thiery (PureData)</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Romain Vuillet</p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">THANKS TO</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Etienne Mathé (documentation), Joachim Montessuis and all users for their observations and suggestions and AFIM (Association Française d'Informatique Musicale).</p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Visit <a href="http://www.iannix.org"><span style=" text-decoration: underline; color:#000000;">http://www.iannix.org</span></a> for more information !</p></body></html> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Arial'; font-weight:400; font-style:normal;"> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">IDÉATION</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thierry Coduys</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Adrien Lefevre</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gerard Pape (CCMIX)</p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">CONTRIBUTEURS</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Christopher Graham</p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">WEB &amp; IDENTITÉ</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Matthieu Ranc</p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">DÉVELOPPEURS IANNIX </span><span style=" font-weight:600; font-style:italic;">(ANCIENNES VERSIONS)</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Adrien Lefevre <span style=" font-style:italic;">(v0.54)</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Guillaume Ferry <span style=" font-style:italic;">(v0.6xx)</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pierre Jullian de la Fuente &amp; Cyrill Duneau <span style=" font-style:italic;">(v0.6xx)</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Matthieu Ranc &amp; Guillaume Jacquemin <span style=" font-style:italic;">(v0.66)</span></p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TESTEURS &amp; CONTRIBUTEURS EXTERNES</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jean Bresson (OpenMusic)</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Paul Crabbe (SuperCollider)</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Francesco (C-Sound)</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cyrille Henry</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thomas Thiery (PureData)</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Romain Vuillet</p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">MERCI À</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Etienne Mathé (documentation), Joachim Montessuis et tous les utilisateurs pour leur observations et suggestions et l'AFIM (Association Française d'Informatique Musicale).</p> <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Visitez <a href="http://www.iannix.org"><span style=" text-decoration: underline; color:#000000;">http://www.iannix.org</span></a> pour plus d'informations !</p></body></html> version <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Arial'; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PROJECT MANAGER</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thierry Coduys</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">DEVELOPPEMENT</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Guillaume Jacquemin</p></body></html> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Arial'; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">CHEF DE PROJET</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thierry Coduys</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">DÉVELOPPEMENT</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Guillaume Jacquemin</p></body></html> beta UiEditor IanniX — Script Editor IanniX — Éditeur de scripts IanniX Save Sauvegarder Ctrl+S Close Fermer Ctrl+W Script Editor Éditeur de scripts UiHelp IanniX Helper Aide de IanniX SYNTAX SYNTAXE IMPLEMENT IN SCRIPT IMPLÉMENTER DANS LE SCRIPT EXAMPLE EXEMPLE SNIPPET SNIPPET UiInspector IanniX — Inspector IanniX — Inspecteur FILES FICHIERS SCORES PARTITIONS Scores list Liste des partitions List of available scores (from your project folder and from IanniX folders). Double-click to open a score. Right-click to show contextual menu. List de toutes les partitions (depuis le projet et depuis les dossiers IanniX). Double-cliquer pour ouvrir une partition. Clic-droit pour afficher le menu contextuel. SCRIPTS & STYLES SCRIPTS && FEUILLES DE STYLE Scripts list Liste des scripts List of available scripts (from your project folder and from IanniX folders). Double-click to launch a script. Right-click to show contextual menu. Liste de tous les scripts (depuis le projet et depuis les dossiers IanniX). Double-cliquer pour exécuter un script. Clic-droit pour afficher le menu contextuel. INFOS INFOS TRIGGER TRIGGER ID / GROUP ID POSITION (X / Y / Z) Change here the absolute coordinates of selected objects Modifier ici les coordonnées absolues des objets sélectionnés SIZE (W / H) TAILLE (L / H) Change here the size of selected objects Modifier ici la taille des objets sélectionnés CURSOR WIDTH / DEPTH TAILLE (L / P) DU CURSEUR Change here the cursor width Modifier ici la taille du curseur CURSOR LOOP PATTERN RÉPÉTITION DU CURSEUR CURSOR OFFSETS OFFSETS DES CURSEURS BEGINS FROM DÉBUTE À Change here the initial offset (first iteration of a cursor on a curve). Positive initial offset means that cursor will start from a position on the curve whereas negative initial offset means that cursor start will be delayed. Modifier ici l'offset initial (première itération du curseur sur la courbe). Un offset initial positif signifie que le curseur démarre sur la courbe à une position données ; un offset initial négatif signifie que le curseur démarre avec un retard. GOES FROM ÉVOLUE DE Change here the start offset of a cursor defining the loop start point on a curve Modifier ici l'offset de démarrage définissant le point de départ d'une boucle sur la courbe TO À Change here the start offset of a cursor defining the loop end point on a curve Modifier ici l'offset de fin définissant le point de fin de boucle sur la courbe the end la fin CURSOR SPEED or LENGTH VITESSE DU CURVEUR Change here the cursor speed factor (1.00 = nominal speed) Modifier ici la vitesse du curseur (1.00 = vitesse nominale) Change here the cursor run duration on the curve Modifier ici la durée d'une itération du curseur sur la courbe CURSOR MASTER SPEED VITESSE GÉNÉRALE Change here the cursor master speed factor (1.00 = nominal speed) (total speed = master speed x speed) Modifier ici la vitesse générale du curseur (1.00 = vitesse nominale) (vitesse total = vitesse générale x vitesse du curseur) VALUE MAPPING MAPPING DE VALEURS x RANGE x ÉVOLUE DE Change here the values for the graphical mapping of cursors position Modifier ici les valeurs pour le mapping des les coordonnées graphiques => À MAPPED RANGE => VALEURS DE y RANGE y ÉVOLUE DE z RANGE z ÉVOLUE NO ITEMS SELECTED AUCUN ÉLÉMENT SÉLECTIONNÉ Click here to change the group ID of the object Cliquer ici pout modifier le group ID de l'objet GROUP GROUPE TRIGGER OFF-TIME TEMPS DE RELÂCHE Change here the duration of a MIDI note Modifier ici la durée d'une note MIDI LABEL ÉTIQUETTE Type here a label for selected objects Taper ici l'étiquette pour les objets sélectionnés ACTIVE ACTIF Click here to enable/disable the object on the score Cliquer ici pour activer/désactiver l'objet dans la partition Click here to edit the message send by the selected objects Cliquer ici pour éditer le(s) message(s) envoyé(s) par les objets sélectionnés EDIT ÉDITER MESSAGES MESSAGES COLORS COULEURS Change here the color of objects that are ACTIVE and that DOESN'T SEND messages Modifier ici la couleur des objets ACTIFS qui N'ENVOIENT PAS de messages Change here the color of objects that are INACTIVE and that DOESN'T SEND messages Modifier ici la couleur des objets INACTIFS qui N'ENVOIENT PAS de messages Change here the color of objects that are ACTIVE and that SEND messages Modifier ici la couleur des objets ACTIFS qui ENVOIENT des messages Change here the color of objects that are INACTIVE and that SEND messages Modifier ici la couleur des objets INACTIFS qui ENVOIENT de messages THICKNESS ÉPAISSEUR Change here the tickness of selected objects Modofier ici l'épaisseur des objets sélectionnés Change here the periodicity of emitted messages Modifier ici la périodicité des messages envoyés SENT EACH ENVOYÉ CHAQUE Click here to change the unique ID of the object Cliquer ici pour modifier l'ID unique de l'objet ID ID Select here the cursor acceleration on a curve Sélectionner ici le courbe d'accélération du curseur du la courbe Change here the cursor depth Modifier ici la profondeur du curseur CURVE POINTS POINTS DE LA COURBE Type here the points coordinates (x, y, z) and the Bezier control points (c1x, c1y, c1z, c2x, c2y, c2z). Checkboxes allow you to activate automatic smoothing or not. Taper ici les coordonnées des points (x, y, z) et les points de contrôle de Bézier (c1x, c1y, c1z, c2x, c2y, c2z). Les cases à cocher permette d'activer un lissage automatique de la courbe. Index Numéro x x y y z z Smooth Lissage c1x c1y c1z c2x c2y c2z Type here the speed pattern separated by spaces Taper ici des vitesses de curseurs séparées par des espaces 1 0 - One run on curve 1 0 - Une seule itération sur la courbe 1 - Loop on curve 1 - Boucle sur la courbe 1 -1 0 - Single roundtrip on curve 1 -1 0 - Aller/retour sur la courbe 1 -1 - Loop roundtrip on curve 1 -1 - Aller/retour sur la courbe en boucle 1 2 0 - One normal run, another at double speed 1 2 0 - Une itération normale, puis une autre à vitesse double OBJECTS OBJETS Display/hide triggers Afficher/cacher les triggers Click here to show/hide triggers of the current score Cliquer ici pour afficher/cacher les triggers de la partition courante TRIGGERS TRIGGERS Display/hide cursors Afficher/cacher les curseurs Click here to show/hide cursors of the current score Cliquer ici pour afficher/cacher les curseurs de la partition courante CURSORS CURSEURS Display/hide curves Afficher/cacher les courbes Click here to show/hide curves of the current score Cliquer ici pour afficher/cacher les courbes de la partition courante CURVES COURBES List of objects Liste des objets Click on a row to highlight and select object in score. Click on checkboxes to switch on/off and solo objects of the current score Cliquer sur une ligne pour sélectionner un objet de la partition. Cocher les cases pour activer/désactiver ou mettre en solo un objet de la partition TYPE TYPE ON/OFF ON/OFF S S GROUP ID Switch on all objects Active tous les objets Click here to switch on all objects of the current score Cliquer ici pour activer tous les objets de la partition Disable solo for all objects Désactiver le solo pour les objets Click here to disable solo of all objects of the current score Cliquer ici pour désactiver le solo de tous les objets de la partition GROUPS GROUPES List of objects group name Liste des groupes Click on a row to highlight and select groups in score. Click on checkboxes to switch on/off and solo groups of the current score Cliquer sur une ligne pour sélectionner un groupe de la partition. Cocher les cases pour activer/désactiver ou mettre en solo un groupe de la partition Switch on all groups Active tous les groupes Click here to switch on of all objects of the current score Cliquer ici pour désactiver tous les objets de la partition Disable solo for all groups Désactiver le solo pour les groupes Click here to disable solo of all groups of the current score Cliquer ici pour désactiver le solo de tous les groups de la partition Z-RANGE FROM AFFICHAGE DES Z DE Z-range values Borne des Z à afficher Change here the minimum displayable Z-value. Objects with a lower Z values will not be displayed. Modificer ici le Z minimum à afficher. Les objets avec un Z inférieur ne seront pas visibles. Change here the maximum displayable Z-value. Objects with a higher Z values will not be displayed. Modificer ici le Z maximum à afficher. Les objets avec un Z supérieurs ne seront pas visibles. CAMERA FOLLOWS OBJECT ID CAMÉRA SUIT L'OBJET Camera Follow ID ID l'objet à suivre avec la caméra Type here the ID of the object that the camera will follow Taper ici l'ID de l'objet à suivre avec la caméra no objects pas d'objets Light off unused curves Atténue les courbes non utilisées Click here to light on/off curves on which no cursor are running Cliquer ici estomper les courbes non parcourues par un curseur LIGHT OFF UNUSED CURVES ESTOMPER LES COURBES NON UTILISÉES NETWORK RÉSEAU SENT MESSAGES MESSAGES ENVOYÉS Sent messages Messages envoyés Logs all the sent messages (will slow down IanniX if kept on-screen) Affiche les messages envoyés (ralentit IanniX si affiché en permanence) RECEIVED MESSAGES MESSAGES REÇUS Received messages Messages reçus Logs all the received messages (will slow down IanniX if kept on-screen) Affiche les messages reçus (ralentit IanniX si affiché en permanence) NETWORK CONFIGURATION CONFIGURATION RÉSEAU OSC IN PORT PORT OSC IN OSC in port Port entrant OSC Type here the OSC in port number Taper ici le numéro du port entrant OSC RAW UDP IN PORT PORT RAW UDP IN TRANSPORT MESSAGE MESSAGE DE TRANSPORT Raw UDP in port Port entrant UDP brut Type here the raw UDP in port number Taper ici le numéro du port entrant raw UDP SYNC MESSAGE MESSAGE DE SYCHRONISATION Sync message Message de synchronisation Type here the message that will be sent when clicking on "Sync" Taper ici le message à envoyer pour la synchronisation MAKE OSC BUNDLE ON BUNDLE OSC POUR L'IP/PORT OSC bundle address Adresse du bundle OSC Type here the IP address number associated to bundled messages. All OSC messages using this IP/port will be bundled. Taper ici l'adresse IP sortante des messages OSC à mettre en bundles. OSC bundle port Port du bundle OSC Type here the port number associated to bundled messages. All OSC messages using this IP/port will be bundled. Taper ici le numéro du port sortant des messages OSC à mettre en bundles. HTTP IN PORT PORT HTTP IN HTTP in port Port entrant HTTP Type here the HTTP in port number Taper ici le numéro du port entrant HTTP Transport message Message de transport Type here the message that will be sent when playback status changed (play, pause, fast rewind) Taper ici le message à envoyer quand le playback change d'état (play, pause, retour à zéro) TCP/XML SERVER IN PORT PORT TCP/XML SERVER IN TCP/XML Server in port Port entrant du serveur TCP/XML Type here the TCP/XML Server in port number Tape ici le port entrant du serveur TCP/XML DEFAULT IP (ALIAS IP_OUT) IP PAR DÉFAUT (ALIAS IP_OUT) Default IP address Adresse IP par défaut Type here the default IP address used by messages containing the keyword ip_out Taper ici l'adresse IP par défaut utilisée pour les messages contenant le mot-clef ip_out DEFAULT MIDI OUT (ALIAS MIDI_OUT) MIDI PAR DÉFAUT (ALIAS MIDI_OUT) Default MIDI device Périphérique MIDI par défaut Type here the default MIDI device used by messages containing the keyword midi_out Taper ici le périphérique MIDI par défaut utilisé pour les messages contenant le mot-clef midi_out SERIAL PORT PORT SÉRIE Serial port address Adresse du port série Type here the configuration of your serial port (syntax : port name:baud rate:data bits:parity:stop bits:flow control) Taper ici la configration du port série (syntaxe : port name:baud rate:data bits:parity:stop bits:flow control) Click here to refresh the MIDI in/out available devices Cliquer ici pour rafraîchir la liste des périphériques MIDI in/out disponibles Refresh MIDI devices Rafraîchir la liste MIDI MIDI TEMPO (FOR CLOCK SYNC.) TEMPO MIDI (HORLOGE MIDI) Score BPM BPM de la partition Type here the BPM (used by MIDI clock for sync) Taper ici le BPM utilisé pour la synchronisation des horologes MIDI Check this option if you want to sync transport (play, pause, stop, fast rewind, song position) from another sequencer Cocher cette case si vous souhaitez synchroniser le transport (play, pause, stop, retour à zéro, position temporelle) depuis un autre séquenceur SYNC TRANSPORT Check this option if you want to sync clock from another sequencer Cocher cette case si vous souhaitez synchroniser l'horloge avec un autre séquenceur SYNC CLOCK SYNC HORLOGE Mouse position Position de la souris Mouse current position on score Position de la souris dans la partition MOUSE SOURIS Zoom Zoom Score current zoom Zoom actuel dans la partition ZOOM ZOOM Easing Accéleration Can't change ID. Impossible de modifier l'ID. Another object has this ID. Try deleting that object, or change its ID. Un autre objet possède déjà cet ID. Essayez de supprimer cet objet ou changez son ID. IanniX Color Inspector Inspecteur de couleurs IanniX Inspector Inspecteur IanniX Enter the new ID: Entez le nouvel ID de l'objet : Enter the name of the destination group: Entrez le nom du groupe : MOUSE: SOURIS : ZOOM: ZOOM : CURVE COURBE CURSOR CURSEUR No client connected Aucune client connecté 1 client connected 1 client connecté %1 clients connected %1 client connecté UiMessageBox IanniX IanniX ENTER A VALUE FOR ENTRER UNE VALEUR POUR PICTURE IMAGE UiRender IanniX — Render IanniX — Rendu Click+move and mouse wheel to navigate/zoom in score. In 3D, Alt+move, Alt+mouse wheel and Alt+double-click to change camera position. Double-clic on an object to edit messages. Shift+double-clic on an object to force its messages to be sent. Cliquer-déplacer/mollette pour naviguer/zoomer dans la partition. En 3D, Alt+déplacer/Alt+molette et Alt+double-click pour déplacer la caméra. Double-clic sur un objet pour éditer ses messages. Shift+double-click sur un objet pour forcer un envoi de message. Image_%1.png IanniX Curve Resample Rééchantionnage de courbes Number of points: Nombre de points : Image drop… Glisser-déposer d'image Please select the desired action: Veuillez sélectionner une action à réaliser : Use this image as a background Utiliser cette image comme fond de la partition Try to vectorize this image automaticaly Essayer de vectoriser automatiquement l'image Click on score to add points. Double-click or press ESC to end your curve. After, Double-click on a curve to add a point, Command+click to remove it, Double-click on a point to enable/disable smoothing. Shift+double-click to resample curve. Cliquer pour ajouter des points. Double-click ou ESC pour finir une courbe. Ensuite, Double-clic sur la courbe pour ajouter un point, Command+click pour le supprimer, Double-click sur un point pour activer/désactiver le lissage. Shift+double-click pour rééchantilloner la courbe. Click on score to add points. Double-click or press ESC to end your curve. After, Double-click on a curve to add a point, Control+click to remove it, Double-click on a point to enable/disable smoothing. Shift+double-click to resample curve. Cliquer pour ajouter des points. Double-click ou ESC pour finir une courbe. Ensuite, Double-clic sur la courbe pour ajouter un point, Control+click pour le supprimer, Double-click sur un point pour activer/désactiver le lissage. Shift+double-click pour rééchantilloner la courbe. UiSplash IanniX version beta UiTimer IanniX - Timer 000:00.000 UiTransport IanniX — Transport Fast rewind Retour à zéro Press this button to fast rewind the playback Appuyer sur ce bouton pour revenir à zéro Play/pause Press this button to start or pause the playback Appuyer sur ce bouton pour démarrer ou mettre en pause le playback Elapsed time Temps écoulé This area display the elapsed time from the beginning of the playback Cette zone affiche le temps écoulé depuis le début du playback Sent messages Messages envoyés This area displays the sent messages by IanniX Cette zone affiche les messages envoyés par IanniX No message Pas de message Playback speed Vitesse du playback Move this slider to adjust the global playback speed Déplacer le slider pour ajuster la vitesse générale du plauback Change this spinbox to adjust the global playback speed Modifier ce champ pour ajuster la vitesse générale du playback Scheduler period Période du scheduler Report of the time between two calculations or type directly in this box to change it manually Affiche le temps écoulé entre deux calculs de la partition (positions des curseurs et déclenchements des triggers). Vous pouvez aussi changer la valeur directement dans le champ Frames per seconds Images par secondes Displays of the number of frames per seconds or type directly in this box to change it manually Affiche le nombre d'images par secondes. Vous pouvez aussi changer la valeur directement dans le champ Click here to enable or disable Syphon output (video frame exchange between Mac OS apps) Cliquer ici pour activer ou désactiver la sortie vidéo dans Syphon (protocole d'échange d'image entre applications Mac OS) Syphon About IanniX À propos de IanniX Click here to display information about IanniX Cliquer ici pour afficher les informations relatives à IanniX CPU usage Usage CPU Report of the CPU usage Affiche l'utilisation CPU de IanniX UiView IanniX — View IanniX PERFORMANCE MODE MODE PERFORMANCE PREVIEW APERÇU Edit Éditer File Fichier Display Afficher Grid setup Réglage de la grille Playback Arrange objects Aligner les objets Align horizontally Aligner horizontalement Align vertically Aligner verticalement Transport Transport Inspector Inspecteur Toolbar Barre d'outils Undo Annuler Click here to undo last action Cliquer ici pour annuler la dernière action Ctrl+Z Redo Refaire Click here to redo last action Cliquer ici pour répéter la dernière action Ctrl+Y Copy Copier Click here to copy selected objects in clipboard Cliquer ici pour copier les objets sélectionnés dans le presse-papier Ctrl+C Paste Coller Click here to paste copied objects from clipboard Cliquer ici pour coller les objets du presse-papier Ctrl+V Cut Couper Click here to copy and remove selected objects Cliquer ici pour copier et supprimer les objets sélectionnés Ctrl+X Select all Tout sélectionner Click here to select all the selectable objects in the score Cliquer ici pour sélectionner tous les objetsn sélectionnables de la partition Ctrl+A Delete Supprimer Click here to remove selected objects Cliquer ici pour supprimer les objets sélectionnés Backspace New score Nouvelle partition Create a new score Créer une nouvelle partition Click here to create a new empty score Cliquer ici pour créer un nouvelle partition vierge Ctrl+N Open project folder… Ouvrir un projet… Click here to open a folder of scores Cliquer ici pour ouvrir le dossier des partitions Ctrl+O Save current score Sauvegarder la partition Click here to save the current score Cliquer ici pour sauvegarder la partition courante Ctrl+S Quit Quitter Click here to quit IanniX Cliquer ici pour quitter IanniX Ctrl+Q Fullscreen Plein écran Click here to switch to fullscreen Cliquer ici pour activer le plein-écran Ctrl+F Inspector panel Inspecteur Click here to hide/show inspector panel Cliquer ici pour afficher/cacher l'inspecteur Ctrl+Alt+I Transport panel Transport Click here to hide/show transport panel Cliquer ici pour afficher/cacher la barre de transport Ctrl+Alt+T Play/pause Click here to play or pause the playback Cliquer ici pour démarrer ou mettre en pause le playback Space Fast rewind Retour à zéro Click here to fast rewind the playback Cliquer ici pour remettre à zéro le playback F Grid && axis Grille && axes Click here to show/hide score grid and axis Cliquer ici pour afficher/cacher la grille et les axes Ctrl+G Duplicate Dupliquer Click here to duplicate selected objects Cliquer ici pour dupliquer les objets sélectionnés Ctrl+D Autoresize object Redimensionnement automatique des objets Click here to rescale objects according to zoom Cliquer ici pour redimensionner automatiquement les objets en fonction du zoom Ctrl+Shift+A Zoom in Zoomer Click here to zoom in Cliquer ici pour zoomer Ctrl+= Zoom out Dézoomer Click here to zoom out Cliquer ici pour dézoomer Ctrl+- Initial zoom Zoom initial Click here to restore initial zoom Cliquer ici pour restaurer le zoome initial Ctrl+Shift+0 Draw a smooth curve Dessiner une courbe lissée Click here to add and draw a smooth curve in your score. Press ESC or click again to end your curve. Cliquer ici pour ajouter et dessiner une courbe lissée dans la partition. Appuyer sur ESC ou recliquer ici pour finir la courbe. Ctrl+Shift+F Draw straight curve Dessiner une courbe Click here to add and draw a straight curve in your score. Press ESC or click again to end your curve. Cliquer ici pour ajouter et dessiner une courbe dans la partition. Appuyer sur ESC ou recliquer ici pour finir la courbe. Ctrl+Shift+G Add triggers Ajouter des triggers Click here to add triggers in your score. Press ESC or click again to stop adding triggers. Cliquer ici pour ajouter des triggers dans la partition. Appuyer sur ESC ou recliquer ici pour terminer l'ajout. Ctrl+Shift+T Add a cursor Ajouter un curseur Click here to add cursors on the selected curve. If no curve is selected, cursor will be free (controlled by an external source) Cliquer ici pour ajouter des curseurs sur la courbe sélectionnée. Si aucune courbe est sélectionnée, le curseur sera libre (contrôlé par exemple depuis une source externe) 10 seconds 10 secondes 1 second 1 seconde 500 milliseconds 500 millisecondes 100 milliseconds 100 millisecondes 10 milliseconds 10 millisecondes Custom value Valeur personnalisée 100% opaque 100% d'opacité 75% opaque 75% d'opacité 50% opaque 50% d'opacité 25% opaque 25% d'opacité 10% opaque 10% d'opacité Add circular curves Ajouter une courbe circulaire Click here to add circular curves in your score. Press ESC or click again to stop adding circular cuvers. Cliquer ici pour ajouter une courbe circlaire dans la partition. Appuyer sur ESC ou recliquer ici pour finir la courbe. Ctrl+Shift+R Help Aide Click here to display IanniX help in your browser Cliquer ici pour afficher l'aide de IanniX dans le navigateur Snap to X-grid Grille magnétique sur X Click here to snap actions (objects position, curve points…) to grid Cliquer ici pour activer/désactiver la grille magnétique Shift+G Save all scores Sauvegarder toutes les partitions Click here to save all the opened scores Cliquer ici pour sauvegarder toutes les partitions ouvertes Ctrl+Alt+Shift+S Rename score… Renommer la partition… Click here to rename your score Cliquer ici pour renommer la partition Ctrl+Alt+Shift+R Remove score from project folder… Supprimer la partition… Click here to remove this score from your project folder Cliquer ici pour supprimer la partition du projet Duplicate score in project folder Dupliquer la partition Click here to duplicate your score in your project folder Cliquer ici pour dupliquer la partition Lock objects position Vérouiller la position des objets Click here to lock/unlock the position of objects (to avoid moving objects while navigating in the score) Cliquer ici vérouiller/dévérouiller la position des objets (pour éviter de déplacer les objets en naviguant dans la partition) Objects labels Étiquette des objets Click here to show/hide labels on objects Cliquer ici pour afficher/cacher les étiquette des objets Open patches folder Ouvrir le dossier des patches Click here to open the patches folder (external objects for hosts software) provided with IanniX Cliquer ici pour le dossier des patches (objets pour les logiciels hôtes) fourni avec IanniX About IanniX À propos de IanniX Click here to display information about IanniX Cliquer ici pour afficher des informations sur IanniX Send score through default sync output Envoyer la partition sur le port de synchronisation Click here to send your score through the default sync output Cliquer ici pour envoyer la partition via le port de synchronisation Import SVG as a curve… Importer une courbe à partir d'un SVG… Click here to import a SVG file as a curve in your score Cliquer ici pour importer une courbe à partir d'un fichier SVG Import image to be vectorized… Importer une courbe à partir d'une image… Click here to import image to be vectorized in your score Cliquer ici pour importer une courbe à partir d'une image vectorisée automatiquement Import glyph as a curve… Importer une courbe à partir d'un glyphe… Click here to import a glyph as a curve in your score Cliquer ici pour importer une courbe à partir d'un glyphe Script editor window Fenêtre d'éditeur de script Click here to show the script editor window (if you're working on a script) Cliquer ici pour afficher l'éditeur de script (si vous travaillez dans un script) Ctrl+E Reload current script Recharger le script Click here to reload the current script Cliquer ici pour recharger le script Ctrl+R Lighter color theme Thème de couleur lumineux Click here to change the color theme of IanniX Cliquer ici pour changer le thème de couleurs de IanniX Import a background image… Importer une image de fond… Click here to import a background image in your score Cliquer ici pour importer une image de fond Allow triggers selection Autoriser la sélection des triggers Click here to allow/forbid the selection of triggers (on hover, on marquee selection, on select all actions) Cliquer ici pour autoriser/interdire la sélection des triggers (sur toutes les actions de sélection) Allow curves selection Autoriser la sélection des courbes Click here to allow/forbid the selection of curves (on hover, on marquee selection, on select all actions) Cliquer ici pour autoriser/interdire la sélection des courbes (sur toutes les actions de sélection) Allow cursors selection Autoriser la sélection des curseurs Click here to allow/forbid the selection of cursors (on hover, on marquee selection, on select all actions) Cliquer ici pour autoriser/interdire la sélection des curseurs (sur toutes les actions de sélection) Snap to Y-grid Grille magnétique sur Y Shift+H Snap to grid Grille magnétique Copy as a script Copier comme un script Click here to copy selected objects in clipboard as script commands Cliquer ici pour copier le script générant les objets sélectionnés dans le presse-papier Ctrl+Shift+C Paste as a script Coller comme un script Click here to paste scripts commands from clipboard (a script must be loaded before) Cliquer ici pour coller du script provenant du presse-papier Ctrl+Shift+V Distribute horizontally Répartir horizontalement Click here to distribute objects horizontally from the leftmost object to the rightmost object Cliquer ici pour répartir les objets horizontalement, de l'objet le plus à gauche à l'objet le plus à droite Distribute vertically Répartir verticalement Click here to distribute objects vertically from the topmost object to the bottommost object Cliquer ici pour répartir les objets verticalement, de l'objet le plus haut à l'objet le plus bas Align left Aligner à gauche Click here to align objects on the leftmost object Cliquer ici pour aligner les objets sur l'objet le plus à gauche Align center Aligner au centre Click here to align objects on the horizontal center of the selection Cliquer ici pour aligner les objets sur le centre de la sélection Align right Aligner à droite Click here to align objects on the rightmost object Cliquer ici pour aligner les objets sur l'objet le plus à droite Align top Aligner en haut Click here to align objects on the topmost object Cliquer ici pour aligner les objets sur l'objet le plus haut Align middle Aligner au milieu Click here to align objects on the vertical center of the selection Cliquer ici pour aligner les objets sur le milieu de la sélection Align bottom Aligner en bas Click here to align objects on the bottommost object Cliquer ici pour aligner les objets sur l'objet le plus bas Distribute circulary Répartir circulairement Click here to align objects as a circle Cliquer ici pour aligner les objets en forme de cercle Distribute on ellipse Répartir en ellipse Click here to align objects as an ellipse Cliquer ici pour aligner les objets en forme d'ellipse Make a high resolution snapshot Faire une capture haute-résolution Click here to save the current view in a high resolution PNG file (file will be placed on your desktop) Cliquer ici pour exporter la vue courant dans un PNG haute-résolution (le fichier sera placé sur le bureau) Ctrl+Shift+P Performance mode Mode performance Click here to switch to performance mode Cliquez ici pour activer le mode performance Ctrl+P Resize viewport Redimensionner la partition Click here to resize the viewport (the rendering area). Note that it is recommended to hide Transport bar and Inspector bar to get the exact desired size. Cliquer ici pour redimensionner la partition (zone de rendu). Il est recommendé de cacher l'inspecteur ainsi que la barre de transport pour obtenir la taille exacte. Timer window Fenêtre de timer Click here to show the timer window, displaying elapsed time Cliquer ici pour afficher la fenêtre du timer, affichant le temps-écoulé du playback Ctrl+T FULLSCREEN ON DISPLAY %1 (%2 x %3) PLEIN ÉCRAN SUR SORTIE %1 (%2 x %3) Select a SVG file… Sélectionner un fichier SVG SVG Files Fichiers SVG Select an image… Sélectionner une image Images Images Type a glyph or text… Tapez un glyphe ou un texte Type a glyphe or a text to import in IanniX: Tapez un glyphe ou un texte à importer dans IanniX : Snaptshot Capture Snapshot will be saved on your desktop. Please enter a scale factor: La capture va être sauvegardée sur le bureau. Veuillez saisir un facteur de taille : Custom grid value Grille personnalisée Enter the desired grid time value in seconds: Veuillez saisir la grille désirée en secondes : Custom value: Valeur: sec New viewport size Redimensionner la partition %1 x %2 EN FR IanniX-0.9.20/abstractionsgl.cpp000066400000000000000000001126241317340345000165210ustar00rootroot00000000000000#include "abstractionsgl.h" #ifdef Q_OS_MAC #include #endif QList OpenGlTexture::textures = QList(); QHash OpenGlTexture::texturesCache = QHash(); quint32 OpenGlTexture::texturesCacheCount = 0; qreal OpenGlDrawing::dpi = 1; OpenGlTexture* OpenGlTexture::createFromFile(QObject *parent, const QString &filename) { if(texturesCache.contains(filename)) { texturesCacheCount++; //qDebug("[CACHE] %d / %d : %s", texturesCacheCount, texturesCache.count(), qPrintable(filename)); return (texturesCache.value(filename)); } else { //qDebug("[NEW TEXTURE] %d / %d : %s", texturesCacheCount, texturesCache.count(), qPrintable(filename)); return (new OpenGlTexture(parent, filename)); } } OpenGlTexture::OpenGlTexture(QObject *parent) : QObject(parent) { mirrorX = mirrorY = false; video = 0; webView = 0; texture = 0; filename = ""; blurKernelSize = 0; openCvProcess = 0; timerCamera = -1; init = false; textures.append(this); } OpenGlTexture::OpenGlTexture(QObject *parent, const QSizeF &_size) : QObject(parent) { mirrorX = mirrorY = false; video = 0; webView = 0; texture = 0; size = _size; blurKernelSize = 0; openCvProcess = 0; timerCamera = -1; init = false; loadManual(); textures.append(this); } OpenGlTexture::OpenGlTexture(QObject *parent, const QUrl &_url, const QSizeF &_size, qreal _blurKernelSize) : QObject(parent) { mirrorX = mirrorY = false; video = 0; webView = 0; texture = 0; openCvProcess = 0; timerCamera = -1; init = false; loadUrl(_url, _size, _blurKernelSize); textures.append(this); } OpenGlTexture::OpenGlTexture(QObject *parent, const QString &_filename, qreal _blurKernelSize) : QObject(parent) { mirrorX = mirrorY = false; video = 0; webView = 0; texture = 0; init = false; openCvProcess = 0; timerCamera = -1; loadFileImage(_filename, _blurKernelSize); textures.append(this); texturesCache.insert(_filename, this); } OpenGlTexture::OpenGlTexture(QObject *parent, const QString &_filename, const QSizeF &_size, bool inLoop, const QStringList &arguments, qreal _blurKernelSize) : QObject(parent) { mirrorX = mirrorY = false; video = 0; webView = 0; texture = 0; init = false; openCvProcess = 0; loadFileVideo(_filename, _size, inLoop, arguments, _blurKernelSize); textures.append(this); } OpenGlTexture::OpenGlTexture(QObject *parent, const QPixmap &_pixmap, qreal _blurKernelSize) : QObject(parent) { mirrorX = mirrorY = false; video = 0; webView = 0; texture = 0; init = false; timerCamera = -1; openCvProcess = 0; loadPixmap(_pixmap, _blurKernelSize); textures.append(this); } OpenGlTexture::OpenGlTexture(QObject *parent, const QImage &_image, qreal _blurKernelSize) : QObject(parent) { mirrorX = mirrorY = false; video = 0; webView = 0; texture = 0; init = false; timerCamera = -1; openCvProcess = 0; loadImage(_image, _blurKernelSize); textures.append(this); } OpenGlTexture::OpenGlTexture(QObject *parent, const QString &_texte, const OpenGlFont &_texteFont, const QSizeF &_texteSize, qreal _blurKernelSize) : QObject(parent) { mirrorX = mirrorY = false; video = 0; webView = 0; texture = 0; init = false; timerCamera = -1; openCvProcess = 0; loadTexte (_texte, _texteFont, _texteSize, _blurKernelSize); textures.append(this); } OpenGlTexture::~OpenGlTexture() { textures.removeOne(this); if(texturesCache.contains(filename)) texturesCache.remove(filename); //qDebug("[OPENGL] Suppression de la texture #%d", texture); if(video) delete video; if(texture) glDeleteTextures(1, &texture); } void OpenGlTexture::loadUrl(const QUrl &_url, const QSizeF _size, qreal _blurKernelSize) { Q_UNUSED(_url); Q_UNUSED(_size); filename = "web"; init = true; blurKernelSize = _blurKernelSize; } void OpenGlTexture::webPageLoaded() { } void OpenGlTexture::loadFileImage(const QString &_filename, qreal _blurKernelSize) { filename = _filename; init = false; blurKernelSize = _blurKernelSize; if(filename.contains(".tile")) { QFile file(filename); if(file.open(QFile::ReadOnly | QFile::Unbuffered)) { filename = "glpixels"; #ifdef Q_OS_MAC fcntl(file.handle(), F_NOCACHE, 1); // <- disable UBC for that file #endif //Taille de l'image QByteArray firstLineItems = file.readLine(); QStringList lineItems = QString(firstLineItems).split(","); if(lineItems.count() == 2) { size = QSize(lineItems.at(0).toInt(), lineItems.at(1).toInt()); //Payload file.seek(firstLineItems.count()); texturePixels = file.readAll(); } else qDebug("[OpenGL] Tile parse error"); } } else { image.load(filename); if(image.isNull()) { image = QImage(QSize(1, 1), QImage::Format_ARGB32_Premultiplied); image.fill(Qt::transparent); } size = image.size(); } } void OpenGlTexture::loadFileVideo(const QString &_filename, const QSizeF &_size, bool inLoop, const QStringList &arguments, qreal _blurKernelSize) { filename = _filename; init = false; blurKernelSize = _blurKernelSize; size = _size; image = QImage(QSize(1, 1), QImage::Format_ARGB32_Premultiplied); image.fill(Qt::transparent); #ifdef VLC_INSTALLED if(!video) { std::vector vlcArguments; vlcArguments.push_back("--aspect-ratio=width:height"); // vlcArguments.push_back("-vvv"); foreach(const QString &argument, arguments) vlcArguments.push_back(qPrintable(argument)); video = new VlcPlayer(size, vlcArguments); connect(video, SIGNAL(textureUpdate()), SLOT(vlcImageReady())); connect(video, SIGNAL(mediaStartEvent(const libvlc_event_t*)), SLOT(vlcMediaStartEvent(const libvlc_event_t*))); connect(video, SIGNAL(mediaEndEvent(const libvlc_event_t*)), SLOT(vlcMediaEndEvent(const libvlc_event_t*))); } video->setUrl(QUrl::fromLocalFile(_filename), inLoop); #else Q_UNUSED(arguments); Q_UNUSED(inLoop); #endif } void OpenGlTexture::loadWebcam(quint16 camId, bool automaticRefresh) { filename = QString::number(camId); init = false; image = QImage(QSize(1, 1), QImage::Format_ARGB32_Premultiplied); image.fill(Qt::transparent); #ifdef OPENCV_INSTALLED cameraFrame = cv::Mat(size.height(), size.width(), CV_8UC3); qDebug("[CAMERA FIXEE] %d %d", cameraFrame.cols, cameraFrame.rows); //Open camera for(qint16 cameraIndex = camId ; cameraIndex >= 0 ; cameraIndex--) if(capture.open(cameraIndex)) break; //Resize if(capture.isOpened()) { capture.retrieve(cameraFrameRaw); qDebug("[CAMERA NATIVE] %d %d", cameraFrameRaw.cols, cameraFrameRaw.rows); if((cameraFrameRaw.cols > 0) && (cameraFrameRaw.rows > 0)) { cv::resize(cameraFrameRaw, cameraFrame, cameraFrame.size()); size = QSize(cameraFrame.cols, cameraFrame.rows); rgbFrame = cv::Mat(size.height(), size.width(), CV_8UC3); //Timers if(automaticRefresh) timerCamera = startTimer(40); } } #else Q_UNUSED(automaticRefresh); #endif } void OpenGlTexture::grabWebcam() { #ifdef OPENCV_INSTALLED if((capture.isOpened()) && (cameraFrameRaw.cols > 0) && (cameraFrameRaw.rows > 0)) { //qint64 t = QDateTime::currentMSecsSinceEpoch(); capture.grab(); capture.retrieve(cameraFrameRaw); cv::resize(cameraFrameRaw, cameraFrame, cameraFrame.size()); if(openCvProcess) openCvProcess->processWebcam(); cv::cvtColor(cameraFrame, rgbFrame, cv::COLOR_BGR2RGB); image = QImage((uchar*)rgbFrame.data, rgbFrame.cols, rgbFrame.rows, rgbFrame.step, QImage::Format_RGB888); init = false; emit(videoWebcamReady(this)); } #endif } void OpenGlTexture::timerEvent(QTimerEvent *e) { if(e->timerId() == timerCamera) grabWebcam(); } void OpenGlTexture::vlcImageReady() { #ifdef VLC_INSTALLED image = video->image; init = false; #endif } #ifdef VLC_INSTALLED void OpenGlTexture::vlcMediaStartEvent(const libvlc_event_t *event) { emit(videoStartEvent(this, event)); } void OpenGlTexture::vlcMediaEndEvent(const libvlc_event_t *event) { emit(videoEndEvent(this, event)); if(video->inLoop) video->replay(); } #endif void OpenGlTexture::loadPixmap(const QPixmap &_pixmap, qreal _blurKernelSize) { filename = "pixmap"; init = false; blurKernelSize = _blurKernelSize; image = _pixmap.toImage(); size = image.size(); } void OpenGlTexture::loadImage(const QImage &_image, qreal _blurKernelSize) { filename = "pixmap"; init = false; blurKernelSize = _blurKernelSize; image = _image; size = image.size(); } void OpenGlTexture::loadSyphon(GLuint _texture) { texture = _texture; filename = "syphon"; init = true; } GLuint OpenGlTexture::loadManual() { filename = "manual"; init = false; pushTexture(); popTexture(); return texture; } void OpenGlTexture::loadTexte(const QString &_texte, const OpenGlFont &_texteFont, const QSizeF &_size, qreal _blurKernelSize) { if((_texte != texte) || (_size != size)) { filename = "texte"; texte = _texte; texteFont = _texteFont; size = _size; init = false; blurKernelSize = _blurKernelSize; } } bool OpenGlTexture::pushTexture() { if((!init) && (!filename.isEmpty()) && (filename != "syphon")) { if(filename == "glpixels") { //Génération de la texture glEnable(GL_TEXTURE_2D); if(!texture) glGenTextures(1, &texture); glBindTexture (GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//GL_NEAREST glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//GL_NEAREST_MIPMAP_LINEAR glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size.width(), size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, texturePixels.data()); glDisable(GL_TEXTURE_2D); } else { QImage sourceImage; if(filename == "texte") sourceImage = OpenGlDrawing::drawText(Qt::white, texteFont, size, texte); else if(filename == "manual") { sourceImage = QImage(size.toSize(), QImage::Format_ARGB32_Premultiplied); sourceImage.fill(Qt::transparent); } else if(filename == "pixmap") { if(!image.isNull()) sourceImage = image; else return init; } else { if(!image.isNull()) sourceImage = image; if(sourceImage.isNull()) { sourceImage = QImage(filename); if(sourceImage.isNull()) return init; } } //Traitements size = sourceImage.size(); if(blurKernelSize) sourceImage = imageBlurred(sourceImage, sourceImage.rect(), blurKernelSize); //Génération de la texture glEnable(GL_TEXTURE_2D); QString verboseTexte = ""; if(!texture) { glGenTextures(1, &texture); verboseTexte = QString("[OPENGL] Création de la texture #%1 => %2 (%3)").arg(texture).arg(filename).arg(texte); } glBindTexture (GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//GL_NEAREST glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//GL_NEAREST_MIPMAP_LINEAR glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); if(filename == "manual") { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB , size.width(), size.height(), 0, GL_RGB , GL_UNSIGNED_BYTE, QGLWidget::convertToGLFormat(sourceImage).bits()); //if(!verboseTexte.isEmpty()) qDebug("%s (GL_RGB - GL_UNSIGNED_BYTE / %f - %f)", qPrintable(verboseTexte), size.width(), size.height()); } else if(filename == "textureFloat") { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, GL_RGBA, GL_DOUBLE, 0); //if(!verboseTexte.isEmpty()) qDebug("%s (GL_RGBA - GL_DOUBLE / %f - %f)", qPrintable(verboseTexte), size.width(), size.height()); } else { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, QGLWidget::convertToGLFormat(sourceImage).bits()); //if(!verboseTexte.isEmpty()) qDebug("%s (GL_RGBA - GL_UNSIGNED_BYTE / %f - %f)", qPrintable(verboseTexte), size.width(), size.height()); } glDisable(GL_TEXTURE_2D); } init = true; } if(init) { if(isSyphon()) { glEnable(GL_TEXTURE_RECTANGLE_ARB); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture); } else { glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture); } /* glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); */ } return init; } bool OpenGlTexture::popTexture() const { if(init) { if(isSyphon()) glDisable(GL_TEXTURE_RECTANGLE_ARB); else glDisable(GL_TEXTURE_2D); } return init; } QImage OpenGlTexture::imageBlurred(const QImage& image, const QRect& rect, int radius, bool alphaOnly) { if(radius > 0) { int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); int r1 = rect.top(); int r2 = rect.bottom(); int c1 = rect.left(); int c2 = rect.right(); int bpl = result.bytesPerLine(); int rgba[4]; unsigned char* p; int i1 = 0; int i2 = 3; if (alphaOnly) i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3); for (int col = c1; col <= c2; col++) { p = result.scanLine(r1) + col * 4; for (int i = i1; i <= i2; i++) rgba[i] = p[i] << 4; p += bpl; for (int j = r1; j < r2; j++, p += bpl) for (int i = i1; i <= i2; i++) p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; } for (int row = r1; row <= r2; row++) { p = result.scanLine(row) + c1 * 4; for (int i = i1; i <= i2; i++) rgba[i] = p[i] << 4; p += 4; for (int j = c1; j < c2; j++, p += 4) for (int i = i1; i <= i2; i++) p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; } for (int col = c1; col <= c2; col++) { p = result.scanLine(r2) + col * 4; for (int i = i1; i <= i2; i++) rgba[i] = p[i] << 4; p -= bpl; for (int j = r1; j < r2; j++, p -= bpl) for (int i = i1; i <= i2; i++) p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; } for (int row = r1; row <= r2; row++) { p = result.scanLine(row) + c2 * 4; for (int i = i1; i <= i2; i++) rgba[i] = p[i] << 4; p -= 4; for (int j = c1; j < c2; j++, p -= 4) for (int i = i1; i <= i2; i++) p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; } return result; } else return image; } void OpenGlDrawing::drawRectCentred(const QSizeF ¢er, const QSizeF &size, const OpenGlColors &colors, OpenGlTexture *texture, qreal alpha, qreal selected, qreal croppingMode, bool ninePatch, QRectF partialTextureRect) { drawRect(QRectF(QPointF(center.width()/2 - size.width()/2, center.height()/2 - size.height()/2), size), colors, texture, alpha, selected, croppingMode, ninePatch, partialTextureRect); } void OpenGlDrawing::drawRectCentred(const QPointF ¢er, const QSizeF &size, const OpenGlColors &colors, OpenGlTexture *texture, qreal alpha, qreal selected, qreal croppingMode, bool ninePatch, QRectF partialTextureRect) { drawRect(QRectF(QPointF(center.x() - size.width()/2, center.y() - size.height()/2), size), colors, texture, alpha, selected, croppingMode, ninePatch, partialTextureRect); } void OpenGlDrawing::drawRect(const QSizeF &size, const OpenGlColors &colors, OpenGlTexture *texture, qreal alpha, qreal selected, qreal croppingMode, bool ninePatch, QRectF partialTextureRect) { drawRect(QRectF(QPointF(0, 0), size), colors, texture, alpha, selected, croppingMode, ninePatch, partialTextureRect); } void OpenGlDrawing::drawRect(OpenGlTexture *texture, const OpenGlColors &colors, qreal alpha, qreal selected, qreal croppingMode, bool ninePatch, QRectF partialTextureRect) { drawRect(QRectF(QPointF(0, 0), texture->size), colors, texture, alpha, selected, croppingMode, ninePatch, partialTextureRect); } void OpenGlDrawing::drawRect(OpenGlTexture *texture, qreal alpha, qreal selected, qreal croppingMode, bool ninePatch, QRectF partialTextureRect) { drawRect(QRectF(QPointF(0, 0), texture->size), OpenGlColors(Qt::white), texture, alpha, selected, croppingMode, ninePatch, partialTextureRect); } void OpenGlDrawing::drawRect(const QRectF &rect, const OpenGlColors &colors, OpenGlTexture *texture, qreal alpha, qreal selected, qreal croppingMode, bool ninePatch, QRectF partialTextureRect) { QRectF textureRect, targetRect = rect; alpha = qBound(qreal(0.), alpha, qreal(1.)); selected = qBound(qreal(0.), selected, qreal(1.)); //Cropping if(!colors.isColorTransparent()) { QList< QPair > drawingRects; if(texture) { if((texture->filename == "texte") && (croppingMode == -1)) croppingMode = -3; if(croppingMode == -3) textureRect = QRectF(QPointF(0, 0), targetRect.size()); else if(croppingMode == -2) { textureRect = QRectF(QPointF(0, 0), texture->size); targetRect.setSize(textureRect.size() / qMax(textureRect.width(), textureRect.height()) * qMax(rect.width(), rect.height())); qreal scaleDepassement = qMax(targetRect.width() / rect.width(), targetRect.height() / rect.height()); if(scaleDepassement > 1) targetRect.setSize(targetRect.size() / scaleDepassement); targetRect = QRectF(QPointF(rect.x() + rect.width() / 2 - targetRect.width() / 2, rect.y() + rect.height() / 2 - targetRect.height() / 2), QSizeF(targetRect.width(), targetRect.height())); } else if(croppingMode == -1) { textureRect = QRectF(QPointF(0, 0), texture->size); if((partialTextureRect.width() > 0) && (partialTextureRect.height() > 0)) textureRect = QRectF(QPointF(partialTextureRect.x() * texture->size.width(), partialTextureRect.y() * texture->size.width()), QSizeF (partialTextureRect.width() * texture->size.width(), partialTextureRect.height() * texture->size.height())); } else if(croppingMode >= 0) { textureRect.setSize(targetRect.size() / qMax(targetRect.width(), targetRect.height()) * qMax(texture->size.width(), texture->size.height())); qreal scaleDepassement = qMax(textureRect.width() / texture->size.width(), textureRect.height() / texture->size.height()); if(scaleDepassement > 1) textureRect.setSize(textureRect.size() / scaleDepassement); qreal panXMax = textureRect.width() - texture->size.width(), panYMax = textureRect.height() - texture->size.height(); qreal panX = ((2*croppingMode)-1) * panXMax/2, panY = ((2*croppingMode)-1) * panYMax/2; textureRect = QRectF(QPointF(panX + texture->size.width() / 2 - textureRect.width() / 2, panY + texture->size.height() / 2 - textureRect.height() / 2), QSizeF(textureRect.width(), textureRect.height())); } if(ninePatch) { QPointF part; qreal textureRectCote = qMin(textureRect.width() / 3., textureRect.height() / 3.); qreal targetRectCote = qMin(targetRect.width() / 3., targetRect.height() / 3.); //4 Coins part = QPointF(0, 0); drawingRects.append(qMakePair(QRectF(QPointF(targetRect.x() + part.x() * (targetRect.width() - targetRectCote), targetRect.y() + part.y() * (targetRect.height() - targetRectCote)), QSizeF(targetRectCote, targetRectCote)), QRectF(QPointF(textureRect.x() + part.x() * (textureRect.width() - textureRectCote), textureRect.y() + (1-part.y()) * (textureRect.height() - textureRectCote)), QSizeF(textureRectCote, textureRectCote)))); part = QPointF(1, 0); drawingRects.append(qMakePair(QRectF(QPointF(targetRect.x() + part.x() * (targetRect.width() - targetRectCote), targetRect.y() + part.y() * (targetRect.height() - targetRectCote)), QSizeF(targetRectCote, targetRectCote)), QRectF(QPointF(textureRect.x() + part.x() * (textureRect.width() - textureRectCote), textureRect.y() + (1-part.y()) * (textureRect.height() - textureRectCote)), QSizeF(textureRectCote, textureRectCote)))); part = QPointF(1, 1); drawingRects.append(qMakePair(QRectF(QPointF(targetRect.x() + part.x() * (targetRect.width() - targetRectCote), targetRect.y() + part.y() * (targetRect.height() - targetRectCote)), QSizeF(targetRectCote, targetRectCote)), QRectF(QPointF(textureRect.x() + part.x() * (textureRect.width() - textureRectCote), textureRect.y() + (1-part.y()) * (textureRect.height() - textureRectCote)), QSizeF(textureRectCote, textureRectCote)))); part = QPointF(0, 1); drawingRects.append(qMakePair(QRectF(QPointF(targetRect.x() + part.x() * (targetRect.width() - targetRectCote), targetRect.y() + part.y() * (targetRect.height() - targetRectCote)), QSizeF(targetRectCote, targetRectCote)), QRectF(QPointF(textureRect.x() + part.x() * (textureRect.width() - textureRectCote), textureRect.y() + (1-part.y()) * (textureRect.height() - textureRectCote)), QSizeF(textureRectCote, textureRectCote)))); //Haut-Bas drawingRects.append(qMakePair(QRectF(QPointF(targetRect.x() + 1 * targetRectCote + 0 * (targetRect.width() - targetRectCote), targetRect.y() + 0 * targetRectCote + 0 * (targetRect.height() - targetRectCote)), QSizeF(0 * targetRectCote + 1 * (targetRect.width() - 2 * targetRectCote), 1 * targetRectCote + 0 * (targetRect.height() - 2 * targetRectCote))), QRectF(QPointF(textureRect.x() + 1 * textureRectCote + 0 * (textureRect.width() - textureRectCote), textureRect.y() + 0 * textureRectCote + 1 * (textureRect.height() - textureRectCote)), QSizeF(0 * textureRectCote + 1 * (textureRect.width() - 2 * textureRectCote), 1 * textureRectCote + 0 * (textureRect.height() - 2 * textureRectCote))))); drawingRects.append(qMakePair(QRectF(QPointF(targetRect.x() + 1 * targetRectCote + 0 * (targetRect.width() - targetRectCote), targetRect.y() + 0 * targetRectCote + 1 * (targetRect.height() - targetRectCote)), QSizeF(0 * targetRectCote + 1 * (targetRect.width() - 2 * targetRectCote), 1 * targetRectCote + 0 * (targetRect.height() - 2 * targetRectCote))), QRectF(QPointF(textureRect.x() + 1 * textureRectCote + 0 * (textureRect.width() - textureRectCote), textureRect.y() + 0 * textureRectCote + 0 * (textureRect.height() - textureRectCote)), QSizeF(0 * textureRectCote + 1 * (textureRect.width() - 2 * textureRectCote), 1 * textureRectCote + 0 * (textureRect.height() - 2 * textureRectCote))))); //Gauche-Droite drawingRects.append(qMakePair(QRectF(QPointF(targetRect.x() + 0 * targetRectCote + 0 * (targetRect.width() - targetRectCote), targetRect.y() + 1 * targetRectCote + 0 * (targetRect.height() - targetRectCote)), QSizeF(1 * targetRectCote + 0 * (targetRect.width() - 2 * targetRectCote), 0 * targetRectCote + 1 * (targetRect.height() - 2 * targetRectCote))), QRectF(QPointF(textureRect.x() + 0 * textureRectCote + 0 * (textureRect.width() - textureRectCote), textureRect.y() + 1 * textureRectCote + 0 * (textureRect.height() - textureRectCote)), QSizeF(1 * textureRectCote + 0 * (textureRect.width() - 2 * textureRectCote), 0 * textureRectCote + 1 * (textureRect.height() - 2 * textureRectCote))))); drawingRects.append(qMakePair(QRectF(QPointF(targetRect.x() + 0 * targetRectCote + 1 * (targetRect.width() - targetRectCote), targetRect.y() + 1 * targetRectCote + 0 * (targetRect.height() - targetRectCote)), QSizeF(1 * targetRectCote + 0 * (targetRect.width() - 2 * targetRectCote), 0 * targetRectCote + 1 * (targetRect.height() - 2 * targetRectCote))), QRectF(QPointF(textureRect.x() + 0 * textureRectCote + 1 * (textureRect.width() - textureRectCote), textureRect.y() + 1 * textureRectCote + 0 * (textureRect.height() - textureRectCote)), QSizeF(1 * textureRectCote + 0 * (textureRect.width() - 2 * textureRectCote), 0 * textureRectCote + 1 * (textureRect.height() - 2 * textureRectCote))))); //Central drawingRects.append(qMakePair(QRectF(QPointF(targetRect.x() + targetRectCote, targetRect.y() + targetRectCote), QSizeF(targetRect.width() - 2 * targetRectCote, targetRect.height() - 2 * targetRectCote)), QRectF(QPointF(textureRect.x() + textureRectCote, textureRect.y() + textureRectCote), QSizeF(textureRect.width() - 2 * textureRectCote, textureRect.height() - 2 * textureRectCote)))); } } //Rectangle intégral if(!drawingRects.count()) drawingRects.append(qMakePair(targetRect, textureRect)); //Dessin if(texture) texture->pushTexture(); for(quint8 drawingRectsIndex = 0 ; drawingRectsIndex < drawingRects.count() ; drawingRectsIndex++) { QRectF currentTargetRect = drawingRects.at(drawingRectsIndex).first, currentTextureRect = drawingRects.at(drawingRectsIndex).second; if((texture) && (!texture->isSyphon())) currentTextureRect = QRectF(QPointF(currentTextureRect.x() / texture->size.width(), currentTextureRect.y() / texture->size.height()), QSizeF (currentTextureRect.width() / texture->size.width(), currentTextureRect.height() / texture->size.height())); if(texture) currentTextureRect = QRectF(QPointF(currentTextureRect.x(), currentTextureRect.y() + currentTextureRect.height()), QSizeF(currentTextureRect.width(), -currentTextureRect.height())); //currentTargetRect = currentTargetRect.toRect(); if(texture) { if(texture->mirrorX) { QRectF oldCurrentTextureRect = currentTextureRect; currentTextureRect.setTopLeft (oldCurrentTextureRect.topRight()); currentTextureRect.setBottomRight(oldCurrentTextureRect.bottomLeft()); } if(texture->mirrorY) { QRectF oldCurrentTextureRect = currentTextureRect; currentTextureRect.setTopLeft (oldCurrentTextureRect.bottomLeft()); currentTextureRect.setBottomRight(oldCurrentTextureRect.topRight()); } } glBegin(GL_QUADS); colors.glColorStart(alpha, selected); if(texture) glTexCoord2f(currentTextureRect.topLeft().x(), currentTextureRect.topLeft().y()); glVertex2f(currentTargetRect.topLeft() .x(), currentTargetRect.topLeft() .y()); if(colors.colorDirection(selected)) colors.glColorEnd(alpha, selected); if(texture) glTexCoord2f(currentTextureRect.topRight().x(), currentTextureRect.topRight().y()); glVertex2f(currentTargetRect.topRight() .x(), currentTargetRect.topRight() .y()); colors.glColorEnd(alpha, selected); if(texture) glTexCoord2f(currentTextureRect.bottomRight().x(), currentTextureRect.bottomRight().y()); glVertex2f(currentTargetRect.bottomRight().x(), currentTargetRect.bottomRight().y()); if(colors.colorDirection(selected)) colors.glColorStart(alpha, selected); if(texture) glTexCoord2f(currentTextureRect.bottomLeft().x(), currentTextureRect.bottomLeft().y()); glVertex2f(currentTargetRect.bottomLeft() .x(), currentTargetRect.bottomLeft() .y()); glEnd(); } if(texture) texture->popTexture(); } //Bordure if((colors.borderNeed()) & (!colors.isBorderTransparent())) { glLineWidth(OpenGlDrawing::dpi * colors.borderWidth(selected)); glBegin(GL_LINE_LOOP); colors.glBorderStart(alpha, selected); glVertex2f(targetRect.topLeft() .x(), targetRect.topLeft() .y()); if(colors.borderDirection(selected)) colors.glBorderEnd(alpha, selected); glVertex2f(targetRect.topRight() .x(), targetRect.topRight() .y()); colors.glBorderEnd(alpha, selected); glVertex2f(targetRect.bottomRight().x(), targetRect.bottomRight().y()); if(colors.borderDirection(selected)) colors.glBorderStart(alpha, selected); glVertex2f(targetRect.bottomLeft() .x(), targetRect.bottomLeft() .y()); glEnd(); glLineWidth(OpenGlDrawing::dpi); } } qreal OpenGlDrawing::measureText(const OpenGlFont &font, qreal width, const QString &text) { return drawText(0, Qt::black, font, QRectF(0, 0, width, 0), text); } QImage OpenGlDrawing::drawText(const QColor &color, const OpenGlFont &font, const QSizeF &size, const QString &text) { QImage sourceImage(size.toSize(), QImage::Format_ARGB32_Premultiplied); sourceImage.fill(Qt::transparent); QPainter painter(&sourceImage); OpenGlDrawing::drawText(&painter, color, font, QRectF(QPointF(0, 0), sourceImage.size()), text); painter.end(); return sourceImage; } qreal OpenGlDrawing::drawText(QPainter *painter, const QColor &color, const OpenGlFont &font, const QRectF &rect, const QString &_text) { if(painter) painter->setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing | QPainter::TextAntialiasing); QFontMetrics fontMetrics(font); QString text = _text; if((font.alignement() & Qt::TextSingleLine) == Qt::TextSingleLine) text = QFontMetrics(font).elidedText(text, Qt::ElideRight, rect.width()); if((text.toLower().startsWith("setFont(font); if(((font.alignementFlags() & Qt::AlignVCenter) == Qt::AlignVCenter) || ((font.alignementFlags() & Qt::AlignBottom ) == Qt::AlignBottom)) { painter->setPen(Qt::transparent); QString textMeasure = text; textMeasure = textMeasure.replace("
    ", "\n").replace("
    ", "\n"); qreal fontHeight = 0; if(text.toLower().startsWith("drawStaticText(QPointF(0, 0), staticText); //qDebug("%s\tH:%f\tC:%f\tSH:%f\tPOS:%f", qPrintable(text), rect.height(), rect.center().y(), staticText.size().height(), rect.center().y() - staticText.size().height()/2); if((font.alignementFlags() & Qt::AlignVCenter) == Qt::AlignVCenter) pos.setY(qMax(qreal(0.), rect.center().y() - fontHeight/2)); else if((font.alignementFlags() & Qt::AlignBottom) == Qt::AlignBottom) pos.setY(rect.bottom() - fontHeight); painter->setPen(color); painter->drawStaticText(pos, staticText); } else { painter->setPen(color); painter->drawStaticText(pos, staticText); } } return staticText.size().height(); } else if((font.leading() == 100) && (font.pLeading() == 0)) { if(painter) { painter->setPen(color); painter->setFont(font); painter->drawText(rect, font.alignement(), text); } return fontMetrics.boundingRect(rect.toRect(), font.alignement(), text).height(); } else { QTextOption textOption(font.alignementFlags()); textOption.setTabStop(40); qreal leading = fontMetrics.leading() + fontMetrics.height() * font. leading() / 100.; qreal interparagraph = fontMetrics.height() * font.pLeading() / 100.; qreal height = 0; //qreal totalHeight = fontMetrics.boundingRect(0, 0, rect.width(), 0, font.alignement(), _text).height(); QStringList paragraphs = text.split("\n"); qreal textPreCalculatedHeight = rect.height(); if(((font.alignementFlags() & Qt::AlignVCenter) == Qt::AlignVCenter) || ((font.alignementFlags() & Qt::AlignBottom ) == Qt::AlignBottom)) textPreCalculatedHeight = fontMetrics.boundingRect(0, 0, rect.width(), 0, font.alignement(), text).height() + paragraphs.count() * interparagraph; foreach(const QString ¶graph, paragraphs) { QTextLayout textLayout(paragraph, font); textLayout.setTextOption(textOption); textLayout.beginLayout(); while (1) { QTextLine line = textLayout.createLine(); if (!line.isValid()) break; line.setLineWidth(rect.width()); line.setPosition(QPointF(0, height)); height += leading; } textLayout.endLayout(); if(painter) painter->setPen(color); QPointF margin(0, 1); if( (font.alignementFlags() & Qt::AlignVCenter) == Qt::AlignVCenter) margin.setY(rect.height() / 2 - textPreCalculatedHeight / 2); else if((font.alignementFlags() & Qt::AlignBottom ) == Qt::AlignBottom) margin.setY(rect.height() - textPreCalculatedHeight); if(painter) textLayout.draw(painter, rect.topLeft() + margin); height += interparagraph; } return height; } } IanniX-0.9.20/abstractionsgl.h000066400000000000000000000411611317340345000161630ustar00rootroot00000000000000#ifndef ABSTRACTIONSGL_H #define ABSTRACTIONSGL_H #include #include #include #include #include #include #include #include #include #include #ifdef USE_GLWIDGET #include #include #else #include #include #include #endif #ifdef VLC_INSTALLED #include "drivers/vlc.h" #endif #ifdef Q_OS_WIN #define GL_TEXTURE_RECTANGLE_ARB GL_TEXTURE_2D #define GL_CLAMP_TO_EDGE GL_REPEAT #endif #ifdef OPENCV_INSTALLED #include #include #include #include #include #include #include #include #endif class OpenGlFont : public QFont { private: qreal _leading, _pLeading; int _alignement; public: explicit OpenGlFont() : QFont() { _leading = 100; _pLeading = 0; _alignement = Qt::AlignCenter | Qt::TextWordWrap; } inline qreal leading() const { return _leading; } inline void setLeading(qreal __leading) { _leading = __leading; } inline qreal pLeading() const { return _pLeading; } inline void setPLeading(qreal __pLeading) { _pLeading = __pLeading; } inline int alignement() const { return _alignement; } inline Qt::Alignment alignementFlags() const { return (Qt::Alignment)_alignement; } inline void setAlignement(int __alignement) { _alignement = __alignement; } public: static inline const OpenGlFont getFont(const QString &family, int options = Qt::AlignCenter, quint16 size = 16, qreal leading = 100, qreal spacing = 100, qreal pLeading = 0, QFont::Stretch strech = QFont::Unstretched, QFont::Weight graisse = QFont::Normal, bool italic = false) { OpenGlFont font; QStringList familySplit = family.split("|", QString::SkipEmptyParts); if(familySplit.count() > 1) { font.setFamily (familySplit.at(0)); #ifndef IANNIX_32 font.setStyleName(familySplit.at(1)); #endif } else font.setFamily(familySplit.at(0)); font.setWeight(graisse); font.setStretch(strech); font.setPixelSize(size); font.setItalic(italic); font.setLeading(leading); font.setPLeading(pLeading); font.setAlignement(options); font.setLetterSpacing(QFont::PercentageSpacing, spacing); #ifndef IANNIX_32 if(!font.exactMatch()) qDebug("[FONT] %s —> %s, %s", qPrintable(family), qPrintable(font.family()), qPrintable(font.styleName())); #endif return font; } }; class OpenCvProcess { public: virtual void processWebcam() = 0; }; class OpenGlTexture : public QObject { Q_OBJECT public: bool mirrorX, mirrorY; static QList textures; static QHash texturesCache; static quint32 texturesCacheCount; GLuint texture; QByteArray texturePixels; bool init; QString filename, texte; QImage image; OpenGlFont texteFont; qreal blurKernelSize; void *webView; #ifdef VLC_INSTALLED VlcPlayer *video; #else void* video; #endif private: int timerCamera; #ifdef OPENCV_INSTALLED cv::VideoCapture capture; public: cv::Mat cameraFrame, rgbFrame, cameraFrameRaw; signals: void videoWebcamReady(OpenGlTexture*); #endif public slots: void grabWebcam(); void timerEvent(QTimerEvent *); public: QSizeF size; OpenCvProcess *openCvProcess; public: static OpenGlTexture* createFromFile(QObject *parent, const QString &filename); public: explicit OpenGlTexture(QObject *parent); explicit OpenGlTexture(QObject *parent, const QSizeF &_size); explicit OpenGlTexture(QObject *parent, const QString &_filename, qreal _blurKernelSize = 0); explicit OpenGlTexture(QObject *parent, const QString &_filename, const QSizeF &_size, bool inLoop = false, const QStringList &arguments = QStringList(), qreal _blurKernelSize = 0); explicit OpenGlTexture(QObject *parent, const QUrl &_url, const QSizeF &_size, qreal _blurKernelSize = 0); explicit OpenGlTexture(QObject *parent, const QPixmap &_pixmap, qreal _blurKernelSize = 0); explicit OpenGlTexture(QObject *parent, const QImage &_image, qreal _blurKernelSize = 0); explicit OpenGlTexture(QObject *parent, const QString &_texte, const OpenGlFont &_texteFont, const QSizeF &_texteSize, qreal _blurKernelSize = 0); ~OpenGlTexture(); public: inline bool isSyphon() const { return (filename == "syphon"); } void loadUrl(const QUrl &_url, const QSizeF _size, qreal _blurKernelSize = 0); void loadFileImage(const QString &_filename, qreal _blurKernelSize = 0); void loadFileVideo(const QString &_filename, const QSizeF &_size, bool inLoop = false, const QStringList &arguments = QStringList(), qreal _blurKernelSize = 0); void loadPixmap(const QPixmap &_pixmap, qreal _blurKernelSize = 0); void loadImage(const QImage &_image, qreal _blurKernelSize = 0); void loadSyphon(GLuint _texture); void loadWebcam(quint16 camId = 1, bool automaticRefresh = true); void loadTexte(const QString &_texte, const OpenGlFont &_texteFont, const QSizeF &_size, qreal _blurKernelSize = 0); GLuint loadManual(); public: bool pushTexture(); bool popTexture() const; #ifdef VLC_INSTALLED signals: void videoStartEvent(OpenGlTexture*, const libvlc_event_t*); void videoEndEvent(OpenGlTexture*, const libvlc_event_t*); private slots: void vlcMediaStartEvent(const libvlc_event_t*); void vlcMediaEndEvent(const libvlc_event_t*); #endif private slots: void webPageLoaded(); void vlcImageReady(); public: static QImage imageBlurred(const QImage& image, const QRect& rect, int radius, bool alphaOnly = false); }; class OpenGlColor : public QList { public: bool direction; public: explicit OpenGlColor() : QList() { append(Qt::transparent); append(Qt::transparent); } explicit OpenGlColor(const QColor &colorStart, const QColor &colorEnd, bool _direction = false) : QList() { append(Qt::transparent); append(Qt::transparent); setColor(colorStart, colorEnd, _direction); } explicit OpenGlColor(const QColor &globalColor) : QList() { append(Qt::transparent); append(Qt::transparent); setColor(globalColor); } public: inline bool isTransparent() const { return ((at(0).alpha() == 0) && (at(1).alpha() == 0)); } inline void setColorStart(const QColor &color, bool _direction = false) { replace(0, color); direction = _direction; } inline void setColorEnd (const QColor &color, bool _direction = false) { replace(1, color); direction = _direction; } inline void setColor(const QColor &colorStart, const QColor &colorEnd, bool _direction = false) { setColorStart(colorStart, _direction); setColorEnd (colorEnd , _direction); } inline void setColor(const QColor &globalColor) { setColorStart(globalColor); setColorEnd (globalColor); } public: inline OpenGlColor& operator=(const QColor &globalColor) { setColor(globalColor); return *this; } public: inline void glColor (qreal alpha = 1) const { glColorStart(alpha); } inline void glColorStart(qreal alpha = 1) const { glColor4f(at(0).redF(), at(0).greenF(), at(0).blueF(), at(0).alphaF() * alpha); } inline void glColorEnd (qreal alpha = 1) const { glColor4f(at(1).redF(), at(1).greenF(), at(1).blueF(), at(1).alphaF() * alpha); } }; class OpenGlColors { private: OpenGlColor unselectedColor, selectedColor; OpenGlColor unselectedBorder, selectedBorder; public: qreal unselectedBorderWidth, selectedBorderWidth; public: explicit OpenGlColors() { } OpenGlColors(const OpenGlColor &globalColor) { OpenGlColors(); setColor(globalColor); selectedBorderWidth = unselectedBorderWidth = 0; } OpenGlColors(const QColor &globalColor) { OpenGlColors(); selectedBorderWidth = unselectedBorderWidth = 0; setColor(globalColor); } OpenGlColors(const OpenGlColor &_unselected, const OpenGlColor &_selected) { OpenGlColors(); selectedBorderWidth = unselectedBorderWidth = 0; setColor(_unselected, _selected); } OpenGlColors(const QColor &_unselected, const OpenGlColor &_selected) { OpenGlColors(); selectedBorderWidth = unselectedBorderWidth = 0; setColor(_unselected, _selected); } OpenGlColors(const OpenGlColor &_unselected, const QColor &_selected) { OpenGlColors(); selectedBorderWidth = unselectedBorderWidth = 0; setColor(_unselected, _selected); } OpenGlColors(const QColor &_unselected, const QColor &_selected) { OpenGlColors(); selectedBorderWidth = unselectedBorderWidth = 0; setColor(_unselected, _selected); } public: inline OpenGlColors& operator=(const OpenGlColor &globalColor) { setColor(globalColor); return *this; } inline OpenGlColors& operator=(const QColor &globalColor) { setColor(globalColor); return *this; } public: inline bool isColorTransparent() const { return (selectedColor.isTransparent() && unselectedColor.isTransparent()); } inline bool isBorderTransparent() const { return (selectedBorder.isTransparent() && unselectedBorder.isTransparent()); } inline void setColor(const QColor &globalColor) { unselectedColor = globalColor; selectedColor = globalColor; } inline void setColor(const OpenGlColor &globalColor) { unselectedColor = globalColor; selectedColor = globalColor; } inline void setColor(const OpenGlColor &_unselected, const OpenGlColor &_selected) { unselectedColor = _unselected; selectedColor = _selected; } inline void setColor(const QColor &_unselected, const OpenGlColor &_selected) { unselectedColor = _unselected; selectedColor = _selected; } inline void setColor(const OpenGlColor &_unselected, const QColor &_selected) { unselectedColor = _unselected; selectedColor = _selected; } inline void setColor(const QColor &_unselected, const QColor &_selected) { unselectedColor = _unselected; selectedColor = _selected; } public: inline void setBorder(const QColor &globalBorder, qreal _borderWidth = 1) { unselectedBorder = globalBorder; selectedBorder = globalBorder; selectedBorderWidth = _borderWidth; unselectedBorderWidth = _borderWidth; } inline void setBorder(const OpenGlColor &globalBorder, qreal _borderWidth = 1) { unselectedBorder = globalBorder; selectedBorder = globalBorder; selectedBorderWidth = _borderWidth; unselectedBorderWidth = _borderWidth; } inline void setBorder(const OpenGlColor &_unselected, const OpenGlColor &_selected, qreal _unselectedBorderWidth = 1, qreal _selectedBorderWidth = 1) { unselectedBorder = _unselected; selectedBorder = _selected; selectedBorderWidth = _selectedBorderWidth; unselectedBorderWidth = _unselectedBorderWidth; } inline void setBorder(const QColor &_unselected, const OpenGlColor &_selected, qreal _unselectedBorderWidth = 1, qreal _selectedBorderWidth = 1) { unselectedBorder = _unselected; selectedBorder = _selected; selectedBorderWidth = _selectedBorderWidth; unselectedBorderWidth = _unselectedBorderWidth; } inline void setBorder(const OpenGlColor &_unselected, const QColor &_selected, qreal _unselectedBorderWidth = 1, qreal _selectedBorderWidth = 1) { unselectedBorder = _unselected; selectedBorder = _selected; selectedBorderWidth = _selectedBorderWidth; unselectedBorderWidth = _unselectedBorderWidth; } inline void setBorder(const QColor &_unselected, const QColor &_selected, qreal _unselectedBorderWidth = 1, qreal _selectedBorderWidth = 1) { unselectedBorder = _unselected; selectedBorder = _selected; selectedBorderWidth = _selectedBorderWidth; unselectedBorderWidth = _unselectedBorderWidth; } public: inline void glColor (qreal alpha = 1, qreal selected = 0) const { glColorStart ( alpha, selected); } inline void glColorStart (qreal alpha = 1, qreal selected = 0) const { glColorIndex (0, alpha, selected); } inline void glColorEnd (qreal alpha = 1, qreal selected = 0) const { glColorIndex (1, alpha, selected); } inline void glBorder (qreal alpha = 1, qreal selected = 0) const { glBorderStart( alpha, selected); } inline void glBorderStart(qreal alpha = 1, qreal selected = 0) const { glBorderIndex(0, alpha, selected); } inline void glBorderEnd (qreal alpha = 1, qreal selected = 0) const { glBorderIndex(1, alpha, selected); } inline bool colorDirection(qreal selected = 0) const { if(selected < 0.5) return unselectedColor.direction; else return selectedColor .direction; } inline bool borderDirection(qreal selected = 0) const { if(selected < 0.5) return unselectedBorder.direction; else return selectedBorder .direction; } inline bool borderNeed() const { return ((unselectedBorderWidth > 0) || (selectedBorderWidth > 0)); } inline qreal borderWidth(qreal selected = 0) const { return (selectedBorderWidth * selected) + (unselectedBorderWidth * (1 - selected)); } private: inline void glColorIndex (qint8 index = 0, qreal alpha = 1, qreal selected = 0) const { glColor4f( selectedColor.at(index).redF() * selected + unselectedColor.at(index).redF() * (1 - selected), selectedColor.at(index).greenF() * selected + unselectedColor.at(index).greenF() * (1 - selected), selectedColor.at(index).blueF() * selected + unselectedColor.at(index).blueF() * (1 - selected), (selectedColor.at(index).alphaF() * selected + unselectedColor.at(index).alphaF() * (1 - selected)) * alpha); } inline void glBorderIndex(qint8 index = 0, qreal alpha = 1, qreal selected = 0) const { glColor4f( selectedBorder.at(index).redF() * selected + unselectedBorder.at(index).redF() * (1 - selected), selectedBorder.at(index).greenF() * selected + unselectedBorder.at(index).greenF() * (1 - selected), selectedBorder.at(index).blueF() * selected + unselectedBorder.at(index).blueF() * (1 - selected), (selectedBorder.at(index).alphaF() * selected + unselectedBorder.at(index).alphaF() * (1 - selected)) * alpha); } }; class OpenGlDrawing { public: static qreal dpi; static void drawRectCentred(const QSizeF ¢er, const QSizeF &size, const OpenGlColors &colors, OpenGlTexture *texture = 0, qreal alpha = 1., qreal selected = 0, qreal croppingMode = -1, bool ninePatch = false, QRectF partialTextureRect = QRectF(0,0,-1,-1)); static void drawRectCentred(const QPointF ¢er, const QSizeF &size, const OpenGlColors &colors, OpenGlTexture *texture = 0, qreal alpha = 1., qreal selected = 0, qreal croppingMode = -1, bool ninePatch = false, QRectF partialTextureRect = QRectF(0,0,-1,-1)); static void drawRect(OpenGlTexture *texture, const OpenGlColors &colors = OpenGlColors(Qt::white), qreal alpha = 1., qreal selected = 0, qreal croppingMode = -1, bool ninePatch = false, QRectF partialTextureRect = QRectF(0,0,-1,-1)); static void drawRect(OpenGlTexture *texture, qreal alpha, qreal selected = 0, qreal croppingMode = -1, bool ninePatch = false, QRectF partialTextureRect = QRectF(0,0,-1,-1)); static void drawRect(const QSizeF &size, const OpenGlColors &colors, OpenGlTexture *texture = 0, qreal alpha = 1., qreal selected = 0, qreal croppingMode = -1, bool ninePatch = false, QRectF partialTextureRect = QRectF(0,0,-1,-1)); static void drawRect(const QRectF &rect, const OpenGlColors &colors, OpenGlTexture *texture = 0, qreal alpha = 1., qreal selected = 0, qreal croppingMode = -1, bool ninePatch = false, QRectF partialTextureRect = QRectF(0,0,-1,-1)); static qreal measureText(const OpenGlFont &font, qreal width, const QString &text); static QImage drawText(const QColor &color, const OpenGlFont &font, const QSizeF &size, const QString &text); static qreal drawText(QPainter *painter, const QColor &color, const OpenGlFont &font, const QRectF &rect, const QString &text); }; #endif // ABSTRACTIONSGL_H IanniX-0.9.20/geometry/000077500000000000000000000000001317340345000146235ustar00rootroot00000000000000IanniX-0.9.20/geometry/nxeasing.cpp000066400000000000000000000027031317340345000171450ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #include "nxeasing.h" const QPixmap NxEasing::getPixmap() const { QPixmap pixmap(128, 128); pixmap.fill(Qt::transparent); QPainter painter; painter.begin(&pixmap); painter.setPen(QPen(Qt::black, 2)); QPointF pt1(0, pixmap.height()), pt2; for(quint16 x = 0 ; x < pixmap.width() ; x++) { pt2 = QPointF(x, pixmap.height() * (1-getValue((qreal)x / (qreal)pixmap.width()))); painter.drawLine(pt1, pt2); pt1 = pt2; } painter.end(); return pixmap; } IanniX-0.9.20/geometry/nxeasing.h000066400000000000000000000027251317340345000166160ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #ifndef NXEASING_H #define NXEASING_H #include #include #include class NxEasing { private: QEasingCurve easing; public: const QPixmap getPixmap() const; public: inline void setType(quint16 type) { easing.setType((QEasingCurve::Type)type); } inline quint16 getType() const { return easing.type(); } inline qreal getValue(qreal progress) const { return qBound(qreal(0.), easing.valueForProgress(progress), qreal(1.)); } }; #endif // NXEASING_H IanniX-0.9.20/geometry/nxline.cpp000066400000000000000000000041261317340345000166270ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #include "nxline.h" bool NxLine::isNull() const { return (qFuzzyCompare(pt1.x(), pt2.x()) && qFuzzyCompare(pt1.y(), pt2.y())) ? true : false; } qreal NxLine::length() const { qreal x = pt2.x() - pt1.x(); qreal y = pt2.y() - pt1.y(); qreal z = pt2.z() - pt1.z(); return qSqrt(x*x + y*y + z*z); } NxLine::IntersectType NxLine::intersect(const NxLine &l, NxPoint *intersectionPoint) const { // ipmlementation is based on Graphics Gems III's "Faster Line Segment Intersection" const NxPoint a = pt2 - pt1; const NxPoint b = l.pt1 - l.pt2; const NxPoint c = pt1 - l.pt1; const qreal denominator = a.y() * b.x() - a.x() * b.y(); if (denominator == 0 || !qIsFinite(denominator)) return NoIntersection; const qreal reciprocal = 1 / denominator; const qreal na = (b.y() * c.x() - b.x() * c.y()) * reciprocal; if (intersectionPoint) *intersectionPoint = pt1 + a * na; if (na < 0 || na > 1) return UnboundedIntersection; const qreal nb = (a.x() * c.y() - a.y() * c.x()) * reciprocal; if (nb < 0 || nb > 1) return UnboundedIntersection; return BoundedIntersection; } IanniX-0.9.20/geometry/nxline.h000066400000000000000000000120231317340345000162670ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #ifndef NXLINE_H #define NXLINE_H #include #include #include "nxpoint.h" class NxLine { public: enum IntersectType { NoIntersection, BoundedIntersection, UnboundedIntersection }; inline NxLine(); inline NxLine(const NxPoint &pt1, const NxPoint &pt2); inline NxLine(qreal x1, qreal y1, qreal x2, qreal y2); inline NxLine(qreal x1, qreal y1, qreal z1, qreal x2, qreal y2, qreal z2); bool isNull() const; inline NxPoint p1() const; inline NxPoint p2() const; inline qreal x1() const; inline qreal y1() const; inline qreal z1() const; inline qreal x2() const; inline qreal y2() const; inline qreal z2() const; inline qreal dx() const; inline qreal dy() const; inline qreal dz() const; qreal length() const; void setLength(qreal len); // ### Qt 5: rename intersects() or intersection() and rename IntersectType IntersectionType IntersectType intersect(const NxLine &l, NxPoint *intersectionPoint) const; NxPoint pointAt(qreal t) const; inline void translate(const NxPoint &p); inline void translate(qreal dx, qreal dy, qreal dz); inline NxLine translated(const NxPoint &p) const; inline NxLine translated(qreal dx, qreal dy, qreal dz) const; inline void setP1(const NxPoint &p1); inline void setP2(const NxPoint &p2); inline void setPoints(const NxPoint &p1, const NxPoint &p2); inline void setLine(qreal x1, qreal y1, qreal z1, qreal x2, qreal y2, qreal z2); inline bool operator==(const NxLine &d) const; inline bool operator!=(const NxLine &d) const { return !(*this == d); } private: NxPoint pt1, pt2; }; Q_DECLARE_TYPEINFO(NxLine, Q_MOVABLE_TYPE); /******************************************************************************* * class NxLine inline members *******************************************************************************/ inline NxLine::NxLine() { } inline NxLine::NxLine(const NxPoint &apt1, const NxPoint &apt2) : pt1(apt1), pt2(apt2) { } inline NxLine::NxLine(qreal x1pos, qreal y1pos, qreal x2pos, qreal y2pos) : pt1(x1pos, y1pos, 0), pt2(x2pos, y2pos, 0) { } inline NxLine::NxLine(qreal x1pos, qreal y1pos, qreal z1pos, qreal x2pos, qreal y2pos, qreal z2pos) : pt1(x1pos, y1pos, z1pos), pt2(x2pos, y2pos, z2pos) { } inline qreal NxLine::x1() const { return pt1.x(); } inline qreal NxLine::y1() const { return pt1.y(); } inline qreal NxLine::z1() const { return pt1.z(); } inline qreal NxLine::x2() const { return pt2.x(); } inline qreal NxLine::y2() const { return pt2.y(); } inline qreal NxLine::z2() const { return pt2.z(); } inline NxPoint NxLine::p1() const { return pt1; } inline NxPoint NxLine::p2() const { return pt2; } inline qreal NxLine::dx() const { return pt2.x() - pt1.x(); } inline qreal NxLine::dy() const { return pt2.y() - pt1.y(); } inline qreal NxLine::dz() const { return pt2.z() - pt1.z(); } inline void NxLine::translate(const NxPoint &point) { pt1 += point; pt2 += point; } inline void NxLine::translate(qreal adx, qreal ady, qreal adz) { this->translate(NxPoint(adx, ady, adz)); } inline NxLine NxLine::translated(const NxPoint &p) const { return NxLine(pt1 + p, pt2 + p); } inline NxLine NxLine::translated(qreal adx, qreal ady, qreal adz) const { return translated(NxPoint(adx, ady, adz)); } inline NxPoint NxLine::pointAt(qreal t) const { qreal vx = pt2.x() - pt1.x(); qreal vy = pt2.y() - pt1.y(); qreal vz = pt2.z() - pt1.z(); return NxPoint(pt1.x() + vx * t, pt1.y() + vy * t, pt2.z() + vz * t); } inline void NxLine::setP1(const NxPoint &aP1) { pt1 = aP1; } inline void NxLine::setP2(const NxPoint &aP2) { pt2 = aP2; } inline void NxLine::setPoints(const NxPoint &aP1, const NxPoint &aP2) { pt1 = aP1; pt2 = aP2; } inline void NxLine::setLine(qreal aX1, qreal aY1, qreal aZ1, qreal aX2, qreal aY2, qreal aZ2) { pt1 = NxPoint(aX1, aY1, aZ1); pt2 = NxPoint(aX2, aY2, aZ2); } inline bool NxLine::operator==(const NxLine &d) const { return pt1 == d.pt1 && pt2 == d.pt2; } #endif // NXLINE_H IanniX-0.9.20/geometry/nxpoint.cpp000066400000000000000000000041001317340345000170210ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #include "nxpoint.h" #include #include #include qreal NxPoint::length() const { return qSqrt(xp * xp + yp * yp + zp * zp); } qreal NxPoint::lengthSquared() const { return xp * xp + yp * yp + zp * zp; } NxPoint NxPoint::normalized() const { // Need some extra precision if the length is very small. double len = double(xp) * double(xp) + double(yp) * double(yp) + double(zp) * double(zp); if (qFuzzyIsNull(len - 1.0f)) return *this; else if (!qFuzzyIsNull(len)) return *this / qSqrt(len); else return NxPoint(); } void NxPoint::normalize() { // Need some extra precision if the length is very small. double len = double(xp) * double(xp) + double(yp) * double(yp) + double(zp) * double(zp); if (qFuzzyIsNull(len - 1.0f) || qFuzzyIsNull(len)) return; len = qSqrt(len); xp /= len; yp /= len; zp /= len; } qreal NxPoint::dotProduct(const NxPoint& v1, const NxPoint& v2) { return v1.xp * v2.xp + v1.yp * v2.yp + v1.zp * v2.zp; } IanniX-0.9.20/geometry/nxpoint.h000066400000000000000000000172751317340345000165070ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #ifndef NXPOINT_H #define NXPOINT_H #include class NxPoint{ public: NxPoint(); NxPoint(qreal xpos, qreal ypos); NxPoint(qreal xpos, qreal ypos, qreal zpos); NxPoint(qreal xpos, qreal ypos, qreal zpos, qreal sx, qreal sy, qreal sz); NxPoint(qreal xpos, qreal ypos, qreal zpos, qreal sx, qreal sy, qreal sz, qreal angleZ); NxPoint(float xpos, float ypos, float zpos, int dummy); bool isNull() const; qreal x() const; qreal y() const; qreal z() const; qreal sx() const; qreal sy() const; qreal sz() const; qreal angleZ() const; void setX(qreal x); void setY(qreal y); void setZ(qreal z); void setSx(qreal sx); void setSy(qreal sy); void setSz(qreal sz); qreal length() const; qreal lengthSquared() const; NxPoint normalized() const; void normalize(); NxPoint &operator+=(const NxPoint &vector); NxPoint &operator-=(const NxPoint &vector); NxPoint &operator*=(qreal factor); NxPoint &operator*=(const NxPoint &vector); NxPoint &operator/=(qreal divisor); static qreal dotProduct(const NxPoint& v1, const NxPoint& v2); friend inline bool operator==(const NxPoint &v1, const NxPoint &v2); friend inline bool operator!=(const NxPoint &v1, const NxPoint &v2); friend inline const NxPoint operator+(const NxPoint &v1, const NxPoint &v2); friend inline const NxPoint operator-(const NxPoint &v1, const NxPoint &v2); friend inline const NxPoint operator*(qreal factor, const NxPoint &vector); friend inline const NxPoint operator*(const NxPoint &vector, qreal factor); friend inline const NxPoint operator*(const NxPoint &v1, const NxPoint& v2); friend inline const NxPoint operator-(const NxPoint &vector); friend inline const NxPoint operator/(const NxPoint &vector, qreal divisor); friend inline bool qFuzzyCompare(const NxPoint& v1, const NxPoint& v2); QPoint toPoint() const; QPointF toPointF() const; private: float xp, yp, zp; float sxp, syp, szp; float angleZp; }; Q_DECLARE_TYPEINFO(NxPoint, Q_MOVABLE_TYPE); inline NxPoint::NxPoint() : xp(0.0f), yp(0.0f), zp(0.0f), sxp(0.0f), syp(0.0f), szp(0.0f) {} inline NxPoint::NxPoint(qreal xpos, qreal ypos) : xp(xpos), yp(ypos), zp(0.0f), sxp(0.0f), syp(0.0f), szp(0.0f) {} inline NxPoint::NxPoint(qreal xpos, qreal ypos, qreal zpos) : xp(xpos), yp(ypos), zp(zpos), sxp(0.0f), syp(0.0f), szp(0.0f) {} inline NxPoint::NxPoint(float xpos, float ypos, float zpos, int) : xp(xpos), yp(ypos), zp(zpos), sxp(0.0f), syp(0.0f), szp(0.0f) {} inline NxPoint::NxPoint(qreal xpos, qreal ypos, qreal zpos, qreal sx, qreal sy, qreal sz) : xp(xpos), yp(ypos), zp(zpos), sxp(sx), syp(sy), szp(sz) {} inline NxPoint::NxPoint(qreal xpos, qreal ypos, qreal zpos, qreal sx, qreal sy, qreal sz, qreal angleZ) : xp(xpos), yp(ypos), zp(zpos), sxp(sx), syp(sy), szp(sz), angleZp(angleZ) {} inline bool NxPoint::isNull() const { return qIsNull(xp) && qIsNull(yp) && qIsNull(zp); } inline qreal NxPoint::x() const { return qreal(xp); } inline qreal NxPoint::y() const { return qreal(yp); } inline qreal NxPoint::z() const { return qreal(zp); } inline qreal NxPoint::sx() const { return qreal(sxp); } inline qreal NxPoint::sy() const { return qreal(syp); } inline qreal NxPoint::sz() const { return qreal(szp); } inline qreal NxPoint::angleZ() const { return qreal(angleZp); } inline void NxPoint::setX(qreal aX) { xp = aX; } inline void NxPoint::setY(qreal aY) { yp = aY; } inline void NxPoint::setZ(qreal aZ) { zp = aZ; } inline void NxPoint::setSx(qreal aSx) { sxp = aSx; } inline void NxPoint::setSy(qreal aSy) { syp = aSy; } inline void NxPoint::setSz(qreal aSz) { szp = aSz; } inline NxPoint &NxPoint::operator+=(const NxPoint &vector) { xp += vector.xp; yp += vector.yp; zp += vector.zp; sxp += vector.sxp; syp += vector.syp; szp += vector.szp; return *this; } inline NxPoint &NxPoint::operator-=(const NxPoint &vector) { xp -= vector.xp; yp -= vector.yp; zp -= vector.zp; sxp -= vector.sxp; syp -= vector.syp; szp -= vector.szp; return *this; } inline NxPoint &NxPoint::operator*=(qreal factor) { xp *= factor; yp *= factor; zp *= factor; sxp *= factor; syp *= factor; szp *= factor; return *this; } inline NxPoint &NxPoint::operator*=(const NxPoint &vector) { xp *= vector.xp; yp *= vector.yp; zp *= vector.zp; sxp *= vector.sxp; syp *= vector.syp; szp *= vector.szp; return *this; } inline NxPoint &NxPoint::operator/=(qreal divisor) { xp /= divisor; yp /= divisor; zp /= divisor; sxp *= divisor; syp *= divisor; szp *= divisor; return *this; } inline bool operator==(const NxPoint &v1, const NxPoint &v2) { return v1.xp == v2.xp && v1.yp == v2.yp && v1.zp == v2.zp && v1.sxp == v2.sxp && v1.syp == v2.syp && v1.szp == v2.szp; } inline bool operator!=(const NxPoint &v1, const NxPoint &v2) { return v1.xp != v2.xp || v1.yp != v2.yp || v1.zp != v2.zp || v1.sxp != v2.sxp || v1.syp != v2.syp || v1.szp != v2.szp; } inline const NxPoint operator+(const NxPoint &v1, const NxPoint &v2) { return NxPoint(v1.xp + v2.xp, v1.yp + v2.yp, v1.zp + v2.zp, v1.sxp + v2.sxp, v1.syp + v2.syp, v1.szp + v2.szp); } inline const NxPoint operator-(const NxPoint &v1, const NxPoint &v2) { return NxPoint(v1.xp - v2.xp, v1.yp - v2.yp, v1.zp - v2.zp, v1.sxp - v2.sxp, v1.syp - v2.syp, v1.szp - v2.szp); } inline const NxPoint operator*(qreal factor, const NxPoint &vector) { return NxPoint(vector.xp * factor, vector.yp * factor, vector.zp * factor, vector.sxp * factor, vector.syp * factor, vector.szp * factor); } inline const NxPoint operator*(const NxPoint &vector, qreal factor) { return NxPoint(vector.xp * factor, vector.yp * factor, vector.zp * factor, vector.sxp * factor, vector.syp * factor, vector.szp * factor); } inline const NxPoint operator*(const NxPoint &v1, const NxPoint& v2) { return NxPoint(v1.xp * v2.xp, v1.yp * v2.yp, v1.zp * v2.zp, v1.sxp * v2.sxp, v1.syp * v2.syp, v1.szp * v2.szp); } inline const NxPoint operator-(const NxPoint &vector) { return NxPoint(-vector.xp, -vector.yp, -vector.zp, -vector.sxp, -vector.syp, -vector.szp); } inline const NxPoint operator/(const NxPoint &vector, qreal divisor) { return NxPoint(vector.xp / divisor, vector.yp / divisor, vector.zp / divisor, vector.sxp / divisor, vector.syp / divisor, vector.szp / divisor); } inline bool qFuzzyCompare(const NxPoint& v1, const NxPoint& v2) { return qFuzzyCompare(v1.xp, v2.xp) && qFuzzyCompare(v1.yp, v2.yp) && qFuzzyCompare(v1.zp, v2.zp) && qFuzzyCompare(v1.sxp, v2.sxp) && qFuzzyCompare(v1.syp, v2.syp) && qFuzzyCompare(v1.szp, v2.szp); } #endif IanniX-0.9.20/geometry/nxpolygon.cpp000066400000000000000000000074701317340345000173740ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #include "nxpolygon.h" /* static void qt_polygon_isect_line(const NxPoint &p1, const NxPoint &p2, const NxPoint &pos, int *winding) { qreal x1 = p1.x(); qreal y1 = p1.y(); //qreal z1 = p1.z(); qreal x2 = p2.x(); qreal y2 = p2.y(); //qreal z2 = p2.z(); qreal y = pos.y(); int dir = 1; if (qFuzzyCompare(y1, y2)) { // ignore horizontal lines according to scan conversion rule return; } else if (y2 < y1) { qreal x_tmp = x2; x2 = x1; x1 = x_tmp; qreal y_tmp = y2; y2 = y1; y1 = y_tmp; dir = -1; } if (y >= y1 && y < y2) { qreal x = x1 + ((x2 - x1) / (y2 - y1)) * (y - y1); // count up the winding number if we're if (x<=pos.x()) { (*winding) += dir; } } } */ NxRect NxPolygon::boundingRect() const { if (isEmpty()) return NxRect(0, 0, 0, 0, 0, 0); register const NxPoint *pd = constData(); qreal minx, maxx, miny, maxy, minz, maxz; minx = maxx = pd->x(); miny = maxy = pd->y(); minz = maxz = pd->z(); ++pd; for (int i = 1; i < size(); ++i) { if (pd->x() < minx) minx = pd->x(); else if (pd->x() > maxx) maxx = pd->x(); if (pd->y() < miny) miny = pd->y(); else if (pd->y() > maxy) maxy = pd->y(); if (pd->z() < minz) minz = pd->z(); else if (pd->z() > maxz) maxz = pd->z(); ++pd; } return NxRect(minx,miny,minz, maxx - minx, maxy - miny, maxz - minz); } bool NxPolygon::containsPoint(const NxPoint &pt, Qt::FillRule) const { if (isEmpty()) return false; /* int winding_number = 0; NxPoint last_pt = at(0); NxPoint last_start = at(0); for (int i = 1; i < size(); ++i) { const NxPoint &e = at(i); qt_polygon_isect_line(last_pt, e, pt, &winding_number); last_pt = e; } // implicitly close last subpath if (last_pt != last_start) qt_polygon_isect_line(last_pt, last_start, pt, &winding_number); return (fillRule == Qt::WindingFill ? (winding_number != 0) : ((winding_number % 2) != 0)); */ //qint16 sum = 0, sum2 = 0; bool first = true, direction = true, directionOk = false; for(quint16 i = 0 ; i < count() ; i++) { NxPoint pt0 = at(i), pt1 = at((i+1)%count()); qreal val = (pt.y() - pt0.y()) * (pt1.x() - pt0.x()) - (pt.x() - pt0.x()) * (pt1.y() - pt0.y()); if(val > 0) { if((!direction) && (directionOk) && (!first)) return false; direction = true; directionOk = true; } else if(val < 0) { if((direction) && (directionOk) && (!first)) return false; direction = false; directionOk = true; } first = false; } return true; } IanniX-0.9.20/geometry/nxpolygon.h000066400000000000000000000030761317340345000170370ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #ifndef NXPOLYGON_H #define NXPOLYGON_H #include #include "nxpoint.h" #include "nxrect.h" #include "math.h" class NxPolygon : public QVector { public: inline NxPolygon() {} inline ~NxPolygon() {} inline NxPolygon(int size); inline NxPolygon(const NxPolygon &a) : QVector(a) {} inline NxPolygon(const QVector &v) : QVector(v) {} NxPolygon(const QPolygon &a); NxRect boundingRect() const; bool containsPoint(const NxPoint &pt, Qt::FillRule fillRule) const; }; inline NxPolygon::NxPolygon(int asize) : QVector(asize) {} #endif // NXPOLYGON_H IanniX-0.9.20/geometry/nxrect.cpp000066400000000000000000000124241317340345000166350ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #include "nxrect.h" NxRect NxRect::normalized() const { NxRect r = *this; if (r.w < 0) { r.xp += r.w; r.w = -r.w; r.l = r.l; } if (r.h < 0) { r.yp += r.h; r.h = -r.h; r.l = r.l; } return r; } bool NxRect::contains(const NxPoint &p) const { qreal l = xp; qreal r = xp; if (w < 0) l += w; else r += w; if (l == r) // null rect return false; if (p.x() < l || p.x() > r) return false; qreal t = yp; qreal b = yp; if (h < 0) t += h; else b += h; if (t == b) // null rect return false; if (p.y() < t || p.y() > b) return false; return true; } bool NxRect::contains(const NxRect &r) const { qreal l1 = xp; qreal r1 = xp; if (w < 0) l1 += w; else r1 += w; if (l1 == r1) // null rect return false; qreal l2 = r.xp; qreal r2 = r.xp; if (r.w < 0) l2 += r.w; else r2 += r.w; if (l2 == r2) // null rect return false; if (l2 < l1 || r2 > r1) return false; qreal t1 = yp; qreal b1 = yp; if (h < 0) t1 += h; else b1 += h; if (t1 == b1) // null rect return false; qreal t2 = r.yp; qreal b2 = r.yp; if (r.h < 0) t2 += r.h; else b2 += r.h; if (t2 == b2) // null rect return false; if (t2 < t1 || b2 > b1) return false; /* qreal f1 = zp; qreal ff1 = zp; if (l < 0) f1 += l; else ff1 += l; if (f1 == ff1) // null rect return false; qreal f2 = r.zp; qreal ff2 = r.zp; if (r.h < 0) f2 += r.l; else ff2 += r.l; if (f2 == f2) // null rect return false; if (f2 < ff1 || f2 > ff1) return false; */ return true; } NxRect NxRect::operator|(const NxRect &r) const { if (isNull()) return r; if (r.isNull()) return *this; qreal left = xp; qreal right = xp; if (w < 0) left += w; else right += w; if (r.w < 0) { left = qMin(left, r.xp + r.w); right = qMax(right, r.xp); } else { left = qMin(left, r.xp); right = qMax(right, r.xp + r.w); } qreal top = yp; qreal bottom = yp; if (h < 0) top += h; else bottom += h; if (r.h < 0) { top = qMin(top, r.yp + r.h); bottom = qMax(bottom, r.yp); } else { top = qMin(top, r.yp); bottom = qMax(bottom, r.yp + r.h); } return NxRect(left, top, right - left, bottom - top); } NxRect NxRect::operator&(const NxRect &r) const { qreal l1 = xp; qreal r1 = xp; if (w < 0) l1 += w; else r1 += w; if (l1 == r1) // null rect return NxRect(); qreal l2 = r.xp; qreal r2 = r.xp; if (r.w < 0) l2 += r.w; else r2 += r.w; if (l2 == r2) // null rect return NxRect(); if (l1 >= r2 || l2 >= r1) return NxRect(); qreal t1 = yp; qreal b1 = yp; if (h < 0) t1 += h; else b1 += h; if (t1 == b1) // null rect return NxRect(); qreal t2 = r.yp; qreal b2 = r.yp; if (r.h < 0) t2 += r.h; else b2 += r.h; if (t2 == b2) // null rect return NxRect(); if (t1 >= b2 || t2 >= b1) return NxRect(); NxRect tmp; tmp.xp = qMax(l1, l2); tmp.yp = qMax(t1, t2); tmp.w = qMin(r1, r2) - tmp.xp; tmp.h = qMin(b1, b2) - tmp.yp; return tmp; } bool NxRect::intersects(const NxRect &r) const { qreal l1 = xp; qreal r1 = xp; if (w < 0) l1 += w; else r1 += w; if (l1 == r1) // null rect return false; qreal l2 = r.xp; qreal r2 = r.xp; if (r.w < 0) l2 += r.w; else r2 += r.w; if (l2 == r2) // null rect return false; if (l1 >= r2 || l2 >= r1) return false; qreal t1 = yp; qreal b1 = yp; if (h < 0) t1 += h; else b1 += h; if (t1 == b1) // null rect return false; qreal t2 = r.yp; qreal b2 = r.yp; if (r.h < 0) t2 += r.h; else b2 += r.h; if (t2 == b2) // null rect return false; if (t1 >= b2 || t2 >= b1) return false; return true; } IanniX-0.9.20/geometry/nxrect.h000066400000000000000000000265731317340345000163140ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #ifndef NXRECT_H #define NXRECT_H #include #include "nxpoint.h" #include "nxsize.h" class NxRect { public: NxRect() { xp = yp = zp = 0.; w = h = l = 0.; } NxRect(const NxPoint &topleft, const NxSize &size); NxRect(const NxPoint &topleft, const NxPoint &bottomRight); NxRect(qreal left, qreal top, qreal width, qreal height); NxRect(qreal left, qreal top, qreal z, qreal width, qreal height, qreal length); NxRect(const QRect &rect); bool isNull() const; bool isEmpty() const; bool isValid() const; NxRect normalized() const; inline qreal left() const { return xp; } inline qreal right() const { return xp + w; } inline qreal top() const { return yp; } inline qreal bottom() const { return yp + h; } inline qreal zTop() const { return zp; } inline qreal zBottom() const { return zp + l; } inline qreal x() const; inline qreal y() const; inline qreal z() const; inline void setLeft(qreal pos); inline void setRight(qreal pos); inline void setTop(qreal pos); inline void setBottom(qreal pos); inline void setzTop(qreal pos); inline void setzBottom(qreal pos); inline void setX(qreal pos) { setLeft(pos); } inline void setY(qreal pos) { setTop(pos); } inline NxPoint topLeft() const { return NxPoint(xp, yp, zp); } inline NxPoint topRight() const { return NxPoint(xp+w, yp, zp); } inline NxPoint bottomLeft() const { return NxPoint(xp, yp+h, zp+l); } inline NxPoint bottomRight() const { return NxPoint(xp+w, yp+h, zp+l); } inline NxPoint center() const; void setTopLeft(const NxPoint &p); void setBottomRight(const NxPoint &p); void setTopRight(const NxPoint &p); void setBottomLeft(const NxPoint &p); void moveLeft(qreal pos); void moveTop(qreal pos); void moveRight(qreal pos); void moveBottom(qreal pos); void moveTopLeft(const NxPoint &p); void moveBottomRight(const NxPoint &p); void moveTopRight(const NxPoint &p); void moveBottomLeft(const NxPoint &p); void moveCenter(const NxPoint &p); void translate(qreal dx, qreal dy, qreal dz); void translate(const NxPoint &p); NxRect translated(qreal dx, qreal dy, qreal dz) const; NxRect translated(const NxPoint &p) const; void moveTo(qreal x, qreal y, qreal z); void moveTo(const NxPoint &p); void setRect(qreal x, qreal y, qreal z, qreal w, qreal h, qreal l); void getRect(qreal *x, qreal *y, qreal *z, qreal *w, qreal *h, qreal *l) const; void setCoords(qreal x1, qreal y1, qreal z1, qreal x2, qreal y2, qreal z2); void getCoords(qreal *x1, qreal *y1, qreal *z1, qreal *x2, qreal *y2, qreal *z2) const; inline void adjust(qreal x1, qreal y1, qreal z1, qreal x2, qreal y2, qreal z2); inline NxRect adjusted(qreal x1, qreal y1, qreal z1, qreal x2, qreal y2, qreal z2) const; NxSize size() const; qreal width() const; qreal height() const; qreal length() const; void setWidth(qreal w); void setHeight(qreal h); void setLength(qreal l); void setSize(const NxSize &s); NxRect operator|(const NxRect &r) const; NxRect operator&(const NxRect &r) const; NxRect& operator|=(const NxRect &r); NxRect& operator&=(const NxRect &r); bool contains(const NxPoint &p) const; bool contains(qreal x, qreal y, qreal z) const; bool contains(const NxRect &r) const; NxRect unite(const NxRect &r) const; // ### Qt 5: make QT4_SUPPORT NxRect united(const NxRect &other) const; NxRect intersect(const NxRect &r) const; // ### Qt 5: make QT4_SUPPORT NxRect intersected(const NxRect &other) const; bool intersects(const NxRect &r) const; friend bool operator==(const NxRect &, const NxRect &); friend bool operator!=(const NxRect &, const NxRect &); private: qreal xp; qreal yp; qreal zp; qreal w; qreal h; qreal l; }; Q_DECLARE_TYPEINFO(NxRect, Q_MOVABLE_TYPE); bool operator==(const NxRect &, const NxRect &); bool operator!=(const NxRect &, const NxRect &); /***************************************************************************** NxRect inline member functions *****************************************************************************/ inline NxRect::NxRect(qreal aleft, qreal atop, qreal az, qreal awidth, qreal aheight, qreal alength) : xp(aleft), yp(atop), zp(az), w(awidth), h(aheight), l(alength) {} inline NxRect::NxRect(qreal aleft, qreal atop, qreal awidth, qreal aheight) : xp(aleft), yp(atop), zp(0), w(awidth), h(aheight), l(0) {} inline NxRect::NxRect(const NxPoint &atopLeft, const NxSize &asize) { xp = atopLeft.x(); yp = atopLeft.y(); zp = atopLeft.z(); w = asize.width(); h = asize.height(); l = asize.length(); } inline NxRect::NxRect(const NxPoint &atopLeft, const NxPoint &abottomRight) { xp = atopLeft.x(); yp = atopLeft.y(); zp = atopLeft.z(); w = abottomRight.x() - xp; h = abottomRight.y() - yp; l = abottomRight.z() - zp; } inline bool NxRect::isNull() const { return w == 0. && h == 0. && l == 0.; } inline bool NxRect::isEmpty() const { return w <= 0. || h <= 0. || l <= 0.; } inline bool NxRect::isValid() const { return w > 0. && h > 0. && l > 0.; } inline qreal NxRect::x() const { return xp; } inline qreal NxRect::y() const { return yp; } inline qreal NxRect::z() const { return zp; } inline void NxRect::setLeft(qreal pos) { qreal diff = pos - xp; xp += diff; w -= diff; } inline void NxRect::setRight(qreal pos) { w = pos - xp; } inline void NxRect::setTop(qreal pos) { qreal diff = pos - yp; yp += diff; h -= diff; } inline void NxRect::setBottom(qreal pos) { h = pos - yp; } inline void NxRect::setzTop(qreal pos) { l = pos - zp; } inline void NxRect::setzBottom(qreal pos) { qreal diff = pos - zp; zp += diff; l -= diff; } inline void NxRect::setTopLeft(const NxPoint &p) { setLeft(p.x()); setTop(p.y()); setzTop(p.z()); } inline void NxRect::setTopRight(const NxPoint &p) { setRight(p.x()); setTop(p.y()); setzTop(p.z()); } inline void NxRect::setBottomLeft(const NxPoint &p) { setLeft(p.x()); setBottom(p.y()); setzBottom(p.z()); } inline void NxRect::setBottomRight(const NxPoint &p) { setRight(p.x()); setBottom(p.y()); setzBottom(p.z()); } inline NxPoint NxRect::center() const { return NxPoint(xp + w/2, yp + h/2, zp + l/2); } inline void NxRect::moveLeft(qreal pos) { xp = pos; } inline void NxRect::moveTop(qreal pos) { yp = pos; } inline void NxRect::moveRight(qreal pos) { xp = pos - w; } inline void NxRect::moveBottom(qreal pos) { yp = pos - h; } inline void NxRect::moveTopLeft(const NxPoint &p) { moveLeft(p.x()); moveTop(p.y()); } inline void NxRect::moveTopRight(const NxPoint &p) { moveRight(p.x()); moveTop(p.y()); } inline void NxRect::moveBottomLeft(const NxPoint &p) { moveLeft(p.x()); moveBottom(p.y()); } inline void NxRect::moveBottomRight(const NxPoint &p) { moveRight(p.x()); moveBottom(p.y()); } inline void NxRect::moveCenter(const NxPoint &p) { xp = p.x() - w/2; yp = p.y() - h/2; } inline qreal NxRect::width() const { return w; } inline qreal NxRect::height() const { return h; } inline qreal NxRect::length() const { return l; } inline NxSize NxRect::size() const { return NxSize(w, h, l); } inline void NxRect::translate(qreal dx, qreal dy, qreal dz) { xp += dx; yp += dy; zp += dz; } inline void NxRect::translate(const NxPoint &p) { xp += p.x(); yp += p.y(); zp += p.z(); } inline void NxRect::moveTo(qreal ax, qreal ay, qreal az) { xp = ax; yp = ay; zp = az; } inline void NxRect::moveTo(const NxPoint &p) { xp = p.x(); yp = p.y(); zp = p.z(); } inline NxRect NxRect::translated(qreal dx, qreal dy, qreal dz) const { return NxRect(xp + dx, yp + dy, zp + dz, w, h, l); } inline NxRect NxRect::translated(const NxPoint &p) const { return NxRect(xp + p.x(), yp + p.y(), zp + p.z(), w, h, l); } inline void NxRect::getRect(qreal *ax, qreal *ay, qreal *az, qreal *aaw, qreal *aah, qreal *aal) const { *ax = this->xp; *ay = this->yp; *az = this->zp; *aaw = this->w; *aah = this->h; *aal = this->l; } inline void NxRect::setRect(qreal ax, qreal ay, qreal az, qreal aaw, qreal aah, qreal aal) { this->xp = ax; this->yp = ay; this->zp = az; this->w = aaw; this->h = aah; this->l = aal; } inline void NxRect::getCoords(qreal *xp1, qreal *yp1, qreal *zp1, qreal *xp2, qreal *yp2, qreal *zp2) const { *xp1 = xp; *yp1 = yp; *zp1 = zp; *xp2 = xp + w; *yp2 = yp + h; *zp2 = zp + l; } inline void NxRect::setCoords(qreal xp1, qreal yp1, qreal zp1, qreal xp2, qreal yp2, qreal zp2) { xp = xp1; yp = yp1; zp = zp1; w = xp2 - xp1; h = yp2 - yp1; l = zp2 - zp1; } inline void NxRect::adjust(qreal xp1, qreal yp1, qreal zp1, qreal xp2, qreal yp2, qreal zp2) { xp += xp1; yp += yp1; zp += zp1; w += xp2 - xp1; h += yp2 - yp1; l += zp2 - zp1; } inline NxRect NxRect::adjusted(qreal xp1, qreal yp1, qreal zp1, qreal xp2, qreal yp2, qreal zp2) const { return NxRect(xp + xp1, yp + yp1, zp + zp1, w + xp2 - xp1, h + yp2 - yp1, l + zp2 - zp1); } inline void NxRect::setWidth(qreal aw) { this->w = aw; } inline void NxRect::setHeight(qreal ah) { this->h = ah; } inline void NxRect::setLength(qreal al) { this->l = al; } inline void NxRect::setSize(const NxSize &s) { w = s.width(); h = s.height(); l = s.length(); } inline bool NxRect::contains(qreal ax, qreal ay, qreal az) const { return contains(NxPoint(ax, ay, az)); } inline NxRect& NxRect::operator|=(const NxRect &r) { *this = *this | r; return *this; } inline NxRect& NxRect::operator&=(const NxRect &r) { *this = *this & r; return *this; } inline NxRect NxRect::intersect(const NxRect &r) const { return *this & r; } inline NxRect NxRect::intersected(const NxRect &r) const { return intersect(r); } inline NxRect NxRect::unite(const NxRect &r) const { return *this | r; } inline NxRect NxRect::united(const NxRect &r) const { return unite(r); } inline bool operator==(const NxRect &r1, const NxRect &r2) { return qFuzzyCompare(r1.xp, r2.xp) && qFuzzyCompare(r1.yp, r2.yp) && qFuzzyCompare(r1.zp, r2.zp) && qFuzzyCompare(r1.w, r2.w) && qFuzzyCompare(r1.h, r2.h) && qFuzzyCompare(r1.l, r2.l); } inline bool operator!=(const NxRect &r1, const NxRect &r2) { return !qFuzzyCompare(r1.xp, r2.xp) || !qFuzzyCompare(r1.yp, r2.yp) || !qFuzzyCompare(r1.zp, r2.zp) || !qFuzzyCompare(r1.w, r2.w) || !qFuzzyCompare(r1.h, r2.h) || !qFuzzyCompare(r1.l, r2.l); } #endif // NXRECT_H IanniX-0.9.20/geometry/nxsize.cpp000066400000000000000000000033151317340345000166510ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #include "nxsize.h" void NxSize::transpose() { qreal tmp = wd; wd = ht; ht = tmp; } void NxSize::scale(const NxSize &s, Qt::AspectRatioMode mode) { if (mode == Qt::IgnoreAspectRatio || qIsNull(wd) || qIsNull(ht) || qIsNull(lg)) { wd = s.wd; ht = s.ht; lg = s.lg; } else { bool useHeight; qreal rw = s.ht * wd / ht; if (mode == Qt::KeepAspectRatio) { useHeight = (rw <= s.wd); } else { // mode == Qt::KeepAspectRatioByExpanding useHeight = (rw >= s.wd); } if (useHeight) { wd = rw; ht = s.ht; lg = s.lg; } else { ht = s.wd * ht / wd; wd = s.wd; lg = s.lg; } } } IanniX-0.9.20/geometry/nxsize.h000066400000000000000000000113771317340345000163250ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #ifndef NXSIZE_H #define NXSIZE_H #include class NxSize { public: NxSize(); NxSize(qreal w, qreal h); NxSize(qreal w, qreal h, qreal l); bool isNull() const; bool isEmpty() const; bool isValid() const; qreal width() const; qreal height() const; qreal length() const; void setWidth(qreal w); void setHeight(qreal h); void setLength(qreal l); void transpose(); void scale(qreal w, qreal h, qreal l, Qt::AspectRatioMode mode); void scale(const NxSize &s, Qt::AspectRatioMode mode); qreal &rwidth(); qreal &rheight(); qreal &rlength(); NxSize &operator+=(const NxSize &); NxSize &operator-=(const NxSize &); NxSize &operator*=(qreal c); NxSize &operator/=(qreal c); friend inline bool operator==(const NxSize &, const NxSize &); friend inline bool operator!=(const NxSize &, const NxSize &); friend inline const NxSize operator+(const NxSize &, const NxSize &); friend inline const NxSize operator-(const NxSize &, const NxSize &); friend inline const NxSize operator*(const NxSize &, qreal); friend inline const NxSize operator*(qreal, const NxSize &); friend inline const NxSize operator/(const NxSize &, qreal); private: qreal wd; qreal ht; qreal lg; }; Q_DECLARE_TYPEINFO(NxSize, Q_MOVABLE_TYPE); /***************************************************************************** NxSize inline functions *****************************************************************************/ inline NxSize::NxSize() { wd = ht = lg = -1.; } inline NxSize::NxSize(qreal w, qreal h, qreal l) { wd = w; ht = h; lg = l; } inline NxSize::NxSize(qreal w, qreal h) { wd = w; ht = h; lg = 0; } inline bool NxSize::isNull() const { return qIsNull(wd) && qIsNull(ht) && qIsNull(lg); } inline bool NxSize::isEmpty() const { return wd <= 0. || ht <= 0.; } inline bool NxSize::isValid() const { return wd >= 0. && ht >= 0.; } inline qreal NxSize::width() const { return wd; } inline qreal NxSize::height() const { return ht; } inline qreal NxSize::length() const { return lg; } inline void NxSize::setWidth(qreal w) { wd = w; } inline void NxSize::setHeight(qreal h) { ht = h; } inline void NxSize::setLength(qreal l) { lg = l; } inline void NxSize::scale(qreal w, qreal h, qreal l, Qt::AspectRatioMode mode) { scale(NxSize(w, h, l), mode); } inline qreal &NxSize::rwidth() { return wd; } inline qreal &NxSize::rheight() { return ht; } inline qreal &NxSize::rlength() { return lg; } inline NxSize &NxSize::operator+=(const NxSize &s) { wd += s.wd; ht += s.ht; lg += s.lg; return *this; } inline NxSize &NxSize::operator-=(const NxSize &s) { wd -= s.wd; ht -= s.ht; lg -= s.lg; return *this; } inline NxSize &NxSize::operator*=(qreal c) { wd *= c; ht *= c; lg *= c; return *this; } inline bool operator==(const NxSize &s1, const NxSize &s2) { return qFuzzyCompare(s1.wd, s2.wd) && qFuzzyCompare(s1.ht, s2.ht) && qFuzzyCompare(s1.lg, s2.lg); } inline bool operator!=(const NxSize &s1, const NxSize &s2) { return !qFuzzyCompare(s1.wd, s2.wd) || !qFuzzyCompare(s1.ht, s2.ht) || !qFuzzyCompare(s1.lg, s2.lg); } inline const NxSize operator+(const NxSize & s1, const NxSize & s2) { return NxSize(s1.wd+s2.wd, s1.ht+s2.ht, s1.lg+s2.lg); } inline const NxSize operator-(const NxSize &s1, const NxSize &s2) { return NxSize(s1.wd-s2.wd, s1.ht-s2.ht, s1.lg-s2.lg); } inline const NxSize operator*(const NxSize &s, qreal c) { return NxSize(s.wd*c, s.ht*c, s.lg*c); } inline const NxSize operator*(qreal c, const NxSize &s) { return NxSize(s.wd*c, s.ht*c, s.lg*c); } inline NxSize &NxSize::operator/=(qreal c) { Q_ASSERT(!qFuzzyIsNull(c)); wd = wd/c; ht = ht/c; lg = lg/c; return *this; } inline const NxSize operator/(const NxSize &s, qreal c) { Q_ASSERT(!qFuzzyIsNull(c)); return NxSize(s.wd/c, s.ht/c, s.lg/c); } #endif // NXSIZE_H IanniX-0.9.20/geometry/qmuparser/000077500000000000000000000000001317340345000166425ustar00rootroot00000000000000IanniX-0.9.20/geometry/qmuparser/muParser.cpp000066400000000000000000000327461317340345000211600ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2013 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParser.h" #include "muParserTemplateMagic.h" //--- Standard includes ------------------------------------------------------------------------ #include #include #include /** \brief Pi (what else?). */ #define PARSER_CONST_PI 3.141592653589793238462643 /** \brief The Eulerian number. */ #define PARSER_CONST_E 2.718281828459045235360287 using namespace std; /** \file \brief Implementation of the standard floating point parser. */ /** \brief Namespace for mathematical applications. */ namespace mu { //--------------------------------------------------------------------------- // Trigonometric function value_type Parser::Sin(value_type v) { return MathImpl::Sin(v); } value_type Parser::Cos(value_type v) { return MathImpl::Cos(v); } value_type Parser::Tan(value_type v) { return MathImpl::Tan(v); } value_type Parser::ASin(value_type v) { return MathImpl::ASin(v); } value_type Parser::ACos(value_type v) { return MathImpl::ACos(v); } value_type Parser::ATan(value_type v) { return MathImpl::ATan(v); } value_type Parser::ATan2(value_type v1, value_type v2) { return MathImpl::ATan2(v1, v2); } value_type Parser::Sinh(value_type v) { return MathImpl::Sinh(v); } value_type Parser::Cosh(value_type v) { return MathImpl::Cosh(v); } value_type Parser::Tanh(value_type v) { return MathImpl::Tanh(v); } value_type Parser::ASinh(value_type v) { return MathImpl::ASinh(v); } value_type Parser::ACosh(value_type v) { return MathImpl::ACosh(v); } value_type Parser::ATanh(value_type v) { return MathImpl::ATanh(v); } //--------------------------------------------------------------------------- // Logarithm functions // Logarithm base 2 value_type Parser::Log2(value_type v) { #ifdef MUP_MATH_EXCEPTIONS if (v<=0) throw ParserError(ecDOMAIN_ERROR, _T("Log2")); #endif return MathImpl::Log2(v); } // Logarithm base 10 value_type Parser::Log10(value_type v) { #ifdef MUP_MATH_EXCEPTIONS if (v<=0) throw ParserError(ecDOMAIN_ERROR, _T("Log10")); #endif return MathImpl::Log10(v); } // Logarithm base e (natural logarithm) value_type Parser::Ln(value_type v) { #ifdef MUP_MATH_EXCEPTIONS if (v<=0) throw ParserError(ecDOMAIN_ERROR, _T("Ln")); #endif return MathImpl::Log(v); } //--------------------------------------------------------------------------- // misc value_type Parser::Exp(value_type v) { return MathImpl::Exp(v); } value_type Parser::Abs(value_type v) { return MathImpl::Abs(v); } value_type Parser::Sqrt(value_type v) { #ifdef MUP_MATH_EXCEPTIONS if (v<0) throw ParserError(ecDOMAIN_ERROR, _T("sqrt")); #endif return MathImpl::Sqrt(v); } value_type Parser::Rint(value_type v) { return MathImpl::Rint(v); } value_type Parser::Sign(value_type v) { return MathImpl::Sign(v); } //--------------------------------------------------------------------------- /** \brief Callback for the unary minus operator. \param v The value to negate \return -v */ value_type Parser::UnaryMinus(value_type v) { return -v; } //--------------------------------------------------------------------------- /** \brief Callback for the unary minus operator. \param v The value to negate \return -v */ value_type Parser::UnaryPlus(value_type v) { return v; } //--------------------------------------------------------------------------- /** \brief Callback for adding multiple values. \param [in] a_afArg Vector with the function arguments \param [in] a_iArgc The size of a_afArg */ value_type Parser::Sum(const value_type *a_afArg, int a_iArgc) { if (!a_iArgc) throw exception_type(_T("too few arguments for function sum.")); value_type fRes=0; for (int i=0; i> fVal; stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading if (iEnd==(stringstream_type::pos_type)-1) return 0; *a_iPos += (int)iEnd; *a_fVal = fVal; return 1; } //--------------------------------------------------------------------------- /** \brief Constructor. Call ParserBase class constructor and trigger Function, Operator and Constant initialization. */ Parser::Parser() :ParserBase() { AddValIdent(IsVal); InitCharSets(); InitFun(); InitConst(); InitOprt(); } //--------------------------------------------------------------------------- /** \brief Define the character sets. \sa DefineNameChars, DefineOprtChars, DefineInfixOprtChars This function is used for initializing the default character sets that define the characters to be useable in function and variable names and operators. */ void Parser::InitCharSets() { DefineNameChars( _T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") ); DefineOprtChars( _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-*^/?<>=#!$%&|~'_{}") ); DefineInfixOprtChars( _T("/+-*^?<>=#!$%&|~'_") ); } //--------------------------------------------------------------------------- /** \brief Initialize the default functions. */ void Parser::InitFun() { if (mu::TypeInfo::IsInteger()) { // When setting MUP_BASETYPE to an integer type // Place functions for dealing with integer values here // ... // ... // ... } else { // trigonometric functions DefineFun(_T("sin"), Sin); DefineFun(_T("cos"), Cos); DefineFun(_T("tan"), Tan); // arcus functions DefineFun(_T("asin"), ASin); DefineFun(_T("acos"), ACos); DefineFun(_T("atan"), ATan); DefineFun(_T("atan2"), ATan2); // hyperbolic functions DefineFun(_T("sinh"), Sinh); DefineFun(_T("cosh"), Cosh); DefineFun(_T("tanh"), Tanh); // arcus hyperbolic functions DefineFun(_T("asinh"), ASinh); DefineFun(_T("acosh"), ACosh); DefineFun(_T("atanh"), ATanh); // Logarithm functions DefineFun(_T("log2"), Log2); DefineFun(_T("log10"), Log10); DefineFun(_T("log"), Ln); DefineFun(_T("ln"), Ln); // misc DefineFun(_T("exp"), Exp); DefineFun(_T("sqrt"), Sqrt); DefineFun(_T("sign"), Sign); DefineFun(_T("rint"), Rint); DefineFun(_T("abs"), Abs); // Functions with variable number of arguments DefineFun(_T("sum"), Sum); DefineFun(_T("avg"), Avg); DefineFun(_T("min"), Min); DefineFun(_T("max"), Max); } } //--------------------------------------------------------------------------- /** \brief Initialize constants. By default the parser recognizes two constants. Pi ("pi") and the Eulerian number ("_e"). */ void Parser::InitConst() { DefineConst(_T("_pi"), (value_type)PARSER_CONST_PI); DefineConst(_T("_e"), (value_type)PARSER_CONST_E); } //--------------------------------------------------------------------------- /** \brief Initialize operators. By default only the unary minus operator is added. */ void Parser::InitOprt() { DefineInfixOprt(_T("-"), UnaryMinus); DefineInfixOprt(_T("+"), UnaryPlus); } //--------------------------------------------------------------------------- void Parser::OnDetectVar(string_type * /*pExpr*/, int & /*nStart*/, int & /*nEnd*/) { // this is just sample code to illustrate modifying variable names on the fly. // I'm not sure anyone really needs such a feature... /* string sVar(pExpr->begin()+nStart, pExpr->begin()+nEnd); string sRepl = std::string("_") + sVar + "_"; int nOrigVarEnd = nEnd; cout << "variable detected!\n"; cout << " Expr: " << *pExpr << "\n"; cout << " Start: " << nStart << "\n"; cout << " End: " << nEnd << "\n"; cout << " Var: \"" << sVar << "\"\n"; cout << " Repl: \"" << sRepl << "\"\n"; nEnd = nStart + sRepl.length(); cout << " End: " << nEnd << "\n"; pExpr->replace(pExpr->begin()+nStart, pExpr->begin()+nOrigVarEnd, sRepl); cout << " New expr: " << *pExpr << "\n"; */ } //--------------------------------------------------------------------------- /** \brief Numerically differentiate with regard to a variable. \param [in] a_Var Pointer to the differentiation variable. \param [in] a_fPos Position at which the differentiation should take place. \param [in] a_fEpsilon Epsilon used for the numerical differentiation. Numerical differentiation uses a 5 point operator yielding a 4th order formula. The default value for epsilon is 0.00074 which is numeric_limits::epsilon() ^ (1/5) as suggested in the muparser forum: http://sourceforge.net/forum/forum.php?thread_id=1994611&forum_id=462843 */ value_type Parser::Diff(value_type *a_Var, value_type a_fPos, value_type a_fEpsilon) const { value_type fRes(0), fBuf(*a_Var), f[4] = {0,0,0,0}, fEpsilon(a_fEpsilon); // Backwards compatible calculation of epsilon inc case the user doesn't provide // his own epsilon if (fEpsilon==0) fEpsilon = (a_fPos==0) ? (value_type)1e-10 : (value_type)1e-7 * a_fPos; *a_Var = a_fPos+2 * fEpsilon; f[0] = Eval(); *a_Var = a_fPos+1 * fEpsilon; f[1] = Eval(); *a_Var = a_fPos-1 * fEpsilon; f[2] = Eval(); *a_Var = a_fPos-2 * fEpsilon; f[3] = Eval(); *a_Var = fBuf; // restore variable fRes = (-f[0] + 8*f[1] - 8*f[2] + f[3]) / (12*fEpsilon); return fRes; } } // namespace mu IanniX-0.9.20/geometry/qmuparser/muParser.h000066400000000000000000000103221317340345000206070ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2013 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_H #define MU_PARSER_H //--- Standard includes ------------------------------------------------------------------------ #include //--- Parser includes -------------------------------------------------------------------------- #include "muParserBase.h" #include "muParserTemplateMagic.h" /** \file \brief Definition of the standard floating point parser. */ namespace mu { /** \brief Mathematical expressions parser. Standard implementation of the mathematical expressions parser. Can be used as a reference implementation for subclassing the parser. (C) 2011 Ingo Berg
    muparser(at)beltoforion.de
    */ /* final */ class Parser : public ParserBase { public: Parser(); virtual void InitCharSets(); virtual void InitFun(); virtual void InitConst(); virtual void InitOprt(); virtual void OnDetectVar(string_type *pExpr, int &nStart, int &nEnd); value_type Diff(value_type *a_Var, value_type a_fPos, value_type a_fEpsilon = 0) const; protected: // Trigonometric functions static value_type Sin(value_type); static value_type Cos(value_type); static value_type Tan(value_type); static value_type Tan2(value_type, value_type); // arcus functions static value_type ASin(value_type); static value_type ACos(value_type); static value_type ATan(value_type); static value_type ATan2(value_type, value_type); // hyperbolic functions static value_type Sinh(value_type); static value_type Cosh(value_type); static value_type Tanh(value_type); // arcus hyperbolic functions static value_type ASinh(value_type); static value_type ACosh(value_type); static value_type ATanh(value_type); // Logarithm functions static value_type Log2(value_type); // Logarithm Base 2 static value_type Log10(value_type); // Logarithm Base 10 static value_type Ln(value_type); // Logarithm Base e (natural logarithm) // misc static value_type Exp(value_type); static value_type Abs(value_type); static value_type Sqrt(value_type); static value_type Rint(value_type); static value_type Sign(value_type); // Prefix operators // !!! Unary Minus is a MUST if you want to use negative signs !!! static value_type UnaryMinus(value_type); static value_type UnaryPlus(value_type); // Functions with variable number of arguments static value_type Sum(const value_type*, int); // sum static value_type Avg(const value_type*, int); // mean value static value_type Min(const value_type*, int); // minimum static value_type Max(const value_type*, int); // maximum static int IsVal(const char_type* a_szExpr, int *a_iPos, value_type *a_fVal); }; } // namespace mu #endif IanniX-0.9.20/geometry/qmuparser/muParserBase.cpp000066400000000000000000001743121317340345000217470ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParserBase.h" #include "muParserTemplateMagic.h" //--- Standard includes ------------------------------------------------------------------------ #include #include #include #include #include #include #include #include #ifdef MUP_USE_OPENMP #include #endif using namespace std; /** \file \brief This file contains the basic implementation of the muparser engine. */ namespace mu { std::locale ParserBase::s_locale = std::locale(std::locale::classic(), new change_dec_sep('.')); bool ParserBase::g_DbgDumpCmdCode = false; bool ParserBase::g_DbgDumpStack = false; //------------------------------------------------------------------------------ /** \brief Identifiers for built in binary operators. When defining custom binary operators with #AddOprt(...) make sure not to choose names conflicting with these definitions. */ const char_type* ParserBase::c_DefaultOprt[] = { _T("<="), _T(">="), _T("!="), _T("=="), _T("<"), _T(">"), _T("+"), _T("-"), _T("*"), _T("/"), _T("^"), _T("&&"), _T("||"), _T("="), _T("("), _T(")"), _T("?"), _T(":"), 0 }; //------------------------------------------------------------------------------ /** \brief Constructor. \param a_szFormula the formula to interpret. \throw ParserException if a_szFormula is null. */ ParserBase::ParserBase() :m_pParseFormula(&ParserBase::ParseString) ,m_vRPN() ,m_vStringBuf() ,m_pTokenReader() ,m_FunDef() ,m_PostOprtDef() ,m_InfixOprtDef() ,m_OprtDef() ,m_ConstDef() ,m_StrVarDef() ,m_VarDef() ,m_bBuiltInOp(true) ,m_sNameChars() ,m_sOprtChars() ,m_sInfixOprtChars() ,m_nIfElseCounter(0) ,m_vStackBuffer() ,m_nFinalResultIdx(0) { InitTokenReader(); } //--------------------------------------------------------------------------- /** \brief Copy constructor. The parser can be safely copy constructed but the bytecode is reset during copy construction. */ ParserBase::ParserBase(const ParserBase &a_Parser) :m_pParseFormula(&ParserBase::ParseString) ,m_vRPN() ,m_vStringBuf() ,m_pTokenReader() ,m_FunDef() ,m_PostOprtDef() ,m_InfixOprtDef() ,m_OprtDef() ,m_ConstDef() ,m_StrVarDef() ,m_VarDef() ,m_bBuiltInOp(true) ,m_sNameChars() ,m_sOprtChars() ,m_sInfixOprtChars() ,m_nIfElseCounter(0) { m_pTokenReader.reset(new token_reader_type(this)); Assign(a_Parser); } //--------------------------------------------------------------------------- ParserBase::~ParserBase() {} //--------------------------------------------------------------------------- /** \brief Assignment operator. Implemented by calling Assign(a_Parser). Self assignment is suppressed. \param a_Parser Object to copy to this. \return *this \throw nothrow */ ParserBase& ParserBase::operator=(const ParserBase &a_Parser) { Assign(a_Parser); return *this; } //--------------------------------------------------------------------------- /** \brief Copy state of a parser object to this. Clears Variables and Functions of this parser. Copies the states of all internal variables. Resets parse function to string parse mode. \param a_Parser the source object. */ void ParserBase::Assign(const ParserBase &a_Parser) { if (&a_Parser==this) return; // Don't copy bytecode instead cause the parser to create new bytecode // by resetting the parse function. ReInit(); m_ConstDef = a_Parser.m_ConstDef; // Copy user define constants m_VarDef = a_Parser.m_VarDef; // Copy user defined variables m_bBuiltInOp = a_Parser.m_bBuiltInOp; m_vStringBuf = a_Parser.m_vStringBuf; m_vStackBuffer = a_Parser.m_vStackBuffer; m_nFinalResultIdx = a_Parser.m_nFinalResultIdx; m_StrVarDef = a_Parser.m_StrVarDef; m_vStringVarBuf = a_Parser.m_vStringVarBuf; m_nIfElseCounter = a_Parser.m_nIfElseCounter; m_pTokenReader.reset(a_Parser.m_pTokenReader->Clone(this)); // Copy function and operator callbacks m_FunDef = a_Parser.m_FunDef; // Copy function definitions m_PostOprtDef = a_Parser.m_PostOprtDef; // post value unary operators m_InfixOprtDef = a_Parser.m_InfixOprtDef; // unary operators for infix notation m_OprtDef = a_Parser.m_OprtDef; // binary operators m_sNameChars = a_Parser.m_sNameChars; m_sOprtChars = a_Parser.m_sOprtChars; m_sInfixOprtChars = a_Parser.m_sInfixOprtChars; } //--------------------------------------------------------------------------- /** \brief Set the decimal separator. \param cDecSep Decimal separator as a character value. \sa SetThousandsSep By default muparser uses the "C" locale. The decimal separator of this locale is overwritten by the one provided here. */ void ParserBase::SetDecSep(char_type cDecSep) { char_type cThousandsSep = std::use_facet< change_dec_sep >(s_locale).thousands_sep(); s_locale = std::locale(std::locale("C"), new change_dec_sep(cDecSep, cThousandsSep)); } //--------------------------------------------------------------------------- /** \brief Sets the thousands operator. \param cThousandsSep The thousands separator as a character \sa SetDecSep By default muparser uses the "C" locale. The thousands separator of this locale is overwritten by the one provided here. */ void ParserBase::SetThousandsSep(char_type cThousandsSep) { char_type cDecSep = std::use_facet< change_dec_sep >(s_locale).decimal_point(); s_locale = std::locale(std::locale("C"), new change_dec_sep(cDecSep, cThousandsSep)); } //--------------------------------------------------------------------------- /** \brief Resets the locale. The default locale used "." as decimal separator, no thousands separator and "," as function argument separator. */ void ParserBase::ResetLocale() { s_locale = std::locale(std::locale("C"), new change_dec_sep('.')); SetArgSep(','); } //--------------------------------------------------------------------------- /** \brief Initialize the token reader. Create new token reader object and submit pointers to function, operator, constant and variable definitions. \post m_pTokenReader.get()!=0 \throw nothrow */ void ParserBase::InitTokenReader() { m_pTokenReader.reset(new token_reader_type(this)); } //--------------------------------------------------------------------------- /** \brief Reset parser to string parsing mode and clear internal buffers. Clear bytecode, reset the token reader. \throw nothrow */ void ParserBase::ReInit() const { m_pParseFormula = &ParserBase::ParseString; m_vStringBuf.clear(); m_vRPN.clear(); m_pTokenReader->ReInit(); m_nIfElseCounter = 0; } //--------------------------------------------------------------------------- void ParserBase::OnDetectVar(string_type * /*pExpr*/, int & /*nStart*/, int & /*nEnd*/) {} //--------------------------------------------------------------------------- /** \brief Returns the version of muparser. \param eInfo A flag indicating whether the full version info should be returned or not. Format is as follows: "MAJOR.MINOR (COMPILER_FLAGS)" The COMPILER_FLAGS are returned only if eInfo==pviFULL. */ string_type ParserBase::GetVersion(EParserVersionInfo eInfo) const { stringstream_type ss; ss << MUP_VERSION; if (eInfo==pviFULL) { ss << _T(" (") << MUP_VERSION_DATE; ss << std::dec << _T("; ") << sizeof(void*)*8 << _T("BIT"); #ifdef _DEBUG ss << _T("; DEBUG"); #else ss << _T("; RELEASE"); #endif #ifdef _UNICODE ss << _T("; UNICODE"); #else #ifdef _MBCS ss << _T("; MBCS"); #else ss << _T("; ASCII"); #endif #endif #ifdef MUP_USE_OPENMP ss << _T("; OPENMP"); //#else // ss << _T("; NO_OPENMP"); #endif #if defined(MUP_MATH_EXCEPTIONS) ss << _T("; MATHEXC"); //#else // ss << _T("; NO_MATHEXC"); #endif ss << _T(")"); } return ss.str(); } //--------------------------------------------------------------------------- /** \brief Add a value parsing function. When parsing an expression muParser tries to detect values in the expression string using different valident callbacks. Thus it's possible to parse for hex values, binary values and floating point values. */ void ParserBase::AddValIdent(identfun_type a_pCallback) { m_pTokenReader->AddValIdent(a_pCallback); } //--------------------------------------------------------------------------- /** \brief Set a function that can create variable pointer for unknown expression variables. \param a_pFactory A pointer to the variable factory. \param pUserData A user defined context pointer. */ void ParserBase::SetVarFactory(facfun_type a_pFactory, void *pUserData) { m_pTokenReader->SetVarCreator(a_pFactory, pUserData); } //--------------------------------------------------------------------------- /** \brief Add a function or operator callback to the parser. */ void ParserBase::AddCallback( const string_type &a_strName, const ParserCallback &a_Callback, funmap_type &a_Storage, const char_type *a_szCharSet ) { if (a_Callback.GetAddr()==0) Error(ecINVALID_FUN_PTR); const funmap_type *pFunMap = &a_Storage; // Check for conflicting operator or function names if ( pFunMap!=&m_FunDef && m_FunDef.find(a_strName)!=m_FunDef.end() ) Error(ecNAME_CONFLICT, -1, a_strName); if ( pFunMap!=&m_PostOprtDef && m_PostOprtDef.find(a_strName)!=m_PostOprtDef.end() ) Error(ecNAME_CONFLICT, -1, a_strName); if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_InfixOprtDef.find(a_strName)!=m_InfixOprtDef.end() ) Error(ecNAME_CONFLICT, -1, a_strName); if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_OprtDef.find(a_strName)!=m_OprtDef.end() ) Error(ecNAME_CONFLICT, -1, a_strName); CheckOprt(a_strName, a_Callback, a_szCharSet); a_Storage[a_strName] = a_Callback; ReInit(); } //--------------------------------------------------------------------------- /** \brief Check if a name contains invalid characters. \throw ParserException if the name contains invalid characters. */ void ParserBase::CheckOprt(const string_type &a_sName, const ParserCallback &a_Callback, const string_type &a_szCharSet) const { if ( !a_sName.length() || (a_sName.find_first_not_of(a_szCharSet)!=string_type::npos) || (a_sName[0]>='0' && a_sName[0]<='9')) { switch(a_Callback.GetCode()) { case cmOPRT_POSTFIX: Error(ecINVALID_POSTFIX_IDENT, -1, a_sName); case cmOPRT_INFIX: Error(ecINVALID_INFIX_IDENT, -1, a_sName); default: Error(ecINVALID_NAME, -1, a_sName); } } } //--------------------------------------------------------------------------- /** \brief Check if a name contains invalid characters. \throw ParserException if the name contains invalid characters. */ void ParserBase::CheckName(const string_type &a_sName, const string_type &a_szCharSet) const { if ( !a_sName.length() || (a_sName.find_first_not_of(a_szCharSet)!=string_type::npos) || (a_sName[0]>='0' && a_sName[0]<='9')) { Error(ecINVALID_NAME); } } //--------------------------------------------------------------------------- /** \brief Set the formula. \param a_strFormula Formula as string_type \throw ParserException in case of syntax errors. Triggers first time calculation thus the creation of the bytecode and scanning of used variables. */ void ParserBase::SetExpr(const string_type &a_sExpr) { // Check locale compatibility std::locale loc; if (m_pTokenReader->GetArgSep()==std::use_facet >(loc).decimal_point()) Error(ecLOCALE); // 20060222: Bugfix for Borland-Kylix: // adding a space to the expression will keep Borlands KYLIX from going wild // when calling tellg on a stringstream created from the expression after // reading a value at the end of an expression. (mu::Parser::IsVal function) // (tellg returns -1 otherwise causing the parser to ignore the value) string_type sBuf(a_sExpr + _T(" ") ); m_pTokenReader->SetFormula(sBuf); ReInit(); } //--------------------------------------------------------------------------- /** \brief Get the default symbols used for the built in operators. \sa c_DefaultOprt */ const char_type** ParserBase::GetOprtDef() const { return (const char_type **)(&c_DefaultOprt[0]); } //--------------------------------------------------------------------------- /** \brief Define the set of valid characters to be used in names of functions, variables, constants. */ void ParserBase::DefineNameChars(const char_type *a_szCharset) { m_sNameChars = a_szCharset; } //--------------------------------------------------------------------------- /** \brief Define the set of valid characters to be used in names of binary operators and postfix operators. */ void ParserBase::DefineOprtChars(const char_type *a_szCharset) { m_sOprtChars = a_szCharset; } //--------------------------------------------------------------------------- /** \brief Define the set of valid characters to be used in names of infix operators. */ void ParserBase::DefineInfixOprtChars(const char_type *a_szCharset) { m_sInfixOprtChars = a_szCharset; } //--------------------------------------------------------------------------- /** \brief Virtual function that defines the characters allowed in name identifiers. \sa #ValidOprtChars, #ValidPrefixOprtChars */ const char_type* ParserBase::ValidNameChars() const { assert(m_sNameChars.size()); return m_sNameChars.c_str(); } //--------------------------------------------------------------------------- /** \brief Virtual function that defines the characters allowed in operator definitions. \sa #ValidNameChars, #ValidPrefixOprtChars */ const char_type* ParserBase::ValidOprtChars() const { assert(m_sOprtChars.size()); return m_sOprtChars.c_str(); } //--------------------------------------------------------------------------- /** \brief Virtual function that defines the characters allowed in infix operator definitions. \sa #ValidNameChars, #ValidOprtChars */ const char_type* ParserBase::ValidInfixOprtChars() const { assert(m_sInfixOprtChars.size()); return m_sInfixOprtChars.c_str(); } //--------------------------------------------------------------------------- /** \brief Add a user defined operator. \post Will reset the Parser to string parsing mode. */ void ParserBase::DefinePostfixOprt(const string_type &a_sName, fun_type1 a_pFun, bool a_bAllowOpt) { AddCallback(a_sName, ParserCallback(a_pFun, a_bAllowOpt, prPOSTFIX, cmOPRT_POSTFIX), m_PostOprtDef, ValidOprtChars() ); } //--------------------------------------------------------------------------- /** \brief Initialize user defined functions. Calls the virtual functions InitFun(), InitConst() and InitOprt(). */ void ParserBase::Init() { InitCharSets(); InitFun(); InitConst(); InitOprt(); } //--------------------------------------------------------------------------- /** \brief Add a user defined operator. \post Will reset the Parser to string parsing mode. \param [in] a_sName operator Identifier \param [in] a_pFun Operator callback function \param [in] a_iPrec Operator Precedence (default=prSIGN) \param [in] a_bAllowOpt True if operator is volatile (default=false) \sa EPrec */ void ParserBase::DefineInfixOprt(const string_type &a_sName, fun_type1 a_pFun, int a_iPrec, bool a_bAllowOpt) { AddCallback(a_sName, ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, cmOPRT_INFIX), m_InfixOprtDef, ValidInfixOprtChars() ); } //--------------------------------------------------------------------------- /** \brief Define a binary operator. \param [in] a_sName The identifier of the operator. \param [in] a_pFun Pointer to the callback function. \param [in] a_iPrec Precedence of the operator. \param [in] a_eAssociativity The associativity of the operator. \param [in] a_bAllowOpt If this is true the operator may be optimized away. Adds a new Binary operator the the parser instance. */ void ParserBase::DefineOprt( const string_type &a_sName, fun_type2 a_pFun, unsigned a_iPrec, EOprtAssociativity a_eAssociativity, bool a_bAllowOpt ) { // Check for conflicts with built in operator names for (int i=0; m_bBuiltInOp && iIgnoreUndefVar(true); CreateRPN(); // try to create bytecode, but don't use it for any further calculations since it // may contain references to nonexisting variables. m_pParseFormula = &ParserBase::ParseString; m_pTokenReader->IgnoreUndefVar(false); } catch(exception_type & /*e*/) { // Make sure to stay in string parse mode, dont call ReInit() // because it deletes the array with the used variables m_pParseFormula = &ParserBase::ParseString; m_pTokenReader->IgnoreUndefVar(false); throw; } return m_pTokenReader->GetUsedVar(); } //--------------------------------------------------------------------------- /** \brief Return a map containing the used variables only. */ const varmap_type& ParserBase::GetVar() const { return m_VarDef; } //--------------------------------------------------------------------------- /** \brief Return a map containing all parser constants. */ const valmap_type& ParserBase::GetConst() const { return m_ConstDef; } //--------------------------------------------------------------------------- /** \brief Return prototypes of all parser functions. \return #m_FunDef \sa FunProt \throw nothrow The return type is a map of the public type #funmap_type containing the prototype definitions for all numerical parser functions. String functions are not part of this map. The Prototype definition is encapsulated in objects of the class FunProt one per parser function each associated with function names via a map construct. */ const funmap_type& ParserBase::GetFunDef() const { return m_FunDef; } //--------------------------------------------------------------------------- /** \brief Retrieve the formula. */ const string_type& ParserBase::GetExpr() const { return m_pTokenReader->GetExpr(); } //--------------------------------------------------------------------------- /** \brief Execute a function that takes a single string argument. \param a_FunTok Function token. \throw exception_type If the function token is not a string function */ ParserBase::token_type ParserBase::ApplyStrFunc(const token_type &a_FunTok, const std::vector &a_vArg) const { if (a_vArg.back().GetCode()!=cmSTRING) Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); token_type valTok; generic_fun_type pFunc = a_FunTok.GetFuncAddr(); assert(pFunc); try { // Check function arguments; write dummy value into valtok to represent the result switch(a_FunTok.GetArgCount()) { case 0: valTok.SetVal(1); a_vArg[0].GetAsString(); break; case 1: valTok.SetVal(1); a_vArg[1].GetAsString(); a_vArg[0].GetVal(); break; case 2: valTok.SetVal(1); a_vArg[2].GetAsString(); a_vArg[1].GetVal(); a_vArg[0].GetVal(); break; default: Error(ecINTERNAL_ERROR); } } catch(ParserError& ) { Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); } // string functions won't be optimized m_vRPN.AddStrFun(pFunc, a_FunTok.GetArgCount(), a_vArg.back().GetIdx()); // Push dummy value representing the function result to the stack return valTok; } //--------------------------------------------------------------------------- /** \brief Apply a function token. \param iArgCount Number of Arguments actually gathered used only for multiarg functions. \post The result is pushed to the value stack \post The function token is removed from the stack \throw exception_type if Argument count does not match function requirements. */ void ParserBase::ApplyFunc( ParserStack &a_stOpt, ParserStack &a_stVal, int a_iArgCount) const { assert(m_pTokenReader.get()); // Operator stack empty or does not contain tokens with callback functions if (a_stOpt.empty() || a_stOpt.top().GetFuncAddr()==0 ) return; token_type funTok = a_stOpt.pop(); assert(funTok.GetFuncAddr()); // Binary operators must rely on their internal operator number // since counting of operators relies on commas for function arguments // binary operators do not have commas in their expression int iArgCount = (funTok.GetCode()==cmOPRT_BIN) ? funTok.GetArgCount() : a_iArgCount; // determine how many parameters the function needs. To remember iArgCount includes the // string parameter whilst GetArgCount() counts only numeric parameters. int iArgRequired = funTok.GetArgCount() + ((funTok.GetType()==tpSTR) ? 1 : 0); // Thats the number of numerical parameters int iArgNumerical = iArgCount - ((funTok.GetType()==tpSTR) ? 1 : 0); if (funTok.GetCode()==cmFUNC_STR && iArgCount-iArgNumerical>1) Error(ecINTERNAL_ERROR); if (funTok.GetArgCount()>=0 && iArgCount>iArgRequired) Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString()); if (funTok.GetCode()!=cmOPRT_BIN && iArgCountGetPos()-1, funTok.GetAsString()); if (funTok.GetCode()==cmFUNC_STR && iArgCount>iArgRequired ) Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString()); // Collect the numeric function arguments from the value stack and store them // in a vector std::vector stArg; for (int i=0; iGetPos(), funTok.GetAsString()); } switch(funTok.GetCode()) { case cmFUNC_STR: stArg.push_back(a_stVal.pop()); if ( stArg.back().GetType()==tpSTR && funTok.GetType()!=tpSTR ) Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString()); ApplyStrFunc(funTok, stArg); break; case cmFUNC_BULK: m_vRPN.AddBulkFun(funTok.GetFuncAddr(), (int)stArg.size()); break; case cmOPRT_BIN: case cmOPRT_POSTFIX: case cmOPRT_INFIX: case cmFUNC: if (funTok.GetArgCount()==-1 && iArgCount==0) Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos(), funTok.GetAsString()); m_vRPN.AddFun(funTok.GetFuncAddr(), (funTok.GetArgCount()==-1) ? -iArgNumerical : iArgNumerical); break; } // Push dummy value representing the function result to the stack token_type token; token.SetVal(1); a_stVal.push(token); } //--------------------------------------------------------------------------- void ParserBase::ApplyIfElse(ParserStack &a_stOpt, ParserStack &a_stVal) const { // Check if there is an if Else clause to be calculated while (a_stOpt.size() && a_stOpt.top().GetCode()==cmELSE) { token_type opElse = a_stOpt.pop(); MUP_ASSERT(a_stOpt.size()>0); // Take the value associated with the else branch from the value stack token_type vVal2 = a_stVal.pop(); MUP_ASSERT(a_stOpt.size()>0); MUP_ASSERT(a_stVal.size()>=2); // it then else is a ternary operator Pop all three values from the value s // tack and just return the right value token_type vVal1 = a_stVal.pop(); token_type vExpr = a_stVal.pop(); a_stVal.push( (vExpr.GetVal()!=0) ? vVal1 : vVal2); token_type opIf = a_stOpt.pop(); MUP_ASSERT(opElse.GetCode()==cmELSE); MUP_ASSERT(opIf.GetCode()==cmIF); m_vRPN.AddIfElse(cmENDIF); } // while pending if-else-clause found } //--------------------------------------------------------------------------- /** \brief Performs the necessary steps to write code for the execution of binary operators into the bytecode. */ void ParserBase::ApplyBinOprt(ParserStack &a_stOpt, ParserStack &a_stVal) const { // is it a user defined binary operator? if (a_stOpt.top().GetCode()==cmOPRT_BIN) { ApplyFunc(a_stOpt, a_stVal, 2); } else { MUP_ASSERT(a_stVal.size()>=2); token_type valTok1 = a_stVal.pop(), valTok2 = a_stVal.pop(), optTok = a_stOpt.pop(), resTok; if ( valTok1.GetType()!=valTok2.GetType() || (valTok1.GetType()==tpSTR && valTok2.GetType()==tpSTR) ) Error(ecOPRT_TYPE_CONFLICT, m_pTokenReader->GetPos(), optTok.GetAsString()); if (optTok.GetCode()==cmASSIGN) { if (valTok2.GetCode()!=cmVAR) Error(ecUNEXPECTED_OPERATOR, -1, _T("=")); m_vRPN.AddAssignOp(valTok2.GetVar()); } else m_vRPN.AddOp(optTok.GetCode()); resTok.SetVal(1); a_stVal.push(resTok); } } //--------------------------------------------------------------------------- /** \brief Apply a binary operator. \param a_stOpt The operator stack \param a_stVal The value stack */ void ParserBase::ApplyRemainingOprt(ParserStack &stOpt, ParserStack &stVal) const { while (stOpt.size() && stOpt.top().GetCode() != cmBO && stOpt.top().GetCode() != cmIF) { token_type tok = stOpt.top(); switch (tok.GetCode()) { case cmOPRT_INFIX: case cmOPRT_BIN: case cmLE: case cmGE: case cmNEQ: case cmEQ: case cmLT: case cmGT: case cmADD: case cmSUB: case cmMUL: case cmDIV: case cmPOW: case cmLAND: case cmLOR: case cmASSIGN: if (stOpt.top().GetCode()==cmOPRT_INFIX) ApplyFunc(stOpt, stVal, 1); else ApplyBinOprt(stOpt, stVal); break; case cmELSE: ApplyIfElse(stOpt, stVal); break; default: Error(ecINTERNAL_ERROR); } } } //--------------------------------------------------------------------------- /** \brief Parse the command code. \sa ParseString(...) Command code contains precalculated stack positions of the values and the associated operators. The Stack is filled beginning from index one the value at index zero is not used at all. */ value_type ParserBase::ParseCmdCode() const { return ParseCmdCodeBulk(0, 0); } //--------------------------------------------------------------------------- /** \brief Evaluate the RPN. \param nOffset The offset added to variable addresses (for bulk mode) \param nThreadID OpenMP Thread id of the calling thread */ value_type ParserBase::ParseCmdCodeBulk(int nOffset, int nThreadID) const { assert(nThreadID<=s_MaxNumOpenMPThreads); // Note: The check for nOffset==0 and nThreadID here is not necessary but // brings a minor performance gain when not in bulk mode. value_type *Stack = ((nOffset==0) && (nThreadID==0)) ? &m_vStackBuffer[0] : &m_vStackBuffer[nThreadID * (m_vStackBuffer.size() / s_MaxNumOpenMPThreads)]; value_type buf; int sidx(0); for (const SToken *pTok = m_vRPN.GetBase(); pTok->Cmd!=cmEND ; ++pTok) { switch (pTok->Cmd) { // built in binary operators case cmLE: --sidx; Stack[sidx] = Stack[sidx] <= Stack[sidx+1]; continue; case cmGE: --sidx; Stack[sidx] = Stack[sidx] >= Stack[sidx+1]; continue; case cmNEQ: --sidx; Stack[sidx] = Stack[sidx] != Stack[sidx+1]; continue; case cmEQ: --sidx; Stack[sidx] = Stack[sidx] == Stack[sidx+1]; continue; case cmLT: --sidx; Stack[sidx] = Stack[sidx] < Stack[sidx+1]; continue; case cmGT: --sidx; Stack[sidx] = Stack[sidx] > Stack[sidx+1]; continue; case cmADD: --sidx; Stack[sidx] += Stack[1+sidx]; continue; case cmSUB: --sidx; Stack[sidx] -= Stack[1+sidx]; continue; case cmMUL: --sidx; Stack[sidx] *= Stack[1+sidx]; continue; case cmDIV: --sidx; #if defined(MUP_MATH_EXCEPTIONS) if (Stack[1+sidx]==0) Error(ecDIV_BY_ZERO); #endif Stack[sidx] /= Stack[1+sidx]; continue; case cmPOW: --sidx; Stack[sidx] = MathImpl::Pow(Stack[sidx], Stack[1+sidx]); continue; case cmLAND: --sidx; Stack[sidx] = Stack[sidx] && Stack[sidx+1]; continue; case cmLOR: --sidx; Stack[sidx] = Stack[sidx] || Stack[sidx+1]; continue; case cmASSIGN: // Bugfix for Bulkmode: // for details see: // https://groups.google.com/forum/embed/?place=forum/muparser-dev&showsearch=true&showpopout=true&showtabs=false&parenturl=http://muparser.beltoforion.de/mup_forum.html&afterlogin&pli=1#!topic/muparser-dev/szgatgoHTws --sidx; Stack[sidx] = *(pTok->Oprt.ptr + nOffset) = Stack[sidx + 1]; continue; // original code: //--sidx; Stack[sidx] = *pTok->Oprt.ptr = Stack[sidx+1]; continue; //case cmBO: // unused, listed for compiler optimization purposes //case cmBC: // MUP_FAIL(INVALID_CODE_IN_BYTECODE); // continue; case cmIF: if (Stack[sidx--]==0) pTok += pTok->Oprt.offset; continue; case cmELSE: pTok += pTok->Oprt.offset; continue; case cmENDIF: continue; //case cmARG_SEP: // MUP_FAIL(INVALID_CODE_IN_BYTECODE); // continue; // value and variable tokens case cmVAR: Stack[++sidx] = *(pTok->Val.ptr + nOffset); continue; case cmVAL: Stack[++sidx] = pTok->Val.data2; continue; case cmVARPOW2: buf = *(pTok->Val.ptr + nOffset); Stack[++sidx] = buf*buf; continue; case cmVARPOW3: buf = *(pTok->Val.ptr + nOffset); Stack[++sidx] = buf*buf*buf; continue; case cmVARPOW4: buf = *(pTok->Val.ptr + nOffset); Stack[++sidx] = buf*buf*buf*buf; continue; case cmVARMUL: Stack[++sidx] = *(pTok->Val.ptr + nOffset) * pTok->Val.data + pTok->Val.data2; continue; // Next is treatment of numeric functions case cmFUNC: { int iArgCount = pTok->Fun.argc; // switch according to argument count switch(iArgCount) { case 0: sidx += 1; Stack[sidx] = (*(fun_type0)pTok->Fun.ptr)(); continue; case 1: Stack[sidx] = (*(fun_type1)pTok->Fun.ptr)(Stack[sidx]); continue; case 2: sidx -= 1; Stack[sidx] = (*(fun_type2)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1]); continue; case 3: sidx -= 2; Stack[sidx] = (*(fun_type3)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2]); continue; case 4: sidx -= 3; Stack[sidx] = (*(fun_type4)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3]); continue; case 5: sidx -= 4; Stack[sidx] = (*(fun_type5)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4]); continue; case 6: sidx -= 5; Stack[sidx] = (*(fun_type6)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]); continue; case 7: sidx -= 6; Stack[sidx] = (*(fun_type7)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6]); continue; case 8: sidx -= 7; Stack[sidx] = (*(fun_type8)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7]); continue; case 9: sidx -= 8; Stack[sidx] = (*(fun_type9)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8]); continue; case 10:sidx -= 9; Stack[sidx] = (*(fun_type10)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8], Stack[sidx+9]); continue; default: if (iArgCount>0) // function with variable arguments store the number as a negative value Error(ecINTERNAL_ERROR, 1); sidx -= -iArgCount - 1; Stack[sidx] =(*(multfun_type)pTok->Fun.ptr)(&Stack[sidx], -iArgCount); continue; } } // Next is treatment of string functions case cmFUNC_STR: { sidx -= pTok->Fun.argc -1; // The index of the string argument in the string table int iIdxStack = pTok->Fun.idx; MUP_ASSERT( iIdxStack>=0 && iIdxStack<(int)m_vStringBuf.size() ); switch(pTok->Fun.argc) // switch according to argument count { case 0: Stack[sidx] = (*(strfun_type1)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str()); continue; case 1: Stack[sidx] = (*(strfun_type2)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx]); continue; case 2: Stack[sidx] = (*(strfun_type3)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx], Stack[sidx+1]); continue; } continue; } case cmFUNC_BULK: { int iArgCount = pTok->Fun.argc; // switch according to argument count switch(iArgCount) { case 0: sidx += 1; Stack[sidx] = (*(bulkfun_type0 )pTok->Fun.ptr)(nOffset, nThreadID); continue; case 1: Stack[sidx] = (*(bulkfun_type1 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx]); continue; case 2: sidx -= 1; Stack[sidx] = (*(bulkfun_type2 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1]); continue; case 3: sidx -= 2; Stack[sidx] = (*(bulkfun_type3 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2]); continue; case 4: sidx -= 3; Stack[sidx] = (*(bulkfun_type4 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3]); continue; case 5: sidx -= 4; Stack[sidx] = (*(bulkfun_type5 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4]); continue; case 6: sidx -= 5; Stack[sidx] = (*(bulkfun_type6 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]); continue; case 7: sidx -= 6; Stack[sidx] = (*(bulkfun_type7 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6]); continue; case 8: sidx -= 7; Stack[sidx] = (*(bulkfun_type8 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7]); continue; case 9: sidx -= 8; Stack[sidx] = (*(bulkfun_type9 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8]); continue; case 10:sidx -= 9; Stack[sidx] = (*(bulkfun_type10)pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8], Stack[sidx+9]); continue; default: Error(ecINTERNAL_ERROR, 2); continue; } } default: Error(ecINTERNAL_ERROR, 3); return 0; } // switch CmdCode } // for all bytecode tokens return Stack[m_nFinalResultIdx]; } //--------------------------------------------------------------------------- void ParserBase::CreateRPN() const { if (!m_pTokenReader->GetExpr().length()) Error(ecUNEXPECTED_EOF, 0); ParserStack stOpt, stVal; ParserStack stArgCount; token_type opta, opt; // for storing operators token_type val, tval; // for storing value ReInit(); // The outermost counter counts the number of separated items // such as in "a=10,b=20,c=c+a" stArgCount.push(1); for(;;) { opt = m_pTokenReader->ReadNextToken(); switch (opt.GetCode()) { // // Next three are different kind of value entries // case cmSTRING: opt.SetIdx((int)m_vStringBuf.size()); // Assign buffer index to token stVal.push(opt); m_vStringBuf.push_back(opt.GetAsString()); // Store string in internal buffer break; case cmVAR: stVal.push(opt); m_vRPN.AddVar( static_cast(opt.GetVar()) ); break; case cmVAL: stVal.push(opt); m_vRPN.AddVal( opt.GetVal() ); break; case cmELSE: m_nIfElseCounter--; if (m_nIfElseCounter<0) Error(ecMISPLACED_COLON, m_pTokenReader->GetPos()); ApplyRemainingOprt(stOpt, stVal); m_vRPN.AddIfElse(cmELSE); stOpt.push(opt); break; case cmARG_SEP: if (stArgCount.empty()) Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos()); ++stArgCount.top(); // fallthrough intentional (no break!) case cmEND: ApplyRemainingOprt(stOpt, stVal); break; case cmBC: { // The argument count for parameterless functions is zero // by default an opening bracket sets parameter count to 1 // in preparation of arguments to come. If the last token // was an opening bracket we know better... if (opta.GetCode()==cmBO) --stArgCount.top(); ApplyRemainingOprt(stOpt, stVal); // Check if the bracket content has been evaluated completely if (stOpt.size() && stOpt.top().GetCode()==cmBO) { // if opt is ")" and opta is "(" the bracket has been evaluated, now its time to check // if there is either a function or a sign pending // neither the opening nor the closing bracket will be pushed back to // the operator stack // Check if a function is standing in front of the opening bracket, // if yes evaluate it afterwards check for infix operators assert(stArgCount.size()); int iArgCount = stArgCount.pop(); stOpt.pop(); // Take opening bracket from stack if (iArgCount>1 && ( stOpt.size()==0 || (stOpt.top().GetCode()!=cmFUNC && stOpt.top().GetCode()!=cmFUNC_BULK && stOpt.top().GetCode()!=cmFUNC_STR) ) ) Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos()); // The opening bracket was popped from the stack now check if there // was a function before this bracket if (stOpt.size() && stOpt.top().GetCode()!=cmOPRT_INFIX && stOpt.top().GetCode()!=cmOPRT_BIN && stOpt.top().GetFuncAddr()!=0) { ApplyFunc(stOpt, stVal, iArgCount); } } } // if bracket content is evaluated break; // // Next are the binary operator entries // //case cmAND: // built in binary operators //case cmOR: //case cmXOR: case cmIF: m_nIfElseCounter++; // fallthrough intentional (no break!) case cmLAND: case cmLOR: case cmLT: case cmGT: case cmLE: case cmGE: case cmNEQ: case cmEQ: case cmADD: case cmSUB: case cmMUL: case cmDIV: case cmPOW: case cmASSIGN: case cmOPRT_BIN: // A binary operator (user defined or built in) has been found. while ( stOpt.size() && stOpt.top().GetCode() != cmBO && stOpt.top().GetCode() != cmELSE && stOpt.top().GetCode() != cmIF) { int nPrec1 = GetOprtPrecedence(stOpt.top()), nPrec2 = GetOprtPrecedence(opt); if (stOpt.top().GetCode()==opt.GetCode()) { // Deal with operator associativity EOprtAssociativity eOprtAsct = GetOprtAssociativity(opt); if ( (eOprtAsct==oaRIGHT && (nPrec1 <= nPrec2)) || (eOprtAsct==oaLEFT && (nPrec1 < nPrec2)) ) { break; } } else if (nPrec1 < nPrec2) { // In case the operators are not equal the precedence decides alone... break; } if (stOpt.top().GetCode()==cmOPRT_INFIX) ApplyFunc(stOpt, stVal, 1); else ApplyBinOprt(stOpt, stVal); } // while ( ... ) if (opt.GetCode()==cmIF) m_vRPN.AddIfElse(opt.GetCode()); // The operator can't be evaluated right now, push back to the operator stack stOpt.push(opt); break; // // Last section contains functions and operators implicitly mapped to functions // case cmBO: stArgCount.push(1); stOpt.push(opt); break; case cmOPRT_INFIX: case cmFUNC: case cmFUNC_BULK: case cmFUNC_STR: stOpt.push(opt); break; case cmOPRT_POSTFIX: stOpt.push(opt); ApplyFunc(stOpt, stVal, 1); // this is the postfix operator break; default: Error(ecINTERNAL_ERROR, 3); } // end of switch operator-token opta = opt; if ( opt.GetCode() == cmEND ) { m_vRPN.Finalize(); break; } if (ParserBase::g_DbgDumpStack) { StackDump(stVal, stOpt); m_vRPN.AsciiDump(); } } // while (true) if (ParserBase::g_DbgDumpCmdCode) m_vRPN.AsciiDump(); if (m_nIfElseCounter>0) Error(ecMISSING_ELSE_CLAUSE); // get the last value (= final result) from the stack MUP_ASSERT(stArgCount.size()==1); m_nFinalResultIdx = stArgCount.top(); if (m_nFinalResultIdx==0) Error(ecINTERNAL_ERROR, 9); if (stVal.size()==0) Error(ecEMPTY_EXPRESSION); if (stVal.top().GetType()!=tpDBL) Error(ecSTR_RESULT); m_vStackBuffer.resize(m_vRPN.GetMaxStackSize() * s_MaxNumOpenMPThreads); } //--------------------------------------------------------------------------- /** \brief One of the two main parse functions. \sa ParseCmdCode(...) Parse expression from input string. Perform syntax checking and create bytecode. After parsing the string and creating the bytecode the function pointer #m_pParseFormula will be changed to the second parse routine the uses bytecode instead of string parsing. */ value_type ParserBase::ParseString() const { try { CreateRPN(); m_pParseFormula = &ParserBase::ParseCmdCode; return (this->*m_pParseFormula)(); } catch(ParserError &exc) { exc.SetFormula(m_pTokenReader->GetExpr()); throw; } } //--------------------------------------------------------------------------- /** \brief Create an error containing the parse error position. This function will create an Parser Exception object containing the error text and its position. \param a_iErrc [in] The error code of type #EErrorCodes. \param a_iPos [in] The position where the error was detected. \param a_strTok [in] The token string representation associated with the error. \throw ParserException always throws thats the only purpose of this function. */ void ParserBase::Error(EErrorCodes a_iErrc, int a_iPos, const string_type &a_sTok) const { throw exception_type(a_iErrc, a_sTok, m_pTokenReader->GetExpr(), a_iPos); } //------------------------------------------------------------------------------ /** \brief Clear all user defined variables. \throw nothrow Resets the parser to string parsing mode by calling #ReInit. */ void ParserBase::ClearVar() { m_VarDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Remove a variable from internal storage. \throw nothrow Removes a variable if it exists. If the Variable does not exist nothing will be done. */ void ParserBase::RemoveVar(const string_type &a_strVarName) { varmap_type::iterator item = m_VarDef.find(a_strVarName); if (item!=m_VarDef.end()) { m_VarDef.erase(item); ReInit(); } } //------------------------------------------------------------------------------ /** \brief Clear all functions. \post Resets the parser to string parsing mode. \throw nothrow */ void ParserBase::ClearFun() { m_FunDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Clear all user defined constants. Both numeric and string constants will be removed from the internal storage. \post Resets the parser to string parsing mode. \throw nothrow */ void ParserBase::ClearConst() { m_ConstDef.clear(); m_StrVarDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Clear all user defined postfix operators. \post Resets the parser to string parsing mode. \throw nothrow */ void ParserBase::ClearPostfixOprt() { m_PostOprtDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Clear all user defined binary operators. \post Resets the parser to string parsing mode. \throw nothrow */ void ParserBase::ClearOprt() { m_OprtDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Clear the user defined Prefix operators. \post Resets the parser to string parser mode. \throw nothrow */ void ParserBase::ClearInfixOprt() { m_InfixOprtDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Enable or disable the formula optimization feature. \post Resets the parser to string parser mode. \throw nothrow */ void ParserBase::EnableOptimizer(bool a_bIsOn) { m_vRPN.EnableOptimizer(a_bIsOn); ReInit(); } //--------------------------------------------------------------------------- /** \brief Enable the dumping of bytecode and stack content on the console. \param bDumpCmd Flag to enable dumping of the current bytecode to the console. \param bDumpStack Flag to enable dumping of the stack content is written to the console. This function is for debug purposes only! */ void ParserBase::EnableDebugDump(bool bDumpCmd, bool bDumpStack) { ParserBase::g_DbgDumpCmdCode = bDumpCmd; ParserBase::g_DbgDumpStack = bDumpStack; } //------------------------------------------------------------------------------ /** \brief Enable or disable the built in binary operators. \throw nothrow \sa m_bBuiltInOp, ReInit() If you disable the built in binary operators there will be no binary operators defined. Thus you must add them manually one by one. It is not possible to disable built in operators selectively. This function will Reinitialize the parser by calling ReInit(). */ void ParserBase::EnableBuiltInOprt(bool a_bIsOn) { m_bBuiltInOp = a_bIsOn; ReInit(); } //------------------------------------------------------------------------------ /** \brief Query status of built in variables. \return #m_bBuiltInOp; true if built in operators are enabled. \throw nothrow */ bool ParserBase::HasBuiltInOprt() const { return m_bBuiltInOp; } //------------------------------------------------------------------------------ /** \brief Get the argument separator character. */ char_type ParserBase::GetArgSep() const { return m_pTokenReader->GetArgSep(); } //------------------------------------------------------------------------------ /** \brief Set argument separator. \param cArgSep the argument separator character. */ void ParserBase::SetArgSep(char_type cArgSep) { m_pTokenReader->SetArgSep(cArgSep); } //------------------------------------------------------------------------------ /** \brief Dump stack content. This function is used for debugging only. */ void ParserBase::StackDump(const ParserStack &a_stVal, const ParserStack &a_stOprt) const { ParserStack stOprt(a_stOprt), stVal(a_stVal); mu::console() << _T("\nValue stack:\n"); while ( !stVal.empty() ) { token_type val = stVal.pop(); if (val.GetType()==tpSTR) mu::console() << _T(" \"") << val.GetAsString() << _T("\" "); else mu::console() << _T(" ") << val.GetVal() << _T(" "); } mu::console() << "\nOperator stack:\n"; while ( !stOprt.empty() ) { if (stOprt.top().GetCode()<=cmASSIGN) { mu::console() << _T("OPRT_INTRNL \"") << ParserBase::c_DefaultOprt[stOprt.top().GetCode()] << _T("\" \n"); } else { switch(stOprt.top().GetCode()) { case cmVAR: mu::console() << _T("VAR\n"); break; case cmVAL: mu::console() << _T("VAL\n"); break; case cmFUNC: mu::console() << _T("FUNC \"") << stOprt.top().GetAsString() << _T("\"\n"); break; case cmFUNC_BULK: mu::console() << _T("FUNC_BULK \"") << stOprt.top().GetAsString() << _T("\"\n"); break; case cmOPRT_INFIX: mu::console() << _T("OPRT_INFIX \"") << stOprt.top().GetAsString() << _T("\"\n"); break; case cmOPRT_BIN: mu::console() << _T("OPRT_BIN \"") << stOprt.top().GetAsString() << _T("\"\n"); break; case cmFUNC_STR: mu::console() << _T("FUNC_STR\n"); break; case cmEND: mu::console() << _T("END\n"); break; case cmUNKNOWN: mu::console() << _T("UNKNOWN\n"); break; case cmBO: mu::console() << _T("BRACKET \"(\"\n"); break; case cmBC: mu::console() << _T("BRACKET \")\"\n"); break; case cmIF: mu::console() << _T("IF\n"); break; case cmELSE: mu::console() << _T("ELSE\n"); break; case cmENDIF: mu::console() << _T("ENDIF\n"); break; default: mu::console() << stOprt.top().GetCode() << _T(" "); break; } } stOprt.pop(); } mu::console() << dec << endl; } //------------------------------------------------------------------------------ /** \brief Evaluate an expression containing comma separated subexpressions \param [out] nStackSize The total number of results available \return Pointer to the array containing all expression results This member function can be used to retrieve all results of an expression made up of multiple comma separated subexpressions (i.e. "x+y,sin(x),cos(y)") */ value_type* ParserBase::Eval(int &nStackSize) const { (this->*m_pParseFormula)(); nStackSize = m_nFinalResultIdx; // (for historic reasons the stack starts at position 1) return &m_vStackBuffer[1]; } //--------------------------------------------------------------------------- /** \brief Return the number of results on the calculation stack. If the expression contains comma separated subexpressions (i.e. "sin(y), x+y"). There may be more than one return value. This function returns the number of available results. */ int ParserBase::GetNumResults() const { return m_nFinalResultIdx; } //--------------------------------------------------------------------------- /** \brief Calculate the result. A note on const correctness: I consider it important that Calc is a const function. Due to caching operations Calc changes only the state of internal variables with one exception m_UsedVar this is reset during string parsing and accessible from the outside. Instead of making Calc non const GetUsedVar is non const because it explicitly calls Eval() forcing this update. \pre A formula must be set. \pre Variables must have been set (if needed) \sa #m_pParseFormula \return The evaluation result \throw ParseException if no Formula is set or in case of any other error related to the formula. */ value_type ParserBase::Eval() const { return (this->*m_pParseFormula)(); } //--------------------------------------------------------------------------- void ParserBase::Eval(value_type *results, int nBulkSize) { /* Commented because it is making a unit test impossible // Parallelization does not make sense for fewer than 10000 computations // due to thread creation overhead. If the bulk size is below 2000 // computation is refused. if (nBulkSize<2000) { throw ParserError(ecUNREASONABLE_NUMBER_OF_COMPUTATIONS); } */ CreateRPN(); int i = 0; #ifdef MUP_USE_OPENMP //#define DEBUG_OMP_STUFF #ifdef DEBUG_OMP_STUFF int *pThread = new int[nBulkSize]; int *pIdx = new int[nBulkSize]; #endif int nMaxThreads = std::min(omp_get_max_threads(), s_MaxNumOpenMPThreads); int nThreadID = 0, ct = 0; omp_set_num_threads(nMaxThreads); #pragma omp parallel for schedule(static, nBulkSize/nMaxThreads) private(nThreadID) for (i=0; i \___ >|__| \/ \/ \/ \/ Copyright (C) 2013 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_BASE_H #define MU_PARSER_BASE_H //--- Standard includes ------------------------------------------------------------------------ #include #include #include #include #include #include #include //--- Parser includes -------------------------------------------------------------------------- #include "muParserDef.h" #include "muParserStack.h" #include "muParserTokenReader.h" #include "muParserBytecode.h" #include "muParserError.h" namespace mu { /** \file \brief This file contains the class definition of the muparser engine. */ //-------------------------------------------------------------------------------------------------- /** \brief Mathematical expressions parser (base parser engine). \author (C) 2013 Ingo Berg This is the implementation of a bytecode based mathematical expressions parser. The formula will be parsed from string and converted into a bytecode. Future calculations will be done with the bytecode instead the formula string resulting in a significant performance increase. Complementary to a set of internally implemented functions the parser is able to handle user defined functions and variables. */ class ParserBase { friend class ParserTokenReader; private: /** \brief Typedef for the parse functions. The parse function do the actual work. The parser exchanges the function pointer to the parser function depending on which state it is in. (i.e. bytecode parser vs. string parser) */ typedef value_type (ParserBase::*ParseFunction)() const; /** \brief Type used for storing an array of values. */ typedef std::vector valbuf_type; /** \brief Type for a vector of strings. */ typedef std::vector stringbuf_type; /** \brief Typedef for the token reader. */ typedef ParserTokenReader token_reader_type; /** \brief Type used for parser tokens. */ typedef ParserToken token_type; /** \brief Maximum number of threads spawned by OpenMP when using the bulk mode. */ static const int s_MaxNumOpenMPThreads = 16; public: /** \brief Type of the error class. Included for backwards compatibility. */ typedef ParserError exception_type; static void EnableDebugDump(bool bDumpCmd, bool bDumpStack); ParserBase(); ParserBase(const ParserBase &a_Parser); ParserBase& operator=(const ParserBase &a_Parser); virtual ~ParserBase(); value_type Eval() const; value_type* Eval(int &nStackSize) const; void Eval(value_type *results, int nBulkSize); int GetNumResults() const; void SetExpr(const string_type &a_sExpr); void SetVarFactory(facfun_type a_pFactory, void *pUserData = NULL); void SetDecSep(char_type cDecSep); void SetThousandsSep(char_type cThousandsSep = 0); void ResetLocale(); void EnableOptimizer(bool a_bIsOn=true); void EnableBuiltInOprt(bool a_bIsOn=true); bool HasBuiltInOprt() const; void AddValIdent(identfun_type a_pCallback); /** \fn void mu::ParserBase::DefineFun(const string_type &a_strName, fun_type0 a_pFun, bool a_bAllowOpt = true) \brief Define a parser function without arguments. \param a_strName Name of the function \param a_pFun Pointer to the callback function \param a_bAllowOpt A flag indicating this function may be optimized */ template void DefineFun(const string_type &a_strName, T a_pFun, bool a_bAllowOpt = true) { AddCallback( a_strName, ParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars() ); } void DefineOprt(const string_type &a_strName, fun_type2 a_pFun, unsigned a_iPri=0, EOprtAssociativity a_eAssociativity = oaLEFT, bool a_bAllowOpt = false); void DefineConst(const string_type &a_sName, value_type a_fVal); void DefineStrConst(const string_type &a_sName, const string_type &a_strVal); void DefineVar(const string_type &a_sName, value_type *a_fVar); void DefinePostfixOprt(const string_type &a_strFun, fun_type1 a_pOprt, bool a_bAllowOpt=true); void DefineInfixOprt(const string_type &a_strName, fun_type1 a_pOprt, int a_iPrec=prINFIX, bool a_bAllowOpt=true); // Clear user defined variables, constants or functions void ClearVar(); void ClearFun(); void ClearConst(); void ClearInfixOprt(); void ClearPostfixOprt(); void ClearOprt(); void RemoveVar(const string_type &a_strVarName); const varmap_type& GetUsedVar() const; const varmap_type& GetVar() const; const valmap_type& GetConst() const; const string_type& GetExpr() const; const funmap_type& GetFunDef() const; string_type GetVersion(EParserVersionInfo eInfo = pviFULL) const; const char_type ** GetOprtDef() const; void DefineNameChars(const char_type *a_szCharset); void DefineOprtChars(const char_type *a_szCharset); void DefineInfixOprtChars(const char_type *a_szCharset); const char_type* ValidNameChars() const; const char_type* ValidOprtChars() const; const char_type* ValidInfixOprtChars() const; void SetArgSep(char_type cArgSep); char_type GetArgSep() const; void Error(EErrorCodes a_iErrc, int a_iPos = (int)mu::string_type::npos, const string_type &a_strTok = string_type() ) const; protected: void Init(); virtual void InitCharSets() = 0; virtual void InitFun() = 0; virtual void InitConst() = 0; virtual void InitOprt() = 0; virtual void OnDetectVar(string_type *pExpr, int &nStart, int &nEnd); static const char_type *c_DefaultOprt[]; static std::locale s_locale; ///< The locale used by the parser static bool g_DbgDumpCmdCode; static bool g_DbgDumpStack; /** \brief A facet class used to change decimal and thousands separator. */ template class change_dec_sep : public std::numpunct { public: explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3) :std::numpunct() ,m_nGroup(nGroup) ,m_cDecPoint(cDecSep) ,m_cThousandsSep(cThousandsSep) {} protected: virtual char_type do_decimal_point() const { return m_cDecPoint; } virtual char_type do_thousands_sep() const { return m_cThousandsSep; } virtual std::string do_grouping() const { // fix for issue 4: https://code.google.com/p/muparser/issues/detail?id=4 // courtesy of Jens Bartsch // original code: // return std::string(1, (char)m_nGroup); // new code: return std::string(1, (char)(m_cThousandsSep > 0 ? m_nGroup : CHAR_MAX)); } private: int m_nGroup; char_type m_cDecPoint; char_type m_cThousandsSep; }; private: void Assign(const ParserBase &a_Parser); void InitTokenReader(); void ReInit() const; void AddCallback( const string_type &a_strName, const ParserCallback &a_Callback, funmap_type &a_Storage, const char_type *a_szCharSet ); void ApplyRemainingOprt(ParserStack &a_stOpt, ParserStack &a_stVal) const; void ApplyBinOprt(ParserStack &a_stOpt, ParserStack &a_stVal) const; void ApplyIfElse(ParserStack &a_stOpt, ParserStack &a_stVal) const; void ApplyFunc(ParserStack &a_stOpt, ParserStack &a_stVal, int iArgCount) const; token_type ApplyStrFunc(const token_type &a_FunTok, const std::vector &a_vArg) const; int GetOprtPrecedence(const token_type &a_Tok) const; EOprtAssociativity GetOprtAssociativity(const token_type &a_Tok) const; void CreateRPN() const; value_type ParseString() const; value_type ParseCmdCode() const; value_type ParseCmdCodeBulk(int nOffset, int nThreadID) const; void CheckName(const string_type &a_strName, const string_type &a_CharSet) const; void CheckOprt(const string_type &a_sName, const ParserCallback &a_Callback, const string_type &a_szCharSet) const; void StackDump(const ParserStack &a_stVal, const ParserStack &a_stOprt) const; /** \brief Pointer to the parser function. Eval() calls the function whose address is stored there. */ mutable ParseFunction m_pParseFormula; mutable ParserByteCode m_vRPN; ///< The Bytecode class. mutable stringbuf_type m_vStringBuf; ///< String buffer, used for storing string function arguments stringbuf_type m_vStringVarBuf; std::auto_ptr m_pTokenReader; ///< Managed pointer to the token reader object. funmap_type m_FunDef; ///< Map of function names and pointers. funmap_type m_PostOprtDef; ///< Postfix operator callbacks funmap_type m_InfixOprtDef; ///< unary infix operator. funmap_type m_OprtDef; ///< Binary operator callbacks valmap_type m_ConstDef; ///< user constants. strmap_type m_StrVarDef; ///< user defined string constants varmap_type m_VarDef; ///< user defind variables. bool m_bBuiltInOp; ///< Flag that can be used for switching built in operators on and off string_type m_sNameChars; ///< Charset for names string_type m_sOprtChars; ///< Charset for postfix/ binary operator tokens string_type m_sInfixOprtChars; ///< Charset for infix operator tokens mutable int m_nIfElseCounter; ///< Internal counter for keeping track of nested if-then-else clauses // items merely used for caching state information mutable valbuf_type m_vStackBuffer; ///< This is merely a buffer used for the stack in the cmd parsing routine mutable int m_nFinalResultIdx; }; } // namespace mu #endif IanniX-0.9.20/geometry/qmuparser/muParserBytecode.cpp000066400000000000000000000501321317340345000226240ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParserBytecode.h" #include #include #include #include #include #include #include "muParserDef.h" #include "muParserError.h" #include "muParserToken.h" #include "muParserStack.h" #include "muParserTemplateMagic.h" namespace mu { //--------------------------------------------------------------------------- /** \brief Bytecode default constructor. */ ParserByteCode::ParserByteCode() :m_iStackPos(0) ,m_iMaxStackSize(0) ,m_vRPN() ,m_bEnableOptimizer(true) { m_vRPN.reserve(50); } //--------------------------------------------------------------------------- /** \brief Copy constructor. Implemented in Terms of Assign(const ParserByteCode &a_ByteCode) */ ParserByteCode::ParserByteCode(const ParserByteCode &a_ByteCode) { Assign(a_ByteCode); } //--------------------------------------------------------------------------- /** \brief Assignment operator. Implemented in Terms of Assign(const ParserByteCode &a_ByteCode) */ ParserByteCode& ParserByteCode::operator=(const ParserByteCode &a_ByteCode) { Assign(a_ByteCode); return *this; } //--------------------------------------------------------------------------- void ParserByteCode::EnableOptimizer(bool bStat) { m_bEnableOptimizer = bStat; } //--------------------------------------------------------------------------- /** \brief Copy state of another object to this. \throw nowthrow */ void ParserByteCode::Assign(const ParserByteCode &a_ByteCode) { if (this==&a_ByteCode) return; m_iStackPos = a_ByteCode.m_iStackPos; m_vRPN = a_ByteCode.m_vRPN; m_iMaxStackSize = a_ByteCode.m_iMaxStackSize; m_bEnableOptimizer = a_ByteCode.m_bEnableOptimizer; } //--------------------------------------------------------------------------- /** \brief Add a Variable pointer to bytecode. \param a_pVar Pointer to be added. \throw nothrow */ void ParserByteCode::AddVar(value_type *a_pVar) { ++m_iStackPos; m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); // optimization does not apply SToken tok; tok.Cmd = cmVAR; tok.Val.ptr = a_pVar; tok.Val.data = 1; tok.Val.data2 = 0; m_vRPN.push_back(tok); } //--------------------------------------------------------------------------- /** \brief Add a Variable pointer to bytecode. Value entries in byte code consist of:
    • value array position of the value
    • the operator code according to ParserToken::cmVAL
    • the value stored in #mc_iSizeVal number of bytecode entries.
    \param a_pVal Value to be added. \throw nothrow */ void ParserByteCode::AddVal(value_type a_fVal) { ++m_iStackPos; m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); // If optimization does not apply SToken tok; tok.Cmd = cmVAL; tok.Val.ptr = NULL; tok.Val.data = 0; tok.Val.data2 = a_fVal; m_vRPN.push_back(tok); } //--------------------------------------------------------------------------- void ParserByteCode::ConstantFolding(ECmdCode a_Oprt) { std::size_t sz = m_vRPN.size(); value_type &x = m_vRPN[sz-2].Val.data2, &y = m_vRPN[sz-1].Val.data2; switch (a_Oprt) { case cmLAND: x = (int)x && (int)y; m_vRPN.pop_back(); break; case cmLOR: x = (int)x || (int)y; m_vRPN.pop_back(); break; case cmLT: x = x < y; m_vRPN.pop_back(); break; case cmGT: x = x > y; m_vRPN.pop_back(); break; case cmLE: x = x <= y; m_vRPN.pop_back(); break; case cmGE: x = x >= y; m_vRPN.pop_back(); break; case cmNEQ: x = x != y; m_vRPN.pop_back(); break; case cmEQ: x = x == y; m_vRPN.pop_back(); break; case cmADD: x = x + y; m_vRPN.pop_back(); break; case cmSUB: x = x - y; m_vRPN.pop_back(); break; case cmMUL: x = x * y; m_vRPN.pop_back(); break; case cmDIV: #if defined(MUP_MATH_EXCEPTIONS) if (y==0) throw ParserError(ecDIV_BY_ZERO, _T("0")); #endif x = x / y; m_vRPN.pop_back(); break; case cmPOW: x = MathImpl::Pow(x, y); m_vRPN.pop_back(); break; default: break; } // switch opcode } //--------------------------------------------------------------------------- /** \brief Add an operator identifier to bytecode. Operator entries in byte code consist of:
    • value array position of the result
    • the operator code according to ParserToken::ECmdCode
    \sa ParserToken::ECmdCode */ void ParserByteCode::AddOp(ECmdCode a_Oprt) { bool bOptimized = false; if (m_bEnableOptimizer) { std::size_t sz = m_vRPN.size(); // Check for foldable constants like: // cmVAL cmVAL cmADD // where cmADD can stand fopr any binary operator applied to // two constant values. if (sz>=2 && m_vRPN[sz-2].Cmd == cmVAL && m_vRPN[sz-1].Cmd == cmVAL) { ConstantFolding(a_Oprt); bOptimized = true; } else { switch(a_Oprt) { case cmPOW: // Optimization for polynomials of low order if (m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-1].Cmd == cmVAL) { if (m_vRPN[sz-1].Val.data2==2) m_vRPN[sz-2].Cmd = cmVARPOW2; else if (m_vRPN[sz-1].Val.data2==3) m_vRPN[sz-2].Cmd = cmVARPOW3; else if (m_vRPN[sz-1].Val.data2==4) m_vRPN[sz-2].Cmd = cmVARPOW4; else break; m_vRPN.pop_back(); bOptimized = true; } break; case cmSUB: case cmADD: // Simple optimization based on pattern recognition for a shitload of different // bytecode combinations of addition/subtraction if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) || (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) || (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) || (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) || (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ) { assert( (m_vRPN[sz-2].Val.ptr==NULL && m_vRPN[sz-1].Val.ptr!=NULL) || (m_vRPN[sz-2].Val.ptr!=NULL && m_vRPN[sz-1].Val.ptr==NULL) || (m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ); m_vRPN[sz-2].Cmd = cmVARMUL; m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr)); // variable m_vRPN[sz-2].Val.data2 += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data2; // offset m_vRPN[sz-2].Val.data += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data; // multiplicand m_vRPN.pop_back(); bOptimized = true; } break; case cmMUL: if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) || (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) ) { m_vRPN[sz-2].Cmd = cmVARMUL; m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr)); m_vRPN[sz-2].Val.data = m_vRPN[sz-2].Val.data2 + m_vRPN[sz-1].Val.data2; m_vRPN[sz-2].Val.data2 = 0; m_vRPN.pop_back(); bOptimized = true; } else if ( (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) || (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) ) { // Optimization: 2*(3*b+1) or (3*b+1)*2 -> 6*b+2 m_vRPN[sz-2].Cmd = cmVARMUL; m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr)); if (m_vRPN[sz-1].Cmd == cmVAL) { m_vRPN[sz-2].Val.data *= m_vRPN[sz-1].Val.data2; m_vRPN[sz-2].Val.data2 *= m_vRPN[sz-1].Val.data2; } else { m_vRPN[sz-2].Val.data = m_vRPN[sz-1].Val.data * m_vRPN[sz-2].Val.data2; m_vRPN[sz-2].Val.data2 = m_vRPN[sz-1].Val.data2 * m_vRPN[sz-2].Val.data2; } m_vRPN.pop_back(); bOptimized = true; } else if (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-1].Val.ptr == m_vRPN[sz-2].Val.ptr) { // Optimization: a*a -> a^2 m_vRPN[sz-2].Cmd = cmVARPOW2; m_vRPN.pop_back(); bOptimized = true; } break; case cmDIV: if (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-1].Val.data2!=0) { // Optimization: 4*a/2 -> 2*a m_vRPN[sz-2].Val.data /= m_vRPN[sz-1].Val.data2; m_vRPN[sz-2].Val.data2 /= m_vRPN[sz-1].Val.data2; m_vRPN.pop_back(); bOptimized = true; } break; } // switch a_Oprt } } // If optimization can't be applied just write the value if (!bOptimized) { --m_iStackPos; SToken tok; tok.Cmd = a_Oprt; m_vRPN.push_back(tok); } } //--------------------------------------------------------------------------- void ParserByteCode::AddIfElse(ECmdCode a_Oprt) { SToken tok; tok.Cmd = a_Oprt; m_vRPN.push_back(tok); } //--------------------------------------------------------------------------- /** \brief Add an assignment operator Operator entries in byte code consist of:
    • cmASSIGN code
    • the pointer of the destination variable
    \sa ParserToken::ECmdCode */ void ParserByteCode::AddAssignOp(value_type *a_pVar) { --m_iStackPos; SToken tok; tok.Cmd = cmASSIGN; tok.Oprt.ptr = a_pVar; m_vRPN.push_back(tok); } //--------------------------------------------------------------------------- /** \brief Add function to bytecode. \param a_iArgc Number of arguments, negative numbers indicate multiarg functions. \param a_pFun Pointer to function callback. */ void ParserByteCode::AddFun(generic_fun_type a_pFun, int a_iArgc) { if (a_iArgc>=0) { m_iStackPos = m_iStackPos - a_iArgc + 1; } else { // function with unlimited number of arguments m_iStackPos = m_iStackPos + a_iArgc + 1; } m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); SToken tok; tok.Cmd = cmFUNC; tok.Fun.argc = a_iArgc; tok.Fun.ptr = a_pFun; m_vRPN.push_back(tok); } //--------------------------------------------------------------------------- /** \brief Add a bulk function to bytecode. \param a_iArgc Number of arguments, negative numbers indicate multiarg functions. \param a_pFun Pointer to function callback. */ void ParserByteCode::AddBulkFun(generic_fun_type a_pFun, int a_iArgc) { m_iStackPos = m_iStackPos - a_iArgc + 1; m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); SToken tok; tok.Cmd = cmFUNC_BULK; tok.Fun.argc = a_iArgc; tok.Fun.ptr = a_pFun; m_vRPN.push_back(tok); } //--------------------------------------------------------------------------- /** \brief Add Strung function entry to the parser bytecode. \throw nothrow A string function entry consists of the stack position of the return value, followed by a cmSTRFUNC code, the function pointer and an index into the string buffer maintained by the parser. */ void ParserByteCode::AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx) { m_iStackPos = m_iStackPos - a_iArgc + 1; SToken tok; tok.Cmd = cmFUNC_STR; tok.Fun.argc = a_iArgc; tok.Fun.idx = a_iIdx; tok.Fun.ptr = a_pFun; m_vRPN.push_back(tok); m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); } //--------------------------------------------------------------------------- /** \brief Add end marker to bytecode. \throw nothrow */ void ParserByteCode::Finalize() { SToken tok; tok.Cmd = cmEND; m_vRPN.push_back(tok); rpn_type(m_vRPN).swap(m_vRPN); // shrink bytecode vector to fit // Determine the if-then-else jump offsets ParserStack stIf, stElse; int idx; for (int i=0; i<(int)m_vRPN.size(); ++i) { switch(m_vRPN[i].Cmd) { case cmIF: stIf.push(i); break; case cmELSE: stElse.push(i); idx = stIf.pop(); m_vRPN[idx].Oprt.offset = i - idx; break; case cmENDIF: idx = stElse.pop(); m_vRPN[idx].Oprt.offset = i - idx; break; default: break; } } } //--------------------------------------------------------------------------- const SToken* ParserByteCode::GetBase() const { if (m_vRPN.size()==0) throw ParserError(ecINTERNAL_ERROR); else return &m_vRPN[0]; } //--------------------------------------------------------------------------- std::size_t ParserByteCode::GetMaxStackSize() const { return m_iMaxStackSize+1; } //--------------------------------------------------------------------------- /** \brief Returns the number of entries in the bytecode. */ std::size_t ParserByteCode::GetSize() const { return m_vRPN.size(); } //--------------------------------------------------------------------------- /** \brief Delete the bytecode. \throw nothrow The name of this function is a violation of my own coding guidelines but this way it's more in line with the STL functions thus more intuitive. */ void ParserByteCode::clear() { m_vRPN.clear(); m_iStackPos = 0; m_iMaxStackSize = 0; } //--------------------------------------------------------------------------- /** \brief Dump bytecode (for debugging only!). */ void ParserByteCode::AsciiDump() { if (!m_vRPN.size()) { mu::console() << _T("No bytecode available\n"); return; } mu::console() << _T("Number of RPN tokens:") << (int)m_vRPN.size() << _T("\n"); for (std::size_t i=0; i \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2013 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_BYTECODE_H #define MU_PARSER_BYTECODE_H #include #include #include #include #include "muParserDef.h" #include "muParserError.h" #include "muParserToken.h" /** \file \brief Definition of the parser bytecode class. */ namespace mu { struct SToken { ECmdCode Cmd; int StackPos; union { struct //SValData { value_type *ptr; value_type data; value_type data2; } Val; struct //SFunData { // Note: generic_fun_type is merely a placeholder. The real type could be // anything between gun_type1 and fun_type9. I can't use a void // pointer due to constraints in the ANSI standard which allows // data pointers and function pointers to differ in size. generic_fun_type ptr; int argc; int idx; } Fun; struct //SOprtData { value_type *ptr; int offset; } Oprt; }; }; /** \brief Bytecode implementation of the Math Parser. The bytecode contains the formula converted to revers polish notation stored in a continious memory area. Associated with this data are operator codes, variable pointers, constant values and function pointers. Those are necessary in order to calculate the result. All those data items will be casted to the underlying datatype of the bytecode. \author (C) 2004-2013 Ingo Berg */ class ParserByteCode { private: /** \brief Token type for internal use only. */ typedef ParserToken token_type; /** \brief Token vector for storing the RPN. */ typedef std::vector rpn_type; /** \brief Position in the Calculation array. */ unsigned m_iStackPos; /** \brief Maximum size needed for the stack. */ std::size_t m_iMaxStackSize; /** \brief The actual rpn storage. */ rpn_type m_vRPN; bool m_bEnableOptimizer; void ConstantFolding(ECmdCode a_Oprt); public: ParserByteCode(); ParserByteCode(const ParserByteCode &a_ByteCode); ParserByteCode& operator=(const ParserByteCode &a_ByteCode); void Assign(const ParserByteCode &a_ByteCode); void AddVar(value_type *a_pVar); void AddVal(value_type a_fVal); void AddOp(ECmdCode a_Oprt); void AddIfElse(ECmdCode a_Oprt); void AddAssignOp(value_type *a_pVar); void AddFun(generic_fun_type a_pFun, int a_iArgc); void AddBulkFun(generic_fun_type a_pFun, int a_iArgc); void AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx); void EnableOptimizer(bool bStat); void Finalize(); void clear(); std::size_t GetMaxStackSize() const; std::size_t GetSize() const; const SToken* GetBase() const; void AsciiDump(); }; } // namespace mu #endif IanniX-0.9.20/geometry/qmuparser/muParserCallback.cpp000066400000000000000000000327441317340345000225730ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParserCallback.h" /** \file \brief Implementation of the parser callback class. */ namespace mu { //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type0 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(0) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec, ECmdCode a_iCode) :m_pFun((void*)a_pFun) ,m_iArgc(1) ,m_iPri(a_iPrec) ,m_eOprtAsct(oaNONE) ,m_iCode(a_iCode) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- /** \brief Constructor for constructing function callbacks taking two arguments. \throw nothrow */ ParserCallback::ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(2) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- /** \brief Constructor for constructing binary operator callbacks. \param a_pFun Pointer to a static function taking two arguments \param a_bAllowOpti A flag indicating this function can be optimized \param a_iPrec The operator precedence \param a_eOprtAsct The operators associativity \throw nothrow */ ParserCallback::ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec, EOprtAssociativity a_eOprtAsct) :m_pFun((void*)a_pFun) ,m_iArgc(2) ,m_iPri(a_iPrec) ,m_eOprtAsct(a_eOprtAsct) ,m_iCode(cmOPRT_BIN) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(3) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(4) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(5) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type6 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(6) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type7 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(7) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type8 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(8) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type9 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(9) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type10 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(10) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type0 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(0) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type1 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(1) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- /** \brief Constructor for constructing function callbacks taking two arguments. \throw nothrow */ ParserCallback::ParserCallback(bulkfun_type2 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(2) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type3 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(3) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type4 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(4) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type5 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(5) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type6 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(6) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type7 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(7) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type8 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(8) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type9 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(9) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type10 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(10) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(multfun_type a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(-1) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(0) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_STR) ,m_iType(tpSTR) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(1) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_STR) ,m_iType(tpSTR) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(2) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_STR) ,m_iType(tpSTR) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- /** \brief Default constructor. \throw nothrow */ ParserCallback::ParserCallback() :m_pFun(0) ,m_iArgc(0) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmUNKNOWN) ,m_iType(tpVOID) ,m_bAllowOpti(0) {} //--------------------------------------------------------------------------- /** \brief Copy constructor. \throw nothrow */ ParserCallback::ParserCallback(const ParserCallback &ref) { m_pFun = ref.m_pFun; m_iArgc = ref.m_iArgc; m_bAllowOpti = ref.m_bAllowOpti; m_iCode = ref.m_iCode; m_iType = ref.m_iType; m_iPri = ref.m_iPri; m_eOprtAsct = ref.m_eOprtAsct; } //--------------------------------------------------------------------------- /** \brief Clone this instance and return a pointer to the new instance. */ ParserCallback* ParserCallback::Clone() const { return new ParserCallback(*this); } //--------------------------------------------------------------------------- /** \brief Return tru if the function is conservative. Conservative functions return always the same result for the same argument. \throw nothrow */ bool ParserCallback::IsOptimizable() const { return m_bAllowOpti; } //--------------------------------------------------------------------------- /** \brief Get the callback address for the parser function. The type of the address is void. It needs to be recasted according to the argument number to the right type. \throw nothrow \return #pFun */ void* ParserCallback::GetAddr() const { return m_pFun; } //--------------------------------------------------------------------------- /** \brief Return the callback code. */ ECmdCode ParserCallback::GetCode() const { return m_iCode; } //--------------------------------------------------------------------------- ETypeCode ParserCallback::GetType() const { return m_iType; } //--------------------------------------------------------------------------- /** \brief Return the operator precedence. \throw nothrown Only valid if the callback token is an operator token (binary or infix). */ int ParserCallback::GetPri() const { return m_iPri; } //--------------------------------------------------------------------------- /** \brief Return the operators associativity. \throw nothrown Only valid if the callback token is a binary operator token. */ EOprtAssociativity ParserCallback::GetAssociativity() const { return m_eOprtAsct; } //--------------------------------------------------------------------------- /** \brief Returns the number of function Arguments. */ int ParserCallback::GetArgc() const { return m_iArgc; } } // namespace mu IanniX-0.9.20/geometry/qmuparser/muParserCallback.h000066400000000000000000000117471317340345000222400ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_CALLBACK_H #define MU_PARSER_CALLBACK_H #include "muParserDef.h" /** \file \brief Definition of the parser callback class. */ namespace mu { /** \brief Encapsulation of prototypes for a numerical parser function. Encapsulates the prototyp for numerical parser functions. The class stores the number of arguments for parser functions as well as additional flags indication the function is non optimizeable. The pointer to the callback function pointer is stored as void* and needs to be casted according to the argument count. Negative argument counts indicate a parser function with a variable number of arguments. \author (C) 2004-2011 Ingo Berg */ class ParserCallback { public: ParserCallback(fun_type0 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec = -1, ECmdCode a_iCode=cmFUNC); ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec, EOprtAssociativity a_eAssociativity); ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type6 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type7 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type8 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type9 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type10 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type0 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type1 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type2 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type3 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type4 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type5 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type6 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type7 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type8 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type9 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type10 a_pFun, bool a_bAllowOpti); ParserCallback(multfun_type a_pFun, bool a_bAllowOpti); ParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti); ParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti); ParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti); ParserCallback(); ParserCallback(const ParserCallback &a_Fun); ParserCallback* Clone() const; bool IsOptimizable() const; void* GetAddr() const; ECmdCode GetCode() const; ETypeCode GetType() const; int GetPri() const; EOprtAssociativity GetAssociativity() const; int GetArgc() const; private: void *m_pFun; ///< Pointer to the callback function, casted to void /** \brief Number of numeric function arguments This number is negative for functions with variable number of arguments. in this cases they represent the actual number of arguments found. */ int m_iArgc; int m_iPri; ///< Valid only for binary and infix operators; Operator precedence. EOprtAssociativity m_eOprtAsct; ///< Operator associativity; Valid only for binary operators ECmdCode m_iCode; ETypeCode m_iType; bool m_bAllowOpti; ///< Flag indication optimizeability }; //------------------------------------------------------------------------------ /** \brief Container for Callback objects. */ typedef std::map funmap_type; } // namespace mu #endif IanniX-0.9.20/geometry/qmuparser/muParserDLL.cpp000066400000000000000000001001601317340345000214760ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #if defined(MUPARSER_DLL) #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN #include #endif #include "muParserDLL.h" #include "muParser.h" #include "muParserInt.h" #include "muParserError.h" #define MU_TRY \ try \ { #define MU_CATCH \ } \ catch (muError_t &e) \ { \ ParserTag *pTag = static_cast(a_hParser); \ pTag->exc = e; \ pTag->bError = true; \ if (pTag->errHandler) \ (pTag->errHandler)(a_hParser); \ } \ catch (...) \ { \ ParserTag *pTag = static_cast(a_hParser); \ pTag->exc = muError_t(mu::ecINTERNAL_ERROR); \ pTag->bError = true; \ if (pTag->errHandler) \ (pTag->errHandler)(a_hParser); \ } /** \file \brief This file contains the implementation of the DLL interface of muparser. */ //--------------------------------------------------------------------------- // private types typedef mu::ParserBase::exception_type muError_t; typedef mu::ParserBase muParser_t; int g_nBulkSize; //--------------------------------------------------------------------------- class ParserTag { public: ParserTag(int nType) :pParser((nType == muBASETYPE_FLOAT) ? (mu::ParserBase*)new mu::Parser() : (nType == muBASETYPE_INT) ? (mu::ParserBase*)new mu::ParserInt() : NULL) , exc() , errHandler(NULL) , bError(false) , m_nParserType(nType) {} ~ParserTag() { delete pParser; } mu::ParserBase *pParser; mu::ParserBase::exception_type exc; muErrorHandler_t errHandler; bool bError; private: ParserTag(const ParserTag &ref); ParserTag& operator=(const ParserTag &ref); int m_nParserType; }; static muChar_t s_tmpOutBuf[2048]; //--------------------------------------------------------------------------- // // // unexported functions // // //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- muParser_t* AsParser(muParserHandle_t a_hParser) { return static_cast(a_hParser)->pParser; } //--------------------------------------------------------------------------- ParserTag* AsParserTag(muParserHandle_t a_hParser) { return static_cast(a_hParser); } //--------------------------------------------------------------------------- #if defined(_WIN32) #define _CRT_SECURE_NO_DEPRECATE BOOL APIENTRY DllMain(HANDLE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } #endif //--------------------------------------------------------------------------- // // // exported functions // // //--------------------------------------------------------------------------- API_EXPORT(void) mupSetVarFactory(muParserHandle_t a_hParser, muFacFun_t a_pFactory, void *pUserData) { MU_TRY muParser_t* p(AsParser(a_hParser)); p->SetVarFactory(a_pFactory, pUserData); MU_CATCH } //--------------------------------------------------------------------------- /** \brief Create a new Parser instance and return its handle. */ API_EXPORT(muParserHandle_t) mupCreate(int nBaseType) { switch (nBaseType) { case muBASETYPE_FLOAT: return (void*)(new ParserTag(muBASETYPE_FLOAT)); case muBASETYPE_INT: return (void*)(new ParserTag(muBASETYPE_INT)); default: return NULL; } } //--------------------------------------------------------------------------- /** \brief Release the parser instance related with a parser handle. */ API_EXPORT(void) mupRelease(muParserHandle_t a_hParser) { MU_TRY ParserTag* p = static_cast(a_hParser); delete p; MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(const muChar_t*) mupGetVersion(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); #ifndef _UNICODE sprintf(s_tmpOutBuf, "%s", p->GetVersion().c_str()); #else wsprintf(s_tmpOutBuf, _T("%s"), p->GetVersion().c_str()); #endif return s_tmpOutBuf; MU_CATCH return _T(""); } //--------------------------------------------------------------------------- /** \brief Evaluate the expression. */ API_EXPORT(muFloat_t) mupEval(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); return p->Eval(); MU_CATCH return 0; } //--------------------------------------------------------------------------- API_EXPORT(muFloat_t*) mupEvalMulti(muParserHandle_t a_hParser, int *nNum) { MU_TRY assert(nNum != NULL); muParser_t* const p(AsParser(a_hParser)); return p->Eval(*nNum); MU_CATCH return 0; } //--------------------------------------------------------------------------- API_EXPORT(void) mupEvalBulk(muParserHandle_t a_hParser, muFloat_t *a_res, int nSize) { MU_TRY muParser_t* p(AsParser(a_hParser)); p->Eval(a_res, nSize); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupSetExpr(muParserHandle_t a_hParser, const muChar_t* a_szExpr) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->SetExpr(a_szExpr); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupRemoveVar(muParserHandle_t a_hParser, const muChar_t* a_szName) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->RemoveVar(a_szName); MU_CATCH } //--------------------------------------------------------------------------- /** \brief Release all parser variables. \param a_hParser Handle to the parser instance. */ API_EXPORT(void) mupClearVar(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->ClearVar(); MU_CATCH } //--------------------------------------------------------------------------- /** \brief Release all parser variables. \param a_hParser Handle to the parser instance. */ API_EXPORT(void) mupClearConst(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->ClearConst(); MU_CATCH } //--------------------------------------------------------------------------- /** \brief Clear all user defined operators. \param a_hParser Handle to the parser instance. */ API_EXPORT(void) mupClearOprt(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->ClearOprt(); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupClearFun(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->ClearFun(); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineFun0(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun0_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineFun1(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun1_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineFun2(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun2_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun3_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineFun4(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun4_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineFun5(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun5_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineFun6(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun6_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineFun7(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun7_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineFun8(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun8_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineFun9(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun9_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineFun10(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun10_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineBulkFun0(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun0_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineBulkFun1(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun1_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineBulkFun2(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun2_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineBulkFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun3_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineBulkFun4(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun4_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineBulkFun5(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun5_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineBulkFun6(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun6_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineBulkFun7(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun7_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineBulkFun8(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun8_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineBulkFun9(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun9_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineBulkFun10(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun10_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineStrFun1(muParserHandle_t a_hParser, const muChar_t *a_szName, muStrFun1_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineStrFun2(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFun2_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineStrFun3(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFun3_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineMultFun(muParserHandle_t a_hParser, const muChar_t *a_szName, muMultFun_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineOprt(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun2_t a_pFun, muInt_t a_nPrec, muInt_t a_nOprtAsct, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineOprt(a_szName, a_pFun, a_nPrec, (mu::EOprtAssociativity)a_nOprtAsct, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineVar(muParserHandle_t a_hParser, const muChar_t *a_szName, muFloat_t *a_pVar) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineVar(a_szName, a_pVar); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineBulkVar(muParserHandle_t a_hParser, const muChar_t *a_szName, muFloat_t *a_pVar) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineVar(a_szName, a_pVar); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineConst(muParserHandle_t a_hParser, const muChar_t *a_szName, muFloat_t a_fVal) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineConst(a_szName, a_fVal); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineStrConst(muParserHandle_t a_hParser, const muChar_t *a_szName, const muChar_t *a_szVal) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineStrConst(a_szName, a_szVal); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(const muChar_t*) mupGetExpr(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); // C# explodes when pMsg is returned directly. For some reason it can't access // the memory where the message lies directly. #ifndef _UNICODE sprintf(s_tmpOutBuf, "%s", p->GetExpr().c_str()); #else wsprintf(s_tmpOutBuf, _T("%s"), p->GetExpr().c_str()); #endif return s_tmpOutBuf; MU_CATCH return _T(""); } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefinePostfixOprt(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun1_t a_pOprt, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefinePostfixOprt(a_szName, a_pOprt, a_bAllowOpt != 0); MU_CATCH } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineInfixOprt(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun1_t a_pOprt, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineInfixOprt(a_szName, a_pOprt, a_bAllowOpt != 0); MU_CATCH } // Define character sets for identifiers //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineNameChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset) { muParser_t* const p(AsParser(a_hParser)); p->DefineNameChars(a_szCharset); } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset) { muParser_t* const p(AsParser(a_hParser)); p->DefineOprtChars(a_szCharset); } //--------------------------------------------------------------------------- API_EXPORT(void) mupDefineInfixOprtChars(muParserHandle_t a_hParser, const muChar_t *a_szCharset) { muParser_t* const p(AsParser(a_hParser)); p->DefineInfixOprtChars(a_szCharset); } //--------------------------------------------------------------------------- /** \brief Get the number of variables defined in the parser. \param a_hParser [in] Must be a valid parser handle. \return The number of used variables. \sa mupGetExprVar */ API_EXPORT(int) mupGetVarNum(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); const mu::varmap_type VarMap = p->GetVar(); return (int)VarMap.size(); MU_CATCH return 0; // never reached } //--------------------------------------------------------------------------- /** \brief Return a variable that is used in an expression. \param a_hParser [in] A valid parser handle. \param a_iVar [in] The index of the variable to return. \param a_szName [out] Pointer to the variable name. \param a_pVar [out] Pointer to the variable. \throw nothrow Prior to calling this function call mupGetExprVarNum in order to get the number of variables in the expression. If the parameter a_iVar is greater than the number of variables both a_szName and a_pVar will be set to zero. As a side effect this function will trigger an internal calculation of the expression undefined variables will be set to zero during this calculation. During the calculation user defined callback functions present in the expression will be called, this is unavoidable. */ API_EXPORT(void) mupGetVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t **a_szName, muFloat_t **a_pVar) { // A static buffer is needed for the name since i cant return the // pointer from the map. static muChar_t szName[1024]; MU_TRY muParser_t* const p(AsParser(a_hParser)); const mu::varmap_type VarMap = p->GetVar(); if (a_iVar >= VarMap.size()) { *a_szName = 0; *a_pVar = 0; return; } mu::varmap_type::const_iterator item; item = VarMap.begin(); for (unsigned i = 0; i < a_iVar; ++i) ++item; #ifndef _UNICODE strncpy(szName, item->first.c_str(), sizeof(szName)); #else wcsncpy(szName, item->first.c_str(), sizeof(szName)); #endif szName[sizeof(szName)-1] = 0; *a_szName = &szName[0]; *a_pVar = item->second; return; MU_CATCH *a_szName = 0; *a_pVar = 0; } //--------------------------------------------------------------------------- /** \brief Get the number of variables used in the expression currently set in the parser. \param a_hParser [in] Must be a valid parser handle. \return The number of used variables. \sa mupGetExprVar */ API_EXPORT(int) mupGetExprVarNum(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); const mu::varmap_type VarMap = p->GetUsedVar(); return (int)VarMap.size(); MU_CATCH return 0; // never reached } //--------------------------------------------------------------------------- /** \brief Return a variable that is used in an expression. Prior to calling this function call mupGetExprVarNum in order to get the number of variables in the expression. If the parameter a_iVar is greater than the number of variables both a_szName and a_pVar will be set to zero. As a side effect this function will trigger an internal calculation of the expression undefined variables will be set to zero during this calculation. During the calculation user defined callback functions present in the expression will be called, this is unavoidable. \param a_hParser [in] A valid parser handle. \param a_iVar [in] The index of the variable to return. \param a_szName [out] Pointer to the variable name. \param a_pVar [out] Pointer to the variable. \throw nothrow */ API_EXPORT(void) mupGetExprVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t **a_szName, muFloat_t **a_pVar) { // A static buffer is needed for the name since i cant return the // pointer from the map. static muChar_t szName[1024]; MU_TRY muParser_t* const p(AsParser(a_hParser)); const mu::varmap_type VarMap = p->GetUsedVar(); if (a_iVar >= VarMap.size()) { *a_szName = 0; *a_pVar = 0; return; } mu::varmap_type::const_iterator item; item = VarMap.begin(); for (unsigned i = 0; i < a_iVar; ++i) ++item; #ifndef _UNICODE strncpy(szName, item->first.c_str(), sizeof(szName)); #else wcsncpy(szName, item->first.c_str(), sizeof(szName)); #endif szName[sizeof(szName)-1] = 0; *a_szName = &szName[0]; *a_pVar = item->second; return; MU_CATCH *a_szName = 0; *a_pVar = 0; } //--------------------------------------------------------------------------- /** \brief Return the number of constants defined in a parser. */ API_EXPORT(int) mupGetConstNum(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); const mu::valmap_type ValMap = p->GetConst(); return (int)ValMap.size(); MU_CATCH return 0; // never reached } //----------------------------------------------------------------------------------------------------- API_EXPORT(void) mupSetArgSep(muParserHandle_t a_hParser, const muChar_t cArgSep) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->SetArgSep(cArgSep); MU_CATCH } //----------------------------------------------------------------------------------------------------- API_EXPORT(void) mupResetLocale(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->ResetLocale(); MU_CATCH } //----------------------------------------------------------------------------------------------------- API_EXPORT(void) mupSetDecSep(muParserHandle_t a_hParser, const muChar_t cDecSep) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->SetDecSep(cDecSep); MU_CATCH } //----------------------------------------------------------------------------------------------------- API_EXPORT(void) mupSetThousandsSep(muParserHandle_t a_hParser, const muChar_t cThousandsSep) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->SetThousandsSep(cThousandsSep); MU_CATCH } //--------------------------------------------------------------------------- /** \brief Retrieve name and value of a single parser constant. \param a_hParser [in] a valid parser handle \param a_iVar [in] Index of the constant to query \param a_pszName [out] pointer to a null terminated string with the constant name \param [out] The constant value */ API_EXPORT(void) mupGetConst(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t **a_pszName, muFloat_t *a_fVal) { // A static buffer is needed for the name since i cant return the // pointer from the map. static muChar_t szName[1024]; MU_TRY muParser_t* const p(AsParser(a_hParser)); const mu::valmap_type ValMap = p->GetConst(); if (a_iVar >= ValMap.size()) { *a_pszName = 0; *a_fVal = 0; return; } mu::valmap_type::const_iterator item; item = ValMap.begin(); for (unsigned i = 0; i < a_iVar; ++i) ++item; #ifndef _UNICODE strncpy(szName, item->first.c_str(), sizeof(szName)); #else wcsncpy(szName, item->first.c_str(), sizeof(szName)); #endif szName[sizeof(szName)-1] = 0; *a_pszName = &szName[0]; *a_fVal = item->second; return; MU_CATCH *a_pszName = 0; *a_fVal = 0; } //--------------------------------------------------------------------------- /** \brief Add a custom value recognition function. */ API_EXPORT(void) mupAddValIdent(muParserHandle_t a_hParser, muIdentFun_t a_pFun) { MU_TRY muParser_t* p(AsParser(a_hParser)); p->AddValIdent(a_pFun); MU_CATCH } //--------------------------------------------------------------------------- /** \brief Query if an error occurred. After querying the internal error bit will be reset. So a consecutive call will return false. */ API_EXPORT(muBool_t) mupError(muParserHandle_t a_hParser) { bool bError(AsParserTag(a_hParser)->bError); AsParserTag(a_hParser)->bError = false; return bError; } //--------------------------------------------------------------------------- /** \brief Reset the internal error flag. */ API_EXPORT(void) mupErrorReset(muParserHandle_t a_hParser) { AsParserTag(a_hParser)->bError = false; } //--------------------------------------------------------------------------- API_EXPORT(void) mupSetErrorHandler(muParserHandle_t a_hParser, muErrorHandler_t a_pHandler) { AsParserTag(a_hParser)->errHandler = a_pHandler; } //--------------------------------------------------------------------------- /** \brief Return the message associated with the last error. */ API_EXPORT(const muChar_t*) mupGetErrorMsg(muParserHandle_t a_hParser) { ParserTag* const p(AsParserTag(a_hParser)); const muChar_t *pMsg = p->exc.GetMsg().c_str(); // C# explodes when pMsg is returned directly. For some reason it can't access // the memory where the message lies directly. #ifndef _UNICODE sprintf(s_tmpOutBuf, "%s", pMsg); #else wsprintf(s_tmpOutBuf, _T("%s"), pMsg); #endif return s_tmpOutBuf; } //--------------------------------------------------------------------------- /** \brief Return the message associated with the last error. */ API_EXPORT(const muChar_t*) mupGetErrorToken(muParserHandle_t a_hParser) { ParserTag* const p(AsParserTag(a_hParser)); const muChar_t *pToken = p->exc.GetToken().c_str(); // C# explodes when pMsg is returned directly. For some reason it can't access // the memory where the message lies directly. #ifndef _UNICODE sprintf(s_tmpOutBuf, "%s", pToken); #else wsprintf(s_tmpOutBuf, _T("%s"), pToken); #endif return s_tmpOutBuf; } //--------------------------------------------------------------------------- /** \brief Return the code associated with the last error. */ API_EXPORT(int) mupGetErrorCode(muParserHandle_t a_hParser) { return AsParserTag(a_hParser)->exc.GetCode(); } //--------------------------------------------------------------------------- /** \brief Return the position associated with the last error. */ API_EXPORT(int) mupGetErrorPos(muParserHandle_t a_hParser) { return (int)AsParserTag(a_hParser)->exc.GetPos(); } ////----------------------------------------------------------------------------------------------------- //API_EXPORT(const muChar_t*) mupGetErrorExpr(muParserHandle_t a_hParser) //{ // return AsParserTag(a_hParser)->exc.GetExpr().c_str(); //} //----------------------------------------------------------------------------------------------------- API_EXPORT(muFloat_t*) mupCreateVar() { return new muFloat_t(0); } //----------------------------------------------------------------------------------------------------- API_EXPORT(void) mupReleaseVar(muFloat_t *ptr) { delete ptr; } #endif // MUPARSER_DLL IanniX-0.9.20/geometry/qmuparser/muParserDLL.h000066400000000000000000000325171317340345000211550ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_DLL_H #define MU_PARSER_DLL_H #if defined(WIN32) || defined(_WIN32) #ifdef MUPARSERLIB_EXPORTS #define API_EXPORT(TYPE) __declspec(dllexport) TYPE __cdecl #else #define API_EXPORT(TYPE) __declspec(dllimport) TYPE __cdecl #endif #else #define API_EXPORT(TYPE) TYPE #endif #ifdef __cplusplus extern "C" { #endif /** \file \brief This file contains the DLL interface of muparser. */ // Basic types typedef void* muParserHandle_t; // parser handle #ifndef _UNICODE typedef char muChar_t; // character type #else typedef wchar_t muChar_t; // character type #endif typedef int muBool_t; // boolean type typedef int muInt_t; // integer type typedef double muFloat_t; // floating point type // function types for calculation typedef muFloat_t (*muFun0_t )(); typedef muFloat_t (*muFun1_t )(muFloat_t); typedef muFloat_t (*muFun2_t )(muFloat_t, muFloat_t); typedef muFloat_t (*muFun3_t )(muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t (*muFun4_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t (*muFun5_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t (*muFun6_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t (*muFun7_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t (*muFun8_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t (*muFun9_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t (*muFun10_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); // Function prototypes for bulkmode functions typedef muFloat_t (*muBulkFun0_t )(int, int); typedef muFloat_t (*muBulkFun1_t )(int, int, muFloat_t); typedef muFloat_t (*muBulkFun2_t )(int, int, muFloat_t, muFloat_t); typedef muFloat_t (*muBulkFun3_t )(int, int, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t (*muBulkFun4_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t (*muBulkFun5_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t (*muBulkFun6_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t (*muBulkFun7_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t (*muBulkFun8_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t (*muBulkFun9_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t (*muBulkFun10_t)(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t (*muMultFun_t)(const muFloat_t*, muInt_t); typedef muFloat_t (*muStrFun1_t)(const muChar_t*); typedef muFloat_t (*muStrFun2_t)(const muChar_t*, muFloat_t); typedef muFloat_t (*muStrFun3_t)(const muChar_t*, muFloat_t, muFloat_t); // Functions for parser management typedef void (*muErrorHandler_t)(muParserHandle_t a_hParser); // [optional] callback to an error handler typedef muFloat_t* (*muFacFun_t)(const muChar_t*, void*); // [optional] callback for creating new variables typedef muInt_t (*muIdentFun_t)(const muChar_t*, muInt_t*, muFloat_t*); // [optional] value identification callbacks //----------------------------------------------------------------------------------------------------- // Constants static const int muOPRT_ASCT_LEFT = 0; static const int muOPRT_ASCT_RIGHT = 1; static const int muBASETYPE_FLOAT = 0; static const int muBASETYPE_INT = 1; //----------------------------------------------------------------------------------------------------- // // // muParser C compatible bindings // // //----------------------------------------------------------------------------------------------------- // Basic operations / initialization API_EXPORT(muParserHandle_t) mupCreate(int nBaseType); API_EXPORT(void) mupRelease(muParserHandle_t a_hParser); API_EXPORT(const muChar_t*) mupGetExpr(muParserHandle_t a_hParser); API_EXPORT(void) mupSetExpr(muParserHandle_t a_hParser, const muChar_t *a_szExpr); API_EXPORT(void) mupSetVarFactory(muParserHandle_t a_hParser, muFacFun_t a_pFactory, void* pUserData); API_EXPORT(const muChar_t*) mupGetVersion(muParserHandle_t a_hParser); API_EXPORT(muFloat_t) mupEval(muParserHandle_t a_hParser); API_EXPORT(muFloat_t*) mupEvalMulti(muParserHandle_t a_hParser, int *nNum); API_EXPORT(void) mupEvalBulk(muParserHandle_t a_hParser, muFloat_t *a_fResult, int nSize); // Defining callbacks / variables / constants API_EXPORT(void) mupDefineFun0(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun0_t a_pFun, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFun1(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun1_t a_pFun, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFun2(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun2_t a_pFun, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun3_t a_pFun, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFun4(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun4_t a_pFun, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFun5(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun5_t a_pFun, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFun6(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun6_t a_pFun, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFun7(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun7_t a_pFun, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFun8(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun8_t a_pFun, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFun9(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun9_t a_pFun, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFun10(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun10_t a_pFun, muBool_t a_bOptimize); // Defining bulkmode functions API_EXPORT(void) mupDefineBulkFun0(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun0_t a_pFun); API_EXPORT(void) mupDefineBulkFun1(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun1_t a_pFun); API_EXPORT(void) mupDefineBulkFun2(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun2_t a_pFun); API_EXPORT(void) mupDefineBulkFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun3_t a_pFun); API_EXPORT(void) mupDefineBulkFun4(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun4_t a_pFun); API_EXPORT(void) mupDefineBulkFun5(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun5_t a_pFun); API_EXPORT(void) mupDefineBulkFun6(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun6_t a_pFun); API_EXPORT(void) mupDefineBulkFun7(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun7_t a_pFun); API_EXPORT(void) mupDefineBulkFun8(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun8_t a_pFun); API_EXPORT(void) mupDefineBulkFun9(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun9_t a_pFun); API_EXPORT(void) mupDefineBulkFun10(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun10_t a_pFun); // string functions API_EXPORT(void) mupDefineStrFun1(muParserHandle_t a_hParser, const muChar_t *a_szName, muStrFun1_t a_pFun); API_EXPORT(void) mupDefineStrFun2(muParserHandle_t a_hParser, const muChar_t *a_szName, muStrFun2_t a_pFun); API_EXPORT(void) mupDefineStrFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muStrFun3_t a_pFun); API_EXPORT(void) mupDefineMultFun( muParserHandle_t a_hParser, const muChar_t* a_szName, muMultFun_t a_pFun, muBool_t a_bOptimize); API_EXPORT(void) mupDefineOprt( muParserHandle_t a_hParser, const muChar_t* a_szName, muFun2_t a_pFun, muInt_t a_nPrec, muInt_t a_nOprtAsct, muBool_t a_bOptimize); API_EXPORT(void) mupDefineConst( muParserHandle_t a_hParser, const muChar_t* a_szName, muFloat_t a_fVal ); API_EXPORT(void) mupDefineStrConst( muParserHandle_t a_hParser, const muChar_t* a_szName, const muChar_t *a_sVal ); API_EXPORT(void) mupDefineVar( muParserHandle_t a_hParser, const muChar_t* a_szName, muFloat_t *a_fVar); API_EXPORT(void) mupDefineBulkVar( muParserHandle_t a_hParser, const muChar_t* a_szName, muFloat_t *a_fVar); API_EXPORT(void) mupDefinePostfixOprt( muParserHandle_t a_hParser, const muChar_t* a_szName, muFun1_t a_pOprt, muBool_t a_bOptimize); API_EXPORT(void) mupDefineInfixOprt( muParserHandle_t a_hParser, const muChar_t* a_szName, muFun1_t a_pOprt, muBool_t a_bOptimize); // Define character sets for identifiers API_EXPORT(void) mupDefineNameChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset); API_EXPORT(void) mupDefineOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset); API_EXPORT(void) mupDefineInfixOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset); // Remove all / single variables API_EXPORT(void) mupRemoveVar(muParserHandle_t a_hParser, const muChar_t* a_szName); API_EXPORT(void) mupClearVar(muParserHandle_t a_hParser); API_EXPORT(void) mupClearConst(muParserHandle_t a_hParser); API_EXPORT(void) mupClearOprt(muParserHandle_t a_hParser); API_EXPORT(void) mupClearFun(muParserHandle_t a_hParser); // Querying variables / expression variables / constants API_EXPORT(int) mupGetExprVarNum(muParserHandle_t a_hParser); API_EXPORT(int) mupGetVarNum(muParserHandle_t a_hParser); API_EXPORT(int) mupGetConstNum(muParserHandle_t a_hParser); API_EXPORT(void) mupGetExprVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t** a_pVar); API_EXPORT(void) mupGetVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t** a_pVar); API_EXPORT(void) mupGetConst(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t* a_pVar); API_EXPORT(void) mupSetArgSep(muParserHandle_t a_hParser, const muChar_t cArgSep); API_EXPORT(void) mupSetDecSep(muParserHandle_t a_hParser, const muChar_t cArgSep); API_EXPORT(void) mupSetThousandsSep(muParserHandle_t a_hParser, const muChar_t cArgSep); API_EXPORT(void) mupResetLocale(muParserHandle_t a_hParser); // Add value recognition callbacks API_EXPORT(void) mupAddValIdent(muParserHandle_t a_hParser, muIdentFun_t); // Error handling API_EXPORT(muBool_t) mupError(muParserHandle_t a_hParser); API_EXPORT(void) mupErrorReset(muParserHandle_t a_hParser); API_EXPORT(void) mupSetErrorHandler(muParserHandle_t a_hParser, muErrorHandler_t a_pErrHandler); API_EXPORT(const muChar_t*) mupGetErrorMsg(muParserHandle_t a_hParser); API_EXPORT(muInt_t) mupGetErrorCode(muParserHandle_t a_hParser); API_EXPORT(muInt_t) mupGetErrorPos(muParserHandle_t a_hParser); API_EXPORT(const muChar_t*) mupGetErrorToken(muParserHandle_t a_hParser); //API_EXPORT(const muChar_t*) mupGetErrorExpr(muParserHandle_t a_hParser); // This is used for .NET only. It creates a new variable allowing the dll to // manage the variable rather than the .NET garbage collector. API_EXPORT(muFloat_t*) mupCreateVar(); API_EXPORT(void) mupReleaseVar(muFloat_t*); #ifdef __cplusplus } #endif #endif // include guard IanniX-0.9.20/geometry/qmuparser/muParserDef.h000066400000000000000000000336071317340345000212410ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2014 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MUP_DEF_H #define MUP_DEF_H #include #include #include #include #include "muParserFixes.h" /** \file \brief This file contains standard definitions used by the parser. */ #define MUP_VERSION _T("2.2.5") #define MUP_VERSION_DATE _T("20150427; GC") #define MUP_CHARS _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") /** \brief If this macro is defined mathematical exceptions (div by zero) will be thrown as exceptions. */ //#define MUP_MATH_EXCEPTIONS /** \brief Define the base datatype for values. This datatype must be a built in value type. You can not use custom classes. It should be working with all types except "int"! */ #ifndef MUP_BASETYPE # define MUP_BASETYPE double #endif /* MUP_BASETYPE */ /** \brief Activate this option in order to compile with OpenMP support. OpenMP is used only in the bulk mode it may increase the performance a bit. */ //#define MUP_USE_OPENMP #if defined(_UNICODE) /** \brief Definition of the basic parser string type. */ #define MUP_STRING_TYPE std::wstring #if !defined(_T) #define _T(x) L##x #endif // not defined _T #else #ifndef _T #define _T(x) x #endif /** \brief Definition of the basic parser string type. */ #define MUP_STRING_TYPE std::string #endif #if defined(_DEBUG) /** \brief Debug macro to force an abortion of the programm with a certain message. */ #define MUP_FAIL(MSG) \ { \ bool MSG=false; \ assert(MSG); \ } /** \brief An assertion that does not kill the program. This macro is neutralised in UNICODE builds. It's too difficult to translate. */ #define MUP_ASSERT(COND) \ if (!(COND)) \ { \ stringstream_type ss; \ ss << _T("Assertion \"") _T(#COND) _T("\" failed: ") \ << __FILE__ << _T(" line ") \ << __LINE__ << _T("."); \ throw ParserError( ss.str() ); \ } #else #define MUP_FAIL(MSG) #define MUP_ASSERT(COND) #endif namespace mu { #if defined(_UNICODE) //------------------------------------------------------------------------------ /** \brief Encapsulate wcout. */ inline std::wostream& console() { return std::wcout; } /** \brief Encapsulate cin. */ inline std::wistream& console_in() { return std::wcin; } #else /** \brief Encapsulate cout. Used for supporting UNICODE more easily. */ inline std::ostream& console() { return std::cout; } /** \brief Encapsulate cin. Used for supporting UNICODE more easily. */ inline std::istream& console_in() { return std::cin; } #endif //------------------------------------------------------------------------------ /** \brief Bytecode values. \attention The order of the operator entries must match the order in ParserBase::c_DefaultOprt! */ enum ECmdCode { // The following are codes for built in binary operators // apart from built in operators the user has the opportunity to // add user defined operators. cmLE = 0, ///< Operator item: less or equal cmGE = 1, ///< Operator item: greater or equal cmNEQ = 2, ///< Operator item: not equal cmEQ = 3, ///< Operator item: equals cmLT = 4, ///< Operator item: less than cmGT = 5, ///< Operator item: greater than cmADD = 6, ///< Operator item: add cmSUB = 7, ///< Operator item: subtract cmMUL = 8, ///< Operator item: multiply cmDIV = 9, ///< Operator item: division cmPOW = 10, ///< Operator item: y to the power of ... cmLAND = 11, cmLOR = 12, cmASSIGN = 13, ///< Operator item: Assignment operator cmBO = 14, ///< Operator item: opening bracket cmBC = 15, ///< Operator item: closing bracket cmIF = 16, ///< For use in the ternary if-then-else operator cmELSE = 17, ///< For use in the ternary if-then-else operator cmENDIF = 18, ///< For use in the ternary if-then-else operator cmARG_SEP = 19, ///< function argument separator cmVAR = 20, ///< variable item cmVAL = 21, ///< value item // For optimization purposes cmVARPOW2, cmVARPOW3, cmVARPOW4, cmVARMUL, cmPOW2, // operators and functions cmFUNC, ///< Code for a generic function item cmFUNC_STR, ///< Code for a function with a string parameter cmFUNC_BULK, ///< Special callbacks for Bulk mode with an additional parameter for the bulk index cmSTRING, ///< Code for a string token cmOPRT_BIN, ///< user defined binary operator cmOPRT_POSTFIX, ///< code for postfix operators cmOPRT_INFIX, ///< code for infix operators cmEND, ///< end of formula cmUNKNOWN ///< uninitialized item }; //------------------------------------------------------------------------------ /** \brief Types internally used by the parser. */ enum ETypeCode { tpSTR = 0, ///< String type (Function arguments and constants only, no string variables) tpDBL = 1, ///< Floating point variables tpVOID = 2 ///< Undefined type. }; //------------------------------------------------------------------------------ enum EParserVersionInfo { pviBRIEF, pviFULL }; //------------------------------------------------------------------------------ /** \brief Parser operator precedence values. */ enum EOprtAssociativity { oaLEFT = 0, oaRIGHT = 1, oaNONE = 2 }; //------------------------------------------------------------------------------ /** \brief Parser operator precedence values. */ enum EOprtPrecedence { // binary operators prLOR = 1, prLAND = 2, prLOGIC = 3, ///< logic operators prCMP = 4, ///< comparsion operators prADD_SUB = 5, ///< addition prMUL_DIV = 6, ///< multiplication/division prPOW = 7, ///< power operator priority (highest) // infix operators prINFIX = 6, ///< Signs have a higher priority than ADD_SUB, but lower than power operator prPOSTFIX = 6 ///< Postfix operator priority (currently unused) }; //------------------------------------------------------------------------------ // basic types /** \brief The numeric datatype used by the parser. Normally this is a floating point type either single or double precision. */ typedef MUP_BASETYPE value_type; /** \brief The stringtype used by the parser. Depends on wether UNICODE is used or not. */ typedef MUP_STRING_TYPE string_type; /** \brief The character type used by the parser. Depends on wether UNICODE is used or not. */ typedef string_type::value_type char_type; /** \brief Typedef for easily using stringstream that respect the parser stringtype. */ typedef std::basic_stringstream, std::allocator > stringstream_type; // Data container types /** \brief Type used for storing variables. */ typedef std::map varmap_type; /** \brief Type used for storing constants. */ typedef std::map valmap_type; /** \brief Type for assigning a string name to an index in the internal string table. */ typedef std::map strmap_type; // Parser callbacks /** \brief Callback type used for functions without arguments. */ typedef value_type (*generic_fun_type)(); /** \brief Callback type used for functions without arguments. */ typedef value_type (*fun_type0)(); /** \brief Callback type used for functions with a single arguments. */ typedef value_type (*fun_type1)(value_type); /** \brief Callback type used for functions with two arguments. */ typedef value_type (*fun_type2)(value_type, value_type); /** \brief Callback type used for functions with three arguments. */ typedef value_type (*fun_type3)(value_type, value_type, value_type); /** \brief Callback type used for functions with four arguments. */ typedef value_type (*fun_type4)(value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*fun_type5)(value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*fun_type6)(value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*fun_type7)(value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*fun_type8)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*fun_type9)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*fun_type10)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions without arguments. */ typedef value_type (*bulkfun_type0)(int, int); /** \brief Callback type used for functions with a single arguments. */ typedef value_type (*bulkfun_type1)(int, int, value_type); /** \brief Callback type used for functions with two arguments. */ typedef value_type (*bulkfun_type2)(int, int, value_type, value_type); /** \brief Callback type used for functions with three arguments. */ typedef value_type (*bulkfun_type3)(int, int, value_type, value_type, value_type); /** \brief Callback type used for functions with four arguments. */ typedef value_type (*bulkfun_type4)(int, int, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*bulkfun_type5)(int, int, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*bulkfun_type6)(int, int, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*bulkfun_type7)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*bulkfun_type8)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*bulkfun_type9)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*bulkfun_type10)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with a variable argument list. */ typedef value_type (*multfun_type)(const value_type*, int); /** \brief Callback type used for functions taking a string as an argument. */ typedef value_type (*strfun_type1)(const char_type*); /** \brief Callback type used for functions taking a string and a value as arguments. */ typedef value_type (*strfun_type2)(const char_type*, value_type); /** \brief Callback type used for functions taking a string and two values as arguments. */ typedef value_type (*strfun_type3)(const char_type*, value_type, value_type); /** \brief Callback used for functions that identify values in a string. */ typedef int (*identfun_type)(const char_type *sExpr, int *nPos, value_type *fVal); /** \brief Callback used for variable creation factory functions. */ typedef value_type* (*facfun_type)(const char_type*, void*); } // end of namespace #endif IanniX-0.9.20/geometry/qmuparser/muParserError.cpp000066400000000000000000000322001317340345000221530ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParserError.h" namespace mu { const ParserErrorMsg ParserErrorMsg::m_Instance; //------------------------------------------------------------------------------ const ParserErrorMsg& ParserErrorMsg::Instance() { return m_Instance; } //------------------------------------------------------------------------------ string_type ParserErrorMsg::operator[](unsigned a_iIdx) const { return (a_iIdx \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_ERROR_H #define MU_PARSER_ERROR_H #include #include #include #include #include #include #include "muParserDef.h" /** \file \brief This file defines the error class used by the parser. */ namespace mu { /** \brief Error codes. */ enum EErrorCodes { // Formula syntax errors ecUNEXPECTED_OPERATOR = 0, ///< Unexpected binary operator found ecUNASSIGNABLE_TOKEN = 1, ///< Token cant be identified. ecUNEXPECTED_EOF = 2, ///< Unexpected end of formula. (Example: "2+sin(") ecUNEXPECTED_ARG_SEP = 3, ///< An unexpected comma has been found. (Example: "1,23") ecUNEXPECTED_ARG = 4, ///< An unexpected argument has been found ecUNEXPECTED_VAL = 5, ///< An unexpected value token has been found ecUNEXPECTED_VAR = 6, ///< An unexpected variable token has been found ecUNEXPECTED_PARENS = 7, ///< Unexpected Parenthesis, opening or closing ecUNEXPECTED_STR = 8, ///< A string has been found at an inapropriate position ecSTRING_EXPECTED = 9, ///< A string function has been called with a different type of argument ecVAL_EXPECTED = 10, ///< A numerical function has been called with a non value type of argument ecMISSING_PARENS = 11, ///< Missing parens. (Example: "3*sin(3") ecUNEXPECTED_FUN = 12, ///< Unexpected function found. (Example: "sin(8)cos(9)") ecUNTERMINATED_STRING = 13, ///< unterminated string constant. (Example: "3*valueof("hello)") ecTOO_MANY_PARAMS = 14, ///< Too many function parameters ecTOO_FEW_PARAMS = 15, ///< Too few function parameters. (Example: "ite(1<2,2)") ecOPRT_TYPE_CONFLICT = 16, ///< binary operators may only be applied to value items of the same type ecSTR_RESULT = 17, ///< result is a string // Invalid Parser input Parameters ecINVALID_NAME = 18, ///< Invalid function, variable or constant name. ecINVALID_BINOP_IDENT = 19, ///< Invalid binary operator identifier ecINVALID_INFIX_IDENT = 20, ///< Invalid function, variable or constant name. ecINVALID_POSTFIX_IDENT = 21, ///< Invalid function, variable or constant name. ecBUILTIN_OVERLOAD = 22, ///< Trying to overload builtin operator ecINVALID_FUN_PTR = 23, ///< Invalid callback function pointer ecINVALID_VAR_PTR = 24, ///< Invalid variable pointer ecEMPTY_EXPRESSION = 25, ///< The Expression is empty ecNAME_CONFLICT = 26, ///< Name conflict ecOPT_PRI = 27, ///< Invalid operator priority // ecDOMAIN_ERROR = 28, ///< catch division by zero, sqrt(-1), log(0) (currently unused) ecDIV_BY_ZERO = 29, ///< Division by zero (currently unused) ecGENERIC = 30, ///< Generic error ecLOCALE = 31, ///< Conflict with current locale ecUNEXPECTED_CONDITIONAL = 32, ecMISSING_ELSE_CLAUSE = 33, ecMISPLACED_COLON = 34, ecUNREASONABLE_NUMBER_OF_COMPUTATIONS = 35, // internal errors ecINTERNAL_ERROR = 36, ///< Internal error of any kind. // The last two are special entries ecCOUNT, ///< This is no error code, It just stores just the total number of error codes ecUNDEFINED = -1 ///< Undefined message, placeholder to detect unassigned error messages }; //--------------------------------------------------------------------------- /** \brief A class that handles the error messages. */ class ParserErrorMsg { public: typedef ParserErrorMsg self_type; ParserErrorMsg& operator=(const ParserErrorMsg &); ParserErrorMsg(const ParserErrorMsg&); ParserErrorMsg(); ~ParserErrorMsg(); static const ParserErrorMsg& Instance(); string_type operator[](unsigned a_iIdx) const; private: std::vector m_vErrMsg; ///< A vector with the predefined error messages static const self_type m_Instance; ///< The instance pointer }; //--------------------------------------------------------------------------- /** \brief Error class of the parser. \author Ingo Berg Part of the math parser package. */ class ParserError { private: /** \brief Replace all ocuurences of a substring with another string. */ void ReplaceSubString( string_type &strSource, const string_type &strFind, const string_type &strReplaceWith); void Reset(); public: ParserError(); explicit ParserError(EErrorCodes a_iErrc); explicit ParserError(const string_type &sMsg); ParserError( EErrorCodes a_iErrc, const string_type &sTok, const string_type &sFormula = string_type(), int a_iPos = -1); ParserError( EErrorCodes a_iErrc, int a_iPos, const string_type &sTok); ParserError( const char_type *a_szMsg, int a_iPos = -1, const string_type &sTok = string_type()); ParserError(const ParserError &a_Obj); ParserError& operator=(const ParserError &a_Obj); ~ParserError(); void SetFormula(const string_type &a_strFormula); const string_type& GetExpr() const; const string_type& GetMsg() const; int GetPos() const; const string_type& GetToken() const; EErrorCodes GetCode() const; private: string_type m_strMsg; ///< The message string string_type m_strFormula; ///< Formula string string_type m_strTok; ///< Token related with the error int m_iPos; ///< Formula position related to the error EErrorCodes m_iErrc; ///< Error code const ParserErrorMsg &m_ErrMsg; }; } // namespace mu #endif IanniX-0.9.20/geometry/qmuparser/muParserFixes.h000066400000000000000000000044321317340345000216130ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2013 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_FIXES_H #define MU_PARSER_FIXES_H /** \file \brief This file contains compatibility fixes for some platforms. */ // // Compatibility fixes // //--------------------------------------------------------------------------- // // Intel Compiler // //--------------------------------------------------------------------------- #ifdef __INTEL_COMPILER // remark #981: operands are evaluated in unspecified order // disabled -> completely pointless if the functions do not have side effects // #pragma warning(disable:981) // remark #383: value copied to temporary, reference to temporary used #pragma warning(disable:383) // remark #1572: floating-point equality and inequality comparisons are unreliable // disabled -> everyone knows it, the parser passes this problem // deliberately to the user #pragma warning(disable:1572) #endif #endif // include guard IanniX-0.9.20/geometry/qmuparser/muParserInt.cpp000066400000000000000000000230631317340345000216230ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParserInt.h" #include #include #include using namespace std; /** \file \brief Implementation of a parser using integer value. */ /** \brief Namespace for mathematical applications. */ namespace mu { value_type ParserInt::Abs(value_type v) { return (value_type)Round(fabs((double)v)); } value_type ParserInt::Sign(value_type v) { return (Round(v)<0) ? -1 : (Round(v)>0) ? 1 : 0; } value_type ParserInt::Ite(value_type v1, value_type v2, value_type v3) { return (Round(v1)==1) ? Round(v2) : Round(v3); } value_type ParserInt::Add(value_type v1, value_type v2) { return Round(v1) + Round(v2); } value_type ParserInt::Sub(value_type v1, value_type v2) { return Round(v1) - Round(v2); } value_type ParserInt::Mul(value_type v1, value_type v2) { return Round(v1) * Round(v2); } value_type ParserInt::Div(value_type v1, value_type v2) { return Round(v1) / Round(v2); } value_type ParserInt::Mod(value_type v1, value_type v2) { return Round(v1) % Round(v2); } value_type ParserInt::Shr(value_type v1, value_type v2) { return Round(v1) >> Round(v2); } value_type ParserInt::Shl(value_type v1, value_type v2) { return Round(v1) << Round(v2); } value_type ParserInt::LogAnd(value_type v1, value_type v2) { return Round(v1) & Round(v2); } value_type ParserInt::LogOr(value_type v1, value_type v2) { return Round(v1) | Round(v2); } value_type ParserInt::And(value_type v1, value_type v2) { return Round(v1) && Round(v2); } value_type ParserInt::Or(value_type v1, value_type v2) { return Round(v1) || Round(v2); } value_type ParserInt::Less(value_type v1, value_type v2) { return Round(v1) < Round(v2); } value_type ParserInt::Greater(value_type v1, value_type v2) { return Round(v1) > Round(v2); } value_type ParserInt::LessEq(value_type v1, value_type v2) { return Round(v1) <= Round(v2); } value_type ParserInt::GreaterEq(value_type v1, value_type v2) { return Round(v1) >= Round(v2); } value_type ParserInt::Equal(value_type v1, value_type v2) { return Round(v1) == Round(v2); } value_type ParserInt::NotEqual(value_type v1, value_type v2) { return Round(v1) != Round(v2); } value_type ParserInt::Not(value_type v) { return !Round(v); } value_type ParserInt::Pow(value_type v1, value_type v2) { return std::pow((double)Round(v1), (double)Round(v2)); } //--------------------------------------------------------------------------- // Unary operator Callbacks: Infix operators value_type ParserInt::UnaryMinus(value_type v) { return -Round(v); } //--------------------------------------------------------------------------- value_type ParserInt::Sum(const value_type* a_afArg, int a_iArgc) { if (!a_iArgc) throw ParserError(_T("too few arguments for function sum.")); value_type fRes=0; for (int i=0; i> iVal; if (stream.fail()) return 0; stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading if (stream.fail()) iEnd = stream.str().length(); if (iEnd==(stringstream_type::pos_type)-1) return 0; *a_iPos += (int)iEnd; *a_fVal = (value_type)iVal; return 1; } //--------------------------------------------------------------------------- /** \brief Check a given position in the expression for the presence of a hex value. \param a_szExpr Pointer to the expression string \param [in/out] a_iPos Pointer to an integer value holding the current parsing position in the expression. \param [out] a_fVal Pointer to the position where the detected value shall be stored. Hey values must be prefixed with "0x" in order to be detected properly. */ int ParserInt::IsHexVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal) { if (a_szExpr[1]==0 || (a_szExpr[0]!='0' || a_szExpr[1]!='x') ) return 0; unsigned iVal(0); // New code based on streams for UNICODE compliance: stringstream_type::pos_type nPos(0); stringstream_type ss(a_szExpr + 2); ss >> std::hex >> iVal; nPos = ss.tellg(); if (nPos==(stringstream_type::pos_type)0) return 1; *a_iPos += (int)(2 + nPos); *a_fVal = (value_type)iVal; return 1; } //--------------------------------------------------------------------------- int ParserInt::IsBinVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal) { if (a_szExpr[0]!='#') return 0; unsigned iVal(0), iBits(sizeof(iVal)*8), i(0); for (i=0; (a_szExpr[i+1]=='0' || a_szExpr[i+1]=='1') && i> (iBits-i) ); *a_iPos += i+1; return 1; } //--------------------------------------------------------------------------- /** \brief Constructor. Call ParserBase class constructor and trigger Function, Operator and Constant initialization. */ ParserInt::ParserInt() :ParserBase() { AddValIdent(IsVal); // lowest priority AddValIdent(IsBinVal); AddValIdent(IsHexVal); // highest priority InitCharSets(); InitFun(); InitOprt(); } //--------------------------------------------------------------------------- void ParserInt::InitConst() { } //--------------------------------------------------------------------------- void ParserInt::InitCharSets() { DefineNameChars( _T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") ); DefineOprtChars( _T("+-*^/?<>=!%&|~'_") ); DefineInfixOprtChars( _T("/+-*^?<>=!%&|~'_") ); } //--------------------------------------------------------------------------- /** \brief Initialize the default functions. */ void ParserInt::InitFun() { DefineFun( _T("sign"), Sign); DefineFun( _T("abs"), Abs); DefineFun( _T("if"), Ite); DefineFun( _T("sum"), Sum); DefineFun( _T("min"), Min); DefineFun( _T("max"), Max); } //--------------------------------------------------------------------------- /** \brief Initialize operators. */ void ParserInt::InitOprt() { // disable all built in operators, not all of them useful for integer numbers // (they don't do rounding of values) EnableBuiltInOprt(false); // Disable all built in operators, they wont work with integer numbers // since they are designed for floating point numbers DefineInfixOprt( _T("-"), UnaryMinus); DefineInfixOprt( _T("!"), Not); DefineOprt( _T("&"), LogAnd, prLOGIC); DefineOprt( _T("|"), LogOr, prLOGIC); DefineOprt( _T("&&"), And, prLOGIC); DefineOprt( _T("||"), Or, prLOGIC); DefineOprt( _T("<"), Less, prCMP); DefineOprt( _T(">"), Greater, prCMP); DefineOprt( _T("<="), LessEq, prCMP); DefineOprt( _T(">="), GreaterEq, prCMP); DefineOprt( _T("=="), Equal, prCMP); DefineOprt( _T("!="), NotEqual, prCMP); DefineOprt( _T("+"), Add, prADD_SUB); DefineOprt( _T("-"), Sub, prADD_SUB); DefineOprt( _T("*"), Mul, prMUL_DIV); DefineOprt( _T("/"), Div, prMUL_DIV); DefineOprt( _T("%"), Mod, prMUL_DIV); DefineOprt( _T("^"), Pow, prPOW, oaRIGHT); DefineOprt( _T(">>"), Shr, prMUL_DIV+1); DefineOprt( _T("<<"), Shl, prMUL_DIV+1); } } // namespace mu IanniX-0.9.20/geometry/qmuparser/muParserInt.h000066400000000000000000000122471317340345000212720ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2013 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_INT_H #define MU_PARSER_INT_H #include "muParserBase.h" #include /** \file \brief Definition of a parser using integer value. */ namespace mu { /** \brief Mathematical expressions parser. This version of the parser handles only integer numbers. It disables the built in operators thus it is slower than muParser. Integer values are stored in the double value_type and converted if needed. */ class ParserInt : public ParserBase { private: static int Round(value_type v) { return (int)(v + ((v>=0) ? 0.5 : -0.5) ); }; static value_type Abs(value_type); static value_type Sign(value_type); static value_type Ite(value_type, value_type, value_type); // !! The unary Minus is a MUST, otherwise you cant use negative signs !! static value_type UnaryMinus(value_type); // Functions with variable number of arguments static value_type Sum(const value_type* a_afArg, int a_iArgc); // sum static value_type Min(const value_type* a_afArg, int a_iArgc); // minimum static value_type Max(const value_type* a_afArg, int a_iArgc); // maximum // binary operator callbacks static value_type Add(value_type v1, value_type v2); static value_type Sub(value_type v1, value_type v2); static value_type Mul(value_type v1, value_type v2); static value_type Div(value_type v1, value_type v2); static value_type Mod(value_type v1, value_type v2); static value_type Pow(value_type v1, value_type v2); static value_type Shr(value_type v1, value_type v2); static value_type Shl(value_type v1, value_type v2); static value_type LogAnd(value_type v1, value_type v2); static value_type LogOr(value_type v1, value_type v2); static value_type And(value_type v1, value_type v2); static value_type Or(value_type v1, value_type v2); static value_type Xor(value_type v1, value_type v2); static value_type Less(value_type v1, value_type v2); static value_type Greater(value_type v1, value_type v2); static value_type LessEq(value_type v1, value_type v2); static value_type GreaterEq(value_type v1, value_type v2); static value_type Equal(value_type v1, value_type v2); static value_type NotEqual(value_type v1, value_type v2); static value_type Not(value_type v1); static int IsHexVal(const char_type* a_szExpr, int *a_iPos, value_type *a_iVal); static int IsBinVal(const char_type* a_szExpr, int *a_iPos, value_type *a_iVal); static int IsVal (const char_type* a_szExpr, int *a_iPos, value_type *a_iVal); /** \brief A facet class used to change decimal and thousands separator. */ template class change_dec_sep : public std::numpunct { public: explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3) :std::numpunct() ,m_cDecPoint(cDecSep) ,m_cThousandsSep(cThousandsSep) ,m_nGroup(nGroup) {} protected: virtual char_type do_decimal_point() const { return m_cDecPoint; } virtual char_type do_thousands_sep() const { return m_cThousandsSep; } virtual std::string do_grouping() const { // fix for issue 4: https://code.google.com/p/muparser/issues/detail?id=4 // courtesy of Jens Bartsch // original code: // return std::string(1, (char)m_nGroup); // new code: return std::string(1, (char)(m_cThousandsSep > 0 ? m_nGroup : CHAR_MAX)); } private: int m_nGroup; char_type m_cDecPoint; char_type m_cThousandsSep; }; public: ParserInt(); virtual void InitFun(); virtual void InitOprt(); virtual void InitConst(); virtual void InitCharSets(); }; } // namespace mu #endif IanniX-0.9.20/geometry/qmuparser/muParserStack.h000066400000000000000000000074441317340345000216100ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_STACK_H #define MU_PARSER_STACK_H #include #include #include #include #include "muParserError.h" #include "muParserToken.h" /** \file \brief This file defines the stack used by muparser. */ namespace mu { /** \brief Parser stack implementation. Stack implementation based on a std::stack. The behaviour of pop() had been slightly changed in order to get an error code if the stack is empty. The stack is used within the Parser both as a value stack and as an operator stack. \author (C) 2004-2011 Ingo Berg */ template class ParserStack { private: /** \brief Type of the underlying stack implementation. */ typedef std::stack > impl_type; impl_type m_Stack; ///< This is the actual stack. public: //--------------------------------------------------------------------------- ParserStack() :m_Stack() {} //--------------------------------------------------------------------------- virtual ~ParserStack() {} //--------------------------------------------------------------------------- /** \brief Pop a value from the stack. Unlike the standard implementation this function will return the value that is going to be taken from the stack. \throw ParserException in case the stack is empty. \sa pop(int &a_iErrc) */ TValueType pop() { if (empty()) throw ParserError( _T("stack is empty.") ); TValueType el = top(); m_Stack.pop(); return el; } /** \brief Push an object into the stack. \param a_Val object to push into the stack. \throw nothrow */ void push(const TValueType& a_Val) { m_Stack.push(a_Val); } /** \brief Return the number of stored elements. */ unsigned size() const { return (unsigned)m_Stack.size(); } /** \brief Returns true if stack is empty false otherwise. */ bool empty() const { return m_Stack.empty(); } /** \brief Return reference to the top object in the stack. The top object is the one pushed most recently. */ TValueType& top() { return m_Stack.top(); } }; } // namespace MathUtils #endif IanniX-0.9.20/geometry/qmuparser/muParserTemplateMagic.h000066400000000000000000000060541317340345000232530ustar00rootroot00000000000000#ifndef MU_PARSER_TEMPLATE_MAGIC_H #define MU_PARSER_TEMPLATE_MAGIC_H #include #include "muParserError.h" namespace mu { //----------------------------------------------------------------------------------------------- // // Compile time type detection // //----------------------------------------------------------------------------------------------- /** \brief A class singling out integer types at compile time using template meta programming. */ template struct TypeInfo { static bool IsInteger() { return false; } }; template<> struct TypeInfo { static bool IsInteger() { return true; } }; template<> struct TypeInfo { static bool IsInteger() { return true; } }; template<> struct TypeInfo { static bool IsInteger() { return true; } }; template<> struct TypeInfo { static bool IsInteger() { return true; } }; template<> struct TypeInfo { static bool IsInteger() { return true; } }; template<> struct TypeInfo { static bool IsInteger() { return true; } }; template<> struct TypeInfo { static bool IsInteger() { return true; } }; template<> struct TypeInfo { static bool IsInteger() { return true; } }; //----------------------------------------------------------------------------------------------- // // Standard math functions with dummy overload for integer types // //----------------------------------------------------------------------------------------------- /** \brief A template class for providing wrappers for essential math functions. This template is spezialized for several types in order to provide a unified interface for parser internal math function calls regardless of the data type. */ template struct MathImpl { static T Sin(T v) { return sin(v); } static T Cos(T v) { return cos(v); } static T Tan(T v) { return tan(v); } static T ASin(T v) { return asin(v); } static T ACos(T v) { return acos(v); } static T ATan(T v) { return atan(v); } static T ATan2(T v1, T v2) { return atan2(v1, v2); } static T Sinh(T v) { return sinh(v); } static T Cosh(T v) { return cosh(v); } static T Tanh(T v) { return tanh(v); } static T ASinh(T v) { return log(v + sqrt(v * v + 1)); } static T ACosh(T v) { return log(v + sqrt(v * v - 1)); } static T ATanh(T v) { return ((T)0.5 * log((1 + v) / (1 - v))); } static T Log(T v) { return log(v); } static T Log2(T v) { return log(v)/log((T)2); } // Logarithm base 2 static T Log10(T v) { return log10(v); } // Logarithm base 10 static T Exp(T v) { return exp(v); } static T Abs(T v) { return (v>=0) ? v : -v; } static T Sqrt(T v) { return sqrt(v); } static T Rint(T v) { return floor(v + (T)0.5); } static T Sign(T v) { return (T)((v<0) ? -1 : (v>0) ? 1 : 0); } static T Pow(T v1, T v2) { return std::pow(v1, v2); } }; } #endif IanniX-0.9.20/geometry/qmuparser/muParserTest.cpp000066400000000000000000001762551317340345000220240ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2013 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParserTest.h" #include #include #include #include #define PARSER_CONST_PI 3.141592653589793238462643 #define PARSER_CONST_E 2.718281828459045235360287 using namespace std; /** \file \brief This file contains the implementation of parser test cases. */ namespace mu { namespace Test { int ParserTester::c_iCount = 0; //--------------------------------------------------------------------------------------------- ParserTester::ParserTester() :m_vTestFun() { AddTest(&ParserTester::TestNames); AddTest(&ParserTester::TestSyntax); AddTest(&ParserTester::TestPostFix); AddTest(&ParserTester::TestInfixOprt); AddTest(&ParserTester::TestVarConst); AddTest(&ParserTester::TestMultiArg); AddTest(&ParserTester::TestExpression); AddTest(&ParserTester::TestIfThenElse); AddTest(&ParserTester::TestInterface); AddTest(&ParserTester::TestBinOprt); AddTest(&ParserTester::TestException); AddTest(&ParserTester::TestStrArg); AddTest(&ParserTester::TestBulkMode); ParserTester::c_iCount = 0; } //--------------------------------------------------------------------------------------------- int ParserTester::IsHexVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal) { if (a_szExpr[1]==0 || (a_szExpr[0]!='0' || a_szExpr[1]!='x') ) return 0; unsigned iVal(0); // New code based on streams for UNICODE compliance: stringstream_type::pos_type nPos(0); stringstream_type ss(a_szExpr + 2); ss >> std::hex >> iVal; nPos = ss.tellg(); if (nPos==(stringstream_type::pos_type)0) return 1; *a_iPos += (int)(2 + nPos); *a_fVal = (value_type)iVal; return 1; } //--------------------------------------------------------------------------------------------- int ParserTester::TestInterface() { int iStat = 0; mu::console() << _T("testing member functions..."); // Test RemoveVar value_type afVal[3] = {1,2,3}; Parser p; try { p.DefineVar( _T("a"), &afVal[0]); p.DefineVar( _T("b"), &afVal[1]); p.DefineVar( _T("c"), &afVal[2]); p.SetExpr( _T("a+b+c") ); p.Eval(); } catch(...) { iStat += 1; // this is not supposed to happen } try { p.RemoveVar( _T("c") ); p.Eval(); iStat += 1; // not supposed to reach this, nonexisting variable "c" deleted... } catch(...) { // failure is expected... } if (iStat==0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------------------------- int ParserTester::TestStrArg() { int iStat = 0; mu::console() << _T("testing string arguments..."); iStat += EqnTest(_T("valueof(\"\")"), 123, true); // empty string arguments caused a crash iStat += EqnTest(_T("valueof(\"aaa\")+valueof(\"bbb\") "), 246, true); iStat += EqnTest(_T("2*(valueof(\"aaa\")-23)+valueof(\"bbb\")"), 323, true); // use in expressions with variables iStat += EqnTest(_T("a*(atof(\"10\")-b)"), 8, true); iStat += EqnTest(_T("a-(atof(\"10\")*b)"), -19, true); // string + numeric arguments iStat += EqnTest(_T("strfun1(\"100\")"), 100, true); iStat += EqnTest(_T("strfun2(\"100\",1)"), 101, true); iStat += EqnTest(_T("strfun3(\"99\",1,2)"), 102, true); // string constants iStat += EqnTest(_T("atof(str1)+atof(str2)"), 3.33, true); if (iStat==0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------------------------- int ParserTester::TestBulkMode() { int iStat = 0; mu::console() << _T("testing bulkmode..."); #define EQN_TEST_BULK(EXPR, R1, R2, R3, R4, PASS) \ { \ double res[] = { R1, R2, R3, R4 }; \ iStat += EqnTestBulk(_T(EXPR), res, (PASS)); \ } // Bulk Variables for the test: // a: 1,2,3,4 // b: 2,2,2,2 // c: 3,3,3,3 // d: 5,4,3,2 EQN_TEST_BULK("a", 1, 1, 1, 1, false) EQN_TEST_BULK("a", 1, 2, 3, 4, true) EQN_TEST_BULK("b=a", 1, 2, 3, 4, true) EQN_TEST_BULK("b=a, b*10", 10, 20, 30, 40, true) EQN_TEST_BULK("b=a, b*10, a", 1, 2, 3, 4, true) EQN_TEST_BULK("a+b", 3, 4, 5, 6, true) EQN_TEST_BULK("c*(a+b)", 9, 12, 15, 18, true) #undef EQN_TEST_BULK if (iStat == 0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------------------------- int ParserTester::TestBinOprt() { int iStat = 0; mu::console() << _T("testing binary operators..."); // built in operators // xor operator iStat += EqnTest(_T("a++b"), 3, true); iStat += EqnTest(_T("a ++ b"), 3, true); iStat += EqnTest(_T("1++2"), 3, true); iStat += EqnTest(_T("1 ++ 2"), 3, true); iStat += EqnTest(_T("a add b"), 3, true); iStat += EqnTest(_T("1 add 2"), 3, true); iStat += EqnTest(_T("aa"), 1, true); iStat += EqnTest(_T("a>a"), 0, true); iStat += EqnTest(_T("aa"), 0, true); iStat += EqnTest(_T("a<=a"), 1, true); iStat += EqnTest(_T("a<=b"), 1, true); iStat += EqnTest(_T("b<=a"), 0, true); iStat += EqnTest(_T("a>=a"), 1, true); iStat += EqnTest(_T("b>=a"), 1, true); iStat += EqnTest(_T("a>=b"), 0, true); // Test logical operators, especially if user defined "&" and the internal "&&" collide iStat += EqnTest(_T("1 && 1"), 1, true); iStat += EqnTest(_T("1 && 0"), 0, true); iStat += EqnTest(_T("(aa)"), 1, true); iStat += EqnTest(_T("(ab)"), 0, true); //iStat += EqnTest(_T("12 and 255"), 12, true); //iStat += EqnTest(_T("12 and 0"), 0, true); iStat += EqnTest(_T("12 & 255"), 12, true); iStat += EqnTest(_T("12 & 0"), 0, true); iStat += EqnTest(_T("12&255"), 12, true); iStat += EqnTest(_T("12&0"), 0, true); // Assignment operator iStat += EqnTest(_T("a = b"), 2, true); iStat += EqnTest(_T("a = sin(b)"), 0.909297, true); iStat += EqnTest(_T("a = 1+sin(b)"), 1.909297, true); iStat += EqnTest(_T("(a=b)*2"), 4, true); iStat += EqnTest(_T("2*(a=b)"), 4, true); iStat += EqnTest(_T("2*(a=b+1)"), 6, true); iStat += EqnTest(_T("(a=b+1)*2"), 6, true); iStat += EqnTest(_T("a=c, a*10"), 30, true); iStat += EqnTest(_T("2^2^3"), 256, true); iStat += EqnTest(_T("1/2/3"), 1.0/6.0, true); // reference: http://www.wolframalpha.com/input/?i=3%2B4*2%2F%281-5%29^2^3 iStat += EqnTest(_T("3+4*2/(1-5)^2^3"), 3.0001220703125, true); // Test user defined binary operators iStat += EqnTestInt(_T("1 | 2"), 3, true); iStat += EqnTestInt(_T("1 || 2"), 1, true); iStat += EqnTestInt(_T("123 & 456"), 72, true); iStat += EqnTestInt(_T("(123 & 456) % 10"), 2, true); iStat += EqnTestInt(_T("1 && 0"), 0, true); iStat += EqnTestInt(_T("123 && 456"), 1, true); iStat += EqnTestInt(_T("1 << 3"), 8, true); iStat += EqnTestInt(_T("8 >> 3"), 1, true); iStat += EqnTestInt(_T("9 / 4"), 2, true); iStat += EqnTestInt(_T("9 % 4"), 1, true); iStat += EqnTestInt(_T("if(5%2,1,0)"), 1, true); iStat += EqnTestInt(_T("if(4%2,1,0)"), 0, true); iStat += EqnTestInt(_T("-10+1"), -9, true); iStat += EqnTestInt(_T("1+2*3"), 7, true); iStat += EqnTestInt(_T("const1 != const2"), 1, true); iStat += EqnTestInt(_T("const1 != const2"), 0, false); iStat += EqnTestInt(_T("const1 == const2"), 0, true); iStat += EqnTestInt(_T("const1 == 1"), 1, true); iStat += EqnTestInt(_T("10*(const1 == 1)"), 10, true); iStat += EqnTestInt(_T("2*(const1 | const2)"), 6, true); iStat += EqnTestInt(_T("2*(const1 | const2)"), 7, false); iStat += EqnTestInt(_T("const1 < const2"), 1, true); iStat += EqnTestInt(_T("const2 > const1"), 1, true); iStat += EqnTestInt(_T("const1 <= 1"), 1, true); iStat += EqnTestInt(_T("const2 >= 2"), 1, true); iStat += EqnTestInt(_T("2*(const1 + const2)"), 6, true); iStat += EqnTestInt(_T("2*(const1 - const2)"), -2, true); iStat += EqnTestInt(_T("a != b"), 1, true); iStat += EqnTestInt(_T("a != b"), 0, false); iStat += EqnTestInt(_T("a == b"), 0, true); iStat += EqnTestInt(_T("a == 1"), 1, true); iStat += EqnTestInt(_T("10*(a == 1)"), 10, true); iStat += EqnTestInt(_T("2*(a | b)"), 6, true); iStat += EqnTestInt(_T("2*(a | b)"), 7, false); iStat += EqnTestInt(_T("a < b"), 1, true); iStat += EqnTestInt(_T("b > a"), 1, true); iStat += EqnTestInt(_T("a <= 1"), 1, true); iStat += EqnTestInt(_T("b >= 2"), 1, true); iStat += EqnTestInt(_T("2*(a + b)"), 6, true); iStat += EqnTestInt(_T("2*(a - b)"), -2, true); iStat += EqnTestInt(_T("a + (a << b)"), 5, true); iStat += EqnTestInt(_T("-2^2"), -4, true); iStat += EqnTestInt(_T("3--a"), 4, true); iStat += EqnTestInt(_T("3+-3^2"), -6, true); // Test reading of hex values: iStat += EqnTestInt(_T("0xff"), 255, true); iStat += EqnTestInt(_T("10+0xff"), 265, true); iStat += EqnTestInt(_T("0xff+10"), 265, true); iStat += EqnTestInt(_T("10*0xff"), 2550, true); iStat += EqnTestInt(_T("0xff*10"), 2550, true); iStat += EqnTestInt(_T("10+0xff+1"), 266, true); iStat += EqnTestInt(_T("1+0xff+10"), 266, true); // incorrect: '^' is yor here, not power // iStat += EqnTestInt("-(1+2)^2", -9, true); // iStat += EqnTestInt("-1^3", -1, true); // Test precedence // a=1, b=2, c=3 iStat += EqnTestInt(_T("a + b * c"), 7, true); iStat += EqnTestInt(_T("a * b + c"), 5, true); iStat += EqnTestInt(_T("a10"), 0, true); iStat += EqnTestInt(_T("a"), f1of1) PARSER_THROWCHECK(PostfixOprt, true, _T("?<"), f1of1) PARSER_THROWCHECK(PostfixOprt, true, _T("**"), f1of1) PARSER_THROWCHECK(PostfixOprt, true, _T("xor"), f1of1) PARSER_THROWCHECK(PostfixOprt, true, _T("and"), f1of1) PARSER_THROWCHECK(PostfixOprt, true, _T("or"), f1of1) PARSER_THROWCHECK(PostfixOprt, true, _T("not"), f1of1) PARSER_THROWCHECK(PostfixOprt, true, _T("!"), f1of1) // Binary operator // The following must fail with builtin operators activated // p.EnableBuiltInOp(true); -> this is the default p.ClearPostfixOprt(); PARSER_THROWCHECK(Oprt, false, _T("+"), f1of2) PARSER_THROWCHECK(Oprt, false, _T("-"), f1of2) PARSER_THROWCHECK(Oprt, false, _T("*"), f1of2) PARSER_THROWCHECK(Oprt, false, _T("/"), f1of2) PARSER_THROWCHECK(Oprt, false, _T("^"), f1of2) PARSER_THROWCHECK(Oprt, false, _T("&&"), f1of2) PARSER_THROWCHECK(Oprt, false, _T("||"), f1of2) // without activated built in operators it should work p.EnableBuiltInOprt(false); PARSER_THROWCHECK(Oprt, true, _T("+"), f1of2) PARSER_THROWCHECK(Oprt, true, _T("-"), f1of2) PARSER_THROWCHECK(Oprt, true, _T("*"), f1of2) PARSER_THROWCHECK(Oprt, true, _T("/"), f1of2) PARSER_THROWCHECK(Oprt, true, _T("^"), f1of2) PARSER_THROWCHECK(Oprt, true, _T("&&"), f1of2) PARSER_THROWCHECK(Oprt, true, _T("||"), f1of2) #undef PARSER_THROWCHECK if (iStat==0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------- int ParserTester::TestSyntax() { int iStat = 0; mu::console() << _T("testing syntax engine..."); iStat += ThrowTest(_T("1,"), ecUNEXPECTED_EOF); // incomplete hex definition iStat += ThrowTest(_T("a,"), ecUNEXPECTED_EOF); // incomplete hex definition iStat += ThrowTest(_T("sin(8),"), ecUNEXPECTED_EOF); // incomplete hex definition iStat += ThrowTest(_T("(sin(8)),"), ecUNEXPECTED_EOF); // incomplete hex definition iStat += ThrowTest(_T("a{m},"), ecUNEXPECTED_EOF); // incomplete hex definition iStat += EqnTest(_T("(1+ 2*a)"), 3, true); // Spaces within formula iStat += EqnTest(_T("sqrt((4))"), 2, true); // Multiple brackets iStat += EqnTest(_T("sqrt((2)+2)"), 2, true);// Multiple brackets iStat += EqnTest(_T("sqrt(2+(2))"), 2, true);// Multiple brackets iStat += EqnTest(_T("sqrt(a+(3))"), 2, true);// Multiple brackets iStat += EqnTest(_T("sqrt((3)+a)"), 2, true);// Multiple brackets iStat += EqnTest(_T("order(1,2)"), 1, true); // May not cause name collision with operator "or" iStat += EqnTest(_T("(2+"), 0, false); // missing closing bracket iStat += EqnTest(_T("2++4"), 0, false); // unexpected operator iStat += EqnTest(_T("2+-4"), 0, false); // unexpected operator iStat += EqnTest(_T("(2+)"), 0, false); // unexpected closing bracket iStat += EqnTest(_T("--2"), 0, false); // double sign iStat += EqnTest(_T("ksdfj"), 0, false); // unknown token iStat += EqnTest(_T("()"), 0, false); // empty bracket without a function iStat += EqnTest(_T("5+()"), 0, false); // empty bracket without a function iStat += EqnTest(_T("sin(cos)"), 0, false); // unexpected function iStat += EqnTest(_T("5t6"), 0, false); // unknown token iStat += EqnTest(_T("5 t 6"), 0, false); // unknown token iStat += EqnTest(_T("8*"), 0, false); // unexpected end of formula iStat += EqnTest(_T(",3"), 0, false); // unexpected comma iStat += EqnTest(_T("3,5"), 0, false); // unexpected comma iStat += EqnTest(_T("sin(8,8)"), 0, false); // too many function args iStat += EqnTest(_T("(7,8)"), 0, false); // too many function args iStat += EqnTest(_T("sin)"), 0, false); // unexpected closing bracket iStat += EqnTest(_T("a)"), 0, false); // unexpected closing bracket iStat += EqnTest(_T("pi)"), 0, false); // unexpected closing bracket iStat += EqnTest(_T("sin(())"), 0, false); // unexpected closing bracket iStat += EqnTest(_T("sin()"), 0, false); // unexpected closing bracket if (iStat==0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------- int ParserTester::TestVarConst() { int iStat = 0; mu::console() << _T("testing variable/constant detection..."); // Test if the result changes when a variable changes iStat += EqnTestWithVarChange( _T("a"), 1, 1, 2, 2 ); iStat += EqnTestWithVarChange( _T("2*a"), 2, 4, 3, 6 ); // distinguish constants with same basename iStat += EqnTest( _T("const"), 1, true); iStat += EqnTest( _T("const1"), 2, true); iStat += EqnTest( _T("const2"), 3, true); iStat += EqnTest( _T("2*const"), 2, true); iStat += EqnTest( _T("2*const1"), 4, true); iStat += EqnTest( _T("2*const2"), 6, true); iStat += EqnTest( _T("2*const+1"), 3, true); iStat += EqnTest( _T("2*const1+1"), 5, true); iStat += EqnTest( _T("2*const2+1"), 7, true); iStat += EqnTest( _T("const"), 0, false); iStat += EqnTest( _T("const1"), 0, false); iStat += EqnTest( _T("const2"), 0, false); // distinguish variables with same basename iStat += EqnTest( _T("a"), 1, true); iStat += EqnTest( _T("aa"), 2, true); iStat += EqnTest( _T("2*a"), 2, true); iStat += EqnTest( _T("2*aa"), 4, true); iStat += EqnTest( _T("2*a-1"), 1, true); iStat += EqnTest( _T("2*aa-1"), 3, true); // custom value recognition iStat += EqnTest( _T("0xff"), 255, true); iStat += EqnTest( _T("0x97 + 0xff"), 406, true); // Finally test querying of used variables try { int idx; mu::Parser p; mu::value_type vVarVal[] = { 1, 2, 3, 4, 5}; p.DefineVar( _T("a"), &vVarVal[0]); p.DefineVar( _T("b"), &vVarVal[1]); p.DefineVar( _T("c"), &vVarVal[2]); p.DefineVar( _T("d"), &vVarVal[3]); p.DefineVar( _T("e"), &vVarVal[4]); // Test lookup of defined variables // 4 used variables p.SetExpr( _T("a+b+c+d") ); mu::varmap_type UsedVar = p.GetUsedVar(); int iCount = (int)UsedVar.size(); if (iCount!=4) throw false; // the next check will fail if the parser // erroneously creates new variables internally if (p.GetVar().size()!=5) throw false; mu::varmap_type::const_iterator item = UsedVar.begin(); for (idx=0; item!=UsedVar.end(); ++item) { if (&vVarVal[idx++]!=item->second) throw false; } // Test lookup of undefined variables p.SetExpr( _T("undef1+undef2+undef3") ); UsedVar = p.GetUsedVar(); iCount = (int)UsedVar.size(); if (iCount!=3) throw false; // the next check will fail if the parser // erroneously creates new variables internally if (p.GetVar().size()!=5) throw false; for (item = UsedVar.begin(); item!=UsedVar.end(); ++item) { if (item->second!=0) throw false; // all pointers to undefined variables must be null } // 1 used variables p.SetExpr( _T("a+b") ); UsedVar = p.GetUsedVar(); iCount = (int)UsedVar.size(); if (iCount!=2) throw false; item = UsedVar.begin(); for (idx=0; item!=UsedVar.end(); ++item) if (&vVarVal[idx++]!=item->second) throw false; } catch(...) { iStat += 1; } if (iStat==0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------- int ParserTester::TestMultiArg() { int iStat = 0; mu::console() << _T("testing multiarg functions..."); // Compound expressions iStat += EqnTest( _T("1,2,3"), 3, true); iStat += EqnTest( _T("a,b,c"), 3, true); iStat += EqnTest( _T("a=10,b=20,c=a*b"), 200, true); iStat += EqnTest( _T("1,\n2,\n3"), 3, true); iStat += EqnTest( _T("a,\nb,\nc"), 3, true); iStat += EqnTest( _T("a=10,\nb=20,\nc=a*b"), 200, true); iStat += EqnTest( _T("1,\r\n2,\r\n3"), 3, true); iStat += EqnTest( _T("a,\r\nb,\r\nc"), 3, true); iStat += EqnTest( _T("a=10,\r\nb=20,\r\nc=a*b"), 200, true); // picking the right argument iStat += EqnTest( _T("f1of1(1)"), 1, true); iStat += EqnTest( _T("f1of2(1, 2)"), 1, true); iStat += EqnTest( _T("f2of2(1, 2)"), 2, true); iStat += EqnTest( _T("f1of3(1, 2, 3)"), 1, true); iStat += EqnTest( _T("f2of3(1, 2, 3)"), 2, true); iStat += EqnTest( _T("f3of3(1, 2, 3)"), 3, true); iStat += EqnTest( _T("f1of4(1, 2, 3, 4)"), 1, true); iStat += EqnTest( _T("f2of4(1, 2, 3, 4)"), 2, true); iStat += EqnTest( _T("f3of4(1, 2, 3, 4)"), 3, true); iStat += EqnTest( _T("f4of4(1, 2, 3, 4)"), 4, true); iStat += EqnTest( _T("f1of5(1, 2, 3, 4, 5)"), 1, true); iStat += EqnTest( _T("f2of5(1, 2, 3, 4, 5)"), 2, true); iStat += EqnTest( _T("f3of5(1, 2, 3, 4, 5)"), 3, true); iStat += EqnTest( _T("f4of5(1, 2, 3, 4, 5)"), 4, true); iStat += EqnTest( _T("f5of5(1, 2, 3, 4, 5)"), 5, true); // Too few arguments / Too many arguments iStat += EqnTest( _T("1+ping()"), 11, true); iStat += EqnTest( _T("ping()+1"), 11, true); iStat += EqnTest( _T("2*ping()"), 20, true); iStat += EqnTest( _T("ping()*2"), 20, true); iStat += EqnTest( _T("ping(1,2)"), 0, false); iStat += EqnTest( _T("1+ping(1,2)"), 0, false); iStat += EqnTest( _T("f1of1(1,2)"), 0, false); iStat += EqnTest( _T("f1of1()"), 0, false); iStat += EqnTest( _T("f1of2(1, 2, 3)"), 0, false); iStat += EqnTest( _T("f1of2(1)"), 0, false); iStat += EqnTest( _T("f1of3(1, 2, 3, 4)"), 0, false); iStat += EqnTest( _T("f1of3(1)"), 0, false); iStat += EqnTest( _T("f1of4(1, 2, 3, 4, 5)"), 0, false); iStat += EqnTest( _T("f1of4(1)"), 0, false); iStat += EqnTest( _T("(1,2,3)"), 0, false); iStat += EqnTest( _T("1,2,3"), 0, false); iStat += EqnTest( _T("(1*a,2,3)"), 0, false); iStat += EqnTest( _T("1,2*a,3"), 0, false); // correct calculation of arguments iStat += EqnTest( _T("min(a, 1)"), 1, true); iStat += EqnTest( _T("min(3*2, 1)"), 1, true); iStat += EqnTest( _T("min(3*2, 1)"), 6, false); iStat += EqnTest( _T("firstArg(2,3,4)"), 2, true); iStat += EqnTest( _T("lastArg(2,3,4)"), 4, true); iStat += EqnTest( _T("min(3*a+1, 1)"), 1, true); iStat += EqnTest( _T("max(3*a+1, 1)"), 4, true); iStat += EqnTest( _T("max(3*a+1, 1)*2"), 8, true); iStat += EqnTest( _T("2*max(3*a+1, 1)+2"), 10, true); // functions with Variable argument count iStat += EqnTest( _T("sum(a)"), 1, true); iStat += EqnTest( _T("sum(1,2,3)"), 6, true); iStat += EqnTest( _T("sum(a,b,c)"), 6, true); iStat += EqnTest( _T("sum(1,-max(1,2),3)*2"), 4, true); iStat += EqnTest( _T("2*sum(1,2,3)"), 12, true); iStat += EqnTest( _T("2*sum(1,2,3)+2"), 14, true); iStat += EqnTest( _T("2*sum(-1,2,3)+2"), 10, true); iStat += EqnTest( _T("2*sum(-1,2,-(-a))+2"), 6, true); iStat += EqnTest( _T("2*sum(-1,10,-a)+2"), 18, true); iStat += EqnTest( _T("2*sum(1,2,3)*2"), 24, true); iStat += EqnTest( _T("sum(1,-max(1,2),3)*2"), 4, true); iStat += EqnTest( _T("sum(1*3, 4, a+2)"), 10, true); iStat += EqnTest( _T("sum(1*3, 2*sum(1,2,2), a+2)"), 16, true); iStat += EqnTest( _T("sum(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2)"), 24, true); // some failures iStat += EqnTest( _T("sum()"), 0, false); iStat += EqnTest( _T("sum(,)"), 0, false); iStat += EqnTest( _T("sum(1,2,)"), 0, false); iStat += EqnTest( _T("sum(,1,2)"), 0, false); if (iStat==0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------- int ParserTester::TestInfixOprt() { int iStat(0); mu::console() << "testing infix operators..."; iStat += EqnTest( _T("+1"), +1, true); iStat += EqnTest( _T("-(+1)"), -1, true); iStat += EqnTest( _T("-(+1)*2"), -2, true); iStat += EqnTest( _T("-(+2)*sqrt(4)"), -4, true); iStat += EqnTest( _T("3-+a"), 2, true); iStat += EqnTest( _T("+1*3"), 3, true); iStat += EqnTest( _T("-1"), -1, true); iStat += EqnTest( _T("-(-1)"), 1, true); iStat += EqnTest( _T("-(-1)*2"), 2, true); iStat += EqnTest( _T("-(-2)*sqrt(4)"), 4, true); iStat += EqnTest( _T("-_pi"), -PARSER_CONST_PI, true); iStat += EqnTest( _T("-a"), -1, true); iStat += EqnTest( _T("-(a)"), -1, true); iStat += EqnTest( _T("-(-a)"), 1, true); iStat += EqnTest( _T("-(-a)*2"), 2, true); iStat += EqnTest( _T("-(8)"), -8, true); iStat += EqnTest( _T("-8"), -8, true); iStat += EqnTest( _T("-(2+1)"), -3, true); iStat += EqnTest( _T("-(f1of1(1+2*3)+1*2)"), -9, true); iStat += EqnTest( _T("-(-f1of1(1+2*3)+1*2)"), 5, true); iStat += EqnTest( _T("-sin(8)"), -0.989358, true); iStat += EqnTest( _T("3-(-a)"), 4, true); iStat += EqnTest( _T("3--a"), 4, true); iStat += EqnTest( _T("-1*3"), -3, true); // Postfix / infix priorities iStat += EqnTest( _T("~2#"), 8, true); iStat += EqnTest( _T("~f1of1(2)#"), 8, true); iStat += EqnTest( _T("~(b)#"), 8, true); iStat += EqnTest( _T("(~b)#"), 12, true); iStat += EqnTest( _T("~(2#)"), 8, true); iStat += EqnTest( _T("~(f1of1(2)#)"), 8, true); // iStat += EqnTest( _T("-2^2"),-4, true); iStat += EqnTest( _T("-(a+b)^2"),-9, true); iStat += EqnTest( _T("(-3)^2"),9, true); iStat += EqnTest( _T("-(-2^2)"),4, true); iStat += EqnTest( _T("3+-3^2"),-6, true); // The following assumes use of sqr as postfix operator ("") together // with a sign operator of low priority: iStat += EqnTest( _T("-2'"), -4, true); iStat += EqnTest( _T("-(1+1)'"),-4, true); iStat += EqnTest( _T("2+-(1+1)'"),-2, true); iStat += EqnTest( _T("2+-2'"), -2, true); // This is the classic behaviour of the infix sign operator (here: "$") which is // now deprecated: iStat += EqnTest( _T("$2^2"),4, true); iStat += EqnTest( _T("$(a+b)^2"),9, true); iStat += EqnTest( _T("($3)^2"),9, true); iStat += EqnTest( _T("$($2^2)"),-4, true); iStat += EqnTest( _T("3+$3^2"),12, true); // infix operators sharing the first few characters iStat += EqnTest( _T("~ 123"), 123+2, true); iStat += EqnTest( _T("~~ 123"), 123+2, true); if (iStat==0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------- int ParserTester::TestPostFix() { int iStat = 0; mu::console() << _T("testing postfix operators..."); // application iStat += EqnTest( _T("3{m}+5"), 5.003, true); iStat += EqnTest( _T("1000{m}"), 1, true); iStat += EqnTest( _T("1000 {m}"), 1, true); iStat += EqnTest( _T("(a){m}"), 1e-3, true); iStat += EqnTest( _T("a{m}"), 1e-3, true); iStat += EqnTest( _T("a {m}"), 1e-3, true); iStat += EqnTest( _T("-(a){m}"), -1e-3, true); iStat += EqnTest( _T("-2{m}"), -2e-3, true); iStat += EqnTest( _T("-2 {m}"), -2e-3, true); iStat += EqnTest( _T("f1of1(1000){m}"), 1, true); iStat += EqnTest( _T("-f1of1(1000){m}"), -1, true); iStat += EqnTest( _T("-f1of1(-1000){m}"), 1, true); iStat += EqnTest( _T("f4of4(0,0,0,1000){m}"), 1, true); iStat += EqnTest( _T("2+(a*1000){m}"), 3, true); // can postfix operators "m" und "meg" be told apart properly? iStat += EqnTest( _T("2*3000meg+2"), 2*3e9+2, true); // some incorrect results iStat += EqnTest( _T("1000{m}"), 0.1, false); iStat += EqnTest( _T("(a){m}"), 2, false); // failure due to syntax checking iStat += ThrowTest(_T("0x"), ecUNASSIGNABLE_TOKEN); // incomplete hex definition iStat += ThrowTest(_T("3+"), ecUNEXPECTED_EOF); iStat += ThrowTest( _T("4 + {m}"), ecUNASSIGNABLE_TOKEN); iStat += ThrowTest( _T("{m}4"), ecUNASSIGNABLE_TOKEN); iStat += ThrowTest( _T("sin({m})"), ecUNASSIGNABLE_TOKEN); iStat += ThrowTest( _T("{m} {m}"), ecUNASSIGNABLE_TOKEN); iStat += ThrowTest( _T("{m}(8)"), ecUNASSIGNABLE_TOKEN); iStat += ThrowTest( _T("4,{m}"), ecUNASSIGNABLE_TOKEN); iStat += ThrowTest( _T("-{m}"), ecUNASSIGNABLE_TOKEN); iStat += ThrowTest( _T("2(-{m})"), ecUNEXPECTED_PARENS); iStat += ThrowTest( _T("2({m})"), ecUNEXPECTED_PARENS); iStat += ThrowTest( _T("multi*1.0"), ecUNASSIGNABLE_TOKEN); if (iStat==0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------- int ParserTester::TestExpression() { int iStat = 0; mu::console() << _T("testing expression samples..."); value_type b = 2; // Optimization iStat += EqnTest( _T("2*b*5"), 20, true); iStat += EqnTest( _T("2*b*5 + 4*b"), 28, true); iStat += EqnTest( _T("2*a/3"), 2.0/3.0, true); // Addition auf cmVARMUL iStat += EqnTest( _T("3+b"), b+3, true); iStat += EqnTest( _T("b+3"), b+3, true); iStat += EqnTest( _T("b*3+2"), b*3+2, true); iStat += EqnTest( _T("3*b+2"), b*3+2, true); iStat += EqnTest( _T("2+b*3"), b*3+2, true); iStat += EqnTest( _T("2+3*b"), b*3+2, true); iStat += EqnTest( _T("b+3*b"), b+3*b, true); iStat += EqnTest( _T("3*b+b"), b+3*b, true); iStat += EqnTest( _T("2+b*3+b"), 2+b*3+b, true); iStat += EqnTest( _T("b+2+b*3"), b+2+b*3, true); iStat += EqnTest( _T("(2*b+1)*4"), (2*b+1)*4, true); iStat += EqnTest( _T("4*(2*b+1)"), (2*b+1)*4, true); // operator precedences iStat += EqnTest( _T("1+2-3*4/5^6"), 2.99923, true); iStat += EqnTest( _T("1^2/3*4-5+6"), 2.33333333, true); iStat += EqnTest( _T("1+2*3"), 7, true); iStat += EqnTest( _T("1+2*3"), 7, true); iStat += EqnTest( _T("(1+2)*3"), 9, true); iStat += EqnTest( _T("(1+2)*(-3)"), -9, true); iStat += EqnTest( _T("2/4"), 0.5, true); iStat += EqnTest( _T("exp(ln(7))"), 7, true); iStat += EqnTest( _T("e^ln(7)"), 7, true); iStat += EqnTest( _T("e^(ln(7))"), 7, true); iStat += EqnTest( _T("(e^(ln(7)))"), 7, true); iStat += EqnTest( _T("1-(e^(ln(7)))"), -6, true); iStat += EqnTest( _T("2*(e^(ln(7)))"), 14, true); iStat += EqnTest( _T("10^log(5)"), pow(10.0, log(5.0)), true); iStat += EqnTest( _T("10^log10(5)"), 5, true); iStat += EqnTest( _T("2^log2(4)"), 4, true); iStat += EqnTest( _T("-(sin(0)+1)"), -1, true); iStat += EqnTest( _T("-(2^1.1)"), -2.14354692, true); iStat += EqnTest( _T("(cos(2.41)/b)"), -0.372056, true); iStat += EqnTest( _T("(1*(2*(3*(4*(5*(6*(a+b)))))))"), 2160, true); iStat += EqnTest( _T("(1*(2*(3*(4*(5*(6*(7*(a+b))))))))"), 15120, true); iStat += EqnTest( _T("(a/((((b+(((e*(((((pi*((((3.45*((pi+a)+pi))+b)+b)*a))+0.68)+e)+a)/a))+a)+b))+b)*a)-pi))"), 0.00377999, true); // long formula (Reference: Matlab) iStat += EqnTest( _T("(((-9))-e/(((((((pi-(((-7)+(-3)/4/e))))/(((-5))-2)-((pi+(-0))*(sqrt((e+e))*(-8))*(((-pi)+(-pi)-(-9)*(6*5))") _T("/(-e)-e))/2)/((((sqrt(2/(-e)+6)-(4-2))+((5/(-2))/(1*(-pi)+3))/8)*pi*((pi/((-2)/(-6)*1*(-1))*(-6)+(-e)))))/") _T("((e+(-2)+(-e)*((((-3)*9+(-e)))+(-9)))))))-((((e-7+(((5/pi-(3/1+pi)))))/e)/(-5))/(sqrt((((((1+(-7))))+((((-") _T("e)*(-e)))-8))*(-5)/((-e)))*(-6)-((((((-2)-(-9)-(-e)-1)/3))))/(sqrt((8+(e-((-6))+(9*(-9))))*(((3+2-8))*(7+6") _T("+(-5))+((0/(-e)*(-pi))+7)))+(((((-e)/e/e)+((-6)*5)*e+(3+(-5)/pi))))+pi))/sqrt((((9))+((((pi))-8+2))+pi))/e") _T("*4)*((-5)/(((-pi))*(sqrt(e)))))-(((((((-e)*(e)-pi))/4+(pi)*(-9)))))))+(-pi)"), -12.23016549, true); // long formula (Reference: Matlab) iStat += EqnTest( _T("(atan(sin((((((((((((((((pi/cos((a/((((0.53-b)-pi)*e)/b))))+2.51)+a)-0.54)/0.98)+b)*b)+e)/a)+b)+a)+b)+pi)/e") _T(")+a)))*2.77)"), -2.16995656, true); // long formula (Reference: Matlab) iStat += EqnTest( _T("1+2-3*4/5^6*(2*(1-5+(3*7^9)*(4+6*7-3)))+12"), -7995810.09926, true); if (iStat==0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------- int ParserTester::TestIfThenElse() { int iStat = 0; mu::console() << _T("testing if-then-else operator..."); // Test error detection iStat += ThrowTest(_T(":3"), ecUNEXPECTED_CONDITIONAL); iStat += ThrowTest(_T("? 1 : 2"), ecUNEXPECTED_CONDITIONAL); iStat += ThrowTest(_T("(ab) ? 10 : 11"), 11, true); iStat += EqnTest(_T("(ab) ? c : d"), -2, true); iStat += EqnTest(_T("(a>b) ? 1 : 0"), 0, true); iStat += EqnTest(_T("((a>b) ? 1 : 0) ? 1 : 2"), 2, true); iStat += EqnTest(_T("((a>b) ? 1 : 0) ? 1 : sum((a>b) ? 1 : 2)"), 2, true); iStat += EqnTest(_T("((a>b) ? 0 : 1) ? 1 : sum((a>b) ? 1 : 2)"), 1, true); iStat += EqnTest(_T("sum((a>b) ? 1 : 2)"), 2, true); iStat += EqnTest(_T("sum((1) ? 1 : 2)"), 1, true); iStat += EqnTest(_T("sum((a>b) ? 1 : 2, 100)"), 102, true); iStat += EqnTest(_T("sum((1) ? 1 : 2, 100)"), 101, true); iStat += EqnTest(_T("sum(3, (a>b) ? 3 : 10)"), 13, true); iStat += EqnTest(_T("sum(3, (ab) ? 3 : 10)"), 130, true); iStat += EqnTest(_T("10*sum(3, (ab) ? 3 : 10)*10"), 130, true); iStat += EqnTest(_T("sum(3, (ab) ? sum(3, (ab) ? sum(3, (ab) ? sum(3, (ab)&&(a2)&&(1<2) ? 128 : 255"), 255, true); iStat += EqnTest(_T("((1<2)&&(1<2)) ? 128 : 255"), 128, true); iStat += EqnTest(_T("((1>2)&&(1<2)) ? 128 : 255"), 255, true); iStat += EqnTest(_T("((ab)&&(a0 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64"), 255, true); iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 :(1>0 ? 32 : 64)"), 255, true); iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64"), 128, true); iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 :(1>2 ? 32 : 64)"), 128, true); iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64"), 32, true); iStat += EqnTest(_T("1>2 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64"), 64, true); iStat += EqnTest(_T("1>0 ? 50 : 1>0 ? 128 : 255"), 50, true); iStat += EqnTest(_T("1>0 ? 50 : (1>0 ? 128 : 255)"), 50, true); iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 : 50"), 128, true); iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 1>2 ? 64 : 16"), 32, true); iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 :(1>2 ? 64 : 16)"), 32, true); iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : 1>0 ? 32 :1>2 ? 64 : 16"), 255, true); iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : (1>0 ? 32 :1>2 ? 64 : 16)"), 255, true); iStat += EqnTest(_T("1 ? 0 ? 128 : 255 : 1 ? 32 : 64"), 255, true); // assignment operators iStat += EqnTest(_T("a= 0 ? 128 : 255, a"), 255, true); iStat += EqnTest(_T("a=((a>b)&&(a // this is now legal, for reference see: // https://sourceforge.net/forum/message.php?msg_id=7411373 // iStat += ThrowTest( _T("sin=9"), ecUNEXPECTED_OPERATOR); //
    iStat += ThrowTest( _T("(8)=5"), ecUNEXPECTED_OPERATOR); iStat += ThrowTest( _T("(a)=5"), ecUNEXPECTED_OPERATOR); iStat += ThrowTest( _T("a=\"tttt\""), ecOPRT_TYPE_CONFLICT); if (iStat==0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------- void ParserTester::AddTest(testfun_type a_pFun) { m_vTestFun.push_back(a_pFun); } //--------------------------------------------------------------------------- void ParserTester::Run() { int iStat = 0; try { for (int i=0; i<(int)m_vTestFun.size(); ++i) iStat += (this->*m_vTestFun[i])(); } catch(Parser::exception_type &e) { mu::console() << "\n" << e.GetMsg() << endl; mu::console() << e.GetToken() << endl; Abort(); } catch(std::exception &e) { mu::console() << e.what() << endl; Abort(); } catch(...) { mu::console() << "Internal error"; Abort(); } if (iStat==0) { mu::console() << "Test passed (" << ParserTester::c_iCount << " expressions)" << endl; } else { mu::console() << "Test failed with " << iStat << " errors (" << ParserTester::c_iCount << " expressions)" << endl; } ParserTester::c_iCount = 0; } //--------------------------------------------------------------------------- int ParserTester::ThrowTest(const string_type &a_str, int a_iErrc, bool a_bFail) { ParserTester::c_iCount++; try { value_type fVal[] = {1,1,1}; Parser p; p.DefineVar( _T("a"), &fVal[0]); p.DefineVar( _T("b"), &fVal[1]); p.DefineVar( _T("c"), &fVal[2]); p.DefinePostfixOprt( _T("{m}"), Milli); p.DefinePostfixOprt( _T("m"), Milli); p.DefineFun( _T("ping"), Ping); p.DefineFun( _T("valueof"), ValueOf); p.DefineFun( _T("strfun1"), StrFun1); p.DefineFun( _T("strfun2"), StrFun2); p.DefineFun( _T("strfun3"), StrFun3); p.SetExpr(a_str); p.Eval(); } catch(ParserError &e) { // output the formula in case of an failed test if (a_bFail==false || (a_bFail==true && a_iErrc!=e.GetCode()) ) { mu::console() << _T("\n ") << _T("Expression: ") << a_str << _T(" Code:") << e.GetCode() << _T("(") << e.GetMsg() << _T(")") << _T(" Expected:") << a_iErrc; } return (a_iErrc==e.GetCode()) ? 0 : 1; } // if a_bFail==false no exception is expected bool bRet((a_bFail==false) ? 0 : 1); if (bRet==1) { mu::console() << _T("\n ") << _T("Expression: ") << a_str << _T(" did evaluate; Expected error:") << a_iErrc; } return bRet; } //--------------------------------------------------------------------------- /** \brief Evaluate a tet expression. \return 1 in case of a failure, 0 otherwise. */ int ParserTester::EqnTestWithVarChange(const string_type &a_str, double a_fVar1, double a_fRes1, double a_fVar2, double a_fRes2) { ParserTester::c_iCount++; try { value_type fVal[2] = {-999, -999 }; // should be equal Parser p; value_type var = 0; // variable p.DefineVar( _T("a"), &var); p.SetExpr(a_str); var = a_fVar1; fVal[0] = p.Eval(); var = a_fVar2; fVal[1] = p.Eval(); if ( fabs(a_fRes1-fVal[0]) > 0.0000000001) throw std::runtime_error("incorrect result (first pass)"); if ( fabs(a_fRes2-fVal[1]) > 0.0000000001) throw std::runtime_error("incorrect result (second pass)"); } catch(Parser::exception_type &e) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")"); return 1; } catch(std::exception &e) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.what() << _T(")"); return 1; // always return a failure since this exception is not expected } catch(...) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); return 1; // exceptions other than ParserException are not allowed } return 0; } //--------------------------------------------------------------------------- /** \brief Evaluate a tet expression. \return 1 in case of a failure, 0 otherwise. */ int ParserTester::EqnTest(const string_type &a_str, double a_fRes, bool a_fPass) { ParserTester::c_iCount++; int iRet(0); value_type fVal[5] = {-999, -998, -997, -996, -995}; // initially should be different try { std::auto_ptr p1; Parser p2, p3; // three parser objects // they will be used for testing copy and assignment operators // p1 is a pointer since i'm going to delete it in order to test if // parsers after copy construction still refer to members of it. // !! If this is the case this function will crash !! p1.reset(new mu::Parser()); // Add constants p1->DefineConst( _T("pi"), (value_type)PARSER_CONST_PI); p1->DefineConst( _T("e"), (value_type)PARSER_CONST_E); p1->DefineConst( _T("const"), 1); p1->DefineConst( _T("const1"), 2); p1->DefineConst( _T("const2"), 3); // string constants p1->DefineStrConst( _T("str1"), _T("1.11")); p1->DefineStrConst( _T("str2"), _T("2.22")); // variables value_type vVarVal[] = { 1, 2, 3, -2}; p1->DefineVar( _T("a"), &vVarVal[0]); p1->DefineVar( _T("aa"), &vVarVal[1]); p1->DefineVar( _T("b"), &vVarVal[1]); p1->DefineVar( _T("c"), &vVarVal[2]); p1->DefineVar( _T("d"), &vVarVal[3]); // custom value ident functions p1->AddValIdent(&ParserTester::IsHexVal); // functions p1->DefineFun( _T("ping"), Ping); p1->DefineFun( _T("f1of1"), f1of1); // one parameter p1->DefineFun( _T("f1of2"), f1of2); // two parameter p1->DefineFun( _T("f2of2"), f2of2); p1->DefineFun( _T("f1of3"), f1of3); // three parameter p1->DefineFun( _T("f2of3"), f2of3); p1->DefineFun( _T("f3of3"), f3of3); p1->DefineFun( _T("f1of4"), f1of4); // four parameter p1->DefineFun( _T("f2of4"), f2of4); p1->DefineFun( _T("f3of4"), f3of4); p1->DefineFun( _T("f4of4"), f4of4); p1->DefineFun( _T("f1of5"), f1of5); // five parameter p1->DefineFun( _T("f2of5"), f2of5); p1->DefineFun( _T("f3of5"), f3of5); p1->DefineFun( _T("f4of5"), f4of5); p1->DefineFun( _T("f5of5"), f5of5); // binary operators p1->DefineOprt( _T("add"), add, 0); p1->DefineOprt( _T("++"), add, 0); p1->DefineOprt( _T("&"), land, prLAND); // sample functions p1->DefineFun( _T("min"), Min); p1->DefineFun( _T("max"), Max); p1->DefineFun( _T("sum"), Sum); p1->DefineFun( _T("valueof"), ValueOf); p1->DefineFun( _T("atof"), StrToFloat); p1->DefineFun( _T("strfun1"), StrFun1); p1->DefineFun( _T("strfun2"), StrFun2); p1->DefineFun( _T("strfun3"), StrFun3); p1->DefineFun( _T("lastArg"), LastArg); p1->DefineFun( _T("firstArg"), FirstArg); p1->DefineFun( _T("order"), FirstArg); // infix / postfix operator // Note: Identifiers used here do not have any meaning // they are mere placeholders to test certain features. p1->DefineInfixOprt( _T("$"), sign, prPOW+1); // sign with high priority p1->DefineInfixOprt( _T("~"), plus2); // high priority p1->DefineInfixOprt( _T("~~"), plus2); p1->DefinePostfixOprt( _T("{m}"), Milli); p1->DefinePostfixOprt( _T("{M}"), Mega); p1->DefinePostfixOprt( _T("m"), Milli); p1->DefinePostfixOprt( _T("meg"), Mega); p1->DefinePostfixOprt( _T("#"), times3); p1->DefinePostfixOprt( _T("'"), sqr); p1->SetExpr(a_str); // Test bytecode integrity // String parsing and bytecode parsing must yield the same result fVal[0] = p1->Eval(); // result from stringparsing fVal[1] = p1->Eval(); // result from bytecode if (fVal[0]!=fVal[1]) throw Parser::exception_type( _T("Bytecode / string parsing mismatch.") ); // Test copy and assignment operators try { // Test copy constructor std::vector vParser; vParser.push_back(*(p1.get())); mu::Parser p2 = vParser[0]; // take parser from vector // destroy the originals from p2 vParser.clear(); // delete the vector p1.reset(0); fVal[2] = p2.Eval(); // Test assignment operator // additionally disable Optimizer this time mu::Parser p3; p3 = p2; p3.EnableOptimizer(false); fVal[3] = p3.Eval(); // Test Eval function for multiple return values // use p2 since it has the optimizer enabled! int nNum; value_type *v = p2.Eval(nNum); fVal[4] = v[nNum-1]; } catch(std::exception &e) { mu::console() << _T("\n ") << e.what() << _T("\n"); } // limited floating point accuracy requires the following test bool bCloseEnough(true); for (unsigned i=0; i::has_infinity) #pragma warning(pop) { bCloseEnough &= (fabs(fVal[i]) != numeric_limits::infinity()); } } iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1; if (iRet==1) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (incorrect result; expected: ") << a_fRes << _T(" ;calculated: ") << fVal[0] << _T(",") << fVal[1] << _T(",") << fVal[2] << _T(",") << fVal[3] << _T(",") << fVal[4] << _T(")."); } } catch(Parser::exception_type &e) { if (a_fPass) { if (fVal[0]!=fVal[2] && fVal[0]!=-999 && fVal[1]!=-998) mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (copy construction)"); else mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")"); return 1; } } catch(std::exception &e) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.what() << _T(")"); return 1; // always return a failure since this exception is not expected } catch(...) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); return 1; // exceptions other than ParserException are not allowed } return iRet; } //--------------------------------------------------------------------------- int ParserTester::EqnTestInt(const string_type &a_str, double a_fRes, bool a_fPass) { ParserTester::c_iCount++; value_type vVarVal[] = {1, 2, 3}; // variable values int iRet(0); try { value_type fVal[2] = {-99, -999}; // results: initially should be different ParserInt p; p.DefineConst( _T("const1"), 1); p.DefineConst( _T("const2"), 2); p.DefineVar( _T("a"), &vVarVal[0]); p.DefineVar( _T("b"), &vVarVal[1]); p.DefineVar( _T("c"), &vVarVal[2]); p.SetExpr(a_str); fVal[0] = p.Eval(); // result from stringparsing fVal[1] = p.Eval(); // result from bytecode if (fVal[0]!=fVal[1]) throw Parser::exception_type( _T("Bytecode corrupt.") ); iRet = ( (a_fRes==fVal[0] && a_fPass) || (a_fRes!=fVal[0] && !a_fPass) ) ? 0 : 1; if (iRet==1) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (incorrect result; expected: ") << a_fRes << _T(" ;calculated: ") << fVal[0]<< _T(")."); } } catch(Parser::exception_type &e) { if (a_fPass) { mu::console() << _T("\n fail: ") << e.GetExpr() << _T(" : ") << e.GetMsg(); iRet = 1; } } catch(...) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); iRet = 1; // exceptions other than ParserException are not allowed } return iRet; } //--------------------------------------------------------------------------- /** \brief Test an expression in Bulk Mode. */ int ParserTester::EqnTestBulk(const string_type &a_str, double a_fRes[4], bool a_fPass) { ParserTester::c_iCount++; // Define Bulk Variables int nBulkSize = 4; value_type vVariableA[] = { 1, 2, 3, 4 }; // variable values value_type vVariableB[] = { 2, 2, 2, 2 }; // variable values value_type vVariableC[] = { 3, 3, 3, 3 }; // variable values value_type vResults[] = { 0, 0, 0, 0 }; // variable values int iRet(0); try { Parser p; p.DefineConst(_T("const1"), 1); p.DefineConst(_T("const2"), 2); p.DefineVar(_T("a"), vVariableA); p.DefineVar(_T("b"), vVariableB); p.DefineVar(_T("c"), vVariableC); p.SetExpr(a_str); p.Eval(vResults, nBulkSize); bool bCloseEnough(true); for (int i = 0; i < nBulkSize; ++i) { bCloseEnough &= (fabs(a_fRes[i] - vResults[i]) <= fabs(a_fRes[i] * 0.00001)); } iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1; if (iRet == 1) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (incorrect result; expected: {") << a_fRes[0] << _T(",") << a_fRes[1] << _T(",") << a_fRes[2] << _T(",") << a_fRes[3] << _T("}") << _T(" ;calculated: ") << vResults[0] << _T(",") << vResults[1] << _T(",") << vResults[2] << _T(",") << vResults[3] << _T("}"); } } catch (Parser::exception_type &e) { if (a_fPass) { mu::console() << _T("\n fail: ") << e.GetExpr() << _T(" : ") << e.GetMsg(); iRet = 1; } } catch (...) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); iRet = 1; // exceptions other than ParserException are not allowed } return iRet; } //--------------------------------------------------------------------------- /** \brief Internal error in test class Test is going to be aborted. */ void ParserTester::Abort() const { mu::console() << _T("Test failed (internal error in test class)") << endl; while (!getchar()); exit(-1); } } // namespace test } // namespace mu IanniX-0.9.20/geometry/qmuparser/muParserTest.h000066400000000000000000000173571317340345000214660ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2013 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_TEST_H #define MU_PARSER_TEST_H #include #include #include // for accumulate #include "muParser.h" #include "muParserInt.h" /** \file \brief This file contains the parser test class. */ namespace mu { /** \brief Namespace for test cases. */ namespace Test { //------------------------------------------------------------------------------ /** \brief Test cases for unit testing. (C) 2004-2011 Ingo Berg */ class ParserTester // final { private: static int c_iCount; // Multiarg callbacks static value_type f1of1(value_type v) { return v;}; static value_type f1of2(value_type v, value_type ) {return v;}; static value_type f2of2(value_type , value_type v) {return v;}; static value_type f1of3(value_type v, value_type , value_type ) {return v;}; static value_type f2of3(value_type , value_type v, value_type ) {return v;}; static value_type f3of3(value_type , value_type , value_type v) {return v;}; static value_type f1of4(value_type v, value_type, value_type , value_type ) {return v;} static value_type f2of4(value_type , value_type v, value_type , value_type ) {return v;} static value_type f3of4(value_type , value_type, value_type v, value_type ) {return v;} static value_type f4of4(value_type , value_type, value_type , value_type v) {return v;} static value_type f1of5(value_type v, value_type, value_type , value_type , value_type ) { return v; } static value_type f2of5(value_type , value_type v, value_type , value_type , value_type ) { return v; } static value_type f3of5(value_type , value_type, value_type v, value_type , value_type ) { return v; } static value_type f4of5(value_type , value_type, value_type , value_type v, value_type ) { return v; } static value_type f5of5(value_type , value_type, value_type , value_type , value_type v) { return v; } static value_type Min(value_type a_fVal1, value_type a_fVal2) { return (a_fVal1a_fVal2) ? a_fVal1 : a_fVal2; } static value_type plus2(value_type v1) { return v1+2; } static value_type times3(value_type v1) { return v1*3; } static value_type sqr(value_type v1) { return v1*v1; } static value_type sign(value_type v) { return -v; } static value_type add(value_type v1, value_type v2) { return v1+v2; } static value_type land(value_type v1, value_type v2) { return (int)v1 & (int)v2; } static value_type FirstArg(const value_type* a_afArg, int a_iArgc) { if (!a_iArgc) throw mu::Parser::exception_type( _T("too few arguments for function FirstArg.") ); return a_afArg[0]; } static value_type LastArg(const value_type* a_afArg, int a_iArgc) { if (!a_iArgc) throw mu::Parser::exception_type( _T("too few arguments for function LastArg.") ); return a_afArg[a_iArgc-1]; } static value_type Sum(const value_type* a_afArg, int a_iArgc) { if (!a_iArgc) throw mu::Parser::exception_type( _T("too few arguments for function sum.") ); value_type fRes=0; for (int i=0; i> val; return (value_type)val; } static value_type StrFun2(const char_type* v1, value_type v2) { int val(0); stringstream_type(v1) >> val; return (value_type)(val + v2); } static value_type StrFun3(const char_type* v1, value_type v2, value_type v3) { int val(0); stringstream_type(v1) >> val; return val + v2 + v3; } static value_type StrToFloat(const char_type* a_szMsg) { value_type val(0); stringstream_type(a_szMsg) >> val; return val; } // postfix operator callback static value_type Mega(value_type a_fVal) { return a_fVal * (value_type)1e6; } static value_type Micro(value_type a_fVal) { return a_fVal * (value_type)1e-6; } static value_type Milli(value_type a_fVal) { return a_fVal / (value_type)1e3; } // Custom value recognition static int IsHexVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal); int TestNames(); int TestSyntax(); int TestMultiArg(); int TestPostFix(); int TestExpression(); int TestInfixOprt(); int TestBinOprt(); int TestVarConst(); int TestInterface(); int TestException(); int TestStrArg(); int TestIfThenElse(); int TestBulkMode(); void Abort() const; public: typedef int (ParserTester::*testfun_type)(); ParserTester(); void Run(); private: std::vector m_vTestFun; void AddTest(testfun_type a_pFun); // Test Double Parser int EqnTest(const string_type& a_str, double a_fRes, bool a_fPass); int EqnTestWithVarChange(const string_type& a_str, double a_fRes1, double a_fVar1, double a_fRes2, double a_fVar2); int ThrowTest(const string_type& a_str, int a_iErrc, bool a_bFail = true); // Test Int Parser int EqnTestInt(const string_type& a_str, double a_fRes, bool a_fPass); // Test Bulkmode int EqnTestBulk(const string_type& a_str, double a_fRes[4], bool a_fPass); }; } // namespace Test } // namespace mu #endif IanniX-0.9.20/geometry/qmuparser/muParserToken.h000066400000000000000000000303101317340345000216070ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2013 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_TOKEN_H #define MU_PARSER_TOKEN_H #include #include #include #include #include #include "muParserError.h" #include "muParserCallback.h" /** \file \brief This file contains the parser token definition. */ namespace mu { /** \brief Encapsulation of the data for a single formula token. Formula token implementation. Part of the Math Parser Package. Formula tokens can be either one of the following:
    • value
    • variable
    • function with numerical arguments
    • functions with a string as argument
    • prefix operators
    • infix operators
    • binary operator
    \author (C) 2004-2013 Ingo Berg */ template class ParserToken { private: ECmdCode m_iCode; ///< Type of the token; The token type is a constant of type #ECmdCode. ETypeCode m_iType; void *m_pTok; ///< Stores Token pointer; not applicable for all tokens int m_iIdx; ///< An otional index to an external buffer storing the token data TString m_strTok; ///< Token string TString m_strVal; ///< Value for string variables value_type m_fVal; ///< the value std::auto_ptr m_pCallback; public: //--------------------------------------------------------------------------- /** \brief Constructor (default). Sets token to an neutral state of type cmUNKNOWN. \throw nothrow \sa ECmdCode */ ParserToken() :m_iCode(cmUNKNOWN) ,m_iType(tpVOID) ,m_pTok(0) ,m_iIdx(-1) ,m_strTok() ,m_strVal() ,m_fVal(0) ,m_pCallback() {} //------------------------------------------------------------------------------ /** \brief Create token from another one. Implemented by calling Assign(...) \throw nothrow \post m_iType==cmUNKNOWN \sa #Assign */ ParserToken(const ParserToken &a_Tok) { Assign(a_Tok); } //------------------------------------------------------------------------------ /** \brief Assignement operator. Copy token state from another token and return this. Implemented by calling Assign(...). \throw nothrow */ ParserToken& operator=(const ParserToken &a_Tok) { Assign(a_Tok); return *this; } //------------------------------------------------------------------------------ /** \brief Copy token information from argument. \throw nothrow */ void Assign(const ParserToken &a_Tok) { m_iCode = a_Tok.m_iCode; m_pTok = a_Tok.m_pTok; m_strTok = a_Tok.m_strTok; m_iIdx = a_Tok.m_iIdx; m_strVal = a_Tok.m_strVal; m_iType = a_Tok.m_iType; m_fVal = a_Tok.m_fVal; // create new callback object if a_Tok has one m_pCallback.reset(a_Tok.m_pCallback.get() ? a_Tok.m_pCallback->Clone() : 0); } //------------------------------------------------------------------------------ /** \brief Assign a token type. Token may not be of type value, variable or function. Those have seperate set functions. \pre [assert] a_iType!=cmVAR \pre [assert] a_iType!=cmVAL \pre [assert] a_iType!=cmFUNC \post m_fVal = 0 \post m_pTok = 0 */ ParserToken& Set(ECmdCode a_iType, const TString &a_strTok=TString()) { // The following types cant be set this way, they have special Set functions assert(a_iType!=cmVAR); assert(a_iType!=cmVAL); assert(a_iType!=cmFUNC); m_iCode = a_iType; m_iType = tpVOID; m_pTok = 0; m_strTok = a_strTok; m_iIdx = -1; return *this; } //------------------------------------------------------------------------------ /** \brief Set Callback type. */ ParserToken& Set(const ParserCallback &a_pCallback, const TString &a_sTok) { assert(a_pCallback.GetAddr()); m_iCode = a_pCallback.GetCode(); m_iType = tpVOID; m_strTok = a_sTok; m_pCallback.reset(new ParserCallback(a_pCallback)); m_pTok = 0; m_iIdx = -1; return *this; } //------------------------------------------------------------------------------ /** \brief Make this token a value token. Member variables not necessary for value tokens will be invalidated. \throw nothrow */ ParserToken& SetVal(TBase a_fVal, const TString &a_strTok=TString()) { m_iCode = cmVAL; m_iType = tpDBL; m_fVal = a_fVal; m_strTok = a_strTok; m_iIdx = -1; m_pTok = 0; m_pCallback.reset(0); return *this; } //------------------------------------------------------------------------------ /** \brief make this token a variable token. Member variables not necessary for variable tokens will be invalidated. \throw nothrow */ ParserToken& SetVar(TBase *a_pVar, const TString &a_strTok) { m_iCode = cmVAR; m_iType = tpDBL; m_strTok = a_strTok; m_iIdx = -1; m_pTok = (void*)a_pVar; m_pCallback.reset(0); return *this; } //------------------------------------------------------------------------------ /** \brief Make this token a variable token. Member variables not necessary for variable tokens will be invalidated. \throw nothrow */ ParserToken& SetString(const TString &a_strTok, std::size_t a_iSize) { m_iCode = cmSTRING; m_iType = tpSTR; m_strTok = a_strTok; m_iIdx = static_cast(a_iSize); m_pTok = 0; m_pCallback.reset(0); return *this; } //------------------------------------------------------------------------------ /** \brief Set an index associated with the token related data. In cmSTRFUNC - This is the index to a string table in the main parser. \param a_iIdx The index the string function result will take in the bytecode parser. \throw exception_type if #a_iIdx<0 or #m_iType!=cmSTRING */ void SetIdx(int a_iIdx) { if (m_iCode!=cmSTRING || a_iIdx<0) throw ParserError(ecINTERNAL_ERROR); m_iIdx = a_iIdx; } //------------------------------------------------------------------------------ /** \brief Return Index associated with the token related data. In cmSTRFUNC - This is the index to a string table in the main parser. \throw exception_type if #m_iIdx<0 or #m_iType!=cmSTRING \return The index the result will take in the Bytecode calculatin array (#m_iIdx). */ int GetIdx() const { if (m_iIdx<0 || m_iCode!=cmSTRING ) throw ParserError(ecINTERNAL_ERROR); return m_iIdx; } //------------------------------------------------------------------------------ /** \brief Return the token type. \return #m_iType \throw nothrow */ ECmdCode GetCode() const { if (m_pCallback.get()) { return m_pCallback->GetCode(); } else { return m_iCode; } } //------------------------------------------------------------------------------ ETypeCode GetType() const { if (m_pCallback.get()) { return m_pCallback->GetType(); } else { return m_iType; } } //------------------------------------------------------------------------------ int GetPri() const { if ( !m_pCallback.get()) throw ParserError(ecINTERNAL_ERROR); if ( m_pCallback->GetCode()!=cmOPRT_BIN && m_pCallback->GetCode()!=cmOPRT_INFIX) throw ParserError(ecINTERNAL_ERROR); return m_pCallback->GetPri(); } //------------------------------------------------------------------------------ EOprtAssociativity GetAssociativity() const { if (m_pCallback.get()==NULL || m_pCallback->GetCode()!=cmOPRT_BIN) throw ParserError(ecINTERNAL_ERROR); return m_pCallback->GetAssociativity(); } //------------------------------------------------------------------------------ /** \brief Return the address of the callback function assoziated with function and operator tokens. \return The pointer stored in #m_pTok. \throw exception_type if token type is non of:
    • cmFUNC
    • cmSTRFUNC
    • cmPOSTOP
    • cmINFIXOP
    • cmOPRT_BIN
    \sa ECmdCode */ generic_fun_type GetFuncAddr() const { return (m_pCallback.get()) ? (generic_fun_type)m_pCallback->GetAddr() : 0; } //------------------------------------------------------------------------------ /** \biref Get value of the token. Only applicable to variable and value tokens. \throw exception_type if token is no value/variable token. */ TBase GetVal() const { switch (m_iCode) { case cmVAL: return m_fVal; case cmVAR: return *((TBase*)m_pTok); default: throw ParserError(ecVAL_EXPECTED); } } //------------------------------------------------------------------------------ /** \brief Get address of a variable token. Valid only if m_iType==CmdVar. \throw exception_type if token is no variable token. */ TBase* GetVar() const { if (m_iCode!=cmVAR) throw ParserError(ecINTERNAL_ERROR); return (TBase*)m_pTok; } //------------------------------------------------------------------------------ /** \brief Return the number of function arguments. Valid only if m_iType==CmdFUNC. */ int GetArgCount() const { assert(m_pCallback.get()); if (!m_pCallback->GetAddr()) throw ParserError(ecINTERNAL_ERROR); return m_pCallback->GetArgc(); } //------------------------------------------------------------------------------ /** \brief Return the token identifier. If #m_iType is cmSTRING the token identifier is the value of the string argument for a string function. \return #m_strTok \throw nothrow \sa m_strTok */ const TString& GetAsString() const { return m_strTok; } }; } // namespace mu #endif IanniX-0.9.20/geometry/qmuparser/muParserTokenReader.cpp000066400000000000000000001007001317340345000232660ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2013 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include "muParserTokenReader.h" #include "muParserBase.h" /** \file \brief This file contains the parser token reader implementation. */ namespace mu { // Forward declaration class ParserBase; //--------------------------------------------------------------------------- /** \brief Copy constructor. \sa Assign \throw nothrow */ ParserTokenReader::ParserTokenReader(const ParserTokenReader &a_Reader) { Assign(a_Reader); } //--------------------------------------------------------------------------- /** \brief Assignment operator. Self assignment will be suppressed otherwise #Assign is called. \param a_Reader Object to copy to this token reader. \throw nothrow */ ParserTokenReader& ParserTokenReader::operator=(const ParserTokenReader &a_Reader) { if (&a_Reader!=this) Assign(a_Reader); return *this; } //--------------------------------------------------------------------------- /** \brief Assign state of a token reader to this token reader. \param a_Reader Object from which the state should be copied. \throw nothrow */ void ParserTokenReader::Assign(const ParserTokenReader &a_Reader) { m_pParser = a_Reader.m_pParser; m_strFormula = a_Reader.m_strFormula; m_iPos = a_Reader.m_iPos; m_iSynFlags = a_Reader.m_iSynFlags; m_UsedVar = a_Reader.m_UsedVar; m_pFunDef = a_Reader.m_pFunDef; m_pConstDef = a_Reader.m_pConstDef; m_pVarDef = a_Reader.m_pVarDef; m_pStrVarDef = a_Reader.m_pStrVarDef; m_pPostOprtDef = a_Reader.m_pPostOprtDef; m_pInfixOprtDef = a_Reader.m_pInfixOprtDef; m_pOprtDef = a_Reader.m_pOprtDef; m_bIgnoreUndefVar = a_Reader.m_bIgnoreUndefVar; m_vIdentFun = a_Reader.m_vIdentFun; m_pFactory = a_Reader.m_pFactory; m_pFactoryData = a_Reader.m_pFactoryData; m_iBrackets = a_Reader.m_iBrackets; m_cArgSep = a_Reader.m_cArgSep; m_fZero = a_Reader.m_fZero; m_lastTok = a_Reader.m_lastTok; } //--------------------------------------------------------------------------- /** \brief Constructor. Create a Token reader and bind it to a parser object. \pre [assert] a_pParser may not be NULL \post #m_pParser==a_pParser \param a_pParent Parent parser object of the token reader. */ ParserTokenReader::ParserTokenReader(ParserBase *a_pParent) :m_pParser(a_pParent) ,m_strFormula() ,m_iPos(0) ,m_iSynFlags(0) ,m_bIgnoreUndefVar(false) ,m_pFunDef(NULL) ,m_pPostOprtDef(NULL) ,m_pInfixOprtDef(NULL) ,m_pOprtDef(NULL) ,m_pConstDef(NULL) ,m_pStrVarDef(NULL) ,m_pVarDef(NULL) ,m_pFactory(NULL) ,m_pFactoryData(NULL) ,m_vIdentFun() ,m_UsedVar() ,m_fZero(0) ,m_iBrackets(0) ,m_lastTok() ,m_cArgSep(',') { assert(m_pParser); SetParent(m_pParser); } //--------------------------------------------------------------------------- /** \brief Create instance of a ParserTokenReader identical with this and return its pointer. This is a factory method the calling function must take care of the object destruction. \return A new ParserTokenReader object. \throw nothrow */ ParserTokenReader* ParserTokenReader::Clone(ParserBase *a_pParent) const { std::auto_ptr ptr(new ParserTokenReader(*this)); ptr->SetParent(a_pParent); return ptr.release(); } //--------------------------------------------------------------------------- ParserTokenReader::token_type& ParserTokenReader::SaveBeforeReturn(const token_type &tok) { m_lastTok = tok; return m_lastTok; } //--------------------------------------------------------------------------- void ParserTokenReader::AddValIdent(identfun_type a_pCallback) { // Use push_front is used to give user defined callbacks a higher priority than // the built in ones. Otherwise reading hex numbers would not work // since the "0" in "0xff" would always be read first making parsing of // the rest impossible. // reference: // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/4824956 m_vIdentFun.push_front(a_pCallback); } //--------------------------------------------------------------------------- void ParserTokenReader::SetVarCreator(facfun_type a_pFactory, void *pUserData) { m_pFactory = a_pFactory; m_pFactoryData = pUserData; } //--------------------------------------------------------------------------- /** \brief Return the current position of the token reader in the formula string. \return #m_iPos \throw nothrow */ int ParserTokenReader::GetPos() const { return m_iPos; } //--------------------------------------------------------------------------- /** \brief Return a reference to the formula. \return #m_strFormula \throw nothrow */ const string_type& ParserTokenReader::GetExpr() const { return m_strFormula; } //--------------------------------------------------------------------------- /** \brief Return a map containing the used variables only. */ varmap_type& ParserTokenReader::GetUsedVar() { return m_UsedVar; } //--------------------------------------------------------------------------- /** \brief Initialize the token Reader. Sets the formula position index to zero and set Syntax flags to default for initial formula parsing. \pre [assert] triggered if a_szFormula==0 */ void ParserTokenReader::SetFormula(const string_type &a_strFormula) { m_strFormula = a_strFormula; ReInit(); } //--------------------------------------------------------------------------- /** \brief Set Flag that controls behaviour in case of undefined variables being found. If true, the parser does not throw an exception if an undefined variable is found. otherwise it does. This variable is used internally only! It suppresses a "undefined variable" exception in GetUsedVar(). Those function should return a complete list of variables including those the are not defined by the time of it's call. */ void ParserTokenReader::IgnoreUndefVar(bool bIgnore) { m_bIgnoreUndefVar = bIgnore; } //--------------------------------------------------------------------------- /** \brief Reset the token reader to the start of the formula. The syntax flags will be reset to a value appropriate for the start of a formula. \post #m_iPos==0, #m_iSynFlags = noOPT | noBC | noPOSTOP | noSTR \throw nothrow \sa ESynCodes */ void ParserTokenReader::ReInit() { m_iPos = 0; m_iSynFlags = sfSTART_OF_LINE; m_iBrackets = 0; m_UsedVar.clear(); m_lastTok = token_type(); } //--------------------------------------------------------------------------- /** \brief Read the next token from the string. */ ParserTokenReader::token_type ParserTokenReader::ReadNextToken() { assert(m_pParser); const char_type *szFormula = m_strFormula.c_str(); token_type tok; // Ignore all non printable characters when reading the expression while (szFormula[m_iPos]>0 && szFormula[m_iPos]<=0x20) ++m_iPos; if ( IsEOF(tok) ) return SaveBeforeReturn(tok); // Check for end of formula if ( IsOprt(tok) ) return SaveBeforeReturn(tok); // Check for user defined binary operator if ( IsFunTok(tok) ) return SaveBeforeReturn(tok); // Check for function token if ( IsBuiltIn(tok) ) return SaveBeforeReturn(tok); // Check built in operators / tokens if ( IsArgSep(tok) ) return SaveBeforeReturn(tok); // Check for function argument separators if ( IsValTok(tok) ) return SaveBeforeReturn(tok); // Check for values / constant tokens if ( IsVarTok(tok) ) return SaveBeforeReturn(tok); // Check for variable tokens if ( IsStrVarTok(tok) ) return SaveBeforeReturn(tok); // Check for string variables if ( IsString(tok) ) return SaveBeforeReturn(tok); // Check for String tokens if ( IsInfixOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators if ( IsPostOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators // Check String for undefined variable token. Done only if a // flag is set indicating to ignore undefined variables. // This is a way to conditionally avoid an error if // undefined variables occur. // (The GetUsedVar function must suppress the error for // undefined variables in order to collect all variable // names including the undefined ones.) if ( (m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok) ) return SaveBeforeReturn(tok); // Check for unknown token // // !!! From this point on there is no exit without an exception possible... // string_type strTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); if (iEnd!=m_iPos) Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok); Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.substr(m_iPos)); return token_type(); // never reached } //--------------------------------------------------------------------------- void ParserTokenReader::SetParent(ParserBase *a_pParent) { m_pParser = a_pParent; m_pFunDef = &a_pParent->m_FunDef; m_pOprtDef = &a_pParent->m_OprtDef; m_pInfixOprtDef = &a_pParent->m_InfixOprtDef; m_pPostOprtDef = &a_pParent->m_PostOprtDef; m_pVarDef = &a_pParent->m_VarDef; m_pStrVarDef = &a_pParent->m_StrVarDef; m_pConstDef = &a_pParent->m_ConstDef; } //--------------------------------------------------------------------------- /** \brief Extract all characters that belong to a certain charset. \param a_szCharSet [in] Const char array of the characters allowed in the token. \param a_strTok [out] The string that consists entirely of characters listed in a_szCharSet. \param a_iPos [in] Position in the string from where to start reading. \return The Position of the first character not listed in a_szCharSet. \throw nothrow */ int ParserTokenReader::ExtractToken(const char_type *a_szCharSet, string_type &a_sTok, int a_iPos) const { int iEnd = (int)m_strFormula.find_first_not_of(a_szCharSet, a_iPos); if (iEnd==(int)string_type::npos) iEnd = (int)m_strFormula.length(); // Assign token string if there was something found if (a_iPos!=iEnd) a_sTok = string_type( m_strFormula.begin()+a_iPos, m_strFormula.begin()+iEnd); return iEnd; } //--------------------------------------------------------------------------- /** \brief Check Expression for the presence of a binary operator token. Userdefined binary operator "++" gives inconsistent parsing result for the equations "a++b" and "a ++ b" if alphabetic characters are allowed in operator tokens. To avoid this this function checks specifically for operator tokens. */ int ParserTokenReader::ExtractOperatorToken(string_type &a_sTok, int a_iPos) const { // Changed as per Issue 6: https://code.google.com/p/muparser/issues/detail?id=6 int iEnd = (int)m_strFormula.find_first_not_of(m_pParser->ValidOprtChars(), a_iPos); if (iEnd==(int)string_type::npos) iEnd = (int)m_strFormula.length(); // Assign token string if there was something found if (a_iPos!=iEnd) { a_sTok = string_type( m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd); return iEnd; } else { // There is still the chance of having to deal with an operator consisting exclusively // of alphabetic characters. return ExtractToken(MUP_CHARS, a_sTok, a_iPos); } } //--------------------------------------------------------------------------- /** \brief Check if a built in operator or other token can be found \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. \return true if an operator token has been found. */ bool ParserTokenReader::IsBuiltIn(token_type &a_Tok) { const char_type **const pOprtDef = m_pParser->GetOprtDef(), *const szFormula = m_strFormula.c_str(); // Compare token with function and operator strings // check string for operator/function for (int i=0; pOprtDef[i]; i++) { std::size_t len( std::char_traits::length(pOprtDef[i]) ); if ( string_type(pOprtDef[i]) == string_type(szFormula + m_iPos, szFormula + m_iPos + len) ) { switch(i) { //case cmAND: //case cmOR: //case cmXOR: case cmLAND: case cmLOR: case cmLT: case cmGT: case cmLE: case cmGE: case cmNEQ: case cmEQ: case cmADD: case cmSUB: case cmMUL: case cmDIV: case cmPOW: case cmASSIGN: //if (len!=sTok.length()) // continue; // The assignment operator need special treatment if (i==cmASSIGN && m_iSynFlags & noASSIGN) Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); if (!m_pParser->HasBuiltInOprt()) continue; if (m_iSynFlags & noOPT) { // Maybe its an infix operator not an operator // Both operator types can share characters in // their identifiers if ( IsInfixOpTok(a_Tok) ) return true; Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); } m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE | noEND; break; case cmBO: if (m_iSynFlags & noBO) Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); if (m_lastTok.GetCode()==cmFUNC) m_iSynFlags = noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; else m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN| noIF | noELSE; ++m_iBrackets; break; case cmBC: if (m_iSynFlags & noBC) Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN; if (--m_iBrackets<0) Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); break; case cmELSE: if (m_iSynFlags & noELSE) Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; break; case cmIF: if (m_iSynFlags & noIF) Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; break; default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing... Error(ecINTERNAL_ERROR); } // switch operator id m_iPos += (int)len; a_Tok.Set( (ECmdCode)i, pOprtDef[i] ); return true; } // if operator string found } // end of for all operator strings return false; } //--------------------------------------------------------------------------- bool ParserTokenReader::IsArgSep(token_type &a_Tok) { const char_type* szFormula = m_strFormula.c_str(); if (szFormula[m_iPos]==m_cArgSep) { // copy the separator into null terminated string char_type szSep[2]; szSep[0] = m_cArgSep; szSep[1] = 0; if (m_iSynFlags & noARG_SEP) Error(ecUNEXPECTED_ARG_SEP, m_iPos, szSep); m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN; m_iPos++; a_Tok.Set(cmARG_SEP, szSep); return true; } return false; } //--------------------------------------------------------------------------- /** \brief Check for End of Formula. \return true if an end of formula is found false otherwise. \param a_Tok [out] If an eof is found the corresponding token will be stored there. \throw nothrow \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsString, IsInfixOpTok, IsPostOpTok */ bool ParserTokenReader::IsEOF(token_type &a_Tok) { const char_type* szFormula = m_strFormula.c_str(); // check for EOF if ( !szFormula[m_iPos] /*|| szFormula[m_iPos] == '\n'*/) { if ( m_iSynFlags & noEND ) Error(ecUNEXPECTED_EOF, m_iPos); if (m_iBrackets>0) Error(ecMISSING_PARENS, m_iPos, _T(")")); m_iSynFlags = 0; a_Tok.Set(cmEND); return true; } return false; } //--------------------------------------------------------------------------- /** \brief Check if a string position contains a unary infix operator. \return true if a function token has been found false otherwise. */ bool ParserTokenReader::IsInfixOpTok(token_type &a_Tok) { string_type sTok; int iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, m_iPos); if (iEnd==m_iPos) return false; // iterate over all postfix operator strings funmap_type::const_reverse_iterator it = m_pInfixOprtDef->rbegin(); for ( ; it!=m_pInfixOprtDef->rend(); ++it) { if (sTok.find(it->first)!=0) continue; a_Tok.Set(it->second, it->first); m_iPos += (int)it->first.length(); if (m_iSynFlags & noINFIXOP) Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; return true; } return false; /* a_Tok.Set(item->second, sTok); m_iPos = (int)iEnd; if (m_iSynFlags & noINFIXOP) Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; return true; */ } //--------------------------------------------------------------------------- /** \brief Check whether the token at a given position is a function token. \param a_Tok [out] If a value token is found it will be placed here. \throw ParserException if Syntaxflags do not allow a function at a_iPos \return true if a function token has been found false otherwise. \pre [assert] m_pParser!=0 */ bool ParserTokenReader::IsFunTok(token_type &a_Tok) { string_type strTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); if (iEnd==m_iPos) return false; funmap_type::const_iterator item = m_pFunDef->find(strTok); if (item==m_pFunDef->end()) return false; // Check if the next sign is an opening bracket const char_type *szFormula = m_strFormula.c_str(); if (szFormula[iEnd]!='(') return false; a_Tok.Set(item->second, strTok); m_iPos = (int)iEnd; if (m_iSynFlags & noFUN) Error(ecUNEXPECTED_FUN, m_iPos-(int)a_Tok.GetAsString().length(), a_Tok.GetAsString()); m_iSynFlags = noANY ^ noBO; return true; } //--------------------------------------------------------------------------- /** \brief Check if a string position contains a binary operator. \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. \return true if an operator token has been found. */ bool ParserTokenReader::IsOprt(token_type &a_Tok) { const char_type *const szExpr = m_strFormula.c_str(); string_type strTok; int iEnd = ExtractOperatorToken(strTok, m_iPos); if (iEnd==m_iPos) return false; // Check if the operator is a built in operator, if so ignore it here const char_type **const pOprtDef = m_pParser->GetOprtDef(); for (int i=0; m_pParser->HasBuiltInOprt() && pOprtDef[i]; ++i) { if (string_type(pOprtDef[i])==strTok) return false; } // Note: // All tokens in oprt_bin_maptype are have been sorted by their length // Long operators must come first! Otherwise short names (like: "add") that // are part of long token names (like: "add123") will be found instead // of the long ones. // Length sorting is done with ascending length so we use a reverse iterator here. funmap_type::const_reverse_iterator it = m_pOprtDef->rbegin(); for ( ; it!=m_pOprtDef->rend(); ++it) { const string_type &sID = it->first; if ( sID == string_type(szExpr + m_iPos, szExpr + m_iPos + sID.length()) ) { a_Tok.Set(it->second, strTok); // operator was found if (m_iSynFlags & noOPT) { // An operator was found but is not expected to occur at // this position of the formula, maybe it is an infix // operator, not a binary operator. Both operator types // can share characters in their identifiers. if ( IsInfixOpTok(a_Tok) ) return true; else { // nope, no infix operator return false; //Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); } } m_iPos += (int)sID.length(); m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noEND | noASSIGN; return true; } } return false; } //--------------------------------------------------------------------------- /** \brief Check if a string position contains a unary post value operator. */ bool ParserTokenReader::IsPostOpTok(token_type &a_Tok) { // Do not check for postfix operators if they are not allowed at // the current expression index. // // This will fix the bug reported here: // // http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979 // if (m_iSynFlags & noPOSTOP) return false; // // Tricky problem with equations like "3m+5": // m is a postfix operator, + is a valid sign for postfix operators and // for binary operators parser detects "m+" as operator string and // finds no matching postfix operator. // // This is a special case so this routine slightly differs from the other // token readers. // Test if there could be a postfix operator string_type sTok; int iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, m_iPos); if (iEnd==m_iPos) return false; // iterate over all postfix operator strings funmap_type::const_reverse_iterator it = m_pPostOprtDef->rbegin(); for ( ; it!=m_pPostOprtDef->rend(); ++it) { if (sTok.find(it->first)!=0) continue; a_Tok.Set(it->second, sTok); m_iPos += (int)it->first.length(); m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN; return true; } return false; } //--------------------------------------------------------------------------- /** \brief Check whether the token at a given position is a value token. Value tokens are either values or constants. \param a_Tok [out] If a value token is found it will be placed here. \return true if a value token has been found. */ bool ParserTokenReader::IsValTok(token_type &a_Tok) { assert(m_pConstDef); assert(m_pParser); string_type strTok; value_type fVal(0); int iEnd(0); // 2.) Check for user defined constant // Read everything that could be a constant name iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); if (iEnd!=m_iPos) { valmap_type::const_iterator item = m_pConstDef->find(strTok); if (item!=m_pConstDef->end()) { m_iPos = iEnd; a_Tok.SetVal(item->second, strTok); if (m_iSynFlags & noVAL) Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; return true; } } // 3.call the value recognition functions provided by the user // Call user defined value recognition functions std::list::const_iterator item = m_vIdentFun.begin(); for (item = m_vIdentFun.begin(); item!=m_vIdentFun.end(); ++item) { int iStart = m_iPos; if ( (*item)(m_strFormula.c_str() + m_iPos, &m_iPos, &fVal)==1 ) { // 2013-11-27 Issue 2: https://code.google.com/p/muparser/issues/detail?id=2 strTok.assign(m_strFormula.c_str(), iStart, m_iPos-iStart); if (m_iSynFlags & noVAL) Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); a_Tok.SetVal(fVal, strTok); m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; return true; } } return false; } //--------------------------------------------------------------------------- /** \brief Check wheter a token at a given position is a variable token. \param a_Tok [out] If a variable token has been found it will be placed here. \return true if a variable token has been found. */ bool ParserTokenReader::IsVarTok(token_type &a_Tok) { if (m_pVarDef->empty()) return false; string_type strTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); if (iEnd==m_iPos) return false; varmap_type::const_iterator item = m_pVarDef->find(strTok); if (item==m_pVarDef->end()) return false; if (m_iSynFlags & noVAR) Error(ecUNEXPECTED_VAR, m_iPos, strTok); m_pParser->OnDetectVar(&m_strFormula, m_iPos, iEnd); m_iPos = iEnd; a_Tok.SetVar(item->second, strTok); m_UsedVar[item->first] = item->second; // Add variable to used-var-list m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR; // Zur Info hier die SynFlags von IsVal(): // m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; return true; } //--------------------------------------------------------------------------- bool ParserTokenReader::IsStrVarTok(token_type &a_Tok) { if (!m_pStrVarDef || m_pStrVarDef->empty()) return false; string_type strTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); if (iEnd==m_iPos) return false; strmap_type::const_iterator item = m_pStrVarDef->find(strTok); if (item==m_pStrVarDef->end()) return false; if (m_iSynFlags & noSTR) Error(ecUNEXPECTED_VAR, m_iPos, strTok); m_iPos = iEnd; if (!m_pParser->m_vStringVarBuf.size()) Error(ecINTERNAL_ERROR); a_Tok.SetString(m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size() ); m_iSynFlags = noANY ^ ( noBC | noOPT | noEND | noARG_SEP); return true; } //--------------------------------------------------------------------------- /** \brief Check wheter a token at a given position is an undefined variable. \param a_Tok [out] If a variable tom_pParser->m_vStringBufken has been found it will be placed here. \return true if a variable token has been found. \throw nothrow */ bool ParserTokenReader::IsUndefVarTok(token_type &a_Tok) { string_type strTok; int iEnd( ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos) ); if ( iEnd==m_iPos ) return false; if (m_iSynFlags & noVAR) { // 20061021 added token string strTok instead of a_Tok.GetAsString() as the // token identifier. // related bug report: // http://sourceforge.net/tracker/index.php?func=detail&aid=1578779&group_id=137191&atid=737979 Error(ecUNEXPECTED_VAR, m_iPos - (int)a_Tok.GetAsString().length(), strTok); } // If a factory is available implicitely create new variables if (m_pFactory) { value_type *fVar = m_pFactory(strTok.c_str(), m_pFactoryData); a_Tok.SetVar(fVar, strTok ); // Do not use m_pParser->DefineVar( strTok, fVar ); // in order to define the new variable, it will clear the // m_UsedVar array which will kill previously defined variables // from the list // This is safe because the new variable can never override an existing one // because they are checked first! (*m_pVarDef)[strTok] = fVar; m_UsedVar[strTok] = fVar; // Add variable to used-var-list } else { a_Tok.SetVar((value_type*)&m_fZero, strTok); m_UsedVar[strTok] = 0; // Add variable to used-var-list } m_iPos = iEnd; // Call the variable factory in order to let it define a new parser variable m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR; return true; } //--------------------------------------------------------------------------- /** \brief Check wheter a token at a given position is a string. \param a_Tok [out] If a variable token has been found it will be placed here. \return true if a string token has been found. \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsEOF, IsInfixOpTok, IsPostOpTok \throw nothrow */ bool ParserTokenReader::IsString(token_type &a_Tok) { if (m_strFormula[m_iPos]!='"') return false; string_type strBuf(&m_strFormula[m_iPos+1]); std::size_t iEnd(0), iSkip(0); // parser over escaped '\"' end replace them with '"' for(iEnd=(int)strBuf.find( _T("\"") ); iEnd!=0 && iEnd!=string_type::npos; iEnd=(int)strBuf.find( _T("\""), iEnd)) { if (strBuf[iEnd-1]!='\\') break; strBuf.replace(iEnd-1, 2, _T("\"") ); iSkip++; } if (iEnd==string_type::npos) Error(ecUNTERMINATED_STRING, m_iPos, _T("\"") ); string_type strTok(strBuf.begin(), strBuf.begin()+iEnd); if (m_iSynFlags & noSTR) Error(ecUNEXPECTED_STR, m_iPos, strTok); m_pParser->m_vStringBuf.push_back(strTok); // Store string in internal buffer a_Tok.SetString(strTok, m_pParser->m_vStringBuf.size()); m_iPos += (int)strTok.length() + 2 + (int)iSkip; // +2 wg Anfhrungszeichen; +iSkip fr entfernte escape zeichen m_iSynFlags = noANY ^ ( noARG_SEP | noBC | noOPT | noEND ); return true; } //--------------------------------------------------------------------------- /** \brief Create an error containing the parse error position. This function will create an Parser Exception object containing the error text and its position. \param a_iErrc [in] The error code of type #EErrorCodes. \param a_iPos [in] The position where the error was detected. \param a_strTok [in] The token string representation associated with the error. \throw ParserException always throws thats the only purpose of this function. */ void ParserTokenReader::Error( EErrorCodes a_iErrc, int a_iPos, const string_type &a_sTok) const { m_pParser->Error(a_iErrc, a_iPos, a_sTok); } //--------------------------------------------------------------------------- void ParserTokenReader::SetArgSep(char_type cArgSep) { m_cArgSep = cArgSep; } //--------------------------------------------------------------------------- char_type ParserTokenReader::GetArgSep() const { return m_cArgSep; } } // namespace mu IanniX-0.9.20/geometry/qmuparser/muParserTokenReader.h000066400000000000000000000134441317340345000227430ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2013 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_TOKEN_READER_H #define MU_PARSER_TOKEN_READER_H #include #include #include #include #include #include #include #include #include "muParserDef.h" #include "muParserToken.h" /** \file \brief This file contains the parser token reader definition. */ namespace mu { // Forward declaration class ParserBase; /** \brief Token reader for the ParserBase class. */ class ParserTokenReader { private: typedef ParserToken token_type; public: ParserTokenReader(ParserBase *a_pParent); ParserTokenReader* Clone(ParserBase *a_pParent) const; void AddValIdent(identfun_type a_pCallback); void SetVarCreator(facfun_type a_pFactory, void *pUserData); void SetFormula(const string_type &a_strFormula); void SetArgSep(char_type cArgSep); int GetPos() const; const string_type& GetExpr() const; varmap_type& GetUsedVar(); char_type GetArgSep() const; void IgnoreUndefVar(bool bIgnore); void ReInit(); token_type ReadNextToken(); private: /** \brief Syntax codes. The syntax codes control the syntax check done during the first time parsing of the expression string. They are flags that indicate which tokens are allowed next if certain tokens are identified. */ enum ESynCodes { noBO = 1 << 0, ///< to avoid i.e. "cos(7)(" noBC = 1 << 1, ///< to avoid i.e. "sin)" or "()" noVAL = 1 << 2, ///< to avoid i.e. "tan 2" or "sin(8)3.14" noVAR = 1 << 3, ///< to avoid i.e. "sin a" or "sin(8)a" noARG_SEP = 1 << 4, ///< to avoid i.e. ",," or "+," ... noFUN = 1 << 5, ///< to avoid i.e. "sqrt cos" or "(1)sin" noOPT = 1 << 6, ///< to avoid i.e. "(+)" noPOSTOP = 1 << 7, ///< to avoid i.e. "(5!!)" "sin!" noINFIXOP = 1 << 8, ///< to avoid i.e. "++4" "!!4" noEND = 1 << 9, ///< to avoid unexpected end of formula noSTR = 1 << 10, ///< to block numeric arguments on string functions noASSIGN = 1 << 11, ///< to block assignement to constant i.e. "4=7" noIF = 1 << 12, noELSE = 1 << 13, sfSTART_OF_LINE = noOPT | noBC | noPOSTOP | noASSIGN | noIF | noELSE | noARG_SEP, noANY = ~0 ///< All of he above flags set }; ParserTokenReader(const ParserTokenReader &a_Reader); ParserTokenReader& operator=(const ParserTokenReader &a_Reader); void Assign(const ParserTokenReader &a_Reader); void SetParent(ParserBase *a_pParent); int ExtractToken(const char_type *a_szCharSet, string_type &a_strTok, int a_iPos) const; int ExtractOperatorToken(string_type &a_sTok, int a_iPos) const; bool IsBuiltIn(token_type &a_Tok); bool IsArgSep(token_type &a_Tok); bool IsEOF(token_type &a_Tok); bool IsInfixOpTok(token_type &a_Tok); bool IsFunTok(token_type &a_Tok); bool IsPostOpTok(token_type &a_Tok); bool IsOprt(token_type &a_Tok); bool IsValTok(token_type &a_Tok); bool IsVarTok(token_type &a_Tok); bool IsStrVarTok(token_type &a_Tok); bool IsUndefVarTok(token_type &a_Tok); bool IsString(token_type &a_Tok); void Error(EErrorCodes a_iErrc, int a_iPos = -1, const string_type &a_sTok = string_type() ) const; token_type& SaveBeforeReturn(const token_type &tok); ParserBase *m_pParser; string_type m_strFormula; int m_iPos; int m_iSynFlags; bool m_bIgnoreUndefVar; const funmap_type *m_pFunDef; const funmap_type *m_pPostOprtDef; const funmap_type *m_pInfixOprtDef; const funmap_type *m_pOprtDef; const valmap_type *m_pConstDef; const strmap_type *m_pStrVarDef; varmap_type *m_pVarDef; ///< The only non const pointer to parser internals facfun_type m_pFactory; void *m_pFactoryData; std::list m_vIdentFun; ///< Value token identification function varmap_type m_UsedVar; value_type m_fZero; ///< Dummy value of zero, referenced by undefined variables int m_iBrackets; token_type m_lastTok; char_type m_cArgSep; ///< The character used for separating function arguments }; } // namespace mu #endif IanniX-0.9.20/gui/000077500000000000000000000000001317340345000135545ustar00rootroot00000000000000IanniX-0.9.20/gui/qffmpeg/000077500000000000000000000000001317340345000152015ustar00rootroot00000000000000IanniX-0.9.20/gui/qffmpeg/QVideoDecoder.cpp000066400000000000000000000420631317340345000203670ustar00rootroot00000000000000/* QTFFmpegWrapper - QT FFmpeg Wrapper Class Copyright (C) 2009,2010: Daniel Roggen, droggen@gmail.com All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "QVideoDecoder.h" #include #include #include "ffmpeg.h" /****************************************************************************** ******************************************************************************* * QVideoDecoder QVideoDecoder QVideoDecoder QVideoDecoder QVideoDecoder ******************************************************************************* ******************************************************************************/ /****************************************************************************** * PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC ******************************************************************************/ /** \brief Constructor - opens a video on later openFile call **/ QVideoDecoder::QVideoDecoder() { InitVars(); initCodec(); } /** \brief Constructor - opens directly a video **/ QVideoDecoder::QVideoDecoder(QString file) { InitVars(); initCodec(); ok = openFile(file.toStdString().c_str()); } QVideoDecoder::~QVideoDecoder() { close(); } void QVideoDecoder::InitVars() { ok=false; pFormatCtx=0; pCodecCtx=0; pCodec=0; pFrame=0; pFrameRGB=0; buffer=0; img_convert_ctx=0; } void QVideoDecoder::close() { if(!ok) return; // Free the RGB image if(buffer) delete [] buffer; // Free the YUV frame if(pFrame) av_free(pFrame); // Free the RGB frame if(pFrameRGB) av_free(pFrameRGB); // Close the codec if(pCodecCtx) avcodec_close(pCodecCtx); // Close the video file if(pFormatCtx) av_close_input_file(pFormatCtx); InitVars(); } bool QVideoDecoder::initCodec() { ffmpeg::avcodec_init(); ffmpeg::avcodec_register_all(); ffmpeg::av_register_all(); qDebug("License: %s\n",ffmpeg::avformat_license()); qDebug("AVCodec version %d\n",ffmpeg::avformat_version()); qDebug("AVFormat configuration: %s\n",ffmpeg::avformat_configuration()); return true; } bool QVideoDecoder::openFile(QString filename) { // Close last video.. close(); LastLastFrameTime=INT_MIN; // Last last must be small to handle the seek well LastFrameTime=0; LastLastFrameNumber=INT_MIN; LastFrameNumber=0; DesiredFrameTime=DesiredFrameNumber=0; LastFrameOk=false; // Open video file if(av_open_input_file(&pFormatCtx, filename.toStdString().c_str(), NULL, 0, NULL)!=0) return false; // Couldn't open file // Retrieve stream information if(av_find_stream_info(pFormatCtx)<0) return false; // Couldn't find stream information // Dump information about file onto standard error dump_format(pFormatCtx, 0, filename.toStdString().c_str(), false); // Find the first video stream videoStream=-1; for(unsigned i=0; inb_streams; i++) if(pFormatCtx->streams[i]->codec->codec_type==ffmpeg::AVMEDIA_TYPE_VIDEO) { videoStream=i; break; } if(videoStream==-1) return false; // Didn't find a video stream // Get a pointer to the codec context for the video stream pCodecCtx=pFormatCtx->streams[videoStream]->codec; // Find the decoder for the video stream pCodec=avcodec_find_decoder(pCodecCtx->codec_id); if(pCodec==NULL) return false; // Codec not found // Open codec if(avcodec_open(pCodecCtx, pCodec)<0) return false; // Could not open codec // Hack to correct wrong frame rates that seem to be generated by some // codecs if(pCodecCtx->time_base.num>1000 && pCodecCtx->time_base.den==1) pCodecCtx->time_base.den=1000; // Allocate video frame pFrame=ffmpeg::avcodec_alloc_frame(); // Allocate an AVFrame structure pFrameRGB=ffmpeg::avcodec_alloc_frame(); if(pFrameRGB==NULL) return false; // Determine required buffer size and allocate buffer numBytes=ffmpeg::avpicture_get_size(ffmpeg::PIX_FMT_RGB24, pCodecCtx->width,pCodecCtx->height); buffer=new uint8_t[numBytes]; // Assign appropriate parts of buffer to image planes in pFrameRGB avpicture_fill((ffmpeg::AVPicture *)pFrameRGB, buffer, ffmpeg::PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height); ok=true; return true; } bool QVideoDecoder::isOk() { return ok; } /** Decodes the video stream until the first frame with number larger or equal than 'after' is found. Returns: - true if a frame is found, false otherwise. - the image as a QImage if img is non-null - time frame time, if frametime is non-null - the frame number, if framenumber is non-null All times are in milliseconds. **/ bool QVideoDecoder::decodeSeekFrame(int after) { if(!ok) return false; //qDebug("decodeSeekFrame. after: %d. LLT: %d. LT: %d. LLF: %d. LF: %d. LastFrameOk: %d.\n",after,LastLastFrameTime,LastFrameTime,LastLastFrameNumber,LastFrameNumber,(int)LastFrameOk); // If the last decoded frame satisfies the time condition we return it //if( after!=-1 && ( LastDataInvalid==false && after>=LastLastFrameTime && after <= LastFrameTime)) if( after!=-1 && ( LastFrameOk==true && after>=LastLastFrameNumber && after <= LastFrameNumber)) { // This is the frame we want to return // Compute desired frame time ffmpeg::AVRational millisecondbase = {1, 1000}; DesiredFrameTime = ffmpeg::av_rescale_q(after,pFormatCtx->streams[videoStream]->time_base,millisecondbase); //qDebug("Returning already available frame %d @ %d. DesiredFrameTime: %d\n",LastFrameNumber,LastFrameTime,DesiredFrameTime); return true; } // The last decoded frame wasn't ok; either we need any new frame (after=-1), or a specific new frame with time>after bool done=false; while(!done) { // Read a frame if(av_read_frame(pFormatCtx, &packet)<0) return false; // Frame read failed (e.g. end of stream) //qDebug("Packet of stream %d, size %d\n",packet.stream_index,packet.size); if(packet.stream_index==videoStream) { // Is this a packet from the video stream -> decode video frame int frameFinished; avcodec_decode_video2(pCodecCtx,pFrame,&frameFinished,&packet); //qDebug("used %d out of %d bytes\n",len,packet.size); //qDebug("Frame type: "); //if(pFrame->pict_type == FF_B_TYPE) // qDebug("B\n"); //else if (pFrame->pict_type == FF_I_TYPE) // qDebug("I\n"); //else // qDebug("P\n"); /*qDebug("codecctx time base: num: %d den: %d\n",pCodecCtx->time_base.num,pCodecCtx->time_base.den); qDebug("formatctx time base: num: %d den: %d\n",pFormatCtx->streams[videoStream]->time_base.num,pFormatCtx->streams[videoStream]->time_base.den); qDebug("pts: %ld\n",pts); qDebug("dts: %ld\n",dts);*/ // Did we get a video frame? if(frameFinished) { ffmpeg::AVRational millisecondbase = {1, 1000}; int f = packet.dts; int t = ffmpeg::av_rescale_q(packet.dts,pFormatCtx->streams[videoStream]->time_base,millisecondbase); if(LastFrameOk==false) { LastFrameOk=true; LastLastFrameTime=LastFrameTime=t; LastLastFrameNumber=LastFrameNumber=f; } else { // If we decoded 2 frames in a row, the last times are okay LastLastFrameTime = LastFrameTime; LastLastFrameNumber = LastFrameNumber; LastFrameTime=t; LastFrameNumber=f; } //qDebug("Frame %d @ %d. LastLastT: %d. LastLastF: %d. LastFrameOk: %d\n",LastFrameNumber,LastFrameTime,LastLastFrameTime,LastLastFrameNumber,(int)LastFrameOk); // Is this frame the desired frame? if(after==-1 || LastFrameNumber>=after) { // It's the desired frame // Convert the image format (init the context the first time) int w = pCodecCtx->width; int h = pCodecCtx->height; img_convert_ctx = ffmpeg::sws_getCachedContext(img_convert_ctx,w, h, pCodecCtx->pix_fmt, w, h, ffmpeg::PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL); if(img_convert_ctx == NULL) { qDebug("Cannot initialize the conversion context!\n"); return false; } ffmpeg::sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); // Convert the frame to QImage LastFrame=QImage(w,h,QImage::Format_RGB888); for(int y=0;ydata[0]+y*pFrameRGB->linesize[0],w*3); // Set the time DesiredFrameTime = ffmpeg::av_rescale_q(after,pFormatCtx->streams[videoStream]->time_base,millisecondbase); LastFrameOk=true; done = true; } // frame of interest } // frameFinished } // stream_index==videoStream av_free_packet(&packet); // Free the packet that was allocated by av_read_frame } //qDebug("Returning new frame %d @ %d. LastLastT: %d. LastLastF: %d. LastFrameOk: %d\n",LastFrameNumber,LastFrameTime,LastLastFrameTime,LastLastFrameNumber,(int)LastFrameOk); //qDebug("\n"); return done; // done indicates whether or not we found a frame } /** \brief Decodes the next frame in the video stream **/ bool QVideoDecoder::seekNextFrame() { bool ret = decodeSeekFrame(DesiredFrameNumber+1); if(ret) DesiredFrameNumber++; // Only updates the DesiredFrameNumber if we were successful in getting that frame else LastFrameOk=false; // We didn't find the next frame (e.g. seek out of range) - mark we don't know where we are. return ret; } /** \brief Seek to millisecond **/ bool QVideoDecoder::seekMs(int tsms) { if(!ok) return false; //qDebug("**** SEEK TO ms %d. LLT: %d. LT: %d. LLF: %d. LF: %d. LastFrameOk: %d\n",tsms,LastLastFrameTime,LastFrameTime,LastLastFrameNumber,LastFrameNumber,(int)LastFrameOk); // Convert time into frame number DesiredFrameNumber = ffmpeg::av_rescale(tsms,pFormatCtx->streams[videoStream]->time_base.den,pFormatCtx->streams[videoStream]->time_base.num); DesiredFrameNumber/=1000; return seekFrame(DesiredFrameNumber); } /** \brief Seek to frame **/ bool QVideoDecoder::seekFrame(int64_t frame) { if(!ok) return false; //qDebug("**** seekFrame to %d. LLT: %d. LT: %d. LLF: %d. LF: %d. LastFrameOk: %d\n",(int)frame,LastLastFrameTime,LastFrameTime,LastLastFrameNumber,LastFrameNumber,(int)LastFrameOk); // Seek if: // - we don't know where we are (Ok=false) // - we know where we are but: // - the desired frame is after the last decoded frame (this could be optimized: if the distance is small, calling decodeSeekFrame may be faster than seeking from the last key frame) // - the desired frame is smaller or equal than the previous to the last decoded frame. Equal because if frame==LastLastFrameNumber we don't want the LastFrame, but the one before->we need to seek there if( (LastFrameOk==false) || ((LastFrameOk==true) && (frame<=LastLastFrameNumber || frame>LastFrameNumber) ) ) { //qDebug("\t avformat_seek_file\n"); if(ffmpeg::avformat_seek_file(pFormatCtx,videoStream,0,frame,frame,AVSEEK_FLAG_FRAME)<0) return false; avcodec_flush_buffers(pCodecCtx); DesiredFrameNumber = frame; LastFrameOk=false; } //qDebug("\t decodeSeekFrame\n"); return decodeSeekFrame(frame); return true; } bool QVideoDecoder::getFrame(QImage&img,int *effectiveframenumber,int *effectiveframetime,int *desiredframenumber,int *desiredframetime) { img = LastFrame; if(effectiveframenumber) *effectiveframenumber = LastFrameNumber; if(effectiveframetime) *effectiveframetime = LastFrameTime; if(desiredframenumber) *desiredframenumber = DesiredFrameNumber; if(desiredframetime) *desiredframetime = DesiredFrameTime; //qDebug("getFrame. Returning valid? %s. Desired %d @ %d. Effective %d @ %d\n",LastFrameOk?"yes":"no",DesiredFrameNumber,DesiredFrameTime,LastFrameNumber,LastFrameTime); return LastFrameOk; } /** \brief Debug function: saves a frame as PPM **/ void QVideoDecoder::saveFramePPM(ffmpeg::AVFrame *pFrame, int width, int height, int iFrame) { FILE *pFile; char szFilename[32]; int y; // Open file sprintf(szFilename, "frame%d.ppm", iFrame); pFile=fopen(szFilename, "wb"); if(pFile==NULL) return; // Write header fprintf(pFile, "P6\n%d %d\n255\n", width, height); // Write pixel data for(y=0; ydata[0]+y*pFrame->linesize[0], 1, width*3, pFile); // Close file fclose(pFile); } void QVideoDecoder::dumpFormat(ffmpeg::AVFormatContext *ic, int index, const char *url, int is_output) { //int i; uint8_t *printed = (uint8_t*)ffmpeg::av_mallocz(ic->nb_streams); if (ic->nb_streams && !printed) return; qDebug("AV_TIME_BASE: %d\n",AV_TIME_BASE); qDebug("%s #%d, %s,\n %s '%s':\n", is_output ? "Output" : "Input", index, is_output ? ic->oformat->name : ic->iformat->name, is_output ? "to" : "from", url); if (!is_output) { qDebug(" Duration: "); //if (ic->duration != AV_NOPTS_VALUE) { int hours, mins, secs, us; secs = ic->duration / AV_TIME_BASE; us = ic->duration % AV_TIME_BASE; mins = secs / 60; secs %= 60; hours = mins / 60; mins %= 60; qDebug("%02d:%02d:%02d.%02d\n", hours, mins, secs, (100 * us) / AV_TIME_BASE); } //else { //qDebug("N/A"); //} //if (ic->start_time != AV_NOPTS_VALUE) { int secs, us; qDebug(", start: "); secs = ic->start_time / AV_TIME_BASE; us = ic->start_time % AV_TIME_BASE; qDebug("%d.%06d\n", secs, (int)ffmpeg::av_rescale(us, 1000000, AV_TIME_BASE)); } qDebug(", bitrate: "); if (ic->bit_rate) { qDebug("%d kb/s\n", ic->bit_rate / 1000); } else { qDebug("N/A\n"); } qDebug("\n"); } if(ic->nb_programs) { unsigned int j, total=0; for(j=0; jnb_programs; j++) { ffmpeg::AVMetadataTag *name = av_metadata_get(ic->programs[j]->metadata, "name", NULL, 0); qDebug(" Program %d %s\n", ic->programs[j]->id, name ? name->value : ""); /*for(k=0; kprograms[j]->nb_stream_indexes; k++) { dump_stream_format(ic, ic->programs[j]->stream_index[k], index, is_output); printed[ic->programs[j]->stream_index[k]] = 1; }*/ total += ic->programs[j]->nb_stream_indexes; } if (total < ic->nb_streams) qDebug( " No Program\n"); } /*for(i=0;inb_streams;i++) if (!printed[i]) ffmpeg::dump_stream_format(ic, i, index, is_output);*/ if (ic->metadata) { ffmpeg::AVMetadataTag *tag=NULL; qDebug(" Metadata\n"); while((tag=av_metadata_get(ic->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX))) { qDebug(" %-16s: %s\n", tag->key, tag->value); } } ffmpeg::av_free(printed); } int QVideoDecoder::getVideoLengthMs() { if(!isOk()) return -1; int secs = pFormatCtx->duration / AV_TIME_BASE; int us = pFormatCtx->duration % AV_TIME_BASE; int l = secs*1000 + us/1000; dumpFormat(pFormatCtx,videoStream,"test video",0); return l; } IanniX-0.9.20/gui/qffmpeg/QVideoDecoder.h000066400000000000000000000061541317340345000200350ustar00rootroot00000000000000/* QTFFmpegWrapper - QT FFmpeg Wrapper Class Copyright (C) 2009,2010: Daniel Roggen, droggen@gmail.com All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __QVIDEODECODER_H #define __QVIDEODECODER_H #include #include #include #include "ffmpeg.h" class QVideoDecoder { protected: // Basic FFmpeg stuff ffmpeg::AVFormatContext *pFormatCtx; int videoStream; ffmpeg::AVCodecContext *pCodecCtx; ffmpeg::AVCodec *pCodec; ffmpeg::AVFrame *pFrame; ffmpeg::AVFrame *pFrameRGB; ffmpeg::AVPacket packet; ffmpeg::SwsContext *img_convert_ctx; uint8_t *buffer; int numBytes; // State infos for the wrapper bool ok; QImage LastFrame; int LastFrameTime,LastLastFrameTime,LastLastFrameNumber,LastFrameNumber; int DesiredFrameTime,DesiredFrameNumber; bool LastFrameOk; // Set upon start or after a seek we don't have a frame yet // Initialization functions virtual bool initCodec(); virtual void InitVars(); // Helpers virtual void dumpFormat(ffmpeg::AVFormatContext *ic,int index,const char *url,int is_output); virtual void saveFramePPM(ffmpeg::AVFrame *pFrame, int width, int height, int iFrame); // Seek virtual bool decodeSeekFrame(int after); public: // Public interface QVideoDecoder(); QVideoDecoder(QString file); virtual ~QVideoDecoder(); virtual bool openFile(QString file); virtual void close(); virtual bool getFrame(QImage&img,int *effectiveframenumber=0,int *effectiveframetime=0,int *desiredframenumber=0,int *desiredframetime=0); virtual bool seekNextFrame(); virtual bool seekMs(int ts); virtual bool seekFrame(int64_t frame); virtual int getVideoLengthMs(); virtual bool isOk(); }; #endif // __QVIDEODECODER_H IanniX-0.9.20/gui/qffmpeg/QVideoEncoder.cpp000066400000000000000000000344431317340345000204040ustar00rootroot00000000000000/* QTFFmpegWrapper - QT FFmpeg Wrapper Class Copyright (C) 2009-2012: Daniel Roggen, droggen@gmail.com All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "QVideoEncoder.h" #include "ffmpeg.h" /****************************************************************************** ******************************************************************************* * QVideoEncoder QVideoEncoder QVideoEncoder QVideoEncoder QVideoEncoder ******************************************************************************* ******************************************************************************/ /****************************************************************************** * PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC ******************************************************************************/ /** gop: maximal interval in frames between keyframes **/ QVideoEncoder::QVideoEncoder() { initVars(); initCodec(); } QVideoEncoder::~QVideoEncoder() { close(); /*if(Initmodefile) { writeFooter(); Outdev->close(); delete Outdev; Outdev=0; } else { // nothing to do }*/ } bool QVideoEncoder::createFile(QString fileName,unsigned width,unsigned height,unsigned bitrate,unsigned gop,unsigned fps) { // If we had an open video, close it. close(); Width=width; Height=height; Gop=gop; Bitrate=bitrate; if(!isSizeValid()) { qDebug("Invalid size\n"); return false; } pOutputFormat = ffmpeg::av_guess_format(NULL, fileName.toStdString().c_str(), NULL); if (!pOutputFormat) { qDebug("Could not deduce output format from file extension: using MPEG.\n"); pOutputFormat = ffmpeg::av_guess_format("mpeg", NULL, NULL); } pFormatCtx=ffmpeg::avformat_alloc_context(); if(!pFormatCtx) { qDebug("Error allocating format context\n"); return false; } pFormatCtx->oformat = pOutputFormat; snprintf(pFormatCtx->filename, sizeof(pFormatCtx->filename), "%s", fileName.toStdString().c_str()); // Add the video stream pVideoStream = av_new_stream(pFormatCtx,0); if(!pVideoStream ) { qDebug("Could not allocate stream\n"); return false; } pCodecCtx=pVideoStream->codec; pCodecCtx->codec_id = pOutputFormat->video_codec; pCodecCtx->codec_type = ffmpeg::AVMEDIA_TYPE_VIDEO; pCodecCtx->bit_rate = Bitrate; pCodecCtx->width = getWidth(); pCodecCtx->height = getHeight(); pCodecCtx->time_base.den = fps; pCodecCtx->time_base.num = 1; pCodecCtx->gop_size = Gop; pCodecCtx->pix_fmt = ffmpeg::PIX_FMT_YUV420P; avcodec_thread_init(pCodecCtx, 10); //if (c->codec_id == CODEC_ID_MPEG2VIDEO) //{ //c->max_b_frames = 2; // just for testing, we also add B frames //} // some formats want stream headers to be separate if(pFormatCtx->oformat->flags & AVFMT_GLOBALHEADER) pCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER; if (av_set_parameters(pFormatCtx, NULL) < 0) { qDebug("Invalid output format parameters\n"); return false; } ffmpeg::dump_format(pFormatCtx, 0, fileName.toStdString().c_str(), 1); // open_video // find the video encoder pCodec = avcodec_find_encoder(pCodecCtx->codec_id); if (!pCodec) { qDebug("codec not found\n"); return false; } // open the codec if (avcodec_open(pCodecCtx, pCodec) < 0) { qDebug("could not open codec\n"); return false; } // Allocate memory for output if(!initOutputBuf()) { qDebug("Can't allocate memory for output bitstream\n"); return false; } // Allocate the YUV frame if(!initFrame()) { qDebug("Can't init frame\n"); return false; } if (url_fopen(&pFormatCtx->pb, fileName.toStdString().c_str(), URL_WRONLY) < 0) { qDebug( "Could not open '%s'\n", fileName.toStdString().c_str()); return false; } av_write_header(pFormatCtx); ok=true; return true; } /** \brief Completes writing the stream, closes it, release resources. **/ bool QVideoEncoder::close() { if(!isOk()) return false; av_write_trailer(pFormatCtx); // close_video avcodec_close(pVideoStream->codec); freeFrame(); freeOutputBuf(); /* free the streams */ for(int i = 0; i < pFormatCtx->nb_streams; i++) { av_freep(&pFormatCtx->streams[i]->codec); av_freep(&pFormatCtx->streams[i]); } // Close file url_fclose(pFormatCtx->pb); // Free the stream av_free(pFormatCtx); initVars(); return true; } /** \brief Encode one frame The frame must be of the same size as specified in the createFile call. This is the standard method to encode videos with fixed frame rates. Each call to encodeImage adds a frame, which will be played back at the frame rate specified in the createFile call. **/ int QVideoEncoder::encodeImage(const QImage &img) { return encodeImage_p(img); } /** \brief Encode one frame The frame must be of the same size as specified in the createFile call. This mehtod allows to specify the presentation time stamp (pts) of the frame. pts is specified in multiples of 1/framerate, where framerate was specified in the createFile call E.g. to encode frames with a 1ms resolution: set the frame rate to 1000, and pts is the presentation time in milliseconds. pts must be monotonously increasing. The first frame ought to have a pts of 0 to be immediately displayed. **/ int QVideoEncoder::encodeImagePts(const QImage &img,unsigned pts) { return encodeImage_p(img,true,pts); } /****************************************************************************** * INTERNAL INTERNAL INTERNAL INTERNAL INTERNAL INTERNAL INTERNAL ******************************************************************************/ void QVideoEncoder::initVars() { ok=false; pFormatCtx=0; pOutputFormat=0; pCodecCtx=0; pVideoStream=0; pCodec=0; ppicture=0; outbuf=0; picture_buf=0; img_convert_ctx=0; } /** \brief Register the codecs **/ bool QVideoEncoder::initCodec() { ffmpeg::avcodec_init(); ffmpeg::av_register_all(); qDebug("License: %s\n",ffmpeg::avformat_license()); qDebug("AVCodec version %d\n",ffmpeg::avformat_version()); qDebug("AVFormat configuration: %s\n",ffmpeg::avformat_configuration()); return true; } /** \brief Encode one frame - internal function custompts: true if a custom presentation time stamp is used pts: presentation time stamp in milliseconds **/ int QVideoEncoder::encodeImage_p(const QImage &img,bool custompts, unsigned pts) { if(!isOk()) return -1; //convertImage(img); // Custom conversion routine convertImage_sws(img); // SWS conversion if(custompts) // Handle custom pts pCodecCtx->coded_frame->pts = pts; // Set the time stamp int out_size = ffmpeg::avcodec_encode_video(pCodecCtx,outbuf,outbuf_size,ppicture); //qDebug("Frame size: %d\n",out_size); if(custompts) // Handle custom pts (must set it again for the rest of the processing) pCodecCtx->coded_frame->pts = pts; // Set the time stamp if (out_size > 0) { av_init_packet(&pkt); //if (pCodecCtx->coded_frame->pts != AV_NOPTS_VALUE) if (pCodecCtx->coded_frame->pts != (0x8000000000000000LL)) pkt.pts= av_rescale_q(pCodecCtx->coded_frame->pts, pCodecCtx->time_base, pVideoStream->time_base); if(pCodecCtx->coded_frame->key_frame) pkt.flags |= AV_PKT_FLAG_KEY; //qDebug("c %d. pts %d. codedframepts: %ld pkt.pts: %ld\n",custompts,pts,pCodecCtx->coded_frame->pts,pkt.pts); pkt.stream_index= pVideoStream->index; pkt.data= outbuf; pkt.size= out_size; int ret = av_interleaved_write_frame(pFormatCtx, &pkt); //qDebug("Wrote %d\n",ret); if(ret<0) return -1; } return out_size; } /** Ensures sizes are some reasonable multiples **/ bool QVideoEncoder::isSizeValid() { if(getWidth()%8) return false; if(getHeight()%8) return false; return true; } unsigned QVideoEncoder::getWidth() { return Width; } unsigned QVideoEncoder::getHeight() { return Height; } bool QVideoEncoder::isOk() { return ok; } /** Allocate memory for the compressed bitstream **/ bool QVideoEncoder::initOutputBuf() { outbuf_size = getWidth()*getHeight()*3; // Some extremely generous memory allocation for the encoded frame. outbuf = new uint8_t[outbuf_size]; if(outbuf==0) return false; return true; } /** Free memory for the compressed bitstream **/ void QVideoEncoder::freeOutputBuf() { if(outbuf) { delete[] outbuf; outbuf=0; } } bool QVideoEncoder::initFrame() { ppicture = ffmpeg::avcodec_alloc_frame(); if(ppicture==0) return false; int size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height); picture_buf = new uint8_t[size]; if(picture_buf==0) { av_free(ppicture); ppicture=0; return false; } // Setup the planes avpicture_fill((ffmpeg::AVPicture *)ppicture, picture_buf,pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height); return true; } void QVideoEncoder::freeFrame() { if(picture_buf) { delete[] picture_buf; picture_buf=0; } if(ppicture) { av_free(ppicture); ppicture=0; } } /** \brief Convert the QImage to the internal YUV format Custom conversion - not very optimized. **/ bool QVideoEncoder::convertImage(const QImage &img) { // Check if the image matches the size if(img.width()!=getWidth() || img.height()!=getHeight()) { qDebug("Wrong image size!\n"); return false; } if(img.format()!=QImage::Format_RGB32 && img.format() != QImage::Format_ARGB32) { qDebug("Wrong image format\n"); return false; } // RGB32 to YUV420 int size = getWidth()*getHeight(); // Y for(unsigned y=0;y> 13; if(Y>235) Y=235; *d = Y; d+=1; s+=4; } } // U,V for(unsigned y=0;y> 2; int g=(s[1] + s[5] + s[ss+1] + s[ss+5] + 2) >> 2; int b=(s[0] + s[4] + s[ss+0] + s[ss+4] + 2) >> 2; int Cb = (-1214*r - 2384*g + 3598*b + 4096 + 1048576)>>13; if(Cb<16) Cb=16; if(Cb>240) Cb=240; int Cr = (3598*r - 3013*g - 585*b + 4096 + 1048576)>>13; if(Cr<16) Cr=16; if(Cr>240) Cr=240; *d = Cb; *(d+size/4) = Cr; d+=1; s+=8; } } return true; } /** \brief Convert the QImage to the internal YUV format SWS conversion Caution: the QImage is allocated by QT without guarantee about the alignment and bytes per lines. It *should* be okay as we make sure the image is a multiple of many bytes (8 or 16)... ... however it is not guaranteed that sws_scale won't at some point require more bytes per line. We keep the custom conversion for that case. **/ bool QVideoEncoder::convertImage_sws(const QImage &img) { // Check if the image matches the size if(img.width()!=getWidth() || img.height()!=getHeight()) { qDebug("Wrong image size!\n"); return false; } if(img.format()!=QImage::Format_RGB32 && img.format() != QImage::Format_ARGB32) { qDebug("Wrong image format\n"); return false; } img_convert_ctx = ffmpeg::sws_getCachedContext(img_convert_ctx,getWidth(),getHeight(),ffmpeg::PIX_FMT_BGRA,getWidth(),getHeight(),ffmpeg::PIX_FMT_YUV420P,SWS_BICUBIC, NULL, NULL, NULL); //img_convert_ctx = ffmpeg::sws_getCachedContext(img_convert_ctx,getWidth(),getHeight(),ffmpeg::PIX_FMT_BGRA,getWidth(),getHeight(),ffmpeg::PIX_FMT_YUV420P,SWS_FAST_BILINEAR, NULL, NULL, NULL); if (img_convert_ctx == NULL) { qDebug("Cannot initialize the conversion context\n"); return false; } uint8_t *srcplanes[3]; srcplanes[0]=(uint8_t*)img.bits(); srcplanes[1]=0; srcplanes[2]=0; int srcstride[3]; srcstride[0]=img.bytesPerLine(); srcstride[1]=0; srcstride[2]=0; ffmpeg::sws_scale(img_convert_ctx, srcplanes, srcstride,0, getHeight(), ppicture->data, ppicture->linesize); return true; } IanniX-0.9.20/gui/qffmpeg/QVideoEncoder.h000066400000000000000000000057201317340345000200450ustar00rootroot00000000000000/* QTFFmpegWrapper - QT FFmpeg Wrapper Class Copyright (C) 2009-2012: Daniel Roggen, droggen@gmail.com All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __QVideoEncoder_H #define __QVideoEncoder_H #include #include #include #include "ffmpeg.h" class QVideoEncoder { protected: unsigned Width,Height; unsigned Bitrate; unsigned Gop; bool ok; // FFmpeg stuff ffmpeg::AVFormatContext *pFormatCtx; ffmpeg::AVOutputFormat *pOutputFormat; ffmpeg::AVCodecContext *pCodecCtx; ffmpeg::AVStream *pVideoStream; ffmpeg::AVCodec *pCodec; // Frame data ffmpeg::AVFrame *ppicture; uint8_t *picture_buf; // Compressed data int outbuf_size; uint8_t* outbuf; // Conversion ffmpeg::SwsContext *img_convert_ctx; // Packet ffmpeg::AVPacket pkt; QString fileName; unsigned getWidth(); unsigned getHeight(); bool isSizeValid(); void initVars(); bool initCodec(); // Alloc/free the output buffer bool initOutputBuf(); void freeOutputBuf(); // Alloc/free a frame bool initFrame(); void freeFrame(); // Frame conversion bool convertImage(const QImage &img); bool convertImage_sws(const QImage &img); virtual int encodeImage_p(const QImage &,bool custompts=false,unsigned pts=0); public: QVideoEncoder(); virtual ~QVideoEncoder(); bool createFile(QString filename,unsigned width,unsigned height,unsigned bitrate,unsigned gop,unsigned fps=25); virtual bool close(); virtual int encodeImage(const QImage &); virtual int encodeImagePts(const QImage &,unsigned pts); virtual bool isOk(); }; #endif // QVideoEncoder_H IanniX-0.9.20/gui/qffmpeg/README000066400000000000000000000025721317340345000160670ustar00rootroot00000000000000 QTFFmpegWrapper - QT FFmpeg Wrapper Class http://code.google.com/p/qtffmpegwrapper Copyright (C) 2009,2010: Daniel Roggen, droggen@gmail.com All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IanniX-0.9.20/gui/qffmpeg/ffmpeg.h000066400000000000000000000042341317340345000166210ustar00rootroot00000000000000/* QTFFmpegWrapper - QT FFmpeg Wrapper Class Copyright (C) 2009,2010: Daniel Roggen, droggen@gmail.com All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Wraps the ffmpeg includes in a namespace and ensures extern "C" */ #ifndef _FFMPEG_H #define _FFMPEG_H namespace ffmpeg { extern "C" { /*#define INT64_C #define __STDC_CONSTANT_MACROS #include */ #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libavutil/mathematics.h" //#include "libavformat/riff.h" //#include "libavformat/metadata.h" //#include "libavformat/utils.h" #include "libavcodec/opt.h" #include "libavutil/rational.h" //#include "options.h" #include "libavutil/avstring.h" //#include "libavutil/internal.h" #include "libswscale/swscale.h" } } /* #ifndef INT64_MIN #define INT64_MIN (-0x7fffffffffffffffLL-1) #endif #ifndef INT64_MAX #define INT64_MAX 9223372036854775807LL #endif*/ /*#ifndef INT64_C #define INT64_C(value) __CONCAT(value, LL) #endif*/ #endif // _FFMPEG_H IanniX-0.9.20/gui/qffmpeg/libavcodec/000077500000000000000000000000001317340345000172745ustar00rootroot00000000000000IanniX-0.9.20/gui/qffmpeg/libavcodec/avcodec.h000066400000000000000000004354371317340345000210710ustar00rootroot00000000000000/* * copyright (c) 2001 Fabrice Bellard * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVCODEC_AVCODEC_H #define AVCODEC_AVCODEC_H /** * @file * external API header */ #include #include "libavutil/samplefmt.h" #include "libavutil/avutil.h" #include "libavutil/cpu.h" #include "libavutil/dict.h" #include "libavutil/log.h" #include "libavutil/pixfmt.h" #include "libavutil/rational.h" #include "libavcodec/version.h" /** * Identify the syntax and semantics of the bitstream. * The principle is roughly: * Two decoders with the same ID can decode the same streams. * Two encoders with the same ID can encode compatible streams. * There may be slight deviations from the principle due to implementation * details. * * If you add a codec ID to this list, add it so that * 1. no value of a existing codec ID changes (that would break ABI), * 2. it is as close as possible to similar codecs. */ enum CodecID { CODEC_ID_NONE, /* video codecs */ CODEC_ID_MPEG1VIDEO, CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding CODEC_ID_MPEG2VIDEO_XVMC, CODEC_ID_H261, CODEC_ID_H263, CODEC_ID_RV10, CODEC_ID_RV20, CODEC_ID_MJPEG, CODEC_ID_MJPEGB, CODEC_ID_LJPEG, CODEC_ID_SP5X, CODEC_ID_JPEGLS, CODEC_ID_MPEG4, CODEC_ID_RAWVIDEO, CODEC_ID_MSMPEG4V1, CODEC_ID_MSMPEG4V2, CODEC_ID_MSMPEG4V3, CODEC_ID_WMV1, CODEC_ID_WMV2, CODEC_ID_H263P, CODEC_ID_H263I, CODEC_ID_FLV1, CODEC_ID_SVQ1, CODEC_ID_SVQ3, CODEC_ID_DVVIDEO, CODEC_ID_HUFFYUV, CODEC_ID_CYUV, CODEC_ID_H264, CODEC_ID_INDEO3, CODEC_ID_VP3, CODEC_ID_THEORA, CODEC_ID_ASV1, CODEC_ID_ASV2, CODEC_ID_FFV1, CODEC_ID_4XM, CODEC_ID_VCR1, CODEC_ID_CLJR, CODEC_ID_MDEC, CODEC_ID_ROQ, CODEC_ID_INTERPLAY_VIDEO, CODEC_ID_XAN_WC3, CODEC_ID_XAN_WC4, CODEC_ID_RPZA, CODEC_ID_CINEPAK, CODEC_ID_WS_VQA, CODEC_ID_MSRLE, CODEC_ID_MSVIDEO1, CODEC_ID_IDCIN, CODEC_ID_8BPS, CODEC_ID_SMC, CODEC_ID_FLIC, CODEC_ID_TRUEMOTION1, CODEC_ID_VMDVIDEO, CODEC_ID_MSZH, CODEC_ID_ZLIB, CODEC_ID_QTRLE, CODEC_ID_SNOW, CODEC_ID_TSCC, CODEC_ID_ULTI, CODEC_ID_QDRAW, CODEC_ID_VIXL, CODEC_ID_QPEG, CODEC_ID_PNG, CODEC_ID_PPM, CODEC_ID_PBM, CODEC_ID_PGM, CODEC_ID_PGMYUV, CODEC_ID_PAM, CODEC_ID_FFVHUFF, CODEC_ID_RV30, CODEC_ID_RV40, CODEC_ID_VC1, CODEC_ID_WMV3, CODEC_ID_LOCO, CODEC_ID_WNV1, CODEC_ID_AASC, CODEC_ID_INDEO2, CODEC_ID_FRAPS, CODEC_ID_TRUEMOTION2, CODEC_ID_BMP, CODEC_ID_CSCD, CODEC_ID_MMVIDEO, CODEC_ID_ZMBV, CODEC_ID_AVS, CODEC_ID_SMACKVIDEO, CODEC_ID_NUV, CODEC_ID_KMVC, CODEC_ID_FLASHSV, CODEC_ID_CAVS, CODEC_ID_JPEG2000, CODEC_ID_VMNC, CODEC_ID_VP5, CODEC_ID_VP6, CODEC_ID_VP6F, CODEC_ID_TARGA, CODEC_ID_DSICINVIDEO, CODEC_ID_TIERTEXSEQVIDEO, CODEC_ID_TIFF, CODEC_ID_GIF, CODEC_ID_FFH264, CODEC_ID_DXA, CODEC_ID_DNXHD, CODEC_ID_THP, CODEC_ID_SGI, CODEC_ID_C93, CODEC_ID_BETHSOFTVID, CODEC_ID_PTX, CODEC_ID_TXD, CODEC_ID_VP6A, CODEC_ID_AMV, CODEC_ID_VB, CODEC_ID_PCX, CODEC_ID_SUNRAST, CODEC_ID_INDEO4, CODEC_ID_INDEO5, CODEC_ID_MIMIC, CODEC_ID_RL2, CODEC_ID_8SVX_EXP, CODEC_ID_8SVX_FIB, CODEC_ID_ESCAPE124, CODEC_ID_DIRAC, CODEC_ID_BFI, CODEC_ID_CMV, CODEC_ID_MOTIONPIXELS, CODEC_ID_TGV, CODEC_ID_TGQ, CODEC_ID_TQI, CODEC_ID_AURA, CODEC_ID_AURA2, CODEC_ID_V210X, CODEC_ID_TMV, CODEC_ID_V210, CODEC_ID_DPX, CODEC_ID_MAD, CODEC_ID_FRWU, CODEC_ID_FLASHSV2, CODEC_ID_CDGRAPHICS, CODEC_ID_R210, CODEC_ID_ANM, CODEC_ID_BINKVIDEO, CODEC_ID_IFF_ILBM, CODEC_ID_IFF_BYTERUN1, CODEC_ID_KGV1, CODEC_ID_YOP, CODEC_ID_VP8, CODEC_ID_PICTOR, CODEC_ID_ANSI, CODEC_ID_A64_MULTI, CODEC_ID_A64_MULTI5, CODEC_ID_R10K, CODEC_ID_MXPEG, CODEC_ID_LAGARITH, CODEC_ID_PRORES, CODEC_ID_JV, CODEC_ID_DFA, CODEC_ID_WMV3IMAGE, CODEC_ID_VC1IMAGE, CODEC_ID_8SVX_RAW, CODEC_ID_G2M, /* various PCM "codecs" */ CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs CODEC_ID_PCM_S16LE= 0x10000, CODEC_ID_PCM_S16BE, CODEC_ID_PCM_U16LE, CODEC_ID_PCM_U16BE, CODEC_ID_PCM_S8, CODEC_ID_PCM_U8, CODEC_ID_PCM_MULAW, CODEC_ID_PCM_ALAW, CODEC_ID_PCM_S32LE, CODEC_ID_PCM_S32BE, CODEC_ID_PCM_U32LE, CODEC_ID_PCM_U32BE, CODEC_ID_PCM_S24LE, CODEC_ID_PCM_S24BE, CODEC_ID_PCM_U24LE, CODEC_ID_PCM_U24BE, CODEC_ID_PCM_S24DAUD, CODEC_ID_PCM_ZORK, CODEC_ID_PCM_S16LE_PLANAR, CODEC_ID_PCM_DVD, CODEC_ID_PCM_F32BE, CODEC_ID_PCM_F32LE, CODEC_ID_PCM_F64BE, CODEC_ID_PCM_F64LE, CODEC_ID_PCM_BLURAY, CODEC_ID_PCM_LXF, CODEC_ID_S302M, /* various ADPCM codecs */ CODEC_ID_ADPCM_IMA_QT= 0x11000, CODEC_ID_ADPCM_IMA_WAV, CODEC_ID_ADPCM_IMA_DK3, CODEC_ID_ADPCM_IMA_DK4, CODEC_ID_ADPCM_IMA_WS, CODEC_ID_ADPCM_IMA_SMJPEG, CODEC_ID_ADPCM_MS, CODEC_ID_ADPCM_4XM, CODEC_ID_ADPCM_XA, CODEC_ID_ADPCM_ADX, CODEC_ID_ADPCM_EA, CODEC_ID_ADPCM_G726, CODEC_ID_ADPCM_CT, CODEC_ID_ADPCM_SWF, CODEC_ID_ADPCM_YAMAHA, CODEC_ID_ADPCM_SBPRO_4, CODEC_ID_ADPCM_SBPRO_3, CODEC_ID_ADPCM_SBPRO_2, CODEC_ID_ADPCM_THP, CODEC_ID_ADPCM_IMA_AMV, CODEC_ID_ADPCM_EA_R1, CODEC_ID_ADPCM_EA_R3, CODEC_ID_ADPCM_EA_R2, CODEC_ID_ADPCM_IMA_EA_SEAD, CODEC_ID_ADPCM_IMA_EA_EACS, CODEC_ID_ADPCM_EA_XAS, CODEC_ID_ADPCM_EA_MAXIS_XA, CODEC_ID_ADPCM_IMA_ISS, CODEC_ID_ADPCM_G722, /* AMR */ CODEC_ID_AMR_NB= 0x12000, CODEC_ID_AMR_WB, /* RealAudio codecs*/ CODEC_ID_RA_144= 0x13000, CODEC_ID_RA_288, /* various DPCM codecs */ CODEC_ID_ROQ_DPCM= 0x14000, CODEC_ID_INTERPLAY_DPCM, CODEC_ID_XAN_DPCM, CODEC_ID_SOL_DPCM, /* audio codecs */ CODEC_ID_MP2= 0x15000, CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3 CODEC_ID_AAC, CODEC_ID_AC3, CODEC_ID_DTS, CODEC_ID_VORBIS, CODEC_ID_DVAUDIO, CODEC_ID_WMAV1, CODEC_ID_WMAV2, CODEC_ID_MACE3, CODEC_ID_MACE6, CODEC_ID_VMDAUDIO, CODEC_ID_SONIC, CODEC_ID_SONIC_LS, CODEC_ID_FLAC, CODEC_ID_MP3ADU, CODEC_ID_MP3ON4, CODEC_ID_SHORTEN, CODEC_ID_ALAC, CODEC_ID_WESTWOOD_SND1, CODEC_ID_GSM, ///< as in Berlin toast format CODEC_ID_QDM2, CODEC_ID_COOK, CODEC_ID_TRUESPEECH, CODEC_ID_TTA, CODEC_ID_SMACKAUDIO, CODEC_ID_QCELP, CODEC_ID_WAVPACK, CODEC_ID_DSICINAUDIO, CODEC_ID_IMC, CODEC_ID_MUSEPACK7, CODEC_ID_MLP, CODEC_ID_GSM_MS, /* as found in WAV */ CODEC_ID_ATRAC3, CODEC_ID_VOXWARE, CODEC_ID_APE, CODEC_ID_NELLYMOSER, CODEC_ID_MUSEPACK8, CODEC_ID_SPEEX, CODEC_ID_WMAVOICE, CODEC_ID_WMAPRO, CODEC_ID_WMALOSSLESS, CODEC_ID_ATRAC3P, CODEC_ID_EAC3, CODEC_ID_SIPR, CODEC_ID_MP1, CODEC_ID_TWINVQ, CODEC_ID_TRUEHD, CODEC_ID_MP4ALS, CODEC_ID_ATRAC1, CODEC_ID_BINKAUDIO_RDFT, CODEC_ID_BINKAUDIO_DCT, CODEC_ID_AAC_LATM, CODEC_ID_QDMC, CODEC_ID_CELT, /* subtitle codecs */ CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. CODEC_ID_DVD_SUBTITLE= 0x17000, CODEC_ID_DVB_SUBTITLE, CODEC_ID_TEXT, ///< raw UTF-8 text CODEC_ID_XSUB, CODEC_ID_SSA, CODEC_ID_MOV_TEXT, CODEC_ID_HDMV_PGS_SUBTITLE, CODEC_ID_DVB_TELETEXT, CODEC_ID_SRT, CODEC_ID_MICRODVD, /* other specific kind of codecs (generally used for attachments) */ CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. CODEC_ID_TTF= 0x18000, CODEC_ID_BINTEXT, CODEC_ID_XBIN, CODEC_ID_IDF, CODEC_ID_PROBE= 0x19000, ///< codec_id is not known (like CODEC_ID_NONE) but lavf should attempt to identify it CODEC_ID_MPEG2TS= 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS * stream (only used by libavformat) */ CODEC_ID_FFMETADATA=0x21000, ///< Dummy codec for streams containing only metadata information. }; #if FF_API_OLD_SAMPLE_FMT #define SampleFormat AVSampleFormat #define SAMPLE_FMT_NONE AV_SAMPLE_FMT_NONE #define SAMPLE_FMT_U8 AV_SAMPLE_FMT_U8 #define SAMPLE_FMT_S16 AV_SAMPLE_FMT_S16 #define SAMPLE_FMT_S32 AV_SAMPLE_FMT_S32 #define SAMPLE_FMT_FLT AV_SAMPLE_FMT_FLT #define SAMPLE_FMT_DBL AV_SAMPLE_FMT_DBL #define SAMPLE_FMT_NB AV_SAMPLE_FMT_NB #endif #if FF_API_OLD_AUDIOCONVERT #include "libavutil/audioconvert.h" /* Audio channel masks */ #define CH_FRONT_LEFT AV_CH_FRONT_LEFT #define CH_FRONT_RIGHT AV_CH_FRONT_RIGHT #define CH_FRONT_CENTER AV_CH_FRONT_CENTER #define CH_LOW_FREQUENCY AV_CH_LOW_FREQUENCY #define CH_BACK_LEFT AV_CH_BACK_LEFT #define CH_BACK_RIGHT AV_CH_BACK_RIGHT #define CH_FRONT_LEFT_OF_CENTER AV_CH_FRONT_LEFT_OF_CENTER #define CH_FRONT_RIGHT_OF_CENTER AV_CH_FRONT_RIGHT_OF_CENTER #define CH_BACK_CENTER AV_CH_BACK_CENTER #define CH_SIDE_LEFT AV_CH_SIDE_LEFT #define CH_SIDE_RIGHT AV_CH_SIDE_RIGHT #define CH_TOP_CENTER AV_CH_TOP_CENTER #define CH_TOP_FRONT_LEFT AV_CH_TOP_FRONT_LEFT #define CH_TOP_FRONT_CENTER AV_CH_TOP_FRONT_CENTER #define CH_TOP_FRONT_RIGHT AV_CH_TOP_FRONT_RIGHT #define CH_TOP_BACK_LEFT AV_CH_TOP_BACK_LEFT #define CH_TOP_BACK_CENTER AV_CH_TOP_BACK_CENTER #define CH_TOP_BACK_RIGHT AV_CH_TOP_BACK_RIGHT #define CH_STEREO_LEFT AV_CH_STEREO_LEFT #define CH_STEREO_RIGHT AV_CH_STEREO_RIGHT /** Channel mask value used for AVCodecContext.request_channel_layout to indicate that the user requests the channel order of the decoder output to be the native codec channel order. */ #define CH_LAYOUT_NATIVE AV_CH_LAYOUT_NATIVE /* Audio channel convenience macros */ #define CH_LAYOUT_MONO AV_CH_LAYOUT_MONO #define CH_LAYOUT_STEREO AV_CH_LAYOUT_STEREO #define CH_LAYOUT_2_1 AV_CH_LAYOUT_2_1 #define CH_LAYOUT_SURROUND AV_CH_LAYOUT_SURROUND #define CH_LAYOUT_4POINT0 AV_CH_LAYOUT_4POINT0 #define CH_LAYOUT_2_2 AV_CH_LAYOUT_2_2 #define CH_LAYOUT_QUAD AV_CH_LAYOUT_QUAD #define CH_LAYOUT_5POINT0 AV_CH_LAYOUT_5POINT0 #define CH_LAYOUT_5POINT1 AV_CH_LAYOUT_5POINT1 #define CH_LAYOUT_5POINT0_BACK AV_CH_LAYOUT_5POINT0_BACK #define CH_LAYOUT_5POINT1_BACK AV_CH_LAYOUT_5POINT1_BACK #define CH_LAYOUT_7POINT0 AV_CH_LAYOUT_7POINT0 #define CH_LAYOUT_7POINT1 AV_CH_LAYOUT_7POINT1 #define CH_LAYOUT_7POINT1_WIDE AV_CH_LAYOUT_7POINT1_WIDE #define CH_LAYOUT_STEREO_DOWNMIX AV_CH_LAYOUT_STEREO_DOWNMIX #endif /* in bytes */ #define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio /** * Required number of additionally allocated bytes at the end of the input bitstream for decoding. * This is mainly needed because some optimized bitstream readers read * 32 or 64 bit at once and could read over the end.
    * Note: If the first 23 bits of the additional bytes are not 0, then damaged * MPEG bitstreams could cause overread and segfault. */ #define FF_INPUT_BUFFER_PADDING_SIZE 16 /** * minimum encoding buffer size * Used to avoid some checks during header writing. */ #define FF_MIN_BUFFER_SIZE 16384 /** * motion estimation type. */ enum Motion_Est_ID { ME_ZERO = 1, ///< no search, that is use 0,0 vector whenever one is needed ME_FULL, ME_LOG, ME_PHODS, ME_EPZS, ///< enhanced predictive zonal search ME_X1, ///< reserved for experiments ME_HEX, ///< hexagon based search ME_UMH, ///< uneven multi-hexagon search ME_ITER, ///< iterative search ME_TESA, ///< transformed exhaustive search algorithm }; enum AVDiscard{ /* We leave some space between them for extensions (drop some * keyframes for intra-only or drop just some bidir frames). */ AVDISCARD_NONE =-16, ///< discard nothing AVDISCARD_DEFAULT= 0, ///< discard useless packets like 0 size packets in avi AVDISCARD_NONREF = 8, ///< discard all non reference AVDISCARD_BIDIR = 16, ///< discard all bidirectional frames AVDISCARD_NONKEY = 32, ///< discard all frames except keyframes AVDISCARD_ALL = 48, ///< discard all }; enum AVColorPrimaries{ AVCOL_PRI_BT709 =1, ///< also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP177 Annex B AVCOL_PRI_UNSPECIFIED=2, AVCOL_PRI_BT470M =4, AVCOL_PRI_BT470BG =5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM AVCOL_PRI_SMPTE170M =6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC AVCOL_PRI_SMPTE240M =7, ///< functionally identical to above AVCOL_PRI_FILM =8, AVCOL_PRI_NB , ///< Not part of ABI }; enum AVColorTransferCharacteristic{ AVCOL_TRC_BT709 =1, ///< also ITU-R BT1361 AVCOL_TRC_UNSPECIFIED=2, AVCOL_TRC_GAMMA22 =4, ///< also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM AVCOL_TRC_GAMMA28 =5, ///< also ITU-R BT470BG AVCOL_TRC_NB , ///< Not part of ABI }; enum AVColorSpace{ AVCOL_SPC_RGB =0, AVCOL_SPC_BT709 =1, ///< also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B AVCOL_SPC_UNSPECIFIED=2, AVCOL_SPC_FCC =4, AVCOL_SPC_BT470BG =5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601 AVCOL_SPC_SMPTE170M =6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC / functionally identical to above AVCOL_SPC_SMPTE240M =7, AVCOL_SPC_NB , ///< Not part of ABI }; enum AVColorRange{ AVCOL_RANGE_UNSPECIFIED=0, AVCOL_RANGE_MPEG =1, ///< the normal 219*2^(n-8) "MPEG" YUV ranges AVCOL_RANGE_JPEG =2, ///< the normal 2^n-1 "JPEG" YUV ranges AVCOL_RANGE_NB , ///< Not part of ABI }; /** * X X 3 4 X X are luma samples, * 1 2 1-6 are possible chroma positions * X X 5 6 X 0 is undefined/unknown position */ enum AVChromaLocation{ AVCHROMA_LOC_UNSPECIFIED=0, AVCHROMA_LOC_LEFT =1, ///< mpeg2/4, h264 default AVCHROMA_LOC_CENTER =2, ///< mpeg1, jpeg, h263 AVCHROMA_LOC_TOPLEFT =3, ///< DV AVCHROMA_LOC_TOP =4, AVCHROMA_LOC_BOTTOMLEFT =5, AVCHROMA_LOC_BOTTOM =6, AVCHROMA_LOC_NB , ///< Not part of ABI }; #if FF_API_FLAC_GLOBAL_OPTS /** * LPC analysis type */ attribute_deprecated enum AVLPCType { AV_LPC_TYPE_DEFAULT = -1, ///< use the codec default LPC type AV_LPC_TYPE_NONE = 0, ///< do not use LPC prediction or use all zero coefficients AV_LPC_TYPE_FIXED = 1, ///< fixed LPC coefficients AV_LPC_TYPE_LEVINSON = 2, ///< Levinson-Durbin recursion AV_LPC_TYPE_CHOLESKY = 3, ///< Cholesky factorization AV_LPC_TYPE_NB , ///< Not part of ABI }; #endif enum AVAudioServiceType { AV_AUDIO_SERVICE_TYPE_MAIN = 0, AV_AUDIO_SERVICE_TYPE_EFFECTS = 1, AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED = 2, AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED = 3, AV_AUDIO_SERVICE_TYPE_DIALOGUE = 4, AV_AUDIO_SERVICE_TYPE_COMMENTARY = 5, AV_AUDIO_SERVICE_TYPE_EMERGENCY = 6, AV_AUDIO_SERVICE_TYPE_VOICE_OVER = 7, AV_AUDIO_SERVICE_TYPE_KARAOKE = 8, AV_AUDIO_SERVICE_TYPE_NB , ///< Not part of ABI }; typedef struct RcOverride{ int start_frame; int end_frame; int qscale; // If this is 0 then quality_factor will be used instead. float quality_factor; } RcOverride; #define FF_MAX_B_FRAMES 16 /* encoding support These flags can be passed in AVCodecContext.flags before initialization. Note: Not everything is supported yet. */ #define CODEC_FLAG_QSCALE 0x0002 ///< Use fixed qscale. #define CODEC_FLAG_4MV 0x0004 ///< 4 MV per MB allowed / advanced prediction for H.263. #define CODEC_FLAG_QPEL 0x0010 ///< Use qpel MC. #define CODEC_FLAG_GMC 0x0020 ///< Use GMC. #define CODEC_FLAG_MV0 0x0040 ///< Always try a MB with MV=<0,0>. /** * The parent program guarantees that the input for B-frames containing * streams is not written to for at least s->max_b_frames+1 frames, if * this is not set the input will be copied. */ #define CODEC_FLAG_INPUT_PRESERVED 0x0100 #define CODEC_FLAG_PASS1 0x0200 ///< Use internal 2pass ratecontrol in first pass mode. #define CODEC_FLAG_PASS2 0x0400 ///< Use internal 2pass ratecontrol in second pass mode. #define CODEC_FLAG_GRAY 0x2000 ///< Only decode/encode grayscale. #define CODEC_FLAG_EMU_EDGE 0x4000 ///< Don't draw edges. #define CODEC_FLAG_PSNR 0x8000 ///< error[?] variables will be set during encoding. #define CODEC_FLAG_TRUNCATED 0x00010000 /** Input bitstream might be truncated at a random location instead of only at frame boundaries. */ #define CODEC_FLAG_NORMALIZE_AQP 0x00020000 ///< Normalize adaptive quantization. #define CODEC_FLAG_INTERLACED_DCT 0x00040000 ///< Use interlaced DCT. #define CODEC_FLAG_LOW_DELAY 0x00080000 ///< Force low delay. #define CODEC_FLAG_GLOBAL_HEADER 0x00400000 ///< Place global headers in extradata instead of every keyframe. #define CODEC_FLAG_BITEXACT 0x00800000 ///< Use only bitexact stuff (except (I)DCT). /* Fx : Flag for h263+ extra options */ #define CODEC_FLAG_AC_PRED 0x01000000 ///< H.263 advanced intra coding / MPEG-4 AC prediction #define CODEC_FLAG_CBP_RD 0x04000000 ///< Use rate distortion optimization for cbp. #define CODEC_FLAG_QP_RD 0x08000000 ///< Use rate distortion optimization for qp selectioon. #define CODEC_FLAG_LOOP_FILTER 0x00000800 ///< loop filter #define CODEC_FLAG_INTERLACED_ME 0x20000000 ///< interlaced motion estimation #define CODEC_FLAG_CLOSED_GOP 0x80000000 #define CODEC_FLAG2_FAST 0x00000001 ///< Allow non spec compliant speedup tricks. #define CODEC_FLAG2_STRICT_GOP 0x00000002 ///< Strictly enforce GOP size. #define CODEC_FLAG2_NO_OUTPUT 0x00000004 ///< Skip bitstream encoding. #define CODEC_FLAG2_LOCAL_HEADER 0x00000008 ///< Place global headers at every keyframe instead of in extradata. #define CODEC_FLAG2_SKIP_RD 0x00004000 ///< RD optimal MB level residual skipping #define CODEC_FLAG2_CHUNKS 0x00008000 ///< Input bitstream might be truncated at a packet boundaries instead of only at frame boundaries. #define CODEC_FLAG2_SHOW_ALL 0x00400000 ///< Show all frames before the first keyframe /** * @defgroup deprecated_flags Deprecated codec flags * Use corresponding private codec options instead. * @{ */ #if FF_API_MPEGVIDEO_GLOBAL_OPTS #define CODEC_FLAG_OBMC 0x00000001 ///< OBMC #define CODEC_FLAG_H263P_AIV 0x00000008 ///< H.263 alternative inter VLC #define CODEC_FLAG_PART 0x0080 ///< Use data partitioning. #define CODEC_FLAG_ALT_SCAN 0x00100000 ///< Use alternate scan. #define CODEC_FLAG_H263P_UMV 0x02000000 ///< unlimited motion vector #define CODEC_FLAG_H263P_SLICE_STRUCT 0x10000000 #define CODEC_FLAG_SVCD_SCAN_OFFSET 0x40000000 ///< Will reserve space for SVCD scan offset user data. #define CODEC_FLAG2_INTRA_VLC 0x00000800 ///< Use MPEG-2 intra VLC table. #define CODEC_FLAG2_DROP_FRAME_TIMECODE 0x00002000 ///< timecode is in drop frame format. #define CODEC_FLAG2_NON_LINEAR_QUANT 0x00010000 ///< Use MPEG-2 nonlinear quantizer. #endif #if FF_API_MJPEG_GLOBAL_OPTS #define CODEC_FLAG_EXTERN_HUFF 0x1000 ///< Use external Huffman table (for MJPEG). #endif #if FF_API_X264_GLOBAL_OPTS #define CODEC_FLAG2_BPYRAMID 0x00000010 ///< H.264 allow B-frames to be used as references. #define CODEC_FLAG2_WPRED 0x00000020 ///< H.264 weighted biprediction for B-frames #define CODEC_FLAG2_MIXED_REFS 0x00000040 ///< H.264 one reference per partition, as opposed to one reference per macroblock #define CODEC_FLAG2_8X8DCT 0x00000080 ///< H.264 high profile 8x8 transform #define CODEC_FLAG2_FASTPSKIP 0x00000100 ///< H.264 fast pskip #define CODEC_FLAG2_AUD 0x00000200 ///< H.264 access unit delimiters #define CODEC_FLAG2_BRDO 0x00000400 ///< B-frame rate-distortion optimization #define CODEC_FLAG2_MBTREE 0x00040000 ///< Use macroblock tree ratecontrol (x264 only) #define CODEC_FLAG2_PSY 0x00080000 ///< Use psycho visual optimizations. #define CODEC_FLAG2_SSIM 0x00100000 ///< Compute SSIM during encoding, error[] values are undefined. #define CODEC_FLAG2_INTRA_REFRESH 0x00200000 ///< Use periodic insertion of intra blocks instead of keyframes. #endif #if FF_API_SNOW_GLOBAL_OPTS #define CODEC_FLAG2_MEMC_ONLY 0x00001000 ///< Only do ME/MC (I frames -> ref, P frame -> ME+MC). #endif #if FF_API_LAME_GLOBAL_OPTS #define CODEC_FLAG2_BIT_RESERVOIR 0x00020000 ///< Use a bit reservoir when encoding if possible #endif /** * @} */ /* Unsupported options : * Syntax Arithmetic coding (SAC) * Reference Picture Selection * Independent Segment Decoding */ /* /Fx */ /* codec capabilities */ #define CODEC_CAP_DRAW_HORIZ_BAND 0x0001 ///< Decoder can use draw_horiz_band callback. /** * Codec uses get_buffer() for allocating buffers and supports custom allocators. * If not set, it might not use get_buffer() at all or use operations that * assume the buffer was allocated by avcodec_default_get_buffer. */ #define CODEC_CAP_DR1 0x0002 /* If 'parse_only' field is true, then avcodec_parse_frame() can be used. */ #define CODEC_CAP_PARSE_ONLY 0x0004 #define CODEC_CAP_TRUNCATED 0x0008 /* Codec can export data for HW decoding (XvMC). */ #define CODEC_CAP_HWACCEL 0x0010 /** * Codec has a nonzero delay and needs to be fed with NULL at the end to get the delayed data. * If this is not set, the codec is guaranteed to never be fed with NULL data. */ #define CODEC_CAP_DELAY 0x0020 /** * Codec can be fed a final frame with a smaller size. * This can be used to prevent truncation of the last audio samples. */ #define CODEC_CAP_SMALL_LAST_FRAME 0x0040 /** * Codec can export data for HW decoding (VDPAU). */ #define CODEC_CAP_HWACCEL_VDPAU 0x0080 /** * Codec can output multiple frames per AVPacket * Normally demuxers return one frame at a time, demuxers which do not do * are connected to a parser to split what they return into proper frames. * This flag is reserved to the very rare category of codecs which have a * bitstream that cannot be split into frames without timeconsuming * operations like full decoding. Demuxers carring such bitstreams thus * may return multiple frames in a packet. This has many disadvantages like * prohibiting stream copy in many cases thus it should only be considered * as a last resort. */ #define CODEC_CAP_SUBFRAMES 0x0100 /** * Codec is experimental and is thus avoided in favor of non experimental * encoders */ #define CODEC_CAP_EXPERIMENTAL 0x0200 /** * Codec should fill in channel configuration and samplerate instead of container */ #define CODEC_CAP_CHANNEL_CONF 0x0400 /** * Codec is able to deal with negative linesizes */ #define CODEC_CAP_NEG_LINESIZES 0x0800 /** * Codec supports frame-level multithreading. */ #define CODEC_CAP_FRAME_THREADS 0x1000 /** * Codec supports slice-based (or partition-based) multithreading. */ #define CODEC_CAP_SLICE_THREADS 0x2000 /** * Codec is lossless. */ #define CODEC_CAP_LOSSLESS 0x80000000 //The following defines may change, don't expect compatibility if you use them. #define MB_TYPE_INTRA4x4 0x0001 #define MB_TYPE_INTRA16x16 0x0002 //FIXME H.264-specific #define MB_TYPE_INTRA_PCM 0x0004 //FIXME H.264-specific #define MB_TYPE_16x16 0x0008 #define MB_TYPE_16x8 0x0010 #define MB_TYPE_8x16 0x0020 #define MB_TYPE_8x8 0x0040 #define MB_TYPE_INTERLACED 0x0080 #define MB_TYPE_DIRECT2 0x0100 //FIXME #define MB_TYPE_ACPRED 0x0200 #define MB_TYPE_GMC 0x0400 #define MB_TYPE_SKIP 0x0800 #define MB_TYPE_P0L0 0x1000 #define MB_TYPE_P1L0 0x2000 #define MB_TYPE_P0L1 0x4000 #define MB_TYPE_P1L1 0x8000 #define MB_TYPE_L0 (MB_TYPE_P0L0 | MB_TYPE_P1L0) #define MB_TYPE_L1 (MB_TYPE_P0L1 | MB_TYPE_P1L1) #define MB_TYPE_L0L1 (MB_TYPE_L0 | MB_TYPE_L1) #define MB_TYPE_QUANT 0x00010000 #define MB_TYPE_CBP 0x00020000 //Note bits 24-31 are reserved for codec specific use (h264 ref0, mpeg1 0mv, ...) /** * Pan Scan area. * This specifies the area which should be displayed. * Note there may be multiple such areas for one frame. */ typedef struct AVPanScan{ /** * id * - encoding: Set by user. * - decoding: Set by libavcodec. */ int id; /** * width and height in 1/16 pel * - encoding: Set by user. * - decoding: Set by libavcodec. */ int width; int height; /** * position of the top left corner in 1/16 pel for up to 3 fields/frames * - encoding: Set by user. * - decoding: Set by libavcodec. */ int16_t position[3][2]; }AVPanScan; #define FF_QSCALE_TYPE_MPEG1 0 #define FF_QSCALE_TYPE_MPEG2 1 #define FF_QSCALE_TYPE_H264 2 #define FF_QSCALE_TYPE_VP56 3 #define FF_BUFFER_TYPE_INTERNAL 1 #define FF_BUFFER_TYPE_USER 2 ///< direct rendering buffers (image is (de)allocated by user) #define FF_BUFFER_TYPE_SHARED 4 ///< Buffer from somewhere else; don't deallocate image (data/base), all other tables are not shared. #define FF_BUFFER_TYPE_COPY 8 ///< Just a (modified) copy of some other buffer, don't deallocate anything. #if FF_API_OLD_FF_PICT_TYPES /* DEPRECATED, directly use the AV_PICTURE_TYPE_* enum values */ #define FF_I_TYPE AV_PICTURE_TYPE_I ///< Intra #define FF_P_TYPE AV_PICTURE_TYPE_P ///< Predicted #define FF_B_TYPE AV_PICTURE_TYPE_B ///< Bi-dir predicted #define FF_S_TYPE AV_PICTURE_TYPE_S ///< S(GMC)-VOP MPEG4 #define FF_SI_TYPE AV_PICTURE_TYPE_SI ///< Switching Intra #define FF_SP_TYPE AV_PICTURE_TYPE_SP ///< Switching Predicted #define FF_BI_TYPE AV_PICTURE_TYPE_BI #endif #define FF_BUFFER_HINTS_VALID 0x01 // Buffer hints value is meaningful (if 0 ignore). #define FF_BUFFER_HINTS_READABLE 0x02 // Codec will read from buffer. #define FF_BUFFER_HINTS_PRESERVE 0x04 // User must not alter buffer content. #define FF_BUFFER_HINTS_REUSABLE 0x08 // Codec will reuse the buffer (update). enum AVPacketSideDataType { AV_PKT_DATA_PALETTE, }; typedef struct AVPacket { /** * Presentation timestamp in AVStream->time_base units; the time at which * the decompressed packet will be presented to the user. * Can be AV_NOPTS_VALUE if it is not stored in the file. * pts MUST be larger or equal to dts as presentation cannot happen before * decompression, unless one wants to view hex dumps. Some formats misuse * the terms dts and pts/cts to mean something different. Such timestamps * must be converted to true pts/dts before they are stored in AVPacket. */ int64_t pts; /** * Decompression timestamp in AVStream->time_base units; the time at which * the packet is decompressed. * Can be AV_NOPTS_VALUE if it is not stored in the file. */ int64_t dts; uint8_t *data; int size; int stream_index; /** * A combination of AV_PKT_FLAG values */ int flags; /** * Additional packet data that can be provided by the container. * Packet can contain several types of side information. */ struct { uint8_t *data; int size; enum AVPacketSideDataType type; } *side_data; int side_data_elems; /** * Duration of this packet in AVStream->time_base units, 0 if unknown. * Equals next_pts - this_pts in presentation order. */ int duration; void (*destruct)(struct AVPacket *); void *priv; int64_t pos; ///< byte position in stream, -1 if unknown /** * Time difference in AVStream->time_base units from the pts of this * packet to the point at which the output from the decoder has converged * independent from the availability of previous frames. That is, the * frames are virtually identical no matter if decoding started from * the very first frame or from this keyframe. * Is AV_NOPTS_VALUE if unknown. * This field is not the display duration of the current packet. * This field has no meaning if the packet does not have AV_PKT_FLAG_KEY * set. * * The purpose of this field is to allow seeking in streams that have no * keyframes in the conventional sense. It corresponds to the * recovery point SEI in H.264 and match_time_delta in NUT. It is also * essential for some types of subtitle streams to ensure that all * subtitles are correctly displayed after seeking. */ int64_t convergence_duration; } AVPacket; #define AV_PKT_FLAG_KEY 0x0001 ///< The packet contains a keyframe #define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted /** * Audio Video Frame. * New fields can be added to the end of AVFRAME with minor version * bumps. Removal, reordering and changes to existing fields require * a major version bump. * sizeof(AVFrame) must not be used outside libav*. */ typedef struct AVFrame { /** * pointer to the picture planes. * This might be different from the first allocated byte * - encoding: * - decoding: */ uint8_t *data[4]; int linesize[4]; /** * pointer to the first allocated byte of the picture. Can be used in get_buffer/release_buffer. * This isn't used by libavcodec unless the default get/release_buffer() is used. * - encoding: * - decoding: */ uint8_t *base[4]; /** * 1 -> keyframe, 0-> not * - encoding: Set by libavcodec. * - decoding: Set by libavcodec. */ int key_frame; /** * Picture type of the frame, see ?_TYPE below. * - encoding: Set by libavcodec. for coded_picture (and set by user for input). * - decoding: Set by libavcodec. */ enum AVPictureType pict_type; /** * presentation timestamp in time_base units (time when frame should be shown to user) * If AV_NOPTS_VALUE then frame_rate = 1/time_base will be assumed. * - encoding: MUST be set by user. * - decoding: Set by libavcodec. */ int64_t pts; /** * picture number in bitstream order * - encoding: set by * - decoding: Set by libavcodec. */ int coded_picture_number; /** * picture number in display order * - encoding: set by * - decoding: Set by libavcodec. */ int display_picture_number; /** * quality (between 1 (good) and FF_LAMBDA_MAX (bad)) * - encoding: Set by libavcodec. for coded_picture (and set by user for input). * - decoding: Set by libavcodec. */ int quality; /** * buffer age (1->was last buffer and dint change, 2->..., ...). * Set to INT_MAX if the buffer has not been used yet. * - encoding: unused * - decoding: MUST be set by get_buffer(). */ int age; /** * is this picture used as reference * The values for this are the same as the MpegEncContext.picture_structure * variable, that is 1->top field, 2->bottom field, 3->frame/both fields. * Set to 4 for delayed, non-reference frames. * - encoding: unused * - decoding: Set by libavcodec. (before get_buffer() call)). */ int reference; /** * QP table * - encoding: unused * - decoding: Set by libavcodec. */ int8_t *qscale_table; /** * QP store stride * - encoding: unused * - decoding: Set by libavcodec. */ int qstride; /** * mbskip_table[mb]>=1 if MB didn't change * stride= mb_width = (width+15)>>4 * - encoding: unused * - decoding: Set by libavcodec. */ uint8_t *mbskip_table; /** * motion vector table * @code * example: * int mv_sample_log2= 4 - motion_subsample_log2; * int mb_width= (width+15)>>4; * int mv_stride= (mb_width << mv_sample_log2) + 1; * motion_val[direction][x + y*mv_stride][0->mv_x, 1->mv_y]; * @endcode * - encoding: Set by user. * - decoding: Set by libavcodec. */ int16_t (*motion_val[2])[2]; /** * macroblock type table * mb_type_base + mb_width + 2 * - encoding: Set by user. * - decoding: Set by libavcodec. */ uint32_t *mb_type; /** * log2 of the size of the block which a single vector in motion_val represents: * (4->16x16, 3->8x8, 2-> 4x4, 1-> 2x2) * - encoding: unused * - decoding: Set by libavcodec. */ uint8_t motion_subsample_log2; /** * for some private data of the user * - encoding: unused * - decoding: Set by user. */ void *opaque; /** * error * - encoding: Set by libavcodec. if flags&CODEC_FLAG_PSNR. * - decoding: unused */ uint64_t error[4]; /** * type of the buffer (to keep track of who has to deallocate data[*]) * - encoding: Set by the one who allocates it. * - decoding: Set by the one who allocates it. * Note: User allocated (direct rendering) & internal buffers cannot coexist currently. */ int type; /** * When decoding, this signals how much the picture must be delayed. * extra_delay = repeat_pict / (2*fps) * - encoding: unused * - decoding: Set by libavcodec. */ int repeat_pict; /** * */ int qscale_type; /** * The content of the picture is interlaced. * - encoding: Set by user. * - decoding: Set by libavcodec. (default 0) */ int interlaced_frame; /** * If the content is interlaced, is top field displayed first. * - encoding: Set by user. * - decoding: Set by libavcodec. */ int top_field_first; /** * Pan scan. * - encoding: Set by user. * - decoding: Set by libavcodec. */ AVPanScan *pan_scan; /** * Tell user application that palette has changed from previous frame. * - encoding: ??? (no palette-enabled encoder yet) * - decoding: Set by libavcodec. (default 0). */ int palette_has_changed; /** * codec suggestion on buffer type if != 0 * - encoding: unused * - decoding: Set by libavcodec. (before get_buffer() call)). */ int buffer_hints; /** * DCT coefficients * - encoding: unused * - decoding: Set by libavcodec. */ short *dct_coeff; /** * motion reference frame index * the order in which these are stored can depend on the codec. * - encoding: Set by user. * - decoding: Set by libavcodec. */ int8_t *ref_index[2]; /** * reordered opaque 64bit (generally an integer or a double precision float * PTS but can be anything). * The user sets AVCodecContext.reordered_opaque to represent the input at * that time, * the decoder reorders values as needed and sets AVFrame.reordered_opaque * to exactly one of the values provided by the user through AVCodecContext.reordered_opaque * @deprecated in favor of pkt_pts * - encoding: unused * - decoding: Read by user. */ int64_t reordered_opaque; /** * hardware accelerator private data (FFmpeg-allocated) * - encoding: unused * - decoding: Set by libavcodec */ void *hwaccel_picture_private; /** * reordered pts from the last AVPacket that has been input into the decoder * - encoding: unused * - decoding: Read by user. */ int64_t pkt_pts; /** * dts from the last AVPacket that has been input into the decoder * - encoding: unused * - decoding: Read by user. */ int64_t pkt_dts; /** * the AVCodecContext which ff_thread_get_buffer() was last called on * - encoding: Set by libavcodec. * - decoding: Set by libavcodec. */ struct AVCodecContext *owner; /** * used by multithreading to store frame-specific info * - encoding: Set by libavcodec. * - decoding: Set by libavcodec. */ void *thread_opaque; /** * frame timestamp estimated using various heuristics, in stream time base * - encoding: unused * - decoding: set by libavcodec, read by user. */ int64_t best_effort_timestamp; /** * reordered pos from the last AVPacket that has been input into the decoder * - encoding: unused * - decoding: Read by user. */ int64_t pkt_pos; /** * reordered sample aspect ratio for the video frame, 0/1 if unknown\unspecified * - encoding: unused * - decoding: Read by user. */ AVRational sample_aspect_ratio; /** * width and height of the video frame * - encoding: unused * - decoding: Read by user. */ int width, height; /** * format of the frame, -1 if unknown or unset * It should be cast to the corresponding enum (enum PixelFormat * for video, enum AVSampleFormat for audio) * - encoding: unused * - decoding: Read by user. */ int format; } AVFrame; /** * main external API structure. * New fields can be added to the end with minor version bumps. * Removal, reordering and changes to existing fields require a major * version bump. * Please use AVOptions (av_opt* / av_set/get*()) to access these fields from user * applications. * sizeof(AVCodecContext) must not be used outside libav*. */ typedef struct AVCodecContext { /** * information on struct for av_log * - set by avcodec_alloc_context */ const AVClass *av_class; /** * the average bitrate * - encoding: Set by user; unused for constant quantizer encoding. * - decoding: Set by libavcodec. 0 or some bitrate if this info is available in the stream. */ int bit_rate; /** * number of bits the bitstream is allowed to diverge from the reference. * the reference can be CBR (for CBR pass1) or VBR (for pass2) * - encoding: Set by user; unused for constant quantizer encoding. * - decoding: unused */ int bit_rate_tolerance; /** * CODEC_FLAG_*. * - encoding: Set by user. * - decoding: Set by user. */ int flags; /** * Some codecs need additional format info. It is stored here. * If any muxer uses this then ALL demuxers/parsers AND encoders for the * specific codec MUST set it correctly otherwise stream copy breaks. * In general use of this field by muxers is not recommanded. * - encoding: Set by libavcodec. * - decoding: Set by libavcodec. (FIXME: Is this OK?) */ int sub_id; /** * Motion estimation algorithm used for video coding. * 1 (zero), 2 (full), 3 (log), 4 (phods), 5 (epzs), 6 (x1), 7 (hex), * 8 (umh), 9 (iter), 10 (tesa) [7, 8, 10 are x264 specific, 9 is snow specific] * - encoding: MUST be set by user. * - decoding: unused */ int me_method; /** * some codecs need / can use extradata like Huffman tables. * mjpeg: Huffman tables * rv10: additional flags * mpeg4: global headers (they can be in the bitstream or here) * The allocated memory should be FF_INPUT_BUFFER_PADDING_SIZE bytes larger * than extradata_size to avoid prolems if it is read with the bitstream reader. * The bytewise contents of extradata must not depend on the architecture or CPU endianness. * - encoding: Set/allocated/freed by libavcodec. * - decoding: Set/allocated/freed by user. */ uint8_t *extradata; int extradata_size; /** * This is the fundamental unit of time (in seconds) in terms * of which frame timestamps are represented. For fixed-fps content, * timebase should be 1/framerate and timestamp increments should be * identically 1. * - encoding: MUST be set by user. * - decoding: Set by libavcodec. */ AVRational time_base; /* video only */ /** * picture width / height. * - encoding: MUST be set by user. * - decoding: Set by libavcodec. * Note: For compatibility it is possible to set this instead of * coded_width/height before decoding. */ int width, height; #define FF_ASPECT_EXTENDED 15 /** * the number of pictures in a group of pictures, or 0 for intra_only * - encoding: Set by user. * - decoding: unused */ int gop_size; /** * Pixel format, see PIX_FMT_xxx. * May be set by the demuxer if known from headers. * May be overriden by the decoder if it knows better. * - encoding: Set by user. * - decoding: Set by user if known, overridden by libavcodec if known */ enum PixelFormat pix_fmt; /** * If non NULL, 'draw_horiz_band' is called by the libavcodec * decoder to draw a horizontal band. It improves cache usage. Not * all codecs can do that. You must check the codec capabilities * beforehand. * When multithreading is used, it may be called from multiple threads * at the same time; threads might draw different parts of the same AVFrame, * or multiple AVFrames, and there is no guarantee that slices will be drawn * in order. * The function is also used by hardware acceleration APIs. * It is called at least once during frame decoding to pass * the data needed for hardware render. * In that mode instead of pixel data, AVFrame points to * a structure specific to the acceleration API. The application * reads the structure and can change some fields to indicate progress * or mark state. * - encoding: unused * - decoding: Set by user. * @param height the height of the slice * @param y the y position of the slice * @param type 1->top field, 2->bottom field, 3->frame * @param offset offset into the AVFrame.data from which the slice should be read */ void (*draw_horiz_band)(struct AVCodecContext *s, const AVFrame *src, int offset[4], int y, int type, int height); /* audio only */ int sample_rate; ///< samples per second int channels; ///< number of audio channels /** * audio sample format * - encoding: Set by user. * - decoding: Set by libavcodec. */ enum AVSampleFormat sample_fmt; ///< sample format /* The following data should not be initialized. */ /** * Samples per packet, initialized when calling 'init'. */ int frame_size; int frame_number; ///< audio or video frame number /** * Number of frames the decoded output will be delayed relative to * the encoded input. * - encoding: Set by libavcodec. * - decoding: unused */ int delay; /* - encoding parameters */ float qcompress; ///< amount of qscale change between easy & hard scenes (0.0-1.0) float qblur; ///< amount of qscale smoothing over time (0.0-1.0) /** * minimum quantizer * - encoding: Set by user. * - decoding: unused */ int qmin; /** * maximum quantizer * - encoding: Set by user. * - decoding: unused */ int qmax; /** * maximum quantizer difference between frames * - encoding: Set by user. * - decoding: unused */ int max_qdiff; /** * maximum number of B-frames between non-B-frames * Note: The output will be delayed by max_b_frames+1 relative to the input. * - encoding: Set by user. * - decoding: unused */ int max_b_frames; /** * qscale factor between IP and B-frames * If > 0 then the last P-frame quantizer will be used (q= lastp_q*factor+offset). * If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset). * - encoding: Set by user. * - decoding: unused */ float b_quant_factor; /** obsolete FIXME remove */ int rc_strategy; #define FF_RC_STRATEGY_XVID 1 int b_frame_strategy; struct AVCodec *codec; void *priv_data; int rtp_payload_size; /* The size of the RTP payload: the coder will */ /* do its best to deliver a chunk with size */ /* below rtp_payload_size, the chunk will start */ /* with a start code on some codecs like H.263. */ /* This doesn't take account of any particular */ /* headers inside the transmitted RTP payload. */ /* The RTP callback: This function is called */ /* every time the encoder has a packet to send. */ /* It depends on the encoder if the data starts */ /* with a Start Code (it should). H.263 does. */ /* mb_nb contains the number of macroblocks */ /* encoded in the RTP payload. */ void (*rtp_callback)(struct AVCodecContext *avctx, void *data, int size, int mb_nb); /* statistics, used for 2-pass encoding */ int mv_bits; int header_bits; int i_tex_bits; int p_tex_bits; int i_count; int p_count; int skip_count; int misc_bits; /** * number of bits used for the previously encoded frame * - encoding: Set by libavcodec. * - decoding: unused */ int frame_bits; /** * Private data of the user, can be used to carry app specific stuff. * - encoding: Set by user. * - decoding: Set by user. */ void *opaque; char codec_name[32]; enum AVMediaType codec_type; /* see AVMEDIA_TYPE_xxx */ enum CodecID codec_id; /* see CODEC_ID_xxx */ /** * fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). * This is used to work around some encoder bugs. * A demuxer should set this to what is stored in the field used to identify the codec. * If there are multiple such fields in a container then the demuxer should choose the one * which maximizes the information about the used codec. * If the codec tag field in a container is larger than 32 bits then the demuxer should * remap the longer ID to 32 bits with a table or other structure. Alternatively a new * extra_codec_tag + size could be added but for this a clear advantage must be demonstrated * first. * - encoding: Set by user, if not then the default based on codec_id will be used. * - decoding: Set by user, will be converted to uppercase by libavcodec during init. */ unsigned int codec_tag; /** * Work around bugs in encoders which sometimes cannot be detected automatically. * - encoding: Set by user * - decoding: Set by user */ int workaround_bugs; #define FF_BUG_AUTODETECT 1 ///< autodetection #define FF_BUG_OLD_MSMPEG4 2 #define FF_BUG_XVID_ILACE 4 #define FF_BUG_UMP4 8 #define FF_BUG_NO_PADDING 16 #define FF_BUG_AMV 32 #define FF_BUG_AC_VLC 0 ///< Will be removed, libavcodec can now handle these non-compliant files by default. #define FF_BUG_QPEL_CHROMA 64 #define FF_BUG_STD_QPEL 128 #define FF_BUG_QPEL_CHROMA2 256 #define FF_BUG_DIRECT_BLOCKSIZE 512 #define FF_BUG_EDGE 1024 #define FF_BUG_HPEL_CHROMA 2048 #define FF_BUG_DC_CLIP 4096 #define FF_BUG_MS 8192 ///< Work around various bugs in Microsoft's broken decoders. #define FF_BUG_TRUNCATED 16384 //#define FF_BUG_FAKE_SCALABILITY 16 //Autodetection should work 100%. /** * luma single coefficient elimination threshold * - encoding: Set by user. * - decoding: unused */ int luma_elim_threshold; /** * chroma single coeff elimination threshold * - encoding: Set by user. * - decoding: unused */ int chroma_elim_threshold; /** * strictly follow the standard (MPEG4, ...). * - encoding: Set by user. * - decoding: Set by user. * Setting this to STRICT or higher means the encoder and decoder will * generally do stupid things, whereas setting it to unofficial or lower * will mean the encoder might produce output that is not supported by all * spec-compliant decoders. Decoders don't differentiate between normal, * unofficial and experimental (that is, they always try to decode things * when they can) unless they are explicitly asked to behave stupidly * (=strictly conform to the specs) */ int strict_std_compliance; #define FF_COMPLIANCE_VERY_STRICT 2 ///< Strictly conform to an older more strict version of the spec or reference software. #define FF_COMPLIANCE_STRICT 1 ///< Strictly conform to all the things in the spec no matter what consequences. #define FF_COMPLIANCE_NORMAL 0 #define FF_COMPLIANCE_UNOFFICIAL -1 ///< Allow unofficial extensions #define FF_COMPLIANCE_EXPERIMENTAL -2 ///< Allow nonstandardized experimental things. /** * qscale offset between IP and B-frames * - encoding: Set by user. * - decoding: unused */ float b_quant_offset; /** * Error recognition; higher values will detect more errors but may * misdetect some more or less valid parts as errors. * - encoding: unused * - decoding: Set by user. */ int error_recognition; #define FF_ER_CAREFUL 1 #define FF_ER_COMPLIANT 2 #define FF_ER_AGGRESSIVE 3 #if FF_API_VERY_AGGRESSIVE #define FF_ER_VERY_AGGRESSIVE 4 #define FF_ER_EXPLODE 5 #else #define FF_ER_EXPLODE 4 #endif /* FF_API_VERY_AGGRESSIVE */ /** * Called at the beginning of each frame to get a buffer for it. * If pic.reference is set then the frame will be read later by libavcodec. * avcodec_align_dimensions2() should be used to find the required width and * height, as they normally need to be rounded up to the next multiple of 16. * if CODEC_CAP_DR1 is not set then get_buffer() must call * avcodec_default_get_buffer() instead of providing buffers allocated by * some other means. * If frame multithreading is used and thread_safe_callbacks is set, * it may be called from a different thread, but not from more than one at once. * Does not need to be reentrant. * - encoding: unused * - decoding: Set by libavcodec, user can override. */ int (*get_buffer)(struct AVCodecContext *c, AVFrame *pic); /** * Called to release buffers which were allocated with get_buffer. * A released buffer can be reused in get_buffer(). * pic.data[*] must be set to NULL. * May be called from a different thread if frame multithreading is used, * but not by more than one thread at once, so does not need to be reentrant. * - encoding: unused * - decoding: Set by libavcodec, user can override. */ void (*release_buffer)(struct AVCodecContext *c, AVFrame *pic); /** * Size of the frame reordering buffer in the decoder. * For MPEG-2 it is 1 IPB or 0 low delay IP. * - encoding: Set by libavcodec. * - decoding: Set by libavcodec. */ int has_b_frames; /** * number of bytes per packet if constant and known or 0 * Used by some WAV based audio codecs. */ int block_align; int parse_only; /* - decoding only: If true, only parsing is done (function avcodec_parse_frame()). The frame data is returned. Only MPEG codecs support this now. */ /** * 0-> h263 quant 1-> mpeg quant * - encoding: Set by user. * - decoding: unused */ int mpeg_quant; /** * pass1 encoding statistics output buffer * - encoding: Set by libavcodec. * - decoding: unused */ char *stats_out; /** * pass2 encoding statistics input buffer * Concatenated stuff from stats_out of pass1 should be placed here. * - encoding: Allocated/set/freed by user. * - decoding: unused */ char *stats_in; /** * ratecontrol qmin qmax limiting method * 0-> clipping, 1-> use a nice continous function to limit qscale wthin qmin/qmax. * - encoding: Set by user. * - decoding: unused */ float rc_qsquish; float rc_qmod_amp; int rc_qmod_freq; /** * ratecontrol override, see RcOverride * - encoding: Allocated/set/freed by user. * - decoding: unused */ RcOverride *rc_override; int rc_override_count; /** * rate control equation * - encoding: Set by user * - decoding: unused */ const char *rc_eq; /** * maximum bitrate * - encoding: Set by user. * - decoding: unused */ int rc_max_rate; /** * minimum bitrate * - encoding: Set by user. * - decoding: unused */ int rc_min_rate; /** * decoder bitstream buffer size * - encoding: Set by user. * - decoding: unused */ int rc_buffer_size; float rc_buffer_aggressivity; /** * qscale factor between P and I-frames * If > 0 then the last p frame quantizer will be used (q= lastp_q*factor+offset). * If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset). * - encoding: Set by user. * - decoding: unused */ float i_quant_factor; /** * qscale offset between P and I-frames * - encoding: Set by user. * - decoding: unused */ float i_quant_offset; /** * initial complexity for pass1 ratecontrol * - encoding: Set by user. * - decoding: unused */ float rc_initial_cplx; /** * DCT algorithm, see FF_DCT_* below * - encoding: Set by user. * - decoding: unused */ int dct_algo; #define FF_DCT_AUTO 0 #define FF_DCT_FASTINT 1 #define FF_DCT_INT 2 #define FF_DCT_MMX 3 #define FF_DCT_MLIB 4 #define FF_DCT_ALTIVEC 5 #define FF_DCT_FAAN 6 /** * luminance masking (0-> disabled) * - encoding: Set by user. * - decoding: unused */ float lumi_masking; /** * temporary complexity masking (0-> disabled) * - encoding: Set by user. * - decoding: unused */ float temporal_cplx_masking; /** * spatial complexity masking (0-> disabled) * - encoding: Set by user. * - decoding: unused */ float spatial_cplx_masking; /** * p block masking (0-> disabled) * - encoding: Set by user. * - decoding: unused */ float p_masking; /** * darkness masking (0-> disabled) * - encoding: Set by user. * - decoding: unused */ float dark_masking; /** * IDCT algorithm, see FF_IDCT_* below. * - encoding: Set by user. * - decoding: Set by user. */ int idct_algo; #define FF_IDCT_AUTO 0 #define FF_IDCT_INT 1 #define FF_IDCT_SIMPLE 2 #define FF_IDCT_SIMPLEMMX 3 #define FF_IDCT_LIBMPEG2MMX 4 #define FF_IDCT_PS2 5 #define FF_IDCT_MLIB 6 #define FF_IDCT_ARM 7 #define FF_IDCT_ALTIVEC 8 #define FF_IDCT_SH4 9 #define FF_IDCT_SIMPLEARM 10 #define FF_IDCT_H264 11 #define FF_IDCT_VP3 12 #define FF_IDCT_IPP 13 #define FF_IDCT_XVIDMMX 14 #define FF_IDCT_CAVS 15 #define FF_IDCT_SIMPLEARMV5TE 16 #define FF_IDCT_SIMPLEARMV6 17 #define FF_IDCT_SIMPLEVIS 18 #define FF_IDCT_WMV2 19 #define FF_IDCT_FAAN 20 #define FF_IDCT_EA 21 #define FF_IDCT_SIMPLENEON 22 #define FF_IDCT_SIMPLEALPHA 23 #define FF_IDCT_BINK 24 /** * slice count * - encoding: Set by libavcodec. * - decoding: Set by user (or 0). */ int slice_count; /** * slice offsets in the frame in bytes * - encoding: Set/allocated by libavcodec. * - decoding: Set/allocated by user (or NULL). */ int *slice_offset; /** * error concealment flags * - encoding: unused * - decoding: Set by user. */ int error_concealment; #define FF_EC_GUESS_MVS 1 #define FF_EC_DEBLOCK 2 /** * dsp_mask could be add used to disable unwanted CPU features * CPU features (i.e. MMX, SSE. ...) * * With the FORCE flag you may instead enable given CPU features. * (Dangerous: Usable in case of misdetection, improper usage however will * result into program crash.) */ unsigned dsp_mask; /** * bits per sample/pixel from the demuxer (needed for huffyuv). * - encoding: Set by libavcodec. * - decoding: Set by user. */ int bits_per_coded_sample; /** * prediction method (needed for huffyuv) * - encoding: Set by user. * - decoding: unused */ int prediction_method; #define FF_PRED_LEFT 0 #define FF_PRED_PLANE 1 #define FF_PRED_MEDIAN 2 /** * sample aspect ratio (0 if unknown) * That is the width of a pixel divided by the height of the pixel. * Numerator and denominator must be relatively prime and smaller than 256 for some video standards. * - encoding: Set by user. * - decoding: Set by libavcodec. */ AVRational sample_aspect_ratio; /** * the picture in the bitstream * - encoding: Set by libavcodec. * - decoding: Set by libavcodec. */ AVFrame *coded_frame; /** * debug * - encoding: Set by user. * - decoding: Set by user. */ int debug; #define FF_DEBUG_PICT_INFO 1 #define FF_DEBUG_RC 2 #define FF_DEBUG_BITSTREAM 4 #define FF_DEBUG_MB_TYPE 8 #define FF_DEBUG_QP 16 #define FF_DEBUG_MV 32 #define FF_DEBUG_DCT_COEFF 0x00000040 #define FF_DEBUG_SKIP 0x00000080 #define FF_DEBUG_STARTCODE 0x00000100 #define FF_DEBUG_PTS 0x00000200 #define FF_DEBUG_ER 0x00000400 #define FF_DEBUG_MMCO 0x00000800 #define FF_DEBUG_BUGS 0x00001000 #define FF_DEBUG_VIS_QP 0x00002000 #define FF_DEBUG_VIS_MB_TYPE 0x00004000 #define FF_DEBUG_BUFFERS 0x00008000 #define FF_DEBUG_THREADS 0x00010000 /** * debug * - encoding: Set by user. * - decoding: Set by user. */ int debug_mv; #define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames #define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames #define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames /** * error * - encoding: Set by libavcodec if flags&CODEC_FLAG_PSNR. * - decoding: unused */ uint64_t error[4]; /** * motion estimation comparison function * - encoding: Set by user. * - decoding: unused */ int me_cmp; /** * subpixel motion estimation comparison function * - encoding: Set by user. * - decoding: unused */ int me_sub_cmp; /** * macroblock comparison function (not supported yet) * - encoding: Set by user. * - decoding: unused */ int mb_cmp; /** * interlaced DCT comparison function * - encoding: Set by user. * - decoding: unused */ int ildct_cmp; #define FF_CMP_SAD 0 #define FF_CMP_SSE 1 #define FF_CMP_SATD 2 #define FF_CMP_DCT 3 #define FF_CMP_PSNR 4 #define FF_CMP_BIT 5 #define FF_CMP_RD 6 #define FF_CMP_ZERO 7 #define FF_CMP_VSAD 8 #define FF_CMP_VSSE 9 #define FF_CMP_NSSE 10 #define FF_CMP_W53 11 #define FF_CMP_W97 12 #define FF_CMP_DCTMAX 13 #define FF_CMP_DCT264 14 #define FF_CMP_CHROMA 256 /** * ME diamond size & shape * - encoding: Set by user. * - decoding: unused */ int dia_size; /** * amount of previous MV predictors (2a+1 x 2a+1 square) * - encoding: Set by user. * - decoding: unused */ int last_predictor_count; /** * prepass for motion estimation * - encoding: Set by user. * - decoding: unused */ int pre_me; /** * motion estimation prepass comparison function * - encoding: Set by user. * - decoding: unused */ int me_pre_cmp; /** * ME prepass diamond size & shape * - encoding: Set by user. * - decoding: unused */ int pre_dia_size; /** * subpel ME quality * - encoding: Set by user. * - decoding: unused */ int me_subpel_quality; /** * callback to negotiate the pixelFormat * @param fmt is the list of formats which are supported by the codec, * it is terminated by -1 as 0 is a valid format, the formats are ordered by quality. * The first is always the native one. * @return the chosen format * - encoding: unused * - decoding: Set by user, if not set the native format will be chosen. */ enum PixelFormat (*get_format)(struct AVCodecContext *s, const enum PixelFormat * fmt); /** * DTG active format information (additional aspect ratio * information only used in DVB MPEG-2 transport streams) * 0 if not set. * * - encoding: unused * - decoding: Set by decoder. */ int dtg_active_format; #define FF_DTG_AFD_SAME 8 #define FF_DTG_AFD_4_3 9 #define FF_DTG_AFD_16_9 10 #define FF_DTG_AFD_14_9 11 #define FF_DTG_AFD_4_3_SP_14_9 13 #define FF_DTG_AFD_16_9_SP_14_9 14 #define FF_DTG_AFD_SP_4_3 15 /** * maximum motion estimation search range in subpel units * If 0 then no limit. * * - encoding: Set by user. * - decoding: unused */ int me_range; /** * intra quantizer bias * - encoding: Set by user. * - decoding: unused */ int intra_quant_bias; #define FF_DEFAULT_QUANT_BIAS 999999 /** * inter quantizer bias * - encoding: Set by user. * - decoding: unused */ int inter_quant_bias; /** * color table ID * - encoding: unused * - decoding: Which clrtable should be used for 8bit RGB images. * Tables have to be stored somewhere. FIXME */ int color_table_id; /** * internal_buffer count * Don't touch, used by libavcodec default_get_buffer(). */ int internal_buffer_count; /** * internal_buffers * Don't touch, used by libavcodec default_get_buffer(). */ void *internal_buffer; /** * Global quality for codecs which cannot change it per frame. * This should be proportional to MPEG-1/2/4 qscale. * - encoding: Set by user. * - decoding: unused */ int global_quality; #define FF_CODER_TYPE_VLC 0 #define FF_CODER_TYPE_AC 1 #define FF_CODER_TYPE_RAW 2 #define FF_CODER_TYPE_RLE 3 #define FF_CODER_TYPE_DEFLATE 4 /** * coder type * - encoding: Set by user. * - decoding: unused */ int coder_type; /** * context model * - encoding: Set by user. * - decoding: unused */ int context_model; #if 0 /** * * - encoding: unused * - decoding: Set by user. */ uint8_t * (*realloc)(struct AVCodecContext *s, uint8_t *buf, int buf_size); #endif /** * slice flags * - encoding: unused * - decoding: Set by user. */ int slice_flags; #define SLICE_FLAG_CODED_ORDER 0x0001 ///< draw_horiz_band() is called in coded order instead of display #define SLICE_FLAG_ALLOW_FIELD 0x0002 ///< allow draw_horiz_band() with field slices (MPEG2 field pics) #define SLICE_FLAG_ALLOW_PLANE 0x0004 ///< allow draw_horiz_band() with 1 component at a time (SVQ1) /** * XVideo Motion Acceleration * - encoding: forbidden * - decoding: set by decoder */ int xvmc_acceleration; /** * macroblock decision mode * - encoding: Set by user. * - decoding: unused */ int mb_decision; #define FF_MB_DECISION_SIMPLE 0 ///< uses mb_cmp #define FF_MB_DECISION_BITS 1 ///< chooses the one which needs the fewest bits #define FF_MB_DECISION_RD 2 ///< rate distortion /** * custom intra quantization matrix * - encoding: Set by user, can be NULL. * - decoding: Set by libavcodec. */ uint16_t *intra_matrix; /** * custom inter quantization matrix * - encoding: Set by user, can be NULL. * - decoding: Set by libavcodec. */ uint16_t *inter_matrix; /** * fourcc from the AVI stream header (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). * This is used to work around some encoder bugs. * - encoding: unused * - decoding: Set by user, will be converted to uppercase by libavcodec during init. */ unsigned int stream_codec_tag; /** * scene change detection threshold * 0 is default, larger means fewer detected scene changes. * - encoding: Set by user. * - decoding: unused */ int scenechange_threshold; /** * minimum Lagrange multipler * - encoding: Set by user. * - decoding: unused */ int lmin; /** * maximum Lagrange multipler * - encoding: Set by user. * - decoding: unused */ int lmax; #if FF_API_PALETTE_CONTROL /** * palette control structure * - encoding: ??? (no palette-enabled encoder yet) * - decoding: Set by user. */ struct AVPaletteControl *palctrl; #endif /** * noise reduction strength * - encoding: Set by user. * - decoding: unused */ int noise_reduction; /** * Called at the beginning of a frame to get cr buffer for it. * Buffer type (size, hints) must be the same. libavcodec won't check it. * libavcodec will pass previous buffer in pic, function should return * same buffer or new buffer with old frame "painted" into it. * If pic.data[0] == NULL must behave like get_buffer(). * if CODEC_CAP_DR1 is not set then reget_buffer() must call * avcodec_default_reget_buffer() instead of providing buffers allocated by * some other means. * - encoding: unused * - decoding: Set by libavcodec, user can override. */ int (*reget_buffer)(struct AVCodecContext *c, AVFrame *pic); /** * Number of bits which should be loaded into the rc buffer before decoding starts. * - encoding: Set by user. * - decoding: unused */ int rc_initial_buffer_occupancy; /** * * - encoding: Set by user. * - decoding: unused */ int inter_threshold; /** * CODEC_FLAG2_* * - encoding: Set by user. * - decoding: Set by user. */ int flags2; /** * Simulates errors in the bitstream to test error concealment. * - encoding: Set by user. * - decoding: unused */ int error_rate; #if FF_API_ANTIALIAS_ALGO /** * MP3 antialias algorithm, see FF_AA_* below. * - encoding: unused * - decoding: Set by user. */ attribute_deprecated int antialias_algo; #define FF_AA_AUTO 0 #define FF_AA_FASTINT 1 //not implemented yet #define FF_AA_INT 2 #define FF_AA_FLOAT 3 #endif /** * quantizer noise shaping * - encoding: Set by user. * - decoding: unused */ int quantizer_noise_shaping; /** * thread count * is used to decide how many independent tasks should be passed to execute() * - encoding: Set by user. * - decoding: Set by user. */ int thread_count; /** * The codec may call this to execute several independent things. * It will return only after finishing all tasks. * The user may replace this with some multithreaded implementation, * the default implementation will execute the parts serially. * @param count the number of things to execute * - encoding: Set by libavcodec, user can override. * - decoding: Set by libavcodec, user can override. */ int (*execute)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg), void *arg2, int *ret, int count, int size); /** * thread opaque * Can be used by execute() to store some per AVCodecContext stuff. * - encoding: set by execute() * - decoding: set by execute() */ void *thread_opaque; /** * Motion estimation threshold below which no motion estimation is * performed, but instead the user specified motion vectors are used. * * - encoding: Set by user. * - decoding: unused */ int me_threshold; /** * Macroblock threshold below which the user specified macroblock types will be used. * - encoding: Set by user. * - decoding: unused */ int mb_threshold; /** * precision of the intra DC coefficient - 8 * - encoding: Set by user. * - decoding: unused */ int intra_dc_precision; /** * noise vs. sse weight for the nsse comparsion function * - encoding: Set by user. * - decoding: unused */ int nsse_weight; /** * Number of macroblock rows at the top which are skipped. * - encoding: unused * - decoding: Set by user. */ int skip_top; /** * Number of macroblock rows at the bottom which are skipped. * - encoding: unused * - decoding: Set by user. */ int skip_bottom; /** * profile * - encoding: Set by user. * - decoding: Set by libavcodec. */ int profile; #define FF_PROFILE_UNKNOWN -99 #define FF_PROFILE_RESERVED -100 #define FF_PROFILE_AAC_MAIN 0 #define FF_PROFILE_AAC_LOW 1 #define FF_PROFILE_AAC_SSR 2 #define FF_PROFILE_AAC_LTP 3 #define FF_PROFILE_DTS 20 #define FF_PROFILE_DTS_ES 30 #define FF_PROFILE_DTS_96_24 40 #define FF_PROFILE_DTS_HD_HRA 50 #define FF_PROFILE_DTS_HD_MA 60 #define FF_PROFILE_MPEG2_422 0 #define FF_PROFILE_MPEG2_HIGH 1 #define FF_PROFILE_MPEG2_SS 2 #define FF_PROFILE_MPEG2_SNR_SCALABLE 3 #define FF_PROFILE_MPEG2_MAIN 4 #define FF_PROFILE_MPEG2_SIMPLE 5 #define FF_PROFILE_H264_CONSTRAINED (1<<9) // 8+1; constraint_set1_flag #define FF_PROFILE_H264_INTRA (1<<11) // 8+3; constraint_set3_flag #define FF_PROFILE_H264_BASELINE 66 #define FF_PROFILE_H264_CONSTRAINED_BASELINE (66|FF_PROFILE_H264_CONSTRAINED) #define FF_PROFILE_H264_MAIN 77 #define FF_PROFILE_H264_EXTENDED 88 #define FF_PROFILE_H264_HIGH 100 #define FF_PROFILE_H264_HIGH_10 110 #define FF_PROFILE_H264_HIGH_10_INTRA (110|FF_PROFILE_H264_INTRA) #define FF_PROFILE_H264_HIGH_422 122 #define FF_PROFILE_H264_HIGH_422_INTRA (122|FF_PROFILE_H264_INTRA) #define FF_PROFILE_H264_HIGH_444 144 #define FF_PROFILE_H264_HIGH_444_PREDICTIVE 244 #define FF_PROFILE_H264_HIGH_444_INTRA (244|FF_PROFILE_H264_INTRA) #define FF_PROFILE_H264_CAVLC_444 44 #define FF_PROFILE_VC1_SIMPLE 0 #define FF_PROFILE_VC1_MAIN 1 #define FF_PROFILE_VC1_COMPLEX 2 #define FF_PROFILE_VC1_ADVANCED 3 #define FF_PROFILE_MPEG4_SIMPLE 0 #define FF_PROFILE_MPEG4_SIMPLE_SCALABLE 1 #define FF_PROFILE_MPEG4_CORE 2 #define FF_PROFILE_MPEG4_MAIN 3 #define FF_PROFILE_MPEG4_N_BIT 4 #define FF_PROFILE_MPEG4_SCALABLE_TEXTURE 5 #define FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION 6 #define FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE 7 #define FF_PROFILE_MPEG4_HYBRID 8 #define FF_PROFILE_MPEG4_ADVANCED_REAL_TIME 9 #define FF_PROFILE_MPEG4_CORE_SCALABLE 10 #define FF_PROFILE_MPEG4_ADVANCED_CODING 11 #define FF_PROFILE_MPEG4_ADVANCED_CORE 12 #define FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE 13 #define FF_PROFILE_MPEG4_SIMPLE_STUDIO 14 #define FF_PROFILE_MPEG4_ADVANCED_SIMPLE 15 /** * level * - encoding: Set by user. * - decoding: Set by libavcodec. */ int level; #define FF_LEVEL_UNKNOWN -99 /** * low resolution decoding, 1-> 1/2 size, 2->1/4 size * - encoding: unused * - decoding: Set by user. */ int lowres; /** * Bitstream width / height, may be different from width/height if lowres enabled. * - encoding: unused * - decoding: Set by user before init if known. Codec should override / dynamically change if needed. */ int coded_width, coded_height; /** * frame skip threshold * - encoding: Set by user. * - decoding: unused */ int frame_skip_threshold; /** * frame skip factor * - encoding: Set by user. * - decoding: unused */ int frame_skip_factor; /** * frame skip exponent * - encoding: Set by user. * - decoding: unused */ int frame_skip_exp; /** * frame skip comparison function * - encoding: Set by user. * - decoding: unused */ int frame_skip_cmp; /** * Border processing masking, raises the quantizer for mbs on the borders * of the picture. * - encoding: Set by user. * - decoding: unused */ float border_masking; /** * minimum MB lagrange multipler * - encoding: Set by user. * - decoding: unused */ int mb_lmin; /** * maximum MB lagrange multipler * - encoding: Set by user. * - decoding: unused */ int mb_lmax; /** * * - encoding: Set by user. * - decoding: unused */ int me_penalty_compensation; /** * * - encoding: unused * - decoding: Set by user. */ enum AVDiscard skip_loop_filter; /** * * - encoding: unused * - decoding: Set by user. */ enum AVDiscard skip_idct; /** * * - encoding: unused * - decoding: Set by user. */ enum AVDiscard skip_frame; /** * * - encoding: Set by user. * - decoding: unused */ int bidir_refine; /** * * - encoding: Set by user. * - decoding: unused */ int brd_scale; #if FF_API_X264_GLOBAL_OPTS /** * constant rate factor - quality-based VBR - values ~correspond to qps * - encoding: Set by user. * - decoding: unused * @deprecated use 'crf' libx264 private option */ attribute_deprecated float crf; /** * constant quantization parameter rate control method * - encoding: Set by user. * - decoding: unused * @deprecated use 'cqp' libx264 private option */ attribute_deprecated int cqp; #endif /** * minimum GOP size * - encoding: Set by user. * - decoding: unused */ int keyint_min; /** * number of reference frames * - encoding: Set by user. * - decoding: Set by lavc. */ int refs; /** * chroma qp offset from luma * - encoding: Set by user. * - decoding: unused */ int chromaoffset; #if FF_API_X264_GLOBAL_OPTS /** * Influences how often B-frames are used. * - encoding: Set by user. * - decoding: unused */ attribute_deprecated int bframebias; #endif /** * trellis RD quantization * - encoding: Set by user. * - decoding: unused */ int trellis; #if FF_API_X264_GLOBAL_OPTS /** * Reduce fluctuations in qp (before curve compression). * - encoding: Set by user. * - decoding: unused */ attribute_deprecated float complexityblur; /** * in-loop deblocking filter alphac0 parameter * alpha is in the range -6...6 * - encoding: Set by user. * - decoding: unused */ attribute_deprecated int deblockalpha; /** * in-loop deblocking filter beta parameter * beta is in the range -6...6 * - encoding: Set by user. * - decoding: unused */ attribute_deprecated int deblockbeta; /** * macroblock subpartition sizes to consider - p8x8, p4x4, b8x8, i8x8, i4x4 * - encoding: Set by user. * - decoding: unused */ attribute_deprecated int partitions; #define X264_PART_I4X4 0x001 /* Analyze i4x4 */ #define X264_PART_I8X8 0x002 /* Analyze i8x8 (requires 8x8 transform) */ #define X264_PART_P8X8 0x010 /* Analyze p16x8, p8x16 and p8x8 */ #define X264_PART_P4X4 0x020 /* Analyze p8x4, p4x8, p4x4 */ #define X264_PART_B8X8 0x100 /* Analyze b16x8, b8x16 and b8x8 */ /** * direct MV prediction mode - 0 (none), 1 (spatial), 2 (temporal), 3 (auto) * - encoding: Set by user. * - decoding: unused */ attribute_deprecated int directpred; #endif /** * Audio cutoff bandwidth (0 means "automatic") * - encoding: Set by user. * - decoding: unused */ int cutoff; /** * Multiplied by qscale for each frame and added to scene_change_score. * - encoding: Set by user. * - decoding: unused */ int scenechange_factor; /** * * Note: Value depends upon the compare function used for fullpel ME. * - encoding: Set by user. * - decoding: unused */ int mv0_threshold; /** * Adjusts sensitivity of b_frame_strategy 1. * - encoding: Set by user. * - decoding: unused */ int b_sensitivity; /** * - encoding: Set by user. * - decoding: unused */ int compression_level; #define FF_COMPRESSION_DEFAULT -1 /** * - encoding: Set by user. * - decoding: unused */ int min_prediction_order; /** * - encoding: Set by user. * - decoding: unused */ int max_prediction_order; #if FF_API_FLAC_GLOBAL_OPTS /** * @name FLAC options * @deprecated Use FLAC encoder private options instead. * @{ */ /** * LPC coefficient precision - used by FLAC encoder * - encoding: Set by user. * - decoding: unused */ attribute_deprecated int lpc_coeff_precision; /** * search method for selecting prediction order * - encoding: Set by user. * - decoding: unused */ attribute_deprecated int prediction_order_method; /** * - encoding: Set by user. * - decoding: unused */ attribute_deprecated int min_partition_order; /** * - encoding: Set by user. * - decoding: unused */ attribute_deprecated int max_partition_order; /** * @} */ #endif /** * GOP timecode frame start number, in non drop frame format * - encoding: Set by user. * - decoding: unused */ int64_t timecode_frame_start; #if FF_API_REQUEST_CHANNELS /** * Decoder should decode to this many channels if it can (0 for default) * - encoding: unused * - decoding: Set by user. * @deprecated Deprecated in favor of request_channel_layout. */ int request_channels; #endif #if FF_API_DRC_SCALE /** * Percentage of dynamic range compression to be applied by the decoder. * The default value is 1.0, corresponding to full compression. * - encoding: unused * - decoding: Set by user. * @deprecated use AC3 decoder private option instead. */ attribute_deprecated float drc_scale; #endif /** * opaque 64bit number (generally a PTS) that will be reordered and * output in AVFrame.reordered_opaque * @deprecated in favor of pkt_pts * - encoding: unused * - decoding: Set by user. */ int64_t reordered_opaque; /** * Bits per sample/pixel of internal libavcodec pixel/sample format. * - encoding: set by user. * - decoding: set by libavcodec. */ int bits_per_raw_sample; /** * Audio channel layout. * - encoding: set by user. * - decoding: set by user, may be overwritten by libavcodec. */ int64_t channel_layout; /** * Request decoder to use this channel layout if it can (0 for default) * - encoding: unused * - decoding: Set by user. */ int64_t request_channel_layout; /** * Ratecontrol attempt to use, at maximum, of what can be used without an underflow. * - encoding: Set by user. * - decoding: unused. */ float rc_max_available_vbv_use; /** * Ratecontrol attempt to use, at least, times the amount needed to prevent a vbv overflow. * - encoding: Set by user. * - decoding: unused. */ float rc_min_vbv_overflow_use; /** * Hardware accelerator in use * - encoding: unused. * - decoding: Set by libavcodec */ struct AVHWAccel *hwaccel; /** * For some codecs, the time base is closer to the field rate than the frame rate. * Most notably, H.264 and MPEG-2 specify time_base as half of frame duration * if no telecine is used ... * * Set to time_base ticks per frame. Default 1, e.g., H.264/MPEG-2 set it to 2. */ int ticks_per_frame; /** * Hardware accelerator context. * For some hardware accelerators, a global context needs to be * provided by the user. In that case, this holds display-dependent * data FFmpeg cannot instantiate itself. Please refer to the * FFmpeg HW accelerator documentation to know how to fill this * is. e.g. for VA API, this is a struct vaapi_context. * - encoding: unused * - decoding: Set by user */ void *hwaccel_context; /** * Chromaticity coordinates of the source primaries. * - encoding: Set by user * - decoding: Set by libavcodec */ enum AVColorPrimaries color_primaries; /** * Color Transfer Characteristic. * - encoding: Set by user * - decoding: Set by libavcodec */ enum AVColorTransferCharacteristic color_trc; /** * YUV colorspace type. * - encoding: Set by user * - decoding: Set by libavcodec */ enum AVColorSpace colorspace; /** * MPEG vs JPEG YUV range. * - encoding: Set by user * - decoding: Set by libavcodec */ enum AVColorRange color_range; /** * This defines the location of chroma samples. * - encoding: Set by user * - decoding: Set by libavcodec */ enum AVChromaLocation chroma_sample_location; /** * The codec may call this to execute several independent things. * It will return only after finishing all tasks. * The user may replace this with some multithreaded implementation, * the default implementation will execute the parts serially. * Also see avcodec_thread_init and e.g. the --enable-pthread configure option. * @param c context passed also to func * @param count the number of things to execute * @param arg2 argument passed unchanged to func * @param ret return values of executed functions, must have space for "count" values. May be NULL. * @param func function that will be called count times, with jobnr from 0 to count-1. * threadnr will be in the range 0 to c->thread_count-1 < MAX_THREADS and so that no * two instances of func executing at the same time will have the same threadnr. * @return always 0 currently, but code should handle a future improvement where when any call to func * returns < 0 no further calls to func may be done and < 0 is returned. * - encoding: Set by libavcodec, user can override. * - decoding: Set by libavcodec, user can override. */ int (*execute2)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg, int jobnr, int threadnr), void *arg2, int *ret, int count); #if FF_API_X264_GLOBAL_OPTS /** * explicit P-frame weighted prediction analysis method * 0: off * 1: fast blind weighting (one reference duplicate with -1 offset) * 2: smart weighting (full fade detection analysis) * - encoding: Set by user. * - decoding: unused */ attribute_deprecated int weighted_p_pred; /** * AQ mode * 0: Disabled * 1: Variance AQ (complexity mask) * 2: Auto-variance AQ (experimental) * - encoding: Set by user * - decoding: unused */ attribute_deprecated int aq_mode; /** * AQ strength * Reduces blocking and blurring in flat and textured areas. * - encoding: Set by user * - decoding: unused */ attribute_deprecated float aq_strength; /** * PSY RD * Strength of psychovisual optimization * - encoding: Set by user * - decoding: unused */ attribute_deprecated float psy_rd; /** * PSY trellis * Strength of psychovisual optimization * - encoding: Set by user * - decoding: unused */ attribute_deprecated float psy_trellis; /** * RC lookahead * Number of frames for frametype and ratecontrol lookahead * - encoding: Set by user * - decoding: unused */ attribute_deprecated int rc_lookahead; /** * Constant rate factor maximum * With CRF encoding mode and VBV restrictions enabled, prevents quality from being worse * than crf_max, even if doing so would violate VBV restrictions. * - encoding: Set by user. * - decoding: unused */ attribute_deprecated float crf_max; #endif int log_level_offset; #if FF_API_FLAC_GLOBAL_OPTS /** * Determines which LPC analysis algorithm to use. * - encoding: Set by user * - decoding: unused */ attribute_deprecated enum AVLPCType lpc_type; /** * Number of passes to use for Cholesky factorization during LPC analysis * - encoding: Set by user * - decoding: unused */ attribute_deprecated int lpc_passes; #endif /** * Number of slices. * Indicates number of picture subdivisions. Used for parallelized * decoding. * - encoding: Set by user * - decoding: unused */ int slices; /** * Header containing style information for text subtitles. * For SUBTITLE_ASS subtitle type, it should contain the whole ASS * [Script Info] and [V4+ Styles] section, plus the [Events] line and * the Format line following. It shouldn't include any Dialogue line. * - encoding: Set/allocated/freed by user (before avcodec_open()) * - decoding: Set/allocated/freed by libavcodec (by avcodec_open()) */ uint8_t *subtitle_header; int subtitle_header_size; /** * Current packet as passed into the decoder, to avoid having * to pass the packet into every function. Currently only valid * inside lavc and get/release_buffer callbacks. * - decoding: set by avcodec_decode_*, read by get_buffer() for setting pkt_pts * - encoding: unused */ AVPacket *pkt; /** * Whether this is a copy of the context which had init() called on it. * This is used by multithreading - shared tables and picture pointers * should be freed from the original context only. * - encoding: Set by libavcodec. * - decoding: Set by libavcodec. */ int is_copy; /** * Which multithreading methods to use. * Use of FF_THREAD_FRAME will increase decoding delay by one frame per thread, * so clients which cannot provide future frames should not use it. * * - encoding: Set by user, otherwise the default is used. * - decoding: Set by user, otherwise the default is used. */ int thread_type; #define FF_THREAD_FRAME 1 ///< Decode more than one frame at once #define FF_THREAD_SLICE 2 ///< Decode more than one part of a single frame at once /** * Which multithreading methods are in use by the codec. * - encoding: Set by libavcodec. * - decoding: Set by libavcodec. */ int active_thread_type; /** * Set by the client if its custom get_buffer() callback can be called * from another thread, which allows faster multithreaded decoding. * draw_horiz_band() will be called from other threads regardless of this setting. * Ignored if the default get_buffer() is used. * - encoding: Set by user. * - decoding: Set by user. */ int thread_safe_callbacks; /** * VBV delay coded in the last frame (in periods of a 27 MHz clock). * Used for compliant TS muxing. * - encoding: Set by libavcodec. * - decoding: unused. */ uint64_t vbv_delay; /** * Type of service that the audio stream conveys. * - encoding: Set by user. * - decoding: Set by libavcodec. */ enum AVAudioServiceType audio_service_type; /** * desired sample format * - encoding: Not used. * - decoding: Set by user. * Decoder will decode to this format if it can. */ enum AVSampleFormat request_sample_fmt; /** * Current statistics for PTS correction. * - decoding: maintained and used by libavcodec, not intended to be used by user apps * - encoding: unused */ int64_t pts_correction_num_faulty_pts; /// Number of incorrect PTS values so far int64_t pts_correction_num_faulty_dts; /// Number of incorrect DTS values so far int64_t pts_correction_last_pts; /// PTS of the last frame int64_t pts_correction_last_dts; /// DTS of the last frame } AVCodecContext; /** * AVProfile. */ typedef struct AVProfile { int profile; const char *name; ///< short name for the profile } AVProfile; typedef struct AVCodecDefault AVCodecDefault; /** * AVCodec. */ typedef struct AVCodec { /** * Name of the codec implementation. * The name is globally unique among encoders and among decoders (but an * encoder and a decoder can share the same name). * This is the primary way to find a codec from the user perspective. */ const char *name; enum AVMediaType type; enum CodecID id; int priv_data_size; int (*init)(AVCodecContext *); int (*encode)(AVCodecContext *, uint8_t *buf, int buf_size, void *data); int (*close)(AVCodecContext *); int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt); /** * Codec capabilities. * see CODEC_CAP_* */ int capabilities; struct AVCodec *next; /** * Flush buffers. * Will be called when seeking */ void (*flush)(AVCodecContext *); const AVRational *supported_framerates; ///< array of supported framerates, or NULL if any, array is terminated by {0,0} const enum PixelFormat *pix_fmts; ///< array of supported pixel formats, or NULL if unknown, array is terminated by -1 /** * Descriptive name for the codec, meant to be more human readable than name. * You should use the NULL_IF_CONFIG_SMALL() macro to define it. */ const char *long_name; const int *supported_samplerates; ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0 const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1 const int64_t *channel_layouts; ///< array of support channel layouts, or NULL if unknown. array is terminated by 0 uint8_t max_lowres; ///< maximum value for lowres supported by the decoder const AVClass *priv_class; ///< AVClass for the private context const AVProfile *profiles; ///< array of recognized profiles, or NULL if unknown, array is terminated by {FF_PROFILE_UNKNOWN} /** * @name Frame-level threading support functions * @{ */ /** * If defined, called on thread contexts when they are created. * If the codec allocates writable tables in init(), re-allocate them here. * priv_data will be set to a copy of the original. */ int (*init_thread_copy)(AVCodecContext *); /** * Copy necessary context variables from a previous thread context to the current one. * If not defined, the next thread will start automatically; otherwise, the codec * must call ff_thread_finish_setup(). * * dst and src will (rarely) point to the same context, in which case memcpy should be skipped. */ int (*update_thread_context)(AVCodecContext *dst, const AVCodecContext *src); /** @} */ /** * Private codec-specific defaults. */ const AVCodecDefault *defaults; } AVCodec; /** * AVHWAccel. */ typedef struct AVHWAccel { /** * Name of the hardware accelerated codec. * The name is globally unique among encoders and among decoders (but an * encoder and a decoder can share the same name). */ const char *name; /** * Type of codec implemented by the hardware accelerator. * * See AVMEDIA_TYPE_xxx */ enum AVMediaType type; /** * Codec implemented by the hardware accelerator. * * See CODEC_ID_xxx */ enum CodecID id; /** * Supported pixel format. * * Only hardware accelerated formats are supported here. */ enum PixelFormat pix_fmt; /** * Hardware accelerated codec capabilities. * see FF_HWACCEL_CODEC_CAP_* */ int capabilities; struct AVHWAccel *next; /** * Called at the beginning of each frame or field picture. * * Meaningful frame information (codec specific) is guaranteed to * be parsed at this point. This function is mandatory. * * Note that buf can be NULL along with buf_size set to 0. * Otherwise, this means the whole frame is available at this point. * * @param avctx the codec context * @param buf the frame data buffer base * @param buf_size the size of the frame in bytes * @return zero if successful, a negative value otherwise */ int (*start_frame)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size); /** * Callback for each slice. * * Meaningful slice information (codec specific) is guaranteed to * be parsed at this point. This function is mandatory. * * @param avctx the codec context * @param buf the slice data buffer base * @param buf_size the size of the slice in bytes * @return zero if successful, a negative value otherwise */ int (*decode_slice)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size); /** * Called at the end of each frame or field picture. * * The whole picture is parsed at this point and can now be sent * to the hardware accelerator. This function is mandatory. * * @param avctx the codec context * @return zero if successful, a negative value otherwise */ int (*end_frame)(AVCodecContext *avctx); /** * Size of HW accelerator private data. * * Private data is allocated with av_mallocz() before * AVCodecContext.get_buffer() and deallocated after * AVCodecContext.release_buffer(). */ int priv_data_size; } AVHWAccel; /** * four components are given, that's all. * the last component is alpha */ typedef struct AVPicture { uint8_t *data[4]; int linesize[4]; ///< number of bytes per line } AVPicture; #if FF_API_PALETTE_CONTROL /** * AVPaletteControl * This structure defines a method for communicating palette changes * between and demuxer and a decoder. * * @deprecated Use AVPacket to send palette changes instead. * This is totally broken. */ #define AVPALETTE_SIZE 1024 #define AVPALETTE_COUNT 256 typedef struct AVPaletteControl { /* Demuxer sets this to 1 to indicate the palette has changed; * decoder resets to 0. */ int palette_changed; /* 4-byte ARGB palette entries, stored in native byte order; note that * the individual palette components should be on a 8-bit scale; if * the palette data comes from an IBM VGA native format, the component * data is probably 6 bits in size and needs to be scaled. */ unsigned int palette[AVPALETTE_COUNT]; } AVPaletteControl attribute_deprecated; #endif enum AVSubtitleType { SUBTITLE_NONE, SUBTITLE_BITMAP, ///< A bitmap, pict will be set /** * Plain text, the text field must be set by the decoder and is * authoritative. ass and pict fields may contain approximations. */ SUBTITLE_TEXT, /** * Formatted text, the ass field must be set by the decoder and is * authoritative. pict and text fields may contain approximations. */ SUBTITLE_ASS, }; typedef struct AVSubtitleRect { int x; ///< top left corner of pict, undefined when pict is not set int y; ///< top left corner of pict, undefined when pict is not set int w; ///< width of pict, undefined when pict is not set int h; ///< height of pict, undefined when pict is not set int nb_colors; ///< number of colors in pict, undefined when pict is not set /** * data+linesize for the bitmap of this subtitle. * can be set for text/ass as well once they where rendered */ AVPicture pict; enum AVSubtitleType type; char *text; ///< 0 terminated plain UTF-8 text /** * 0 terminated ASS/SSA compatible event line. * The pressentation of this is unaffected by the other values in this * struct. */ char *ass; } AVSubtitleRect; typedef struct AVSubtitle { uint16_t format; /* 0 = graphics */ uint32_t start_display_time; /* relative to packet pts, in ms */ uint32_t end_display_time; /* relative to packet pts, in ms */ unsigned num_rects; AVSubtitleRect **rects; int64_t pts; ///< Same as packet pts, in AV_TIME_BASE } AVSubtitle; /* packet functions */ /** * @deprecated use NULL instead */ attribute_deprecated void av_destruct_packet_nofree(AVPacket *pkt); /** * Default packet destructor. */ void av_destruct_packet(AVPacket *pkt); /** * Initialize optional fields of a packet with default values. * * @param pkt packet */ void av_init_packet(AVPacket *pkt); /** * Allocate the payload of a packet and initialize its fields with * default values. * * @param pkt packet * @param size wanted payload size * @return 0 if OK, AVERROR_xxx otherwise */ int av_new_packet(AVPacket *pkt, int size); /** * Reduce packet size, correctly zeroing padding * * @param pkt packet * @param size new size */ void av_shrink_packet(AVPacket *pkt, int size); /** * Increase packet size, correctly zeroing padding * * @param pkt packet * @param grow_by number of bytes by which to increase the size of the packet */ int av_grow_packet(AVPacket *pkt, int grow_by); /** * @warning This is a hack - the packet memory allocation stuff is broken. The * packet is allocated if it was not really allocated. */ int av_dup_packet(AVPacket *pkt); /** * Free a packet. * * @param pkt packet to free */ void av_free_packet(AVPacket *pkt); /** * Allocate new information of a packet. * * @param pkt packet * @param type side information type * @param size side information size * @return pointer to fresh allocated data or NULL otherwise */ uint8_t* av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type, int size); /** * Get side information from packet. * * @param pkt packet * @param type desired side information type * @param size pointer for side information size to store (optional) * @return pointer to data if present or NULL otherwise */ uint8_t* av_packet_get_side_data(AVPacket *pkt, enum AVPacketSideDataType type, int *size); int av_packet_merge_side_data(AVPacket *pkt); int av_packet_split_side_data(AVPacket *pkt); /* resample.c */ struct ReSampleContext; struct AVResampleContext; typedef struct ReSampleContext ReSampleContext; /** * Initialize audio resampling context. * * @param output_channels number of output channels * @param input_channels number of input channels * @param output_rate output sample rate * @param input_rate input sample rate * @param sample_fmt_out requested output sample format * @param sample_fmt_in input sample format * @param filter_length length of each FIR filter in the filterbank relative to the cutoff frequency * @param log2_phase_count log2 of the number of entries in the polyphase filterbank * @param linear if 1 then the used FIR filter will be linearly interpolated between the 2 closest, if 0 the closest will be used * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate * @return allocated ReSampleContext, NULL if error occured */ ReSampleContext *av_audio_resample_init(int output_channels, int input_channels, int output_rate, int input_rate, enum AVSampleFormat sample_fmt_out, enum AVSampleFormat sample_fmt_in, int filter_length, int log2_phase_count, int linear, double cutoff); int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples); /** * Free resample context. * * @param s a non-NULL pointer to a resample context previously * created with av_audio_resample_init() */ void audio_resample_close(ReSampleContext *s); /** * Initialize an audio resampler. * Note, if either rate is not an integer then simply scale both rates up so they are. * @param filter_length length of each FIR filter in the filterbank relative to the cutoff freq * @param log2_phase_count log2 of the number of entries in the polyphase filterbank * @param linear If 1 then the used FIR filter will be linearly interpolated between the 2 closest, if 0 the closest will be used * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate */ struct AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_length, int log2_phase_count, int linear, double cutoff); /** * Resample an array of samples using a previously configured context. * @param src an array of unconsumed samples * @param consumed the number of samples of src which have been consumed are returned here * @param src_size the number of unconsumed samples available * @param dst_size the amount of space in samples available in dst * @param update_ctx If this is 0 then the context will not be modified, that way several channels can be resampled with the same context. * @return the number of samples written in dst or -1 if an error occurred */ int av_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx); /** * Compensate samplerate/timestamp drift. The compensation is done by changing * the resampler parameters, so no audible clicks or similar distortions occur * @param compensation_distance distance in output samples over which the compensation should be performed * @param sample_delta number of output samples which should be output less * * example: av_resample_compensate(c, 10, 500) * here instead of 510 samples only 500 samples would be output * * note, due to rounding the actual compensation might be slightly different, * especially if the compensation_distance is large and the in_rate used during init is small */ void av_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance); void av_resample_close(struct AVResampleContext *c); /** * Allocate memory for a picture. Call avpicture_free() to free it. * * @see avpicture_fill() * * @param picture the picture to be filled in * @param pix_fmt the format of the picture * @param width the width of the picture * @param height the height of the picture * @return zero if successful, a negative value if not */ int avpicture_alloc(AVPicture *picture, enum PixelFormat pix_fmt, int width, int height); /** * Free a picture previously allocated by avpicture_alloc(). * The data buffer used by the AVPicture is freed, but the AVPicture structure * itself is not. * * @param picture the AVPicture to be freed */ void avpicture_free(AVPicture *picture); /** * Fill in the AVPicture fields. * The fields of the given AVPicture are filled in by using the 'ptr' address * which points to the image data buffer. Depending on the specified picture * format, one or multiple image data pointers and line sizes will be set. * If a planar format is specified, several pointers will be set pointing to * the different picture planes and the line sizes of the different planes * will be stored in the lines_sizes array. * Call with ptr == NULL to get the required size for the ptr buffer. * * To allocate the buffer and fill in the AVPicture fields in one call, * use avpicture_alloc(). * * @param picture AVPicture whose fields are to be filled in * @param ptr Buffer which will contain or contains the actual image data * @param pix_fmt The format in which the picture data is stored. * @param width the width of the image in pixels * @param height the height of the image in pixels * @return size of the image data in bytes */ int avpicture_fill(AVPicture *picture, uint8_t *ptr, enum PixelFormat pix_fmt, int width, int height); /** * Copy pixel data from an AVPicture into a buffer. * The data is stored compactly, without any gaps for alignment or padding * which may be applied by avpicture_fill(). * * @see avpicture_get_size() * * @param[in] src AVPicture containing image data * @param[in] pix_fmt The format in which the picture data is stored. * @param[in] width the width of the image in pixels. * @param[in] height the height of the image in pixels. * @param[out] dest A buffer into which picture data will be copied. * @param[in] dest_size The size of 'dest'. * @return The number of bytes written to dest, or a negative value (error code) on error. */ int avpicture_layout(const AVPicture* src, enum PixelFormat pix_fmt, int width, int height, unsigned char *dest, int dest_size); /** * Calculate the size in bytes that a picture of the given width and height * would occupy if stored in the given picture format. * Note that this returns the size of a compact representation as generated * by avpicture_layout(), which can be smaller than the size required for e.g. * avpicture_fill(). * * @param pix_fmt the given picture format * @param width the width of the image * @param height the height of the image * @return Image data size in bytes or -1 on error (e.g. too large dimensions). */ int avpicture_get_size(enum PixelFormat pix_fmt, int width, int height); void avcodec_get_chroma_sub_sample(enum PixelFormat pix_fmt, int *h_shift, int *v_shift); /** * Get the name of a codec. * @return a static string identifying the codec; never NULL */ const char *avcodec_get_name(enum CodecID id); #if FF_API_GET_PIX_FMT_NAME /** * Return the short name for a pixel format. * * \see av_get_pix_fmt(), av_get_pix_fmt_string(). * @deprecated Deprecated in favor of av_get_pix_fmt_name(). */ attribute_deprecated const char *avcodec_get_pix_fmt_name(enum PixelFormat pix_fmt); #endif void avcodec_set_dimensions(AVCodecContext *s, int width, int height); /** * Return a value representing the fourCC code associated to the * pixel format pix_fmt, or 0 if no associated fourCC code can be * found. */ unsigned int avcodec_pix_fmt_to_codec_tag(enum PixelFormat pix_fmt); /** * Put a string representing the codec tag codec_tag in buf. * * @param buf_size size in bytes of buf * @return the length of the string that would have been generated if * enough space had been available, excluding the trailing null */ size_t av_get_codec_tag_string(char *buf, size_t buf_size, unsigned int codec_tag); #define FF_LOSS_RESOLUTION 0x0001 /**< loss due to resolution change */ #define FF_LOSS_DEPTH 0x0002 /**< loss due to color depth change */ #define FF_LOSS_COLORSPACE 0x0004 /**< loss due to color space conversion */ #define FF_LOSS_ALPHA 0x0008 /**< loss of alpha bits */ #define FF_LOSS_COLORQUANT 0x0010 /**< loss due to color quantization */ #define FF_LOSS_CHROMA 0x0020 /**< loss of chroma (e.g. RGB to gray conversion) */ /** * Compute what kind of losses will occur when converting from one specific * pixel format to another. * When converting from one pixel format to another, information loss may occur. * For example, when converting from RGB24 to GRAY, the color information will * be lost. Similarly, other losses occur when converting from some formats to * other formats. These losses can involve loss of chroma, but also loss of * resolution, loss of color depth, loss due to the color space conversion, loss * of the alpha bits or loss due to color quantization. * avcodec_get_fix_fmt_loss() informs you about the various types of losses * which will occur when converting from one pixel format to another. * * @param[in] dst_pix_fmt destination pixel format * @param[in] src_pix_fmt source pixel format * @param[in] has_alpha Whether the source pixel format alpha channel is used. * @return Combination of flags informing you what kind of losses will occur * (maximum loss for an invalid dst_pix_fmt). */ int avcodec_get_pix_fmt_loss(enum PixelFormat dst_pix_fmt, enum PixelFormat src_pix_fmt, int has_alpha); /** * Find the best pixel format to convert to given a certain source pixel * format. When converting from one pixel format to another, information loss * may occur. For example, when converting from RGB24 to GRAY, the color * information will be lost. Similarly, other losses occur when converting from * some formats to other formats. avcodec_find_best_pix_fmt() searches which of * the given pixel formats should be used to suffer the least amount of loss. * The pixel formats from which it chooses one, are determined by the * pix_fmt_mask parameter. * * Note, only the first 64 pixel formats will fit in pix_fmt_mask. * * @code * src_pix_fmt = PIX_FMT_YUV420P; * pix_fmt_mask = (1 << PIX_FMT_YUV422P) | (1 << PIX_FMT_RGB24); * dst_pix_fmt = avcodec_find_best_pix_fmt(pix_fmt_mask, src_pix_fmt, alpha, &loss); * @endcode * * @param[in] pix_fmt_mask bitmask determining which pixel format to choose from * @param[in] src_pix_fmt source pixel format * @param[in] has_alpha Whether the source pixel format alpha channel is used. * @param[out] loss_ptr Combination of flags informing you what kind of losses will occur. * @return The best pixel format to convert to or -1 if none was found. */ enum PixelFormat avcodec_find_best_pix_fmt(int64_t pix_fmt_mask, enum PixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); /** * Find the best pixel format to convert to given a certain source pixel * format and a selection of two destination pixel formats. When converting from * one pixel format to another, information loss may occur. For example, when converting * from RGB24 to GRAY, the color information will be lost. Similarly, other losses occur when * converting from some formats to other formats. avcodec_find_best_pix_fmt2() selects which of * the given pixel formats should be used to suffer the least amount of loss. * * If one of the destination formats is PIX_FMT_NONE the other pixel format (if valid) will be * returned. * * @code * src_pix_fmt = PIX_FMT_YUV420P; * dst_pix_fmt1= PIX_FMT_RGB24; * dst_pix_fmt2= PIX_FMT_GRAY8; * dst_pix_fmt3= PIX_FMT_RGB8; * loss= FF_LOSS_CHROMA; // don't care about chroma loss, so chroma loss will be ignored. * dst_pix_fmt = avcodec_find_best_pix_fmt2(dst_pix_fmt1, dst_pix_fmt2, src_pix_fmt, alpha, &loss); * dst_pix_fmt = avcodec_find_best_pix_fmt2(dst_pix_fmt, dst_pix_fmt3, src_pix_fmt, alpha, &loss); * @endcode * * @param[in] dst_pix_fmt1 One of the two destination pixel formats to choose from * @param[in] dst_pix_fmt2 The other of the two destination pixel formats to choose from * @param[in] src_pix_fmt Source pixel format * @param[in] has_alpha Whether the source pixel format alpha channel is used. * @param[in, out] loss_ptr Combination of loss flags. In: selects which of the losses to ignore, i.e. * NULL or value of zero means we care about all losses. Out: the loss * that occurs when converting from src to selected dst pixel format. * @return The best pixel format to convert to or -1 if none was found. */ enum PixelFormat avcodec_find_best_pix_fmt2(enum PixelFormat dst_pix_fmt1, enum PixelFormat dst_pix_fmt2, enum PixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); #define FF_ALPHA_TRANSP 0x0001 /* image has some totally transparent pixels */ #define FF_ALPHA_SEMI_TRANSP 0x0002 /* image has some transparent pixels */ /** * Tell if an image really has transparent alpha values. * @return ored mask of FF_ALPHA_xxx constants */ int img_get_alpha_info(const AVPicture *src, enum PixelFormat pix_fmt, int width, int height); /* deinterlace a picture */ /* deinterlace - if not supported return -1 */ int avpicture_deinterlace(AVPicture *dst, const AVPicture *src, enum PixelFormat pix_fmt, int width, int height); /* external high level API */ /** * If c is NULL, returns the first registered codec, * if c is non-NULL, returns the next registered codec after c, * or NULL if c is the last one. */ AVCodec *av_codec_next(AVCodec *c); /** * Return the LIBAVCODEC_VERSION_INT constant. */ unsigned avcodec_version(void); /** * Return the libavcodec build-time configuration. */ const char *avcodec_configuration(void); /** * Return the libavcodec license. */ const char *avcodec_license(void); #if FF_API_AVCODEC_INIT /** * @deprecated this function is called automatically from avcodec_register() * and avcodec_register_all(), there is no need to call it manually */ attribute_deprecated void avcodec_init(void); #endif /** * Register the codec codec and initialize libavcodec. * * @warning either this function or avcodec_register_all() must be called * before any other libavcodec functions. * * @see avcodec_register_all() */ void avcodec_register(AVCodec *codec); /** * Find a registered encoder with a matching codec ID. * * @param id CodecID of the requested encoder * @return An encoder if one was found, NULL otherwise. */ AVCodec *avcodec_find_encoder(enum CodecID id); /** * Find a registered encoder with the specified name. * * @param name name of the requested encoder * @return An encoder if one was found, NULL otherwise. */ AVCodec *avcodec_find_encoder_by_name(const char *name); /** * Find a registered decoder with a matching codec ID. * * @param id CodecID of the requested decoder * @return A decoder if one was found, NULL otherwise. */ AVCodec *avcodec_find_decoder(enum CodecID id); /** * Find a registered decoder with the specified name. * * @param name name of the requested decoder * @return A decoder if one was found, NULL otherwise. */ AVCodec *avcodec_find_decoder_by_name(const char *name); void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode); /** * Return a name for the specified profile, if available. * * @param codec the codec that is searched for the given profile * @param profile the profile value for which a name is requested * @return A name for the profile if found, NULL otherwise. */ const char *av_get_profile_name(const AVCodec *codec, int profile); /** * Set the fields of the given AVCodecContext to default values. * * @param s The AVCodecContext of which the fields should be set to default values. */ void avcodec_get_context_defaults(AVCodecContext *s); /** THIS FUNCTION IS NOT YET PART OF THE PUBLIC API! * we WILL change its arguments and name a few times! */ void avcodec_get_context_defaults2(AVCodecContext *s, enum AVMediaType); /** THIS FUNCTION IS NOT YET PART OF THE PUBLIC API! * we WILL change its arguments and name a few times! */ int avcodec_get_context_defaults3(AVCodecContext *s, AVCodec *codec); #if FF_API_ALLOC_CONTEXT /** * Allocate an AVCodecContext and set its fields to default values. The * resulting struct can be deallocated by simply calling av_free(). * * @return An AVCodecContext filled with default values or NULL on failure. * @see avcodec_get_context_defaults * * @deprecated use avcodec_alloc_context3() */ attribute_deprecated AVCodecContext *avcodec_alloc_context(void); /** THIS FUNCTION IS NOT YET PART OF THE PUBLIC API! * we WILL change its arguments and name a few times! */ attribute_deprecated AVCodecContext *avcodec_alloc_context2(enum AVMediaType); #endif /** * Allocate an AVCodecContext and set its fields to default values. The * resulting struct can be deallocated by simply calling av_free(). * * @param codec if non-NULL, allocate private data and initialize defaults * for the given codec. It is illegal to then call avcodec_open() * with a different codec. * * @return An AVCodecContext filled with default values or NULL on failure. * @see avcodec_get_context_defaults * * @deprecated use avcodec_alloc_context3() */ AVCodecContext *avcodec_alloc_context3(AVCodec *codec); /** * Copy the settings of the source AVCodecContext into the destination * AVCodecContext. The resulting destination codec context will be * unopened, i.e. you are required to call avcodec_open() before you * can use this AVCodecContext to decode/encode video/audio data. * * @param dest target codec context, should be initialized with * avcodec_alloc_context3(), but otherwise uninitialized * @param src source codec context * @return AVERROR() on error (e.g. memory allocation error), 0 on success */ int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src); /** * Set the fields of the given AVFrame to default values. * * @param pic The AVFrame of which the fields should be set to default values. */ void avcodec_get_frame_defaults(AVFrame *pic); /** * Allocate an AVFrame and set its fields to default values. The resulting * struct can be deallocated by simply calling av_free(). * * @return An AVFrame filled with default values or NULL on failure. * @see avcodec_get_frame_defaults */ AVFrame *avcodec_alloc_frame(void); int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic); void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic); int avcodec_default_reget_buffer(AVCodecContext *s, AVFrame *pic); /** * Return the amount of padding in pixels which the get_buffer callback must * provide around the edge of the image for codecs which do not have the * CODEC_FLAG_EMU_EDGE flag. * * @return Required padding in pixels. */ unsigned avcodec_get_edge_width(void); /** * Modify width and height values so that they will result in a memory * buffer that is acceptable for the codec if you do not use any horizontal * padding. * * May only be used if a codec with CODEC_CAP_DR1 has been opened. * If CODEC_FLAG_EMU_EDGE is not set, the dimensions must have been increased * according to avcodec_get_edge_width() before. */ void avcodec_align_dimensions(AVCodecContext *s, int *width, int *height); /** * Modify width and height values so that they will result in a memory * buffer that is acceptable for the codec if you also ensure that all * line sizes are a multiple of the respective linesize_align[i]. * * May only be used if a codec with CODEC_CAP_DR1 has been opened. * If CODEC_FLAG_EMU_EDGE is not set, the dimensions must have been increased * according to avcodec_get_edge_width() before. */ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height, int linesize_align[4]); enum PixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum PixelFormat * fmt); #if FF_API_THREAD_INIT /** * @deprecated Set s->thread_count before calling avcodec_open() instead of calling this. */ attribute_deprecated int avcodec_thread_init(AVCodecContext *s, int thread_count); #endif int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2),void *arg, int *ret, int count, int size); int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2, int, int),void *arg, int *ret, int count); //FIXME func typedef #if FF_API_AVCODEC_OPEN /** * Initialize the AVCodecContext to use the given AVCodec. Prior to using this * function the context has to be allocated. * * The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(), * avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for * retrieving a codec. * * @warning This function is not thread safe! * * @code * avcodec_register_all(); * codec = avcodec_find_decoder(CODEC_ID_H264); * if (!codec) * exit(1); * * context = avcodec_alloc_context3(codec); * * if (avcodec_open(context, codec) < 0) * exit(1); * @endcode * * @param avctx The context which will be set up to use the given codec. * @param codec The codec to use within the context. * @return zero on success, a negative value on error * @see avcodec_alloc_context3, avcodec_find_decoder, avcodec_find_encoder, avcodec_close * * @deprecated use avcodec_open2 */ attribute_deprecated int avcodec_open(AVCodecContext *avctx, AVCodec *codec); #endif /** * Initialize the AVCodecContext to use the given AVCodec. Prior to using this * function the context has to be allocated with avcodec_alloc_context(). * * The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(), * avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for * retrieving a codec. * * @warning This function is not thread safe! * * @code * avcodec_register_all(); * av_dict_set(&opts, "b", "2.5M", 0); * codec = avcodec_find_decoder(CODEC_ID_H264); * if (!codec) * exit(1); * * context = avcodec_alloc_context(); * * if (avcodec_open(context, codec, opts) < 0) * exit(1); * @endcode * * @param avctx The context to initialize. * @param options A dictionary filled with AVCodecContext and codec-private options. * On return this object will be filled with options that were not found. * * @return zero on success, a negative value on error * @see avcodec_alloc_context3(), avcodec_find_decoder(), avcodec_find_encoder(), * av_dict_set(), av_opt_find(). */ int avcodec_open2(AVCodecContext *avctx, AVCodec *codec, AVDictionary **options); /** * Decode the audio frame of size avpkt->size from avpkt->data into samples. * Some decoders may support multiple frames in a single AVPacket, such * decoders would then just decode the first frame. In this case, * avcodec_decode_audio3 has to be called again with an AVPacket that contains * the remaining data in order to decode the second frame etc. * If no frame * could be outputted, frame_size_ptr is zero. Otherwise, it is the * decompressed frame size in bytes. * * @warning You must set frame_size_ptr to the allocated size of the * output buffer before calling avcodec_decode_audio3(). * * @warning The input buffer must be FF_INPUT_BUFFER_PADDING_SIZE larger than * the actual read bytes because some optimized bitstream readers read 32 or 64 * bits at once and could read over the end. * * @warning The end of the input buffer avpkt->data should be set to 0 to ensure that * no overreading happens for damaged MPEG streams. * * @note You might have to align the input buffer avpkt->data and output buffer * samples. The alignment requirements depend on the CPU: On some CPUs it isn't * necessary at all, on others it won't work at all if not aligned and on others * it will work but it will have an impact on performance. * * In practice, avpkt->data should have 4 byte alignment at minimum and * samples should be 16 byte aligned unless the CPU doesn't need it * (AltiVec and SSE do). * * @param avctx the codec context * @param[out] samples the output buffer, sample type in avctx->sample_fmt * @param[in,out] frame_size_ptr the output buffer size in bytes * @param[in] avpkt The input AVPacket containing the input buffer. * You can create such packet with av_init_packet() and by then setting * data and size, some decoders might in addition need other fields. * All decoders are designed to use the least fields possible though. * @return On error a negative value is returned, otherwise the number of bytes * used or zero if no frame data was decompressed (used) from the input AVPacket. */ int avcodec_decode_audio3(AVCodecContext *avctx, int16_t *samples, int *frame_size_ptr, AVPacket *avpkt); /** * Decode the video frame of size avpkt->size from avpkt->data into picture. * Some decoders may support multiple frames in a single AVPacket, such * decoders would then just decode the first frame. * * @warning The input buffer must be FF_INPUT_BUFFER_PADDING_SIZE larger than * the actual read bytes because some optimized bitstream readers read 32 or 64 * bits at once and could read over the end. * * @warning The end of the input buffer buf should be set to 0 to ensure that * no overreading happens for damaged MPEG streams. * * @note You might have to align the input buffer avpkt->data. * The alignment requirements depend on the CPU: on some CPUs it isn't * necessary at all, on others it won't work at all if not aligned and on others * it will work but it will have an impact on performance. * * In practice, avpkt->data should have 4 byte alignment at minimum. * * @note Some codecs have a delay between input and output, these need to be * fed with avpkt->data=NULL, avpkt->size=0 at the end to return the remaining frames. * * @param avctx the codec context * @param[out] picture The AVFrame in which the decoded video frame will be stored. * Use avcodec_alloc_frame to get an AVFrame, the codec will * allocate memory for the actual bitmap. * with default get/release_buffer(), the decoder frees/reuses the bitmap as it sees fit. * with overridden get/release_buffer() (needs CODEC_CAP_DR1) the user decides into what buffer the decoder * decodes and the decoder tells the user once it does not need the data anymore, * the user app can at this point free/reuse/keep the memory as it sees fit. * * @param[in] avpkt The input AVpacket containing the input buffer. * You can create such packet with av_init_packet() and by then setting * data and size, some decoders might in addition need other fields like * flags&AV_PKT_FLAG_KEY. All decoders are designed to use the least * fields possible. * @param[in,out] got_picture_ptr Zero if no frame could be decompressed, otherwise, it is nonzero. * @return On error a negative value is returned, otherwise the number of bytes * used or zero if no frame could be decompressed. */ int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, AVPacket *avpkt); /** * Decode a subtitle message. * Return a negative value on error, otherwise return the number of bytes used. * If no subtitle could be decompressed, got_sub_ptr is zero. * Otherwise, the subtitle is stored in *sub. * Note that CODEC_CAP_DR1 is not available for subtitle codecs. This is for * simplicity, because the performance difference is expect to be negligible * and reusing a get_buffer written for video codecs would probably perform badly * due to a potentially very different allocation pattern. * * @param avctx the codec context * @param[out] sub The AVSubtitle in which the decoded subtitle will be stored, must be freed with avsubtitle_free if *got_sub_ptr is set. * @param[in,out] got_sub_ptr Zero if no subtitle could be decompressed, otherwise, it is nonzero. * @param[in] avpkt The input AVPacket containing the input buffer. */ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub_ptr, AVPacket *avpkt); /** * Frees all allocated data in the given subtitle struct. * * @param sub AVSubtitle to free. */ void avsubtitle_free(AVSubtitle *sub); int avcodec_parse_frame(AVCodecContext *avctx, uint8_t **pdata, int *data_size_ptr, uint8_t *buf, int buf_size); /** * Encode an audio frame from samples into buf. * * @note The output buffer should be at least FF_MIN_BUFFER_SIZE bytes large. * However, for PCM audio the user will know how much space is needed * because it depends on the value passed in buf_size as described * below. In that case a lower value can be used. * * @param avctx the codec context * @param[out] buf the output buffer * @param[in] buf_size the output buffer size * @param[in] samples the input buffer containing the samples * The number of samples read from this buffer is frame_size*channels, * both of which are defined in avctx. * For PCM audio the number of samples read from samples is equal to * buf_size * input_sample_size / output_sample_size. * @return On error a negative value is returned, on success zero or the number * of bytes used to encode the data read from the input buffer. */ int avcodec_encode_audio(AVCodecContext *avctx, uint8_t *buf, int buf_size, const short *samples); /** * Encode a video frame from pict into buf. * The input picture should be * stored using a specific format, namely avctx.pix_fmt. * * @param avctx the codec context * @param[out] buf the output buffer for the bitstream of encoded frame * @param[in] buf_size the size of the output buffer in bytes * @param[in] pict the input picture to encode * @return On error a negative value is returned, on success zero or the number * of bytes used from the output buffer. */ int avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size, const AVFrame *pict); int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, const AVSubtitle *sub); int avcodec_close(AVCodecContext *avctx); /** * Register all the codecs, parsers and bitstream filters which were enabled at * configuration time. If you do not call this function you can select exactly * which formats you want to support, by using the individual registration * functions. * * @see avcodec_register * @see av_register_codec_parser * @see av_register_bitstream_filter */ void avcodec_register_all(void); /** * Flush buffers, should be called when seeking or when switching to a different stream. */ void avcodec_flush_buffers(AVCodecContext *avctx); void avcodec_default_free_buffers(AVCodecContext *s); /* misc useful functions */ #if FF_API_OLD_FF_PICT_TYPES /** * Return a single letter to describe the given picture type pict_type. * * @param[in] pict_type the picture type * @return A single character representing the picture type. * @deprecated Use av_get_picture_type_char() instead. */ attribute_deprecated char av_get_pict_type_char(int pict_type); #endif /** * Return codec bits per sample. * * @param[in] codec_id the codec * @return Number of bits per sample or zero if unknown for the given codec. */ int av_get_bits_per_sample(enum CodecID codec_id); #if FF_API_OLD_SAMPLE_FMT /** * @deprecated Use av_get_bytes_per_sample() instead. */ attribute_deprecated int av_get_bits_per_sample_format(enum AVSampleFormat sample_fmt); #endif /* frame parsing */ typedef struct AVCodecParserContext { void *priv_data; struct AVCodecParser *parser; int64_t frame_offset; /* offset of the current frame */ int64_t cur_offset; /* current offset (incremented by each av_parser_parse()) */ int64_t next_frame_offset; /* offset of the next frame */ /* video info */ int pict_type; /* XXX: Put it back in AVCodecContext. */ /** * This field is used for proper frame duration computation in lavf. * It signals, how much longer the frame duration of the current frame * is compared to normal frame duration. * * frame_duration = (1 + repeat_pict) * time_base * * It is used by codecs like H.264 to display telecined material. */ int repeat_pict; /* XXX: Put it back in AVCodecContext. */ int64_t pts; /* pts of the current frame */ int64_t dts; /* dts of the current frame */ /* private data */ int64_t last_pts; int64_t last_dts; int fetch_timestamp; #define AV_PARSER_PTS_NB 4 int cur_frame_start_index; int64_t cur_frame_offset[AV_PARSER_PTS_NB]; int64_t cur_frame_pts[AV_PARSER_PTS_NB]; int64_t cur_frame_dts[AV_PARSER_PTS_NB]; int flags; #define PARSER_FLAG_COMPLETE_FRAMES 0x0001 #define PARSER_FLAG_ONCE 0x0002 /// Set if the parser has a valid file offset #define PARSER_FLAG_FETCHED_OFFSET 0x0004 int64_t offset; ///< byte offset from starting packet start int64_t cur_frame_end[AV_PARSER_PTS_NB]; /** * Set by parser to 1 for key frames and 0 for non-key frames. * It is initialized to -1, so if the parser doesn't set this flag, * old-style fallback using AV_PICTURE_TYPE_I picture type as key frames * will be used. */ int key_frame; /** * Time difference in stream time base units from the pts of this * packet to the point at which the output from the decoder has converged * independent from the availability of previous frames. That is, the * frames are virtually identical no matter if decoding started from * the very first frame or from this keyframe. * Is AV_NOPTS_VALUE if unknown. * This field is not the display duration of the current frame. * This field has no meaning if the packet does not have AV_PKT_FLAG_KEY * set. * * The purpose of this field is to allow seeking in streams that have no * keyframes in the conventional sense. It corresponds to the * recovery point SEI in H.264 and match_time_delta in NUT. It is also * essential for some types of subtitle streams to ensure that all * subtitles are correctly displayed after seeking. */ int64_t convergence_duration; // Timestamp generation support: /** * Synchronization point for start of timestamp generation. * * Set to >0 for sync point, 0 for no sync point and <0 for undefined * (default). * * For example, this corresponds to presence of H.264 buffering period * SEI message. */ int dts_sync_point; /** * Offset of the current timestamp against last timestamp sync point in * units of AVCodecContext.time_base. * * Set to INT_MIN when dts_sync_point unused. Otherwise, it must * contain a valid timestamp offset. * * Note that the timestamp of sync point has usually a nonzero * dts_ref_dts_delta, which refers to the previous sync point. Offset of * the next frame after timestamp sync point will be usually 1. * * For example, this corresponds to H.264 cpb_removal_delay. */ int dts_ref_dts_delta; /** * Presentation delay of current frame in units of AVCodecContext.time_base. * * Set to INT_MIN when dts_sync_point unused. Otherwise, it must * contain valid non-negative timestamp delta (presentation time of a frame * must not lie in the past). * * This delay represents the difference between decoding and presentation * time of the frame. * * For example, this corresponds to H.264 dpb_output_delay. */ int pts_dts_delta; /** * Position of the packet in file. * * Analogous to cur_frame_pts/dts */ int64_t cur_frame_pos[AV_PARSER_PTS_NB]; /** * Byte position of currently parsed frame in stream. */ int64_t pos; /** * Previous frame byte position. */ int64_t last_pos; } AVCodecParserContext; typedef struct AVCodecParser { int codec_ids[5]; /* several codec IDs are permitted */ int priv_data_size; int (*parser_init)(AVCodecParserContext *s); int (*parser_parse)(AVCodecParserContext *s, AVCodecContext *avctx, const uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size); void (*parser_close)(AVCodecParserContext *s); int (*split)(AVCodecContext *avctx, const uint8_t *buf, int buf_size); struct AVCodecParser *next; } AVCodecParser; AVCodecParser *av_parser_next(AVCodecParser *c); void av_register_codec_parser(AVCodecParser *parser); AVCodecParserContext *av_parser_init(int codec_id); /** * Parse a packet. * * @param s parser context. * @param avctx codec context. * @param poutbuf set to pointer to parsed buffer or NULL if not yet finished. * @param poutbuf_size set to size of parsed buffer or zero if not yet finished. * @param buf input buffer. * @param buf_size input length, to signal EOF, this should be 0 (so that the last frame can be output). * @param pts input presentation timestamp. * @param dts input decoding timestamp. * @param pos input byte position in stream. * @return the number of bytes of the input bitstream used. * * Example: * @code * while(in_len){ * len = av_parser_parse2(myparser, AVCodecContext, &data, &size, * in_data, in_len, * pts, dts, pos); * in_data += len; * in_len -= len; * * if(size) * decode_frame(data, size); * } * @endcode */ int av_parser_parse2(AVCodecParserContext *s, AVCodecContext *avctx, uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size, int64_t pts, int64_t dts, int64_t pos); int av_parser_change(AVCodecParserContext *s, AVCodecContext *avctx, uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size, int keyframe); void av_parser_close(AVCodecParserContext *s); typedef struct AVBitStreamFilterContext { void *priv_data; struct AVBitStreamFilter *filter; AVCodecParserContext *parser; struct AVBitStreamFilterContext *next; } AVBitStreamFilterContext; typedef struct AVBitStreamFilter { const char *name; int priv_data_size; int (*filter)(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size, int keyframe); void (*close)(AVBitStreamFilterContext *bsfc); struct AVBitStreamFilter *next; } AVBitStreamFilter; void av_register_bitstream_filter(AVBitStreamFilter *bsf); AVBitStreamFilterContext *av_bitstream_filter_init(const char *name); int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size, int keyframe); void av_bitstream_filter_close(AVBitStreamFilterContext *bsf); AVBitStreamFilter *av_bitstream_filter_next(AVBitStreamFilter *f); /* memory */ /** * Reallocate the given block if it is not large enough, otherwise do nothing. * * @see av_realloc */ void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size); /** * Allocate a buffer, reusing the given one if large enough. * * Contrary to av_fast_realloc the current buffer contents might not be * preserved and on error the old buffer is freed, thus no special * handling to avoid memleaks is necessary. * * @param ptr pointer to pointer to already allocated buffer, overwritten with pointer to new buffer * @param size size of the buffer *ptr points to * @param min_size minimum size of *ptr buffer after returning, *ptr will be NULL and * *size 0 if an error occurred. */ void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size); /** * Copy image src to dst. Wraps av_picture_data_copy() above. */ void av_picture_copy(AVPicture *dst, const AVPicture *src, enum PixelFormat pix_fmt, int width, int height); /** * Crop image top and left side. */ int av_picture_crop(AVPicture *dst, const AVPicture *src, enum PixelFormat pix_fmt, int top_band, int left_band); /** * Pad image. */ int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width, enum PixelFormat pix_fmt, int padtop, int padbottom, int padleft, int padright, int *color); /** * Encode extradata length to a buffer. Used by xiph codecs. * * @param s buffer to write to; must be at least (v/255+1) bytes long * @param v size of extradata in bytes * @return number of bytes written to the buffer. */ unsigned int av_xiphlacing(unsigned char *s, unsigned int v); /** * Logs a generic warning message about a missing feature. This function is * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.) * only, and would normally not be used by applications. * @param[in] avc a pointer to an arbitrary struct of which the first field is * a pointer to an AVClass struct * @param[in] feature string containing the name of the missing feature * @param[in] want_sample indicates if samples are wanted which exhibit this feature. * If want_sample is non-zero, additional verbage will be added to the log * message which tells the user how to report samples to the development * mailing list. */ void av_log_missing_feature(void *avc, const char *feature, int want_sample); /** * Log a generic warning message asking for a sample. This function is * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.) * only, and would normally not be used by applications. * @param[in] avc a pointer to an arbitrary struct of which the first field is * a pointer to an AVClass struct * @param[in] msg string containing an optional message, or NULL if no message */ void av_log_ask_for_sample(void *avc, const char *msg, ...) av_printf_format(2, 3); /** * Register the hardware accelerator hwaccel. */ void av_register_hwaccel(AVHWAccel *hwaccel); /** * If hwaccel is NULL, returns the first registered hardware accelerator, * if hwaccel is non-NULL, returns the next registered hardware accelerator * after hwaccel, or NULL if hwaccel is the last one. */ AVHWAccel *av_hwaccel_next(AVHWAccel *hwaccel); /** * Lock operation used by lockmgr */ enum AVLockOp { AV_LOCK_CREATE, ///< Create a mutex AV_LOCK_OBTAIN, ///< Lock the mutex AV_LOCK_RELEASE, ///< Unlock the mutex AV_LOCK_DESTROY, ///< Free mutex resources }; /** * Register a user provided lock manager supporting the operations * specified by AVLockOp. mutex points to a (void *) where the * lockmgr should store/get a pointer to a user allocated mutex. It's * NULL upon AV_LOCK_CREATE and != NULL for all other ops. * * @param cb User defined callback. Note: FFmpeg may invoke calls to this * callback during the call to av_lockmgr_register(). * Thus, the application must be prepared to handle that. * If cb is set to NULL the lockmgr will be unregistered. * Also note that during unregistration the previously registered * lockmgr callback may also be invoked. */ int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op)); /** * Get the type of the given codec. */ enum AVMediaType avcodec_get_type(enum CodecID codec_id); /** * Get the AVClass for AVCodecContext. It can be used in combination with * AV_OPT_SEARCH_FAKE_OBJ for examining options. * * @see av_opt_find(). */ const AVClass *avcodec_get_class(void); #endif /* AVCODEC_AVCODEC_H */ IanniX-0.9.20/gui/qffmpeg/libavcodec/avfft.h000066400000000000000000000055201317340345000205550ustar00rootroot00000000000000/* * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVCODEC_AVFFT_H #define AVCODEC_AVFFT_H typedef float FFTSample; typedef struct FFTComplex { FFTSample re, im; } FFTComplex; typedef struct FFTContext FFTContext; /** * Set up a complex FFT. * @param nbits log2 of the length of the input array * @param inverse if 0 perform the forward transform, if 1 perform the inverse */ FFTContext *av_fft_init(int nbits, int inverse); /** * Do the permutation needed BEFORE calling ff_fft_calc(). */ void av_fft_permute(FFTContext *s, FFTComplex *z); /** * Do a complex FFT with the parameters defined in av_fft_init(). The * input data must be permuted before. No 1.0/sqrt(n) normalization is done. */ void av_fft_calc(FFTContext *s, FFTComplex *z); void av_fft_end(FFTContext *s); FFTContext *av_mdct_init(int nbits, int inverse, double scale); void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input); void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); void av_mdct_end(FFTContext *s); /* Real Discrete Fourier Transform */ enum RDFTransformType { DFT_R2C, IDFT_C2R, IDFT_R2C, DFT_C2R, }; typedef struct RDFTContext RDFTContext; /** * Set up a real FFT. * @param nbits log2 of the length of the input array * @param trans the type of transform */ RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans); void av_rdft_calc(RDFTContext *s, FFTSample *data); void av_rdft_end(RDFTContext *s); /* Discrete Cosine Transform */ typedef struct DCTContext DCTContext; enum DCTTransformType { DCT_II = 0, DCT_III, DCT_I, DST_I, }; /** * Set up DCT. * @param nbits size of the input array: * (1 << nbits) for DCT-II, DCT-III and DST-I * (1 << nbits) + 1 for DCT-I * * @note the first element of the input of DST-I is ignored */ DCTContext *av_dct_init(int nbits, enum DCTTransformType type); void av_dct_calc(DCTContext *s, FFTSample *data); void av_dct_end (DCTContext *s); #endif /* AVCODEC_AVFFT_H */ IanniX-0.9.20/gui/qffmpeg/libavcodec/dxva2.h000066400000000000000000000035501317340345000204740ustar00rootroot00000000000000/* * DXVA2 HW acceleration * * copyright (c) 2009 Laurent Aimar * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVCODEC_DXVA_H #define AVCODEC_DXVA_H #include #include #define FF_DXVA2_WORKAROUND_SCALING_LIST_ZIGZAG 1 ///< Work around for DXVA2 and old UVD/UVD+ ATI video cards /** * This structure is used to provides the necessary configurations and data * to the DXVA2 FFmpeg HWAccel implementation. * * The application must make it available as AVCodecContext.hwaccel_context. */ struct dxva_context { /** * DXVA2 decoder object */ IDirectXVideoDecoder *decoder; /** * DXVA2 configuration used to create the decoder */ const DXVA2_ConfigPictureDecode *cfg; /** * The number of surface in the surface array */ unsigned surface_count; /** * The array of Direct3D surfaces used to create the decoder */ LPDIRECT3DSURFACE9 *surface; /** * A bit field configuring the workarounds needed for using the decoder */ uint64_t workaround; /** * Private to the FFmpeg AVHWAccel implementation */ unsigned report_id; }; #endif /* AVCODEC_DXVA_H */ IanniX-0.9.20/gui/qffmpeg/libavcodec/opt.h000066400000000000000000000017621317340345000202550ustar00rootroot00000000000000/* * This file is part of Libav. * * Libav is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * Libav 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with Libav; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * This header is provided for compatibility only and will be removed * on next major bump */ #ifndef AVCODEC_OPT_H #define AVCODEC_OPT_H #include "libavcodec/version.h" #if FF_API_OPT_H #include "libavutil/opt.h" #endif #endif /* AVCODEC_OPT_H */ IanniX-0.9.20/gui/qffmpeg/libavcodec/vaapi.h000066400000000000000000000074461317340345000205600ustar00rootroot00000000000000/* * Video Acceleration API (shared data between FFmpeg and the video player) * HW decode acceleration for MPEG-2, MPEG-4, H.264 and VC-1 * * Copyright (C) 2008-2009 Splitted-Desktop Systems * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVCODEC_VAAPI_H #define AVCODEC_VAAPI_H #include /** * @defgroup VAAPI_Decoding VA API Decoding * @ingroup Decoder * @{ */ /** * This structure is used to share data between the FFmpeg library and * the client video application. * This shall be zero-allocated and available as * AVCodecContext.hwaccel_context. All user members can be set once * during initialization or through each AVCodecContext.get_buffer() * function call. In any case, they must be valid prior to calling * decoding functions. */ struct vaapi_context { /** * Window system dependent data * * - encoding: unused * - decoding: Set by user */ void *display; /** * Configuration ID * * - encoding: unused * - decoding: Set by user */ uint32_t config_id; /** * Context ID (video decode pipeline) * * - encoding: unused * - decoding: Set by user */ uint32_t context_id; /** * VAPictureParameterBuffer ID * * - encoding: unused * - decoding: Set by libavcodec */ uint32_t pic_param_buf_id; /** * VAIQMatrixBuffer ID * * - encoding: unused * - decoding: Set by libavcodec */ uint32_t iq_matrix_buf_id; /** * VABitPlaneBuffer ID (for VC-1 decoding) * * - encoding: unused * - decoding: Set by libavcodec */ uint32_t bitplane_buf_id; /** * Slice parameter/data buffer IDs * * - encoding: unused * - decoding: Set by libavcodec */ uint32_t *slice_buf_ids; /** * Number of effective slice buffer IDs to send to the HW * * - encoding: unused * - decoding: Set by libavcodec */ unsigned int n_slice_buf_ids; /** * Size of pre-allocated slice_buf_ids * * - encoding: unused * - decoding: Set by libavcodec */ unsigned int slice_buf_ids_alloc; /** * Pointer to VASliceParameterBuffers * * - encoding: unused * - decoding: Set by libavcodec */ void *slice_params; /** * Size of a VASliceParameterBuffer element * * - encoding: unused * - decoding: Set by libavcodec */ unsigned int slice_param_size; /** * Size of pre-allocated slice_params * * - encoding: unused * - decoding: Set by libavcodec */ unsigned int slice_params_alloc; /** * Number of slices currently filled in * * - encoding: unused * - decoding: Set by libavcodec */ unsigned int slice_count; /** * Pointer to slice data buffer base * - encoding: unused * - decoding: Set by libavcodec */ const uint8_t *slice_data; /** * Current size of slice data * * - encoding: unused * - decoding: Set by libavcodec */ uint32_t slice_data_size; }; /* @} */ #endif /* AVCODEC_VAAPI_H */ IanniX-0.9.20/gui/qffmpeg/libavcodec/vdpau.h000066400000000000000000000054171317340345000205730ustar00rootroot00000000000000/* * The Video Decode and Presentation API for UNIX (VDPAU) is used for * hardware-accelerated decoding of MPEG-1/2, H.264 and VC-1. * * Copyright (C) 2008 NVIDIA * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVCODEC_VDPAU_H #define AVCODEC_VDPAU_H /** * @defgroup Decoder VDPAU Decoder and Renderer * * VDPAU hardware acceleration has two modules * - VDPAU decoding * - VDPAU presentation * * The VDPAU decoding module parses all headers using FFmpeg * parsing mechanisms and uses VDPAU for the actual decoding. * * As per the current implementation, the actual decoding * and rendering (API calls) are done as part of the VDPAU * presentation (vo_vdpau.c) module. * * @defgroup VDPAU_Decoding VDPAU Decoding * @ingroup Decoder * @{ */ #include #include /** @brief The videoSurface is used for rendering. */ #define FF_VDPAU_STATE_USED_FOR_RENDER 1 /** * @brief The videoSurface is needed for reference/prediction. * The codec manipulates this. */ #define FF_VDPAU_STATE_USED_FOR_REFERENCE 2 /** * @brief This structure is used as a callback between the FFmpeg * decoder (vd_) and presentation (vo_) module. * This is used for defining a video frame containing surface, * picture parameter, bitstream information etc which are passed * between the FFmpeg decoder and its clients. */ struct vdpau_render_state { VdpVideoSurface surface; ///< Used as rendered surface, never changed. int state; ///< Holds FF_VDPAU_STATE_* values. /** Describe size/location of the compressed video data. Set to 0 when freeing bitstream_buffers. */ int bitstream_buffers_allocated; int bitstream_buffers_used; /** The user is responsible for freeing this buffer using av_freep(). */ VdpBitstreamBuffer *bitstream_buffers; /** picture parameter information for all supported codecs */ union VdpPictureInfo { VdpPictureInfoH264 h264; VdpPictureInfoMPEG1Or2 mpeg; VdpPictureInfoVC1 vc1; VdpPictureInfoMPEG4Part2 mpeg4; } info; }; /* @}*/ #endif /* AVCODEC_VDPAU_H */ IanniX-0.9.20/gui/qffmpeg/libavcodec/version.h000066400000000000000000000071171317340345000211400ustar00rootroot00000000000000/* * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVCODEC_VERSION_H #define AVCODEC_VERSION_H #define LIBAVCODEC_VERSION_MAJOR 53 #define LIBAVCODEC_VERSION_MINOR 16 #define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ LIBAVCODEC_VERSION_MICRO) #define LIBAVCODEC_VERSION AV_VERSION(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ LIBAVCODEC_VERSION_MICRO) #define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT #define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) /** * Those FF_API_* defines are not part of public API. * They may change, break or disappear at any time. */ #ifndef FF_API_PALETTE_CONTROL #define FF_API_PALETTE_CONTROL (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_OLD_SAMPLE_FMT #define FF_API_OLD_SAMPLE_FMT (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_OLD_AUDIOCONVERT #define FF_API_OLD_AUDIOCONVERT (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_ANTIALIAS_ALGO #define FF_API_ANTIALIAS_ALGO (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_REQUEST_CHANNELS #define FF_API_REQUEST_CHANNELS (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_OPT_H #define FF_API_OPT_H (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_THREAD_INIT #define FF_API_THREAD_INIT (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_OLD_FF_PICT_TYPES #define FF_API_OLD_FF_PICT_TYPES (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_FLAC_GLOBAL_OPTS #define FF_API_FLAC_GLOBAL_OPTS (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_GET_PIX_FMT_NAME #define FF_API_GET_PIX_FMT_NAME (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_ALLOC_CONTEXT #define FF_API_ALLOC_CONTEXT (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_AVCODEC_OPEN #define FF_API_AVCODEC_OPEN (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_DRC_SCALE #define FF_API_DRC_SCALE (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_VERY_AGGRESSIVE #define FF_API_VERY_AGGRESSIVE (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_AVCODEC_INIT #define FF_API_AVCODEC_INIT (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_X264_GLOBAL_OPTS #define FF_API_X264_GLOBAL_OPTS (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_MPEGVIDEO_GLOBAL_OPTS #define FF_API_MPEGVIDEO_GLOBAL_OPTS (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_LAME_GLOBAL_OPTS #define FF_API_LAME_GLOBAL_OPTS (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_SNOW_GLOBAL_OPTS #define FF_API_SNOW_GLOBAL_OPTS (LIBAVCODEC_VERSION_MAJOR < 54) #endif #ifndef FF_API_MJPEG_GLOBAL_OPTS #define FF_API_MJPEG_GLOBAL_OPTS (LIBAVCODEC_VERSION_MAJOR < 54) #endif #endif /* AVCODEC_VERSION_H */ IanniX-0.9.20/gui/qffmpeg/libavcodec/xvmc.h000066400000000000000000000132231317340345000204230ustar00rootroot00000000000000/* * Copyright (C) 2003 Ivan Kalvachev * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVCODEC_XVMC_H #define AVCODEC_XVMC_H #include #include "avcodec.h" #define AV_XVMC_ID 0x1DC711C0 /**< special value to ensure that regular pixel routines haven't corrupted the struct the number is 1337 speak for the letters IDCT MCo (motion compensation) */ struct xvmc_pix_fmt { /** The field contains the special constant value AV_XVMC_ID. It is used as a test that the application correctly uses the API, and that there is no corruption caused by pixel routines. - application - set during initialization - libavcodec - unchanged */ int xvmc_id; /** Pointer to the block array allocated by XvMCCreateBlocks(). The array has to be freed by XvMCDestroyBlocks(). Each group of 64 values represents one data block of differential pixel information (in MoCo mode) or coefficients for IDCT. - application - set the pointer during initialization - libavcodec - fills coefficients/pixel data into the array */ short* data_blocks; /** Pointer to the macroblock description array allocated by XvMCCreateMacroBlocks() and freed by XvMCDestroyMacroBlocks(). - application - set the pointer during initialization - libavcodec - fills description data into the array */ XvMCMacroBlock* mv_blocks; /** Number of macroblock descriptions that can be stored in the mv_blocks array. - application - set during initialization - libavcodec - unchanged */ int allocated_mv_blocks; /** Number of blocks that can be stored at once in the data_blocks array. - application - set during initialization - libavcodec - unchanged */ int allocated_data_blocks; /** Indicate that the hardware would interpret data_blocks as IDCT coefficients and perform IDCT on them. - application - set during initialization - libavcodec - unchanged */ int idct; /** In MoCo mode it indicates that intra macroblocks are assumed to be in unsigned format; same as the XVMC_INTRA_UNSIGNED flag. - application - set during initialization - libavcodec - unchanged */ int unsigned_intra; /** Pointer to the surface allocated by XvMCCreateSurface(). It has to be freed by XvMCDestroySurface() on application exit. It identifies the frame and its state on the video hardware. - application - set during initialization - libavcodec - unchanged */ XvMCSurface* p_surface; /** Set by the decoder before calling ff_draw_horiz_band(), needed by the XvMCRenderSurface function. */ //@{ /** Pointer to the surface used as past reference - application - unchanged - libavcodec - set */ XvMCSurface* p_past_surface; /** Pointer to the surface used as future reference - application - unchanged - libavcodec - set */ XvMCSurface* p_future_surface; /** top/bottom field or frame - application - unchanged - libavcodec - set */ unsigned int picture_structure; /** XVMC_SECOND_FIELD - 1st or 2nd field in the sequence - application - unchanged - libavcodec - set */ unsigned int flags; //}@ /** Number of macroblock descriptions in the mv_blocks array that have already been passed to the hardware. - application - zeroes it on get_buffer(). A successful ff_draw_horiz_band() may increment it with filled_mb_block_num or zero both. - libavcodec - unchanged */ int start_mv_blocks_num; /** Number of new macroblock descriptions in the mv_blocks array (after start_mv_blocks_num) that are filled by libavcodec and have to be passed to the hardware. - application - zeroes it on get_buffer() or after successful ff_draw_horiz_band(). - libavcodec - increment with one of each stored MB */ int filled_mv_blocks_num; /** Number of the the next free data block; one data block consists of 64 short values in the data_blocks array. All blocks before this one have already been claimed by placing their position into the corresponding block description structure field, that are part of the mv_blocks array. - application - zeroes it on get_buffer(). A successful ff_draw_horiz_band() may zero it together with start_mb_blocks_num. - libavcodec - each decoded macroblock increases it by the number of coded blocks it contains. */ int next_free_data_block_num; }; #endif /* AVCODEC_XVMC_H */ IanniX-0.9.20/gui/qffmpeg/libavdevice/000077500000000000000000000000001317340345000174565ustar00rootroot00000000000000IanniX-0.9.20/gui/qffmpeg/libavdevice/avdevice.h000066400000000000000000000037671317340345000214320ustar00rootroot00000000000000/* * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVDEVICE_AVDEVICE_H #define AVDEVICE_AVDEVICE_H #include "libavutil/avutil.h" #include "libavformat/avformat.h" #define LIBAVDEVICE_VERSION_MAJOR 53 #define LIBAVDEVICE_VERSION_MINOR 4 #define LIBAVDEVICE_VERSION_MICRO 0 #define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \ LIBAVDEVICE_VERSION_MINOR, \ LIBAVDEVICE_VERSION_MICRO) #define LIBAVDEVICE_VERSION AV_VERSION(LIBAVDEVICE_VERSION_MAJOR, \ LIBAVDEVICE_VERSION_MINOR, \ LIBAVDEVICE_VERSION_MICRO) #define LIBAVDEVICE_BUILD LIBAVDEVICE_VERSION_INT #ifndef FF_API_V4L #define FF_API_V4L (LIBAVDEVICE_VERSION_MAJOR < 54) #endif /** * Return the LIBAVDEVICE_VERSION_INT constant. */ unsigned avdevice_version(void); /** * Return the libavdevice build-time configuration. */ const char *avdevice_configuration(void); /** * Return the libavdevice license. */ const char *avdevice_license(void); /** * Initialize libavdevice and register all the input and output devices. * @warning This function is not thread safe. */ void avdevice_register_all(void); #endif /* AVDEVICE_AVDEVICE_H */ IanniX-0.9.20/gui/qffmpeg/libavformat/000077500000000000000000000000001317340345000175075ustar00rootroot00000000000000IanniX-0.9.20/gui/qffmpeg/libavformat/avformat.h000066400000000000000000001750771317340345000215200ustar00rootroot00000000000000/* * copyright (c) 2001 Fabrice Bellard * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVFORMAT_AVFORMAT_H #define AVFORMAT_AVFORMAT_H /** * Return the LIBAVFORMAT_VERSION_INT constant. */ unsigned avformat_version(void); /** * Return the libavformat build-time configuration. */ const char *avformat_configuration(void); /** * Return the libavformat license. */ const char *avformat_license(void); #include #include /* FILE */ #include "libavcodec/avcodec.h" #include "libavutil/dict.h" #include "libavutil/log.h" #include "avio.h" #include "libavformat/version.h" struct AVFormatContext; /** * @defgroup metadata_api Public Metadata API * @{ * The metadata API allows libavformat to export metadata tags to a client * application using a sequence of key/value pairs. Like all strings in FFmpeg, * metadata must be stored as UTF-8 encoded Unicode. Note that metadata * exported by demuxers isn't checked to be valid UTF-8 in most cases. * Important concepts to keep in mind: * - Keys are unique; there can never be 2 tags with the same key. This is * also meant semantically, i.e., a demuxer should not knowingly produce * several keys that are literally different but semantically identical. * E.g., key=Author5, key=Author6. In this example, all authors must be * placed in the same tag. * - Metadata is flat, not hierarchical; there are no subtags. If you * want to store, e.g., the email address of the child of producer Alice * and actor Bob, that could have key=alice_and_bobs_childs_email_address. * - Several modifiers can be applied to the tag name. This is done by * appending a dash character ('-') and the modifier name in the order * they appear in the list below -- e.g. foo-eng-sort, not foo-sort-eng. * - language -- a tag whose value is localized for a particular language * is appended with the ISO 639-2/B 3-letter language code. * For example: Author-ger=Michael, Author-eng=Mike * The original/default language is in the unqualified "Author" tag. * A demuxer should set a default if it sets any translated tag. * - sorting -- a modified version of a tag that should be used for * sorting will have '-sort' appended. E.g. artist="The Beatles", * artist-sort="Beatles, The". * * - Demuxers attempt to export metadata in a generic format, however tags * with no generic equivalents are left as they are stored in the container. * Follows a list of generic tag names: * @verbatim album -- name of the set this work belongs to album_artist -- main creator of the set/album, if different from artist. e.g. "Various Artists" for compilation albums. artist -- main creator of the work comment -- any additional description of the file. composer -- who composed the work, if different from artist. copyright -- name of copyright holder. creation_time-- date when the file was created, preferably in ISO 8601. date -- date when the work was created, preferably in ISO 8601. disc -- number of a subset, e.g. disc in a multi-disc collection. encoder -- name/settings of the software/hardware that produced the file. encoded_by -- person/group who created the file. filename -- original name of the file. genre -- . language -- main language in which the work is performed, preferably in ISO 639-2 format. Multiple languages can be specified by separating them with commas. performer -- artist who performed the work, if different from artist. E.g for "Also sprach Zarathustra", artist would be "Richard Strauss" and performer "London Philharmonic Orchestra". publisher -- name of the label/publisher. service_name -- name of the service in broadcasting (channel name). service_provider -- name of the service provider in broadcasting. title -- name of the work. track -- number of this work in the set, can be in form current/total. variant_bitrate -- the total bitrate of the bitrate variant that the current stream is part of @endverbatim * * Look in the examples section for an application example how to use the Metadata API. * * @} */ #if FF_API_OLD_METADATA2 /** * @defgroup old_metadata Old metadata API * The following functions are deprecated, use * their equivalents from libavutil/dict.h instead. * @{ */ #define AV_METADATA_MATCH_CASE AV_DICT_MATCH_CASE #define AV_METADATA_IGNORE_SUFFIX AV_DICT_IGNORE_SUFFIX #define AV_METADATA_DONT_STRDUP_KEY AV_DICT_DONT_STRDUP_KEY #define AV_METADATA_DONT_STRDUP_VAL AV_DICT_DONT_STRDUP_VAL #define AV_METADATA_DONT_OVERWRITE AV_DICT_DONT_OVERWRITE typedef attribute_deprecated AVDictionary AVMetadata; typedef attribute_deprecated AVDictionaryEntry AVMetadataTag; typedef struct AVMetadataConv AVMetadataConv; /** * Get a metadata element with matching key. * * @param prev Set to the previous matching element to find the next. * If set to NULL the first matching element is returned. * @param flags Allows case as well as suffix-insensitive comparisons. * @return Found tag or NULL, changing key or value leads to undefined behavior. */ attribute_deprecated AVDictionaryEntry * av_metadata_get(AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags); /** * Set the given tag in *pm, overwriting an existing tag. * * @param pm pointer to a pointer to a metadata struct. If *pm is NULL * a metadata struct is allocated and put in *pm. * @param key tag key to add to *pm (will be av_strduped depending on flags) * @param value tag value to add to *pm (will be av_strduped depending on flags). * Passing a NULL value will cause an existing tag to be deleted. * @return >= 0 on success otherwise an error code <0 */ attribute_deprecated int av_metadata_set2(AVDictionary **pm, const char *key, const char *value, int flags); /** * This function is provided for compatibility reason and currently does nothing. */ attribute_deprecated void av_metadata_conv(struct AVFormatContext *ctx, const AVMetadataConv *d_conv, const AVMetadataConv *s_conv); /** * Copy metadata from one AVDictionary struct into another. * @param dst pointer to a pointer to a AVDictionary struct. If *dst is NULL, * this function will allocate a struct for you and put it in *dst * @param src pointer to source AVDictionary struct * @param flags flags to use when setting metadata in *dst * @note metadata is read using the AV_DICT_IGNORE_SUFFIX flag */ attribute_deprecated void av_metadata_copy(AVDictionary **dst, AVDictionary *src, int flags); /** * Free all the memory allocated for an AVDictionary struct. */ attribute_deprecated void av_metadata_free(AVDictionary **m); /** * @} */ #endif /* packet functions */ /** * Allocate and read the payload of a packet and initialize its * fields with default values. * * @param pkt packet * @param size desired payload size * @return >0 (read size) if OK, AVERROR_xxx otherwise */ int av_get_packet(AVIOContext *s, AVPacket *pkt, int size); /** * Read data and append it to the current content of the AVPacket. * If pkt->size is 0 this is identical to av_get_packet. * Note that this uses av_grow_packet and thus involves a realloc * which is inefficient. Thus this function should only be used * when there is no reasonable way to know (an upper bound of) * the final size. * * @param pkt packet * @param size amount of data to read * @return >0 (read size) if OK, AVERROR_xxx otherwise, previous data * will not be lost even if an error occurs. */ int av_append_packet(AVIOContext *s, AVPacket *pkt, int size); /*************************************************/ /* fractional numbers for exact pts handling */ /** * The exact value of the fractional number is: 'val + num / den'. * num is assumed to be 0 <= num < den. */ typedef struct AVFrac { int64_t val, num, den; } AVFrac; /*************************************************/ /* input/output formats */ struct AVCodecTag; /** * This structure contains the data a format has to probe a file. */ typedef struct AVProbeData { const char *filename; unsigned char *buf; /**< Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero. */ int buf_size; /**< Size of buf except extra allocated bytes */ } AVProbeData; #define AVPROBE_SCORE_MAX 100 ///< maximum score, half of that is used for file-extension-based detection #define AVPROBE_PADDING_SIZE 32 ///< extra allocated bytes at the end of the probe buffer typedef struct AVFormatParameters { #if FF_API_FORMAT_PARAMETERS attribute_deprecated AVRational time_base; attribute_deprecated int sample_rate; attribute_deprecated int channels; attribute_deprecated int width; attribute_deprecated int height; attribute_deprecated enum PixelFormat pix_fmt; attribute_deprecated int channel; /**< Used to select DV channel. */ attribute_deprecated const char *standard; /**< deprecated, use demuxer-specific options instead. */ attribute_deprecated unsigned int mpeg2ts_raw:1; /**< deprecated, use mpegtsraw demuxer */ /**< deprecated, use mpegtsraw demuxer-specific options instead */ attribute_deprecated unsigned int mpeg2ts_compute_pcr:1; attribute_deprecated unsigned int initial_pause:1; /**< Do not begin to play the stream immediately (RTSP only). */ attribute_deprecated unsigned int prealloced_context:1; #endif } AVFormatParameters; //! Demuxer will use avio_open, no opened file should be provided by the caller. #define AVFMT_NOFILE 0x0001 #define AVFMT_NEEDNUMBER 0x0002 /**< Needs '%d' in filename. */ #define AVFMT_SHOW_IDS 0x0008 /**< Show format stream IDs numbers. */ #define AVFMT_RAWPICTURE 0x0020 /**< Format wants AVPicture structure for raw picture data. */ #define AVFMT_GLOBALHEADER 0x0040 /**< Format wants global header. */ #define AVFMT_NOTIMESTAMPS 0x0080 /**< Format does not need / have any timestamps. */ #define AVFMT_GENERIC_INDEX 0x0100 /**< Use generic index building code. */ #define AVFMT_TS_DISCONT 0x0200 /**< Format allows timestamp discontinuities. Note, muxers always require valid (monotone) timestamps */ #define AVFMT_VARIABLE_FPS 0x0400 /**< Format allows variable fps. */ #define AVFMT_NODIMENSIONS 0x0800 /**< Format does not need width/height */ #define AVFMT_NOSTREAMS 0x1000 /**< Format does not require any streams */ #define AVFMT_NOBINSEARCH 0x2000 /**< Format does not allow to fallback to binary search via read_timestamp */ #define AVFMT_NOGENSEARCH 0x4000 /**< Format does not allow to fallback to generic search */ #define AVFMT_TS_NONSTRICT 0x8000 /**< Format does not require strictly increasing timestamps, but they must still be monotonic */ typedef struct AVOutputFormat { const char *name; /** * Descriptive name for the format, meant to be more human-readable * than name. You should use the NULL_IF_CONFIG_SMALL() macro * to define it. */ const char *long_name; const char *mime_type; const char *extensions; /**< comma-separated filename extensions */ /** * size of private data so that it can be allocated in the wrapper */ int priv_data_size; /* output support */ enum CodecID audio_codec; /**< default audio codec */ enum CodecID video_codec; /**< default video codec */ int (*write_header)(struct AVFormatContext *); int (*write_packet)(struct AVFormatContext *, AVPacket *pkt); int (*write_trailer)(struct AVFormatContext *); /** * can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_RAWPICTURE, * AVFMT_GLOBALHEADER, AVFMT_NOTIMESTAMPS, AVFMT_VARIABLE_FPS, * AVFMT_NODIMENSIONS, AVFMT_NOSTREAMS */ int flags; void *dummy; int (*interleave_packet)(struct AVFormatContext *, AVPacket *out, AVPacket *in, int flush); /** * List of supported codec_id-codec_tag pairs, ordered by "better * choice first". The arrays are all terminated by CODEC_ID_NONE. */ const struct AVCodecTag * const *codec_tag; enum CodecID subtitle_codec; /**< default subtitle codec */ #if FF_API_OLD_METADATA2 const AVMetadataConv *metadata_conv; #endif const AVClass *priv_class; ///< AVClass for the private context /** * Test if the given codec can be stored in this container. * * @return 1 if the codec is supported, 0 if it is not. * A negative number if unknown. */ int (*query_codec)(enum CodecID id, int std_compliance); void (*get_output_timestamp)(struct AVFormatContext *s, int stream, int64_t *dts, int64_t *wall); /* private fields */ struct AVOutputFormat *next; } AVOutputFormat; typedef struct AVInputFormat { /** * A comma separated list of short names for the format. New names * may be appended with a minor bump. */ const char *name; /** * Descriptive name for the format, meant to be more human-readable * than name. You should use the NULL_IF_CONFIG_SMALL() macro * to define it. */ const char *long_name; /** * Size of private data so that it can be allocated in the wrapper. */ int priv_data_size; /** * Tell if a given file has a chance of being parsed as this format. * The buffer provided is guaranteed to be AVPROBE_PADDING_SIZE bytes * big so you do not have to check for that unless you need more. */ int (*read_probe)(AVProbeData *); /** * Read the format header and initialize the AVFormatContext * structure. Return 0 if OK. 'ap' if non-NULL contains * additional parameters. Only used in raw format right * now. 'av_new_stream' should be called to create new streams. */ int (*read_header)(struct AVFormatContext *, AVFormatParameters *ap); /** * Read one packet and put it in 'pkt'. pts and flags are also * set. 'av_new_stream' can be called only if the flag * AVFMTCTX_NOHEADER is used and only in the calling thread (not in a * background thread). * @return 0 on success, < 0 on error. * When returning an error, pkt must not have been allocated * or must be freed before returning */ int (*read_packet)(struct AVFormatContext *, AVPacket *pkt); /** * Close the stream. The AVFormatContext and AVStreams are not * freed by this function */ int (*read_close)(struct AVFormatContext *); #if FF_API_READ_SEEK /** * Seek to a given timestamp relative to the frames in * stream component stream_index. * @param stream_index Must not be -1. * @param flags Selects which direction should be preferred if no exact * match is available. * @return >= 0 on success (but not necessarily the new offset) */ attribute_deprecated int (*read_seek)(struct AVFormatContext *, int stream_index, int64_t timestamp, int flags); #endif /** * Gets the next timestamp in stream[stream_index].time_base units. * @return the timestamp or AV_NOPTS_VALUE if an error occurred */ int64_t (*read_timestamp)(struct AVFormatContext *s, int stream_index, int64_t *pos, int64_t pos_limit); /** * Can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER. */ int flags; /** * If extensions are defined, then no probe is done. You should * usually not use extension format guessing because it is not * reliable enough */ const char *extensions; /** * General purpose read-only value that the format can use. */ int value; /** * Start/resume playing - only meaningful if using a network-based format * (RTSP). */ int (*read_play)(struct AVFormatContext *); /** * Pause playing - only meaningful if using a network-based format * (RTSP). */ int (*read_pause)(struct AVFormatContext *); const struct AVCodecTag * const *codec_tag; /** * Seek to timestamp ts. * Seeking will be done so that the point from which all active streams * can be presented successfully will be closest to ts and within min/max_ts. * Active streams are all streams that have AVStream.discard < AVDISCARD_ALL. */ int (*read_seek2)(struct AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags); #if FF_API_OLD_METADATA2 const AVMetadataConv *metadata_conv; #endif const AVClass *priv_class; ///< AVClass for the private context /* private fields */ struct AVInputFormat *next; } AVInputFormat; enum AVStreamParseType { AVSTREAM_PARSE_NONE, AVSTREAM_PARSE_FULL, /**< full parsing and repack */ AVSTREAM_PARSE_HEADERS, /**< Only parse headers, do not repack. */ AVSTREAM_PARSE_TIMESTAMPS, /**< full parsing and interpolation of timestamps for frames not starting on a packet boundary */ AVSTREAM_PARSE_FULL_ONCE, /**< full parsing and repack of the first frame only, only implemented for H.264 currently */ }; typedef struct AVIndexEntry { int64_t pos; int64_t timestamp; #define AVINDEX_KEYFRAME 0x0001 int flags:2; int size:30; //Yeah, trying to keep the size of this small to reduce memory requirements (it is 24 vs. 32 bytes due to possible 8-byte alignment). int min_distance; /**< Minimum distance between this and the previous keyframe, used to avoid unneeded searching. */ } AVIndexEntry; #define AV_DISPOSITION_DEFAULT 0x0001 #define AV_DISPOSITION_DUB 0x0002 #define AV_DISPOSITION_ORIGINAL 0x0004 #define AV_DISPOSITION_COMMENT 0x0008 #define AV_DISPOSITION_LYRICS 0x0010 #define AV_DISPOSITION_KARAOKE 0x0020 /** * Track should be used during playback by default. * Useful for subtitle track that should be displayed * even when user did not explicitly ask for subtitles. */ #define AV_DISPOSITION_FORCED 0x0040 #define AV_DISPOSITION_HEARING_IMPAIRED 0x0080 /**< stream for hearing impaired audiences */ #define AV_DISPOSITION_VISUAL_IMPAIRED 0x0100 /**< stream for visual impaired audiences */ #define AV_DISPOSITION_CLEAN_EFFECTS 0x0200 /**< stream without voice */ /** * Stream structure. * New fields can be added to the end with minor version bumps. * Removal, reordering and changes to existing fields require a major * version bump. * sizeof(AVStream) must not be used outside libav*. */ typedef struct AVStream { int index; /**< stream index in AVFormatContext */ int id; /**< format-specific stream ID */ AVCodecContext *codec; /**< codec context */ /** * Real base framerate of the stream. * This is the lowest framerate with which all timestamps can be * represented accurately (it is the least common multiple of all * framerates in the stream). Note, this value is just a guess! * For example, if the time base is 1/90000 and all frames have either * approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1. */ AVRational r_frame_rate; void *priv_data; /* internal data used in av_find_stream_info() */ int64_t first_dts; /** * encoding: pts generation when outputting stream */ struct AVFrac pts; /** * This is the fundamental unit of time (in seconds) in terms * of which frame timestamps are represented. For fixed-fps content, * time base should be 1/framerate and timestamp increments should be 1. * decoding: set by libavformat * encoding: set by libavformat in av_write_header */ AVRational time_base; int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */ /* ffmpeg.c private use */ int stream_copy; /**< If set, just copy stream. */ enum AVDiscard discard; ///< Selects which packets can be discarded at will and do not need to be demuxed. #if FF_API_AVSTREAM_QUALITY //FIXME move stuff to a flags field? /** * Quality, as it has been removed from AVCodecContext and put in AVVideoFrame. * MN: dunno if that is the right place for it */ attribute_deprecated float quality; #endif /** * Decoding: pts of the first frame of the stream, in stream time base. * Only set this if you are absolutely 100% sure that the value you set * it to really is the pts of the first frame. * This may be undefined (AV_NOPTS_VALUE). * @note The ASF header does NOT contain a correct start_time the ASF * demuxer must NOT set this. */ int64_t start_time; /** * Decoding: duration of the stream, in stream time base. * If a source file does not specify a duration, but does specify * a bitrate, this value will be estimated from bitrate and file size. */ int64_t duration; /* av_read_frame() support */ enum AVStreamParseType need_parsing; struct AVCodecParserContext *parser; int64_t cur_dts; int last_IP_duration; int64_t last_IP_pts; /* av_seek_frame() support */ AVIndexEntry *index_entries; /**< Only used if the format does not support seeking natively. */ int nb_index_entries; unsigned int index_entries_allocated_size; int64_t nb_frames; ///< number of frames in this stream if known or 0 int disposition; /**< AV_DISPOSITION_* bit field */ AVProbeData probe_data; #define MAX_REORDER_DELAY 16 int64_t pts_buffer[MAX_REORDER_DELAY+1]; /** * sample aspect ratio (0 if unknown) * - encoding: Set by user. * - decoding: Set by libavformat. */ AVRational sample_aspect_ratio; AVDictionary *metadata; /* Intended mostly for av_read_frame() support. Not supposed to be used by */ /* external applications; try to use something else if at all possible. */ const uint8_t *cur_ptr; int cur_len; AVPacket cur_pkt; // Timestamp generation support: /** * Timestamp corresponding to the last dts sync point. * * Initialized when AVCodecParserContext.dts_sync_point >= 0 and * a DTS is received from the underlying container. Otherwise set to * AV_NOPTS_VALUE by default. */ int64_t reference_dts; /** * Number of packets to buffer for codec probing * NOT PART OF PUBLIC API */ #define MAX_PROBE_PACKETS 2500 int probe_packets; /** * last packet in packet_buffer for this stream when muxing. * used internally, NOT PART OF PUBLIC API, dont read or write from outside of libav* */ struct AVPacketList *last_in_packet_buffer; /** * Average framerate */ AVRational avg_frame_rate; /** * Number of frames that have been demuxed during av_find_stream_info() */ int codec_info_nb_frames; /** * Stream Identifier * This is the MPEG-TS stream identifier +1 * 0 means unknown */ int stream_identifier; /** * Stream informations used internally by av_find_stream_info() */ #define MAX_STD_TIMEBASES (60*12+5) struct { int64_t last_dts; int64_t duration_gcd; int duration_count; double duration_error[2][2][MAX_STD_TIMEBASES]; int64_t codec_info_duration; } *info; /** * flag to indicate that probing is requested * NOT PART OF PUBLIC API */ int request_probe; } AVStream; #define AV_PROGRAM_RUNNING 1 /** * New fields can be added to the end with minor version bumps. * Removal, reordering and changes to existing fields require a major * version bump. * sizeof(AVProgram) must not be used outside libav*. */ typedef struct AVProgram { int id; int flags; enum AVDiscard discard; ///< selects which program to discard and which to feed to the caller unsigned int *stream_index; unsigned int nb_stream_indexes; AVDictionary *metadata; int program_num; int pmt_pid; int pcr_pid; } AVProgram; #define AVFMTCTX_NOHEADER 0x0001 /**< signal that no header is present (streams are added dynamically) */ typedef struct AVChapter { int id; ///< unique ID to identify the chapter AVRational time_base; ///< time base in which the start/end timestamps are specified int64_t start, end; ///< chapter start/end time in time_base units AVDictionary *metadata; } AVChapter; /** * Format I/O context. * New fields can be added to the end with minor version bumps. * Removal, reordering and changes to existing fields require a major * version bump. * sizeof(AVFormatContext) must not be used outside libav*. */ typedef struct AVFormatContext { const AVClass *av_class; /**< Set by avformat_alloc_context. */ /* Can only be iformat or oformat, not both at the same time. */ struct AVInputFormat *iformat; struct AVOutputFormat *oformat; void *priv_data; AVIOContext *pb; unsigned int nb_streams; AVStream **streams; char filename[1024]; /**< input or output filename */ /* stream info */ #if FF_API_TIMESTAMP /** * @deprecated use 'creation_time' metadata tag instead */ attribute_deprecated int64_t timestamp; #endif int ctx_flags; /**< Format-specific flags, see AVFMTCTX_xx */ /* private data for pts handling (do not modify directly). */ /** * This buffer is only needed when packets were already buffered but * not decoded, for example to get the codec parameters in MPEG * streams. */ struct AVPacketList *packet_buffer; /** * Decoding: position of the first frame of the component, in * AV_TIME_BASE fractional seconds. NEVER set this value directly: * It is deduced from the AVStream values. */ int64_t start_time; /** * Decoding: duration of the stream, in AV_TIME_BASE fractional * seconds. Only set this value if you know none of the individual stream * durations and also dont set any of them. This is deduced from the * AVStream values if not set. */ int64_t duration; /** * decoding: total file size, 0 if unknown */ int64_t file_size; /** * Decoding: total stream bitrate in bit/s, 0 if not * available. Never set it directly if the file_size and the * duration are known as FFmpeg can compute it automatically. */ int bit_rate; /* av_read_frame() support */ AVStream *cur_st; /* av_seek_frame() support */ int64_t data_offset; /**< offset of the first packet */ int mux_rate; unsigned int packet_size; int preload; int max_delay; #if FF_API_LOOP_OUTPUT #define AVFMT_NOOUTPUTLOOP -1 #define AVFMT_INFINITEOUTPUTLOOP 0 /** * number of times to loop output in formats that support it * * @deprecated use the 'loop' private option in the gif muxer. */ attribute_deprecated int loop_output; #endif int flags; #define AVFMT_FLAG_GENPTS 0x0001 ///< Generate missing pts even if it requires parsing future frames. #define AVFMT_FLAG_IGNIDX 0x0002 ///< Ignore index. #define AVFMT_FLAG_NONBLOCK 0x0004 ///< Do not block when reading packets from input. #define AVFMT_FLAG_IGNDTS 0x0008 ///< Ignore DTS on frames that contain both DTS & PTS #define AVFMT_FLAG_NOFILLIN 0x0010 ///< Do not infer any values from other values, just return what is stored in the container #define AVFMT_FLAG_NOPARSE 0x0020 ///< Do not use AVParsers, you also must set AVFMT_FLAG_NOFILLIN as the fillin code works on frames and no parsing -> no frames. Also seeking to frames can not work if parsing to find frame boundaries has been disabled #if FF_API_FLAG_RTP_HINT #define AVFMT_FLAG_RTP_HINT 0x0040 ///< Deprecated, use the -movflags rtphint muxer specific AVOption instead #endif #define AVFMT_FLAG_CUSTOM_IO 0x0080 ///< The caller has supplied a custom AVIOContext, don't avio_close() it. #define AVFMT_FLAG_DISCARD_CORRUPT 0x0100 ///< Discard frames marked corrupted #define AVFMT_FLAG_MP4A_LATM 0x8000 ///< Enable RTP MP4A-LATM payload #define AVFMT_FLAG_SORT_DTS 0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down) #define AVFMT_FLAG_PRIV_OPT 0x20000 ///< Enable use of private options by delaying codec open (this could be made default once all code is converted) #define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Dont merge side data but keep it seperate. #if FF_API_LOOP_INPUT /** * @deprecated, use the 'loop' img2 demuxer private option. */ attribute_deprecated int loop_input; #endif /** * decoding: size of data to probe; encoding: unused. */ unsigned int probesize; /** * Maximum time (in AV_TIME_BASE units) during which the input should * be analyzed in av_find_stream_info(). */ int max_analyze_duration; const uint8_t *key; int keylen; unsigned int nb_programs; AVProgram **programs; /** * Forced video codec_id. * Demuxing: Set by user. */ enum CodecID video_codec_id; /** * Forced audio codec_id. * Demuxing: Set by user. */ enum CodecID audio_codec_id; /** * Forced subtitle codec_id. * Demuxing: Set by user. */ enum CodecID subtitle_codec_id; /** * Maximum amount of memory in bytes to use for the index of each stream. * If the index exceeds this size, entries will be discarded as * needed to maintain a smaller size. This can lead to slower or less * accurate seeking (depends on demuxer). * Demuxers for which a full in-memory index is mandatory will ignore * this. * muxing : unused * demuxing: set by user */ unsigned int max_index_size; /** * Maximum amount of memory in bytes to use for buffering frames * obtained from realtime capture devices. */ unsigned int max_picture_buffer; unsigned int nb_chapters; AVChapter **chapters; /** * Flags to enable debugging. */ int debug; #define FF_FDEBUG_TS 0x0001 /** * Raw packets from the demuxer, prior to parsing and decoding. * This buffer is used for buffering packets until the codec can * be identified, as parsing cannot be done without knowing the * codec. */ struct AVPacketList *raw_packet_buffer; struct AVPacketList *raw_packet_buffer_end; struct AVPacketList *packet_buffer_end; AVDictionary *metadata; /** * Remaining size available for raw_packet_buffer, in bytes. * NOT PART OF PUBLIC API */ #define RAW_PACKET_BUFFER_SIZE 2500000 int raw_packet_buffer_remaining_size; /** * Start time of the stream in real world time, in microseconds * since the unix epoch (00:00 1st January 1970). That is, pts=0 * in the stream was captured at this real world time. * - encoding: Set by user. * - decoding: Unused. */ int64_t start_time_realtime; /** * decoding: number of frames used to probe fps */ int fps_probe_size; /** * Error recognition; higher values will detect more errors but may * misdetect some more or less valid parts as errors. * - encoding: unused * - decoding: Set by user. */ int error_recognition; /** * Transport stream id. * This will be moved into demuxer private options. Thus no API/ABI compatibility */ int ts_id; } AVFormatContext; typedef struct AVPacketList { AVPacket pkt; struct AVPacketList *next; } AVPacketList; /** * If f is NULL, returns the first registered input format, * if f is non-NULL, returns the next registered input format after f * or NULL if f is the last one. */ AVInputFormat *av_iformat_next(AVInputFormat *f); /** * If f is NULL, returns the first registered output format, * if f is non-NULL, returns the next registered output format after f * or NULL if f is the last one. */ AVOutputFormat *av_oformat_next(AVOutputFormat *f); #if FF_API_GUESS_IMG2_CODEC attribute_deprecated enum CodecID av_guess_image2_codec(const char *filename); #endif /* XXX: Use automatic init with either ELF sections or C file parser */ /* modules. */ /* utils.c */ void av_register_input_format(AVInputFormat *format); void av_register_output_format(AVOutputFormat *format); /** * Return the output format in the list of registered output formats * which best matches the provided parameters, or return NULL if * there is no match. * * @param short_name if non-NULL checks if short_name matches with the * names of the registered formats * @param filename if non-NULL checks if filename terminates with the * extensions of the registered formats * @param mime_type if non-NULL checks if mime_type matches with the * MIME type of the registered formats */ AVOutputFormat *av_guess_format(const char *short_name, const char *filename, const char *mime_type); /** * Guess the codec ID based upon muxer and filename. */ enum CodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, const char *filename, const char *mime_type, enum AVMediaType type); /** * Send a nice hexadecimal dump of a buffer to the specified file stream. * * @param f The file stream pointer where the dump should be sent to. * @param buf buffer * @param size buffer size * * @see av_hex_dump_log, av_pkt_dump2, av_pkt_dump_log2 */ void av_hex_dump(FILE *f, uint8_t *buf, int size); /** * Send a nice hexadecimal dump of a buffer to the log. * * @param avcl A pointer to an arbitrary struct of which the first field is a * pointer to an AVClass struct. * @param level The importance level of the message, lower values signifying * higher importance. * @param buf buffer * @param size buffer size * * @see av_hex_dump, av_pkt_dump2, av_pkt_dump_log2 */ void av_hex_dump_log(void *avcl, int level, uint8_t *buf, int size); /** * Send a nice dump of a packet to the specified file stream. * * @param f The file stream pointer where the dump should be sent to. * @param pkt packet to dump * @param dump_payload True if the payload must be displayed, too. * @param st AVStream that the packet belongs to */ void av_pkt_dump2(FILE *f, AVPacket *pkt, int dump_payload, AVStream *st); /** * Send a nice dump of a packet to the log. * * @param avcl A pointer to an arbitrary struct of which the first field is a * pointer to an AVClass struct. * @param level The importance level of the message, lower values signifying * higher importance. * @param pkt packet to dump * @param dump_payload True if the payload must be displayed, too. * @param st AVStream that the packet belongs to */ void av_pkt_dump_log2(void *avcl, int level, AVPacket *pkt, int dump_payload, AVStream *st); #if FF_API_PKT_DUMP attribute_deprecated void av_pkt_dump(FILE *f, AVPacket *pkt, int dump_payload); attribute_deprecated void av_pkt_dump_log(void *avcl, int level, AVPacket *pkt, int dump_payload); #endif /** * Initialize libavformat and register all the muxers, demuxers and * protocols. If you do not call this function, then you can select * exactly which formats you want to support. * * @see av_register_input_format() * @see av_register_output_format() * @see av_register_protocol() */ void av_register_all(void); /** * Get the CodecID for the given codec tag tag. * If no codec id is found returns CODEC_ID_NONE. * * @param tags list of supported codec_id-codec_tag pairs, as stored * in AVInputFormat.codec_tag and AVOutputFormat.codec_tag */ enum CodecID av_codec_get_id(const struct AVCodecTag * const *tags, unsigned int tag); /** * Get the codec tag for the given codec id id. * If no codec tag is found returns 0. * * @param tags list of supported codec_id-codec_tag pairs, as stored * in AVInputFormat.codec_tag and AVOutputFormat.codec_tag */ unsigned int av_codec_get_tag(const struct AVCodecTag * const *tags, enum CodecID id); /* media file input */ /** * Find AVInputFormat based on the short name of the input format. */ AVInputFormat *av_find_input_format(const char *short_name); /** * Guess the file format. * * @param is_opened Whether the file is already opened; determines whether * demuxers with or without AVFMT_NOFILE are probed. */ AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened); /** * Guess the file format. * * @param is_opened Whether the file is already opened; determines whether * demuxers with or without AVFMT_NOFILE are probed. * @param score_max A probe score larger that this is required to accept a * detection, the variable is set to the actual detection * score afterwards. * If the score is <= AVPROBE_SCORE_MAX / 4 it is recommended * to retry with a larger probe buffer. */ AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max); /** * Guess the file format. * * @param is_opened Whether the file is already opened; determines whether * demuxers with or without AVFMT_NOFILE are probed. * @param score_ret The score of the best detection. */ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score_ret); /** * Probe a bytestream to determine the input format. Each time a probe returns * with a score that is too low, the probe buffer size is increased and another * attempt is made. When the maximum probe size is reached, the input format * with the highest score is returned. * * @param pb the bytestream to probe * @param fmt the input format is put here * @param filename the filename of the stream * @param logctx the log context * @param offset the offset within the bytestream to probe from * @param max_probe_size the maximum probe buffer size (zero for default) * @return 0 in case of success, a negative value corresponding to an * AVERROR code otherwise */ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, const char *filename, void *logctx, unsigned int offset, unsigned int max_probe_size); #if FF_API_FORMAT_PARAMETERS /** * Allocate all the structures needed to read an input stream. * This does not open the needed codecs for decoding the stream[s]. * @deprecated use avformat_open_input instead. */ attribute_deprecated int av_open_input_stream(AVFormatContext **ic_ptr, AVIOContext *pb, const char *filename, AVInputFormat *fmt, AVFormatParameters *ap); /** * Open a media file as input. The codecs are not opened. Only the file * header (if present) is read. * * @param ic_ptr The opened media file handle is put here. * @param filename filename to open * @param fmt If non-NULL, force the file format to use. * @param buf_size optional buffer size (zero if default is OK) * @param ap Additional parameters needed when opening the file * (NULL if default). * @return 0 if OK, AVERROR_xxx otherwise * * @deprecated use avformat_open_input instead. */ attribute_deprecated int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, AVInputFormat *fmt, int buf_size, AVFormatParameters *ap); #endif /** * Open an input stream and read the header. The codecs are not opened. * The stream must be closed with av_close_input_file(). * * @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context). * May be a pointer to NULL, in which case an AVFormatContext is allocated by this * function and written into ps. * Note that a user-supplied AVFormatContext will be freed on failure. * @param filename Name of the stream to open. * @param fmt If non-NULL, this parameter forces a specific input format. * Otherwise the format is autodetected. * @param options A dictionary filled with AVFormatContext and demuxer-private options. * On return this parameter will be destroyed and replaced with a dict containing * options that were not found. May be NULL. * * @return 0 on success, a negative AVERROR on failure. * * @note If you want to use custom IO, preallocate the format context and set its pb field. */ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options); int av_demuxer_open(AVFormatContext *ic, AVFormatParameters *ap); /** * Allocate an AVFormatContext. * avformat_free_context() can be used to free the context and everything * allocated by the framework within it. */ AVFormatContext *avformat_alloc_context(void); #if FF_API_ALLOC_OUTPUT_CONTEXT /** * @deprecated deprecated in favor of avformat_alloc_output_context2() */ attribute_deprecated AVFormatContext *avformat_alloc_output_context(const char *format, AVOutputFormat *oformat, const char *filename); #endif /** * Allocate an AVFormatContext for an output format. * avformat_free_context() can be used to free the context and * everything allocated by the framework within it. * * @param *ctx is set to the created format context, or to NULL in * case of failure * @param oformat format to use for allocating the context, if NULL * format_name and filename are used instead * @param format_name the name of output format to use for allocating the * context, if NULL filename is used instead * @param filename the name of the filename to use for allocating the * context, may be NULL * @return >= 0 in case of success, a negative AVERROR code in case of * failure */ int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat, const char *format_name, const char *filename); #if FF_API_FORMAT_PARAMETERS /** * Read packets of a media file to get stream information. This * is useful for file formats with no headers such as MPEG. This * function also computes the real framerate in case of MPEG-2 repeat * frame mode. * The logical file position is not changed by this function; * examined packets may be buffered for later processing. * * @param ic media file handle * @return >=0 if OK, AVERROR_xxx on error * @todo Let the user decide somehow what information is needed so that * we do not waste time getting stuff the user does not need. * * @deprecated use avformat_find_stream_info. */ attribute_deprecated int av_find_stream_info(AVFormatContext *ic); #endif /** * Read packets of a media file to get stream information. This * is useful for file formats with no headers such as MPEG. This * function also computes the real framerate in case of MPEG-2 repeat * frame mode. * The logical file position is not changed by this function; * examined packets may be buffered for later processing. * * @param ic media file handle * @param options If non-NULL, an ic.nb_streams long array of pointers to * dictionaries, where i-th member contains options for * codec corresponding to i-th stream. * On return each dictionary will be filled with options that were not found. * @return >=0 if OK, AVERROR_xxx on error * * @note this function isn't guaranteed to open all the codecs, so * options being non-empty at return is a perfectly normal behavior. * * @todo Let the user decide somehow what information is needed so that * we do not waste time getting stuff the user does not need. */ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options); /** * Find the programs which belong to a given stream. * * @param ic media file handle * @param last the last found program, the search will start after this * program, or from the beginning if it is NULL * @param s stream index * @return the next program which belongs to s, NULL if no program is found or * the last program is not among the programs of ic. */ AVProgram *av_find_program_from_stream(AVFormatContext *ic, AVProgram *last, int s); /** * Find the "best" stream in the file. * The best stream is determined according to various heuristics as the most * likely to be what the user expects. * If the decoder parameter is non-NULL, av_find_best_stream will find the * default decoder for the stream's codec; streams for which no decoder can * be found are ignored. * * @param ic media file handle * @param type stream type: video, audio, subtitles, etc. * @param wanted_stream_nb user-requested stream number, * or -1 for automatic selection * @param related_stream try to find a stream related (eg. in the same * program) to this one, or -1 if none * @param decoder_ret if non-NULL, returns the decoder for the * selected stream * @param flags flags; none are currently defined * @return the non-negative stream number in case of success, * AVERROR_STREAM_NOT_FOUND if no stream with the requested type * could be found, * AVERROR_DECODER_NOT_FOUND if streams were found but no decoder * @note If av_find_best_stream returns successfully and decoder_ret is not * NULL, then *decoder_ret is guaranteed to be set to a valid AVCodec. */ int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type, int wanted_stream_nb, int related_stream, AVCodec **decoder_ret, int flags); /** * Read a transport packet from a media file. * * This function is obsolete and should never be used. * Use av_read_frame() instead. * * @param s media file handle * @param pkt is filled * @return 0 if OK, AVERROR_xxx on error */ int av_read_packet(AVFormatContext *s, AVPacket *pkt); /** * Return the next frame of a stream. * This function returns what is stored in the file, and does not validate * that what is there are valid frames for the decoder. It will split what is * stored in the file into frames and return one for each call. It will not * omit invalid data between valid frames so as to give the decoder the maximum * information possible for decoding. * * The returned packet is valid * until the next av_read_frame() or until av_close_input_file() and * must be freed with av_free_packet. For video, the packet contains * exactly one frame. For audio, it contains an integer number of * frames if each frame has a known fixed size (e.g. PCM or ADPCM * data). If the audio frames have a variable size (e.g. MPEG audio), * then it contains one frame. * * pkt->pts, pkt->dts and pkt->duration are always set to correct * values in AVStream.time_base units (and guessed if the format cannot * provide them). pkt->pts can be AV_NOPTS_VALUE if the video format * has B-frames, so it is better to rely on pkt->dts if you do not * decompress the payload. * * @return 0 if OK, < 0 on error or end of file */ int av_read_frame(AVFormatContext *s, AVPacket *pkt); /** * Seek to the keyframe at timestamp. * 'timestamp' in 'stream_index'. * @param stream_index If stream_index is (-1), a default * stream is selected, and timestamp is automatically converted * from AV_TIME_BASE units to the stream specific time_base. * @param timestamp Timestamp in AVStream.time_base units * or, if no stream is specified, in AV_TIME_BASE units. * @param flags flags which select direction and seeking mode * @return >= 0 on success */ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags); /** * Seek to timestamp ts. * Seeking will be done so that the point from which all active streams * can be presented successfully will be closest to ts and within min/max_ts. * Active streams are all streams that have AVStream.discard < AVDISCARD_ALL. * * If flags contain AVSEEK_FLAG_BYTE, then all timestamps are in bytes and * are the file position (this may not be supported by all demuxers). * If flags contain AVSEEK_FLAG_FRAME, then all timestamps are in frames * in the stream with stream_index (this may not be supported by all demuxers). * Otherwise all timestamps are in units of the stream selected by stream_index * or if stream_index is -1, in AV_TIME_BASE units. * If flags contain AVSEEK_FLAG_ANY, then non-keyframes are treated as * keyframes (this may not be supported by all demuxers). * * @param stream_index index of the stream which is used as time base reference * @param min_ts smallest acceptable timestamp * @param ts target timestamp * @param max_ts largest acceptable timestamp * @param flags flags * @return >=0 on success, error code otherwise * * @note This is part of the new seek API which is still under construction. * Thus do not use this yet. It may change at any time, do not expect * ABI compatibility yet! */ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags); /** * Start playing a network-based stream (e.g. RTSP stream) at the * current position. */ int av_read_play(AVFormatContext *s); /** * Pause a network-based stream (e.g. RTSP stream). * * Use av_read_play() to resume it. */ int av_read_pause(AVFormatContext *s); /** * Free a AVFormatContext allocated by av_open_input_stream. * @param s context to free */ void av_close_input_stream(AVFormatContext *s); /** * Close a media file (but not its codecs). * * @param s media file handle */ void av_close_input_file(AVFormatContext *s); /** * Free an AVFormatContext and all its streams. * @param s context to free */ void avformat_free_context(AVFormatContext *s); /** * Add a new stream to a media file. * * Can only be called in the read_header() function. If the flag * AVFMTCTX_NOHEADER is in the format context, then new streams * can be added in read_packet too. * * @param s media file handle * @param id file-format-dependent stream ID */ AVStream *av_new_stream(AVFormatContext *s, int id); AVProgram *av_new_program(AVFormatContext *s, int id); /** * Set the pts for a given stream. If the new values would be invalid * (<= 0), it leaves the AVStream unchanged. * * @param s stream * @param pts_wrap_bits number of bits effectively used by the pts * (used for wrap control, 33 is the value for MPEG) * @param pts_num numerator to convert to seconds (MPEG: 1) * @param pts_den denominator to convert to seconds (MPEG: 90000) */ void av_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den); #define AVSEEK_FLAG_BACKWARD 1 ///< seek backward #define AVSEEK_FLAG_BYTE 2 ///< seeking based on position in bytes #define AVSEEK_FLAG_ANY 4 ///< seek to any frame, even non-keyframes #define AVSEEK_FLAG_FRAME 8 ///< seeking based on frame number int av_find_default_stream_index(AVFormatContext *s); /** * Get the index for a specific timestamp. * @param flags if AVSEEK_FLAG_BACKWARD then the returned index will correspond * to the timestamp which is <= the requested one, if backward * is 0, then it will be >= * if AVSEEK_FLAG_ANY seek to any frame, only keyframes otherwise * @return < 0 if no such timestamp could be found */ int av_index_search_timestamp(AVStream *st, int64_t timestamp, int flags); /** * Add an index entry into a sorted list. Update the entry if the list * already contains it. * * @param timestamp timestamp in the time base of the given stream */ int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, int size, int distance, int flags); /** * Perform a binary search using av_index_search_timestamp() and * AVInputFormat.read_timestamp(). * This is not supposed to be called directly by a user application, * but by demuxers. * @param target_ts target timestamp in the time base of the given stream * @param stream_index stream number */ int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags); /** * Update cur_dts of all streams based on the given timestamp and AVStream. * * Stream ref_st unchanged, others set cur_dts in their native time base. * Only needed for timestamp wrapping or if (dts not set and pts!=dts). * @param timestamp new dts expressed in time_base of param ref_st * @param ref_st reference stream giving time_base of param timestamp */ void av_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp); /** * Perform a binary search using read_timestamp(). * This is not supposed to be called directly by a user application, * but by demuxers. * @param target_ts target timestamp in the time base of the given stream * @param stream_index stream number */ int64_t av_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, int64_t pos_min, int64_t pos_max, int64_t pos_limit, int64_t ts_min, int64_t ts_max, int flags, int64_t *ts_ret, int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t )); /** * media file output */ #if FF_API_FORMAT_PARAMETERS /** * @deprecated pass the options to avformat_write_header directly. */ attribute_deprecated int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap); #endif /** * Split a URL string into components. * * The pointers to buffers for storing individual components may be null, * in order to ignore that component. Buffers for components not found are * set to empty strings. If the port is not found, it is set to a negative * value. * * @param proto the buffer for the protocol * @param proto_size the size of the proto buffer * @param authorization the buffer for the authorization * @param authorization_size the size of the authorization buffer * @param hostname the buffer for the host name * @param hostname_size the size of the hostname buffer * @param port_ptr a pointer to store the port number in * @param path the buffer for the path * @param path_size the size of the path buffer * @param url the URL to split */ void av_url_split(char *proto, int proto_size, char *authorization, int authorization_size, char *hostname, int hostname_size, int *port_ptr, char *path, int path_size, const char *url); /** * Allocate the stream private data and write the stream header to * an output media file. * * @param s Media file handle, must be allocated with avformat_alloc_context(). * Its oformat field must be set to the desired output format; * Its pb field must be set to an already openened AVIOContext. * @param options An AVDictionary filled with AVFormatContext and muxer-private options. * On return this parameter will be destroyed and replaced with a dict containing * options that were not found. May be NULL. * * @return 0 on success, negative AVERROR on failure. * * @see av_opt_find, av_dict_set, avio_open, av_oformat_next. */ int avformat_write_header(AVFormatContext *s, AVDictionary **options); #if FF_API_FORMAT_PARAMETERS /** * Allocate the stream private data and write the stream header to an * output media file. * @note: this sets stream time-bases, if possible to stream->codec->time_base * but for some formats it might also be some other time base * * @param s media file handle * @return 0 if OK, AVERROR_xxx on error * * @deprecated use avformat_write_header. */ attribute_deprecated int av_write_header(AVFormatContext *s); #endif /** * Write a packet to an output media file. * * The packet shall contain one audio or video frame. * The packet must be correctly interleaved according to the container * specification, if not then av_interleaved_write_frame must be used. * * @param s media file handle * @param pkt The packet, which contains the stream_index, buf/buf_size, dts/pts, ... * @return < 0 on error, = 0 if OK, 1 if end of stream wanted */ int av_write_frame(AVFormatContext *s, AVPacket *pkt); /** * Write a packet to an output media file ensuring correct interleaving. * * The packet must contain one audio or video frame. * If the packets are already correctly interleaved, the application should * call av_write_frame() instead as it is slightly faster. It is also important * to keep in mind that completely non-interleaved input will need huge amounts * of memory to interleave with this, so it is preferable to interleave at the * demuxer level. * * @param s media file handle * @param pkt The packet, which contains the stream_index, buf/buf_size, dts/pts, ... * @return < 0 on error, = 0 if OK, 1 if end of stream wanted */ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt); /** * Interleave a packet per dts in an output media file. * * Packets with pkt->destruct == av_destruct_packet will be freed inside this * function, so they cannot be used after it. Note that calling av_free_packet() * on them is still safe. * * @param s media file handle * @param out the interleaved packet will be output here * @param pkt the input packet * @param flush 1 if no further packets are available as input and all * remaining packets should be output * @return 1 if a packet was output, 0 if no packet could be output, * < 0 if an error occurred */ int av_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush); /** * Write the stream trailer to an output media file and free the * file private data. * * May only be called after a successful call to av_write_header. * * @param s media file handle * @return 0 if OK, AVERROR_xxx on error */ int av_write_trailer(AVFormatContext *s); /** * Get timing information for the data currently output. * The exact meaning of "currently output" depends on the format. * It is mostly relevant for devices that have an internal buffer and/or * work in real time. * @param s media file handle * @param stream stream in the media file * @param dts[out] DTS of the last packet output for the stream, in stream * time_base units * @param wall[out] absolute time when that packet whas output, * in microsecond * @return 0 if OK, AVERROR(ENOSYS) if the format does not support it * Note: some formats or devices may not allow to measure dts and wall * atomically. */ int av_get_output_timestamp(struct AVFormatContext *s, int stream, int64_t *dts, int64_t *wall); #if FF_API_DUMP_FORMAT /** * @deprecated Deprecated in favor of av_dump_format(). */ attribute_deprecated void dump_format(AVFormatContext *ic, int index, const char *url, int is_output); #endif void av_dump_format(AVFormatContext *ic, int index, const char *url, int is_output); #if FF_API_PARSE_DATE /** * Parse datestr and return a corresponding number of microseconds. * * @param datestr String representing a date or a duration. * See av_parse_time() for the syntax of the provided string. * @deprecated in favor of av_parse_time() */ attribute_deprecated int64_t parse_date(const char *datestr, int duration); #endif /** * Get the current time in microseconds. */ int64_t av_gettime(void); #if FF_API_FIND_INFO_TAG /** * @deprecated use av_find_info_tag in libavutil instead. */ attribute_deprecated int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info); #endif /** * Return in 'buf' the path with '%d' replaced by a number. * * Also handles the '%0nd' format where 'n' is the total number * of digits and '%%'. * * @param buf destination buffer * @param buf_size destination buffer size * @param path numbered sequence string * @param number frame number * @return 0 if OK, -1 on format error */ int av_get_frame_filename(char *buf, int buf_size, const char *path, int number); /** * Check whether filename actually is a numbered sequence generator. * * @param filename possible numbered sequence string * @return 1 if a valid numbered sequence string, 0 otherwise */ int av_filename_number_test(const char *filename); /** * Generate an SDP for an RTP session. * * @param ac array of AVFormatContexts describing the RTP streams. If the * array is composed by only one context, such context can contain * multiple AVStreams (one AVStream per RTP stream). Otherwise, * all the contexts in the array (an AVCodecContext per RTP stream) * must contain only one AVStream. * @param n_files number of AVCodecContexts contained in ac * @param buf buffer where the SDP will be stored (must be allocated by * the caller) * @param size the size of the buffer * @return 0 if OK, AVERROR_xxx on error */ int av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size); #if FF_API_SDP_CREATE attribute_deprecated int avf_sdp_create(AVFormatContext *ac[], int n_files, char *buff, int size); #endif /** * Return a positive value if the given filename has one of the given * extensions, 0 otherwise. * * @param extensions a comma-separated list of filename extensions */ int av_match_ext(const char *filename, const char *extensions); /** * Test if the given container can store a codec. * * @param std_compliance standards compliance level, one of FF_COMPLIANCE_* * * @return 1 if codec with ID codec_id can be stored in ofmt, 0 if it cannot. * A negative number if this information is not available. */ int avformat_query_codec(AVOutputFormat *ofmt, enum CodecID codec_id, int std_compliance); /** * Get the AVClass for AVFormatContext. It can be used in combination with * AV_OPT_SEARCH_FAKE_OBJ for examining options. * * @see av_opt_find(). */ const AVClass *avformat_get_class(void); #endif /* AVFORMAT_AVFORMAT_H */ IanniX-0.9.20/gui/qffmpeg/libavformat/avio.h000066400000000000000000000576721317340345000206370ustar00rootroot00000000000000/* * copyright (c) 2001 Fabrice Bellard * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVFORMAT_AVIO_H #define AVFORMAT_AVIO_H /** * @file * Buffered I/O operations */ #include #include "libavutil/common.h" #include "libavutil/log.h" #include "libavformat/version.h" #define AVIO_SEEKABLE_NORMAL 0x0001 /**< Seeking works like for a local file */ /** * Bytestream IO Context. * New fields can be added to the end with minor version bumps. * Removal, reordering and changes to existing fields require a major * version bump. * sizeof(AVIOContext) must not be used outside libav*. * * @note None of the function pointers in AVIOContext should be called * directly, they should only be set by the client application * when implementing custom I/O. Normally these are set to the * function pointers specified in avio_alloc_context() */ typedef struct { unsigned char *buffer; /**< Start of the buffer. */ int buffer_size; /**< Maximum buffer size */ unsigned char *buf_ptr; /**< Current position in the buffer */ unsigned char *buf_end; /**< End of the data, may be less than buffer+buffer_size if the read function returned less data than requested, e.g. for streams where no more data has been received yet. */ void *opaque; /**< A private pointer, passed to the read/write/seek/... functions. */ int (*read_packet)(void *opaque, uint8_t *buf, int buf_size); int (*write_packet)(void *opaque, uint8_t *buf, int buf_size); int64_t (*seek)(void *opaque, int64_t offset, int whence); int64_t pos; /**< position in the file of the current buffer */ int must_flush; /**< true if the next seek should flush */ int eof_reached; /**< true if eof reached */ int write_flag; /**< true if open for writing */ #if FF_API_OLD_AVIO attribute_deprecated int is_streamed; #endif int max_packet_size; unsigned long checksum; unsigned char *checksum_ptr; unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size); int error; /**< contains the error code or 0 if no error happened */ /** * Pause or resume playback for network streaming protocols - e.g. MMS. */ int (*read_pause)(void *opaque, int pause); /** * Seek to a given timestamp in stream with the specified stream_index. * Needed for some network streaming protocols which don't support seeking * to byte position. */ int64_t (*read_seek)(void *opaque, int stream_index, int64_t timestamp, int flags); /** * A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable. */ int seekable; } AVIOContext; /* unbuffered I/O */ #if FF_API_OLD_AVIO /** * URL Context. * New fields can be added to the end with minor version bumps. * Removal, reordering and changes to existing fields require a major * version bump. * sizeof(URLContext) must not be used outside libav*. * @deprecated This struct will be made private */ typedef struct URLContext { const AVClass *av_class; ///< information for av_log(). Set by url_open(). struct URLProtocol *prot; int flags; int is_streamed; /**< true if streamed (no seek possible), default = false */ int max_packet_size; /**< if non zero, the stream is packetized with this max packet size */ void *priv_data; char *filename; /**< specified URL */ int is_connected; } URLContext; #define URL_PROTOCOL_FLAG_NESTED_SCHEME 1 /*< The protocol name can be the first part of a nested protocol scheme */ /** * @deprecated This struct is to be made private. Use the higher-level * AVIOContext-based API instead. */ typedef struct URLProtocol { const char *name; int (*url_open)(URLContext *h, const char *url, int flags); int (*url_read)(URLContext *h, unsigned char *buf, int size); int (*url_write)(URLContext *h, const unsigned char *buf, int size); int64_t (*url_seek)(URLContext *h, int64_t pos, int whence); int (*url_close)(URLContext *h); struct URLProtocol *next; int (*url_read_pause)(URLContext *h, int pause); int64_t (*url_read_seek)(URLContext *h, int stream_index, int64_t timestamp, int flags); int (*url_get_file_handle)(URLContext *h); int priv_data_size; const AVClass *priv_data_class; int flags; int (*url_check)(URLContext *h, int mask); } URLProtocol; typedef struct URLPollEntry { URLContext *handle; int events; int revents; } URLPollEntry; /* not implemented */ attribute_deprecated int url_poll(URLPollEntry *poll_table, int n, int timeout); /** * @name URL open modes * The flags argument to url_open and cosins must be one of the following * constants, optionally ORed with other flags. * @{ */ #define URL_RDONLY 1 /**< read-only */ #define URL_WRONLY 2 /**< write-only */ #define URL_RDWR (URL_RDONLY|URL_WRONLY) /**< read-write */ /** * @} */ /** * Use non-blocking mode. * If this flag is set, operations on the context will return * AVERROR(EAGAIN) if they can not be performed immediately. * If this flag is not set, operations on the context will never return * AVERROR(EAGAIN). * Note that this flag does not affect the opening/connecting of the * context. Connecting a protocol will always block if necessary (e.g. on * network protocols) but never hang (e.g. on busy devices). * Warning: non-blocking protocols is work-in-progress; this flag may be * silently ignored. */ #define URL_FLAG_NONBLOCK 4 typedef int URLInterruptCB(void); extern URLInterruptCB *url_interrupt_cb; /** * @defgroup old_url_funcs Old url_* functions * The following functions are deprecated. Use the buffered API based on #AVIOContext instead. * @{ */ attribute_deprecated int url_open_protocol (URLContext **puc, struct URLProtocol *up, const char *url, int flags); attribute_deprecated int url_alloc(URLContext **h, const char *url, int flags); attribute_deprecated int url_connect(URLContext *h); attribute_deprecated int url_open(URLContext **h, const char *url, int flags); attribute_deprecated int url_read(URLContext *h, unsigned char *buf, int size); attribute_deprecated int url_read_complete(URLContext *h, unsigned char *buf, int size); attribute_deprecated int url_write(URLContext *h, const unsigned char *buf, int size); attribute_deprecated int64_t url_seek(URLContext *h, int64_t pos, int whence); attribute_deprecated int url_close(URLContext *h); attribute_deprecated int64_t url_filesize(URLContext *h); attribute_deprecated int url_get_file_handle(URLContext *h); attribute_deprecated int url_get_max_packet_size(URLContext *h); attribute_deprecated void url_get_filename(URLContext *h, char *buf, int buf_size); attribute_deprecated int av_url_read_pause(URLContext *h, int pause); attribute_deprecated int64_t av_url_read_seek(URLContext *h, int stream_index, int64_t timestamp, int flags); attribute_deprecated void url_set_interrupt_cb(int (*interrupt_cb)(void)); /** * returns the next registered protocol after the given protocol (the first if * NULL is given), or NULL if protocol is the last one. */ URLProtocol *av_protocol_next(URLProtocol *p); /** * Register the URLProtocol protocol. * * @param size the size of the URLProtocol struct referenced */ attribute_deprecated int av_register_protocol2(URLProtocol *protocol, int size); /** * @} */ typedef attribute_deprecated AVIOContext ByteIOContext; attribute_deprecated int init_put_byte(AVIOContext *s, unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t (*seek)(void *opaque, int64_t offset, int whence)); attribute_deprecated AVIOContext *av_alloc_put_byte( unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t (*seek)(void *opaque, int64_t offset, int whence)); /** * @defgroup old_avio_funcs Old put_/get_*() functions * The following functions are deprecated. Use the "avio_"-prefixed functions instead. * @{ */ attribute_deprecated int get_buffer(AVIOContext *s, unsigned char *buf, int size); attribute_deprecated int get_partial_buffer(AVIOContext *s, unsigned char *buf, int size); attribute_deprecated int get_byte(AVIOContext *s); attribute_deprecated unsigned int get_le16(AVIOContext *s); attribute_deprecated unsigned int get_le24(AVIOContext *s); attribute_deprecated unsigned int get_le32(AVIOContext *s); attribute_deprecated uint64_t get_le64(AVIOContext *s); attribute_deprecated unsigned int get_be16(AVIOContext *s); attribute_deprecated unsigned int get_be24(AVIOContext *s); attribute_deprecated unsigned int get_be32(AVIOContext *s); attribute_deprecated uint64_t get_be64(AVIOContext *s); attribute_deprecated void put_byte(AVIOContext *s, int b); attribute_deprecated void put_nbyte(AVIOContext *s, int b, int count); attribute_deprecated void put_buffer(AVIOContext *s, const unsigned char *buf, int size); attribute_deprecated void put_le64(AVIOContext *s, uint64_t val); attribute_deprecated void put_be64(AVIOContext *s, uint64_t val); attribute_deprecated void put_le32(AVIOContext *s, unsigned int val); attribute_deprecated void put_be32(AVIOContext *s, unsigned int val); attribute_deprecated void put_le24(AVIOContext *s, unsigned int val); attribute_deprecated void put_be24(AVIOContext *s, unsigned int val); attribute_deprecated void put_le16(AVIOContext *s, unsigned int val); attribute_deprecated void put_be16(AVIOContext *s, unsigned int val); attribute_deprecated void put_tag(AVIOContext *s, const char *tag); /** * @} */ attribute_deprecated int av_url_read_fpause(AVIOContext *h, int pause); attribute_deprecated int64_t av_url_read_fseek (AVIOContext *h, int stream_index, int64_t timestamp, int flags); /** * @defgroup old_url_f_funcs Old url_f* functions * The following functions are deprecated, use the "avio_"-prefixed functions instead. * @{ */ attribute_deprecated int url_fopen( AVIOContext **s, const char *url, int flags); attribute_deprecated int url_fclose(AVIOContext *s); attribute_deprecated int64_t url_fseek(AVIOContext *s, int64_t offset, int whence); attribute_deprecated int url_fskip(AVIOContext *s, int64_t offset); attribute_deprecated int64_t url_ftell(AVIOContext *s); attribute_deprecated int64_t url_fsize(AVIOContext *s); #define URL_EOF (-1) attribute_deprecated int url_fgetc(AVIOContext *s); attribute_deprecated int url_setbufsize(AVIOContext *s, int buf_size); attribute_deprecated int url_fprintf(AVIOContext *s, const char *fmt, ...) av_printf_format(2, 3); attribute_deprecated void put_flush_packet(AVIOContext *s); attribute_deprecated int url_open_dyn_buf(AVIOContext **s); attribute_deprecated int url_open_dyn_packet_buf(AVIOContext **s, int max_packet_size); attribute_deprecated int url_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer); attribute_deprecated int url_fdopen(AVIOContext **s, URLContext *h); /** * @} */ attribute_deprecated int url_ferror(AVIOContext *s); attribute_deprecated int udp_set_remote_url(URLContext *h, const char *uri); attribute_deprecated int udp_get_local_port(URLContext *h); attribute_deprecated void init_checksum(AVIOContext *s, unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len), unsigned long checksum); attribute_deprecated unsigned long get_checksum(AVIOContext *s); attribute_deprecated void put_strz(AVIOContext *s, const char *buf); /** @note unlike fgets, the EOL character is not returned and a whole line is parsed. return NULL if first char read was EOF */ attribute_deprecated char *url_fgets(AVIOContext *s, char *buf, int buf_size); /** * @deprecated use avio_get_str instead */ attribute_deprecated char *get_strz(AVIOContext *s, char *buf, int maxlen); /** * @deprecated Use AVIOContext.seekable field directly. */ attribute_deprecated static inline int url_is_streamed(AVIOContext *s) { return !s->seekable; } attribute_deprecated URLContext *url_fileno(AVIOContext *s); /** * @deprecated use AVIOContext.max_packet_size directly. */ attribute_deprecated int url_fget_max_packet_size(AVIOContext *s); attribute_deprecated int url_open_buf(AVIOContext **s, uint8_t *buf, int buf_size, int flags); /** return the written or read size */ attribute_deprecated int url_close_buf(AVIOContext *s); /** * Return a non-zero value if the resource indicated by url * exists, 0 otherwise. * @deprecated Use avio_check instead. */ attribute_deprecated int url_exist(const char *url); #endif // FF_API_OLD_AVIO /** * Return AVIO_FLAG_* access flags corresponding to the access permissions * of the resource in url, or a negative value corresponding to an * AVERROR code in case of failure. The returned access flags are * masked by the value in flags. * * @note This function is intrinsically unsafe, in the sense that the * checked resource may change its existence or permission status from * one call to another. Thus you should not trust the returned value, * unless you are sure that no other processes are accessing the * checked resource. */ int avio_check(const char *url, int flags); /** * The callback is called in blocking functions to test regulary if * asynchronous interruption is needed. AVERROR_EXIT is returned * in this case by the interrupted function. 'NULL' means no interrupt * callback is given. */ void avio_set_interrupt_cb(int (*interrupt_cb)(void)); /** * Allocate and initialize an AVIOContext for buffered I/O. It must be later * freed with av_free(). * * @param buffer Memory block for input/output operations via AVIOContext. * The buffer must be allocated with av_malloc() and friends. * @param buffer_size The buffer size is very important for performance. * For protocols with fixed blocksize it should be set to this blocksize. * For others a typical size is a cache page, e.g. 4kb. * @param write_flag Set to 1 if the buffer should be writable, 0 otherwise. * @param opaque An opaque pointer to user-specific data. * @param read_packet A function for refilling the buffer, may be NULL. * @param write_packet A function for writing the buffer contents, may be NULL. * @param seek A function for seeking to specified byte position, may be NULL. * * @return Allocated AVIOContext or NULL on failure. */ AVIOContext *avio_alloc_context( unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t (*seek)(void *opaque, int64_t offset, int whence)); void avio_w8(AVIOContext *s, int b); void avio_write(AVIOContext *s, const unsigned char *buf, int size); void avio_wl64(AVIOContext *s, uint64_t val); void avio_wb64(AVIOContext *s, uint64_t val); void avio_wl32(AVIOContext *s, unsigned int val); void avio_wb32(AVIOContext *s, unsigned int val); void avio_wl24(AVIOContext *s, unsigned int val); void avio_wb24(AVIOContext *s, unsigned int val); void avio_wl16(AVIOContext *s, unsigned int val); void avio_wb16(AVIOContext *s, unsigned int val); /** * Write a NULL-terminated string. * @return number of bytes written. */ int avio_put_str(AVIOContext *s, const char *str); /** * Convert an UTF-8 string to UTF-16LE and write it. * @return number of bytes written. */ int avio_put_str16le(AVIOContext *s, const char *str); /** * Passing this as the "whence" parameter to a seek function causes it to * return the filesize without seeking anywhere. Supporting this is optional. * If it is not supported then the seek function will return <0. */ #define AVSEEK_SIZE 0x10000 /** * Oring this flag as into the "whence" parameter to a seek function causes it to * seek by any means (like reopening and linear reading) or other normally unreasonble * means that can be extreemly slow. * This may be ignored by the seek code. */ #define AVSEEK_FORCE 0x20000 /** * fseek() equivalent for AVIOContext. * @return new position or AVERROR. */ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence); /** * Skip given number of bytes forward * @return new position or AVERROR. */ int64_t avio_skip(AVIOContext *s, int64_t offset); /** * ftell() equivalent for AVIOContext. * @return position or AVERROR. */ static av_always_inline int64_t avio_tell(AVIOContext *s) { return avio_seek(s, 0, SEEK_CUR); } /** * Get the filesize. * @return filesize or AVERROR */ int64_t avio_size(AVIOContext *s); /** * feof() equivalent for AVIOContext. * @return non zero if and only if end of file */ int url_feof(AVIOContext *s); /** @warning currently size is limited */ int avio_printf(AVIOContext *s, const char *fmt, ...) av_printf_format(2, 3); void avio_flush(AVIOContext *s); /** * Read size bytes from AVIOContext into buf. * @return number of bytes read or AVERROR */ int avio_read(AVIOContext *s, unsigned char *buf, int size); /** * @name Functions for reading from AVIOContext * @{ * * @note return 0 if EOF, so you cannot use it if EOF handling is * necessary */ int avio_r8 (AVIOContext *s); unsigned int avio_rl16(AVIOContext *s); unsigned int avio_rl24(AVIOContext *s); unsigned int avio_rl32(AVIOContext *s); uint64_t avio_rl64(AVIOContext *s); unsigned int avio_rb16(AVIOContext *s); unsigned int avio_rb24(AVIOContext *s); unsigned int avio_rb32(AVIOContext *s); uint64_t avio_rb64(AVIOContext *s); /** * @} */ /** * Read a string from pb into buf. The reading will terminate when either * a NULL character was encountered, maxlen bytes have been read, or nothing * more can be read from pb. The result is guaranteed to be NULL-terminated, it * will be truncated if buf is too small. * Note that the string is not interpreted or validated in any way, it * might get truncated in the middle of a sequence for multi-byte encodings. * * @return number of bytes read (is always <= maxlen). * If reading ends on EOF or error, the return value will be one more than * bytes actually read. */ int avio_get_str(AVIOContext *pb, int maxlen, char *buf, int buflen); /** * Read a UTF-16 string from pb and convert it to UTF-8. * The reading will terminate when either a null or invalid character was * encountered or maxlen bytes have been read. * @return number of bytes read (is always <= maxlen) */ int avio_get_str16le(AVIOContext *pb, int maxlen, char *buf, int buflen); int avio_get_str16be(AVIOContext *pb, int maxlen, char *buf, int buflen); /** * @name URL open modes * The flags argument to avio_open must be one of the following * constants, optionally ORed with other flags. * @{ */ #define AVIO_FLAG_READ 1 /**< read-only */ #define AVIO_FLAG_WRITE 2 /**< write-only */ #define AVIO_FLAG_READ_WRITE (AVIO_FLAG_READ|AVIO_FLAG_WRITE) /**< read-write pseudo flag */ /** * @} */ /** * Use non-blocking mode. * If this flag is set, operations on the context will return * AVERROR(EAGAIN) if they can not be performed immediately. * If this flag is not set, operations on the context will never return * AVERROR(EAGAIN). * Note that this flag does not affect the opening/connecting of the * context. Connecting a protocol will always block if necessary (e.g. on * network protocols) but never hang (e.g. on busy devices). * Warning: non-blocking protocols is work-in-progress; this flag may be * silently ignored. */ #define AVIO_FLAG_NONBLOCK 8 /** * Create and initialize a AVIOContext for accessing the * resource indicated by url. * @note When the resource indicated by url has been opened in * read+write mode, the AVIOContext can be used only for writing. * * @param s Used to return the pointer to the created AVIOContext. * In case of failure the pointed to value is set to NULL. * @param flags flags which control how the resource indicated by url * is to be opened * @return 0 in case of success, a negative value corresponding to an * AVERROR code in case of failure */ int avio_open(AVIOContext **s, const char *url, int flags); /** * Close the resource accessed by the AVIOContext s and free it. * This function can only be used if s was opened by avio_open(). * * @return 0 on success, an AVERROR < 0 on error. */ int avio_close(AVIOContext *s); /** * Open a write only memory stream. * * @param s new IO context * @return zero if no error. */ int avio_open_dyn_buf(AVIOContext **s); /** * Return the written size and a pointer to the buffer. The buffer * must be freed with av_free(). * Padding of FF_INPUT_BUFFER_PADDING_SIZE is added to the buffer. * * @param s IO context * @param pbuffer pointer to a byte buffer * @return the length of the byte buffer */ int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer); /** * Iterate through names of available protocols. * @note it is recommanded to use av_protocol_next() instead of this * * @param opaque A private pointer representing current protocol. * It must be a pointer to NULL on first iteration and will * be updated by successive calls to avio_enum_protocols. * @param output If set to 1, iterate over output protocols, * otherwise over input protocols. * * @return A static string containing the name of current protocol or NULL */ const char *avio_enum_protocols(void **opaque, int output); /** * Pause and resume playing - only meaningful if using a network streaming * protocol (e.g. MMS). * @param pause 1 for pause, 0 for resume */ int avio_pause(AVIOContext *h, int pause); /** * Seek to a given timestamp relative to some component stream. * Only meaningful if using a network streaming protocol (e.g. MMS.). * @param stream_index The stream index that the timestamp is relative to. * If stream_index is (-1) the timestamp should be in AV_TIME_BASE * units from the beginning of the presentation. * If a stream_index >= 0 is used and the protocol does not support * seeking based on component streams, the call will fail with ENOTSUP. * @param timestamp timestamp in AVStream.time_base units * or if there is no stream specified then in AV_TIME_BASE units. * @param flags Optional combination of AVSEEK_FLAG_BACKWARD, AVSEEK_FLAG_BYTE * and AVSEEK_FLAG_ANY. The protocol may silently ignore * AVSEEK_FLAG_BACKWARD and AVSEEK_FLAG_ANY, but AVSEEK_FLAG_BYTE will * fail with ENOTSUP if used and not supported. * @return >= 0 on success * @see AVInputFormat::read_seek */ int64_t avio_seek_time(AVIOContext *h, int stream_index, int64_t timestamp, int flags); #endif /* AVFORMAT_AVIO_H */ IanniX-0.9.20/gui/qffmpeg/libavformat/version.h000066400000000000000000000065131317340345000213520ustar00rootroot00000000000000/* * Version macros. * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVFORMAT_VERSION_H #define AVFORMAT_VERSION_H #include "libavutil/avutil.h" #define LIBAVFORMAT_VERSION_MAJOR 53 #define LIBAVFORMAT_VERSION_MINOR 12 #define LIBAVFORMAT_VERSION_MICRO 0 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ LIBAVFORMAT_VERSION_MICRO) #define LIBAVFORMAT_VERSION AV_VERSION(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ LIBAVFORMAT_VERSION_MICRO) #define LIBAVFORMAT_BUILD LIBAVFORMAT_VERSION_INT #define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION) /** * Those FF_API_* defines are not part of public API. * They may change, break or disappear at any time. */ #ifndef FF_API_OLD_METADATA2 #define FF_API_OLD_METADATA2 (LIBAVFORMAT_VERSION_MAJOR < 54) #endif #ifndef FF_API_READ_SEEK #define FF_API_READ_SEEK (LIBAVFORMAT_VERSION_MAJOR < 54) #endif #ifndef FF_API_OLD_AVIO #define FF_API_OLD_AVIO (LIBAVFORMAT_VERSION_MAJOR < 54) #endif #ifndef FF_API_DUMP_FORMAT #define FF_API_DUMP_FORMAT (LIBAVFORMAT_VERSION_MAJOR < 54) #endif #ifndef FF_API_PARSE_DATE #define FF_API_PARSE_DATE (LIBAVFORMAT_VERSION_MAJOR < 54) #endif #ifndef FF_API_FIND_INFO_TAG #define FF_API_FIND_INFO_TAG (LIBAVFORMAT_VERSION_MAJOR < 54) #endif #ifndef FF_API_PKT_DUMP #define FF_API_PKT_DUMP (LIBAVFORMAT_VERSION_MAJOR < 54) #endif #ifndef FF_API_GUESS_IMG2_CODEC #define FF_API_GUESS_IMG2_CODEC (LIBAVFORMAT_VERSION_MAJOR < 54) #endif #ifndef FF_API_SDP_CREATE #define FF_API_SDP_CREATE (LIBAVFORMAT_VERSION_MAJOR < 54) #endif #ifndef FF_API_ALLOC_OUTPUT_CONTEXT #define FF_API_ALLOC_OUTPUT_CONTEXT (LIBAVFORMAT_VERSION_MAJOR < 54) #endif #ifndef FF_API_FORMAT_PARAMETERS #define FF_API_FORMAT_PARAMETERS (LIBAVFORMAT_VERSION_MAJOR < 54) #endif #ifndef FF_API_FLAG_RTP_HINT #define FF_API_FLAG_RTP_HINT (LIBAVFORMAT_VERSION_MAJOR < 54) #endif #ifndef FF_API_AVSTREAM_QUALITY #define FF_API_AVSTREAM_QUALITY (LIBAVFORMAT_VERSION_MAJOR < 54) #endif #ifndef FF_API_LOOP_INPUT #define FF_API_LOOP_INPUT (LIBAVFORMAT_VERSION_MAJOR < 54) #endif #ifndef FF_API_LOOP_OUTPUT #define FF_API_LOOP_OUTPUT (LIBAVFORMAT_VERSION_MAJOR < 54) #endif #ifndef FF_API_TIMESTAMP #define FF_API_TIMESTAMP (LIBAVFORMAT_VERSION_MAJOR < 54) #endif #endif /* AVFORMAT_VERSION_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/000077500000000000000000000000001317340345000171745ustar00rootroot00000000000000IanniX-0.9.20/gui/qffmpeg/libavutil/adler32.h000066400000000000000000000026151317340345000206050ustar00rootroot00000000000000/* * copyright (c) 2006 Mans Rullgard * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_ADLER32_H #define AVUTIL_ADLER32_H #include #include "attributes.h" /** * Calculate the Adler32 checksum of a buffer. * * Passing the return value to a subsequent av_adler32_update() call * allows the checksum of multiple buffers to be calculated as though * they were concatenated. * * @param adler initial checksum value * @param buf pointer to input buffer * @param len size of input buffer * @return updated checksum */ unsigned long av_adler32_update(unsigned long adler, const uint8_t *buf, unsigned int len) av_pure; #endif /* AVUTIL_ADLER32_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/aes.h000066400000000000000000000031221317340345000201130ustar00rootroot00000000000000/* * copyright (c) 2007 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_AES_H #define AVUTIL_AES_H #include extern const int av_aes_size; struct AVAES; /** * Initialize an AVAES context. * @param key_bits 128, 192 or 256 * @param decrypt 0 for encryption, 1 for decryption */ int av_aes_init(struct AVAES *a, const uint8_t *key, int key_bits, int decrypt); /** * Encrypt or decrypt a buffer using a previously initialized context. * @param count number of 16 byte blocks * @param dst destination array, can be equal to src * @param src source array, can be equal to dst * @param iv initialization vector for CBC mode, if NULL then ECB will be used * @param decrypt 0 for encryption, 1 for decryption */ void av_aes_crypt(struct AVAES *a, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); #endif /* AVUTIL_AES_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/attributes.h000066400000000000000000000062131317340345000215350ustar00rootroot00000000000000/* * copyright (c) 2006 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * Macro definitions for various function/variable attributes */ #ifndef AVUTIL_ATTRIBUTES_H #define AVUTIL_ATTRIBUTES_H #ifdef __GNUC__ # define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > x || __GNUC__ == x && __GNUC_MINOR__ >= y) #else # define AV_GCC_VERSION_AT_LEAST(x,y) 0 #endif #ifndef av_always_inline #if AV_GCC_VERSION_AT_LEAST(3,1) # define av_always_inline __attribute__((always_inline)) inline #else # define av_always_inline inline #endif #endif #ifndef av_noinline #if AV_GCC_VERSION_AT_LEAST(3,1) # define av_noinline __attribute__((noinline)) #else # define av_noinline #endif #endif #ifndef av_pure #if AV_GCC_VERSION_AT_LEAST(3,1) # define av_pure __attribute__((pure)) #else # define av_pure #endif #endif #ifndef av_const #if AV_GCC_VERSION_AT_LEAST(2,6) # define av_const __attribute__((const)) #else # define av_const #endif #endif #ifndef av_cold #if AV_GCC_VERSION_AT_LEAST(4,3) # define av_cold __attribute__((cold)) #else # define av_cold #endif #endif #ifndef av_flatten #if AV_GCC_VERSION_AT_LEAST(4,1) # define av_flatten __attribute__((flatten)) #else # define av_flatten #endif #endif #ifndef attribute_deprecated #if AV_GCC_VERSION_AT_LEAST(3,1) # define attribute_deprecated __attribute__((deprecated)) #else # define attribute_deprecated #endif #endif #ifndef av_unused #if defined(__GNUC__) # define av_unused __attribute__((unused)) #else # define av_unused #endif #endif /** * Mark a variable as used and prevent the compiler from optimizing it * away. This is useful for variables accessed only from inline * assembler without the compiler being aware. */ #ifndef av_used #if AV_GCC_VERSION_AT_LEAST(3,1) # define av_used __attribute__((used)) #else # define av_used #endif #endif #ifndef av_alias #if AV_GCC_VERSION_AT_LEAST(3,3) # define av_alias __attribute__((may_alias)) #else # define av_alias #endif #endif #ifndef av_uninit #if defined(__GNUC__) && !defined(__INTEL_COMPILER) # define av_uninit(x) x=x #else # define av_uninit(x) x #endif #endif #ifdef __GNUC__ # define av_builtin_constant_p __builtin_constant_p # define av_printf_format(fmtpos, attrpos) __attribute__((__format__(__printf__, fmtpos, attrpos))) #else # define av_builtin_constant_p(x) 0 # define av_printf_format(fmtpos, attrpos) #endif #endif /* AVUTIL_ATTRIBUTES_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/audioconvert.h000066400000000000000000000102171317340345000220500ustar00rootroot00000000000000/* * Copyright (c) 2006 Michael Niedermayer * Copyright (c) 2008 Peter Ross * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_AUDIOCONVERT_H #define AVUTIL_AUDIOCONVERT_H #include /** * @file * audio conversion routines */ /* Audio channel masks */ #define AV_CH_FRONT_LEFT 0x00000001 #define AV_CH_FRONT_RIGHT 0x00000002 #define AV_CH_FRONT_CENTER 0x00000004 #define AV_CH_LOW_FREQUENCY 0x00000008 #define AV_CH_BACK_LEFT 0x00000010 #define AV_CH_BACK_RIGHT 0x00000020 #define AV_CH_FRONT_LEFT_OF_CENTER 0x00000040 #define AV_CH_FRONT_RIGHT_OF_CENTER 0x00000080 #define AV_CH_BACK_CENTER 0x00000100 #define AV_CH_SIDE_LEFT 0x00000200 #define AV_CH_SIDE_RIGHT 0x00000400 #define AV_CH_TOP_CENTER 0x00000800 #define AV_CH_TOP_FRONT_LEFT 0x00001000 #define AV_CH_TOP_FRONT_CENTER 0x00002000 #define AV_CH_TOP_FRONT_RIGHT 0x00004000 #define AV_CH_TOP_BACK_LEFT 0x00008000 #define AV_CH_TOP_BACK_CENTER 0x00010000 #define AV_CH_TOP_BACK_RIGHT 0x00020000 #define AV_CH_STEREO_LEFT 0x20000000 ///< Stereo downmix. #define AV_CH_STEREO_RIGHT 0x40000000 ///< See AV_CH_STEREO_LEFT. /** Channel mask value used for AVCodecContext.request_channel_layout to indicate that the user requests the channel order of the decoder output to be the native codec channel order. */ #define AV_CH_LAYOUT_NATIVE 0x8000000000000000LL /* Audio channel convenience macros */ #define AV_CH_LAYOUT_MONO (AV_CH_FRONT_CENTER) #define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT) #define AV_CH_LAYOUT_2_1 (AV_CH_LAYOUT_STEREO|AV_CH_BACK_CENTER) #define AV_CH_LAYOUT_SURROUND (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER) #define AV_CH_LAYOUT_4POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_CENTER) #define AV_CH_LAYOUT_2_2 (AV_CH_LAYOUT_STEREO|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT) #define AV_CH_LAYOUT_QUAD (AV_CH_LAYOUT_STEREO|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) #define AV_CH_LAYOUT_5POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT) #define AV_CH_LAYOUT_5POINT1 (AV_CH_LAYOUT_5POINT0|AV_CH_LOW_FREQUENCY) #define AV_CH_LAYOUT_5POINT0_BACK (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) #define AV_CH_LAYOUT_5POINT1_BACK (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_LOW_FREQUENCY) #define AV_CH_LAYOUT_7POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) #define AV_CH_LAYOUT_7POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) #define AV_CH_LAYOUT_7POINT1_WIDE (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) #define AV_CH_LAYOUT_STEREO_DOWNMIX (AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT) /** * Return a channel layout id that matches name, 0 if no match. */ int64_t av_get_channel_layout(const char *name); /** * Return a description of a channel layout. * If nb_channels is <= 0, it is guessed from the channel_layout. * * @param buf put here the string containing the channel layout * @param buf_size size in bytes of the buffer */ void av_get_channel_layout_string(char *buf, int buf_size, int nb_channels, int64_t channel_layout); /** * Return the number of channels in the channel layout. */ int av_get_channel_layout_nb_channels(int64_t channel_layout); #endif /* AVUTIL_AUDIOCONVERT_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/avassert.h000066400000000000000000000040601317340345000211750ustar00rootroot00000000000000/* * copyright (c) 2010 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * simple assert() macros that are a bit more flexible than ISO C assert(). * @author Michael Niedermayer */ #ifndef AVUTIL_AVASSERT_H #define AVUTIL_AVASSERT_H #include #include "avutil.h" #include "log.h" /** * assert() equivalent, that is always enabled. */ #define av_assert0(cond) do { \ if (!(cond)) { \ av_log(NULL, AV_LOG_FATAL, "Assertion %s failed at %s:%d\n", \ AV_STRINGIFY(cond), __FILE__, __LINE__); \ abort(); \ } \ } while (0) /** * assert() equivalent, that does not lie in speed critical code. * These asserts() thus can be enabled without fearing speedloss. */ #if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 0 #define av_assert1(cond) av_assert0(cond) #else #define av_assert1(cond) ((void)0) #endif /** * assert() equivalent, that does lie in speed critical code. */ #if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1 #define av_assert2(cond) av_assert0(cond) #else #define av_assert2(cond) ((void)0) #endif #endif /* AVUTIL_AVASSERT_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/avconfig.h000066400000000000000000000002521317340345000211400ustar00rootroot00000000000000/* Generated by ffconf */ #ifndef AVUTIL_AVCONFIG_H #define AVUTIL_AVCONFIG_H #define AV_HAVE_BIGENDIAN 0 #define AV_HAVE_FAST_UNALIGNED 1 #endif /* AVUTIL_AVCONFIG_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/avstring.h000066400000000000000000000117611317340345000212100ustar00rootroot00000000000000/* * Copyright (c) 2007 Mans Rullgard * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_AVSTRING_H #define AVUTIL_AVSTRING_H #include #include "attributes.h" /** * Return non-zero if pfx is a prefix of str. If it is, *ptr is set to * the address of the first character in str after the prefix. * * @param str input string * @param pfx prefix to test * @param ptr updated if the prefix is matched inside str * @return non-zero if the prefix matches, zero otherwise */ int av_strstart(const char *str, const char *pfx, const char **ptr); /** * Return non-zero if pfx is a prefix of str independent of case. If * it is, *ptr is set to the address of the first character in str * after the prefix. * * @param str input string * @param pfx prefix to test * @param ptr updated if the prefix is matched inside str * @return non-zero if the prefix matches, zero otherwise */ int av_stristart(const char *str, const char *pfx, const char **ptr); /** * Locate the first case-independent occurrence in the string haystack * of the string needle. A zero-length string needle is considered to * match at the start of haystack. * * This function is a case-insensitive version of the standard strstr(). * * @param haystack string to search in * @param needle string to search for * @return pointer to the located match within haystack * or a null pointer if no match */ char *av_stristr(const char *haystack, const char *needle); /** * Copy the string src to dst, but no more than size - 1 bytes, and * null-terminate dst. * * This function is the same as BSD strlcpy(). * * @param dst destination buffer * @param src source string * @param size size of destination buffer * @return the length of src * * WARNING: since the return value is the length of src, src absolutely * _must_ be a properly 0-terminated string, otherwise this will read beyond * the end of the buffer and possibly crash. */ size_t av_strlcpy(char *dst, const char *src, size_t size); /** * Append the string src to the string dst, but to a total length of * no more than size - 1 bytes, and null-terminate dst. * * This function is similar to BSD strlcat(), but differs when * size <= strlen(dst). * * @param dst destination buffer * @param src source string * @param size size of destination buffer * @return the total length of src and dst * * WARNING: since the return value use the length of src and dst, these absolutely * _must_ be a properly 0-terminated strings, otherwise this will read beyond * the end of the buffer and possibly crash. */ size_t av_strlcat(char *dst, const char *src, size_t size); /** * Append output to a string, according to a format. Never write out of * the destination buffer, and always put a terminating 0 within * the buffer. * @param dst destination buffer (string to which the output is * appended) * @param size total size of the destination buffer * @param fmt printf-compatible format string, specifying how the * following parameters are used * @return the length of the string that would have been generated * if enough space had been available */ size_t av_strlcatf(char *dst, size_t size, const char *fmt, ...) av_printf_format(3, 4); /** * Print arguments following specified format into a large enough auto * allocated buffer. It is similar to GNU asprintf(). * @param fmt printf-compatible format string, specifying how the * following parameters are used. * @return the allocated string * @note You have to free the string yourself with av_free(). */ char *av_asprintf(const char *fmt, ...) av_printf_format(1, 2); /** * Convert a number to a av_malloced string. */ char *av_d2str(double d); /** * Unescape the given string until a non escaped terminating char, * and return the token corresponding to the unescaped string. * * The normal \ and ' escaping is supported. Leading and trailing * whitespaces are removed, unless they are escaped with '\' or are * enclosed between ''. * * @param buf the buffer to parse, buf will be updated to point to the * terminating char * @param term a 0-terminated list of terminating chars * @return the malloced unescaped string, which must be av_freed by * the user, NULL in case of allocation failure */ char *av_get_token(const char **buf, const char *term); #endif /* AVUTIL_AVSTRING_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/avutil.h000066400000000000000000000105051317340345000206520ustar00rootroot00000000000000/* * copyright (c) 2006 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_AVUTIL_H #define AVUTIL_AVUTIL_H /** * @file * external API header */ #define AV_STRINGIFY(s) AV_TOSTRING(s) #define AV_TOSTRING(s) #s #define AV_GLUE(a, b) a ## b #define AV_JOIN(a, b) AV_GLUE(a, b) #define AV_PRAGMA(s) _Pragma(#s) #define AV_VERSION_INT(a, b, c) (a<<16 | b<<8 | c) #define AV_VERSION_DOT(a, b, c) a ##.## b ##.## c #define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c) #define LIBAVUTIL_VERSION_MAJOR 51 #define LIBAVUTIL_VERSION_MINOR 16 #define LIBAVUTIL_VERSION_MICRO 1 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ LIBAVUTIL_VERSION_MINOR, \ LIBAVUTIL_VERSION_MICRO) #define LIBAVUTIL_VERSION AV_VERSION(LIBAVUTIL_VERSION_MAJOR, \ LIBAVUTIL_VERSION_MINOR, \ LIBAVUTIL_VERSION_MICRO) #define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT #define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION) /** * Those FF_API_* defines are not part of public API. * They may change, break or disappear at any time. */ #ifndef FF_API_OLD_EVAL_NAMES #define FF_API_OLD_EVAL_NAMES (LIBAVUTIL_VERSION_MAJOR < 52) #endif #ifndef FF_API_GET_BITS_PER_SAMPLE_FMT #define FF_API_GET_BITS_PER_SAMPLE_FMT (LIBAVUTIL_VERSION_MAJOR < 52) #endif #ifndef FF_API_FIND_OPT #define FF_API_FIND_OPT (LIBAVUTIL_VERSION_MAJOR < 52) #endif #ifndef FF_API_AV_FIFO_PEEK #define FF_API_AV_FIFO_PEEK (LIBAVUTIL_VERSION_MAJOR < 52) #endif #ifndef FF_API_OLD_AVOPTIONS #define FF_API_OLD_AVOPTIONS (LIBAVUTIL_VERSION_MAJOR < 52) #endif /** * Return the LIBAVUTIL_VERSION_INT constant. */ unsigned avutil_version(void); /** * Return the libavutil build-time configuration. */ const char *avutil_configuration(void); /** * Return the libavutil license. */ const char *avutil_license(void); enum AVMediaType { AVMEDIA_TYPE_UNKNOWN = -1, AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_DATA, AVMEDIA_TYPE_SUBTITLE, AVMEDIA_TYPE_ATTACHMENT, AVMEDIA_TYPE_NB }; /** * Return a string describing the media_type enum, NULL if media_type * is unknown. */ const char *av_get_media_type_string(enum AVMediaType media_type); #define FF_LAMBDA_SHIFT 7 #define FF_LAMBDA_SCALE (1< /** * Decode a base64-encoded string. * * @param out buffer for decoded data * @param in null-terminated input string * @param out_size size in bytes of the out buffer, must be at * least 3/4 of the length of in * @return number of bytes written, or a negative value in case of * invalid input */ int av_base64_decode(uint8_t *out, const char *in, int out_size); /** * Encode data to base64 and null-terminate. * * @param out buffer for encoded data * @param out_size size in bytes of the output buffer, must be at * least AV_BASE64_SIZE(in_size) * @param in_size size in bytes of the 'in' buffer * @return 'out' or NULL in case of error */ char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size); /** * Calculate the output size needed to base64-encode x bytes. */ #define AV_BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1) #endif /* AVUTIL_BASE64_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/bswap.h000066400000000000000000000061761317340345000204730ustar00rootroot00000000000000/* * copyright (c) 2006 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * byte swapping routines */ #ifndef AVUTIL_BSWAP_H #define AVUTIL_BSWAP_H #include #include "libavutil/avconfig.h" #include "attributes.h" #ifdef HAVE_AV_CONFIG_H #include "config.h" #if ARCH_ARM # include "arm/bswap.h" #elif ARCH_AVR32 # include "avr32/bswap.h" #elif ARCH_BFIN # include "bfin/bswap.h" #elif ARCH_SH4 # include "sh4/bswap.h" #elif ARCH_X86 # include "x86/bswap.h" #endif #endif /* HAVE_AV_CONFIG_H */ #define AV_BSWAP16C(x) (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff)) #define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16)) #define AV_BSWAP64C(x) (AV_BSWAP32C(x) << 32 | AV_BSWAP32C((x) >> 32)) #define AV_BSWAPC(s, x) AV_BSWAP##s##C(x) #ifndef av_bswap16 static av_always_inline av_const uint16_t av_bswap16(uint16_t x) { x= (x>>8) | (x<<8); return x; } #endif #ifndef av_bswap32 static av_always_inline av_const uint32_t av_bswap32(uint32_t x) { x= ((x<<8)&0xFF00FF00) | ((x>>8)&0x00FF00FF); x= (x>>16) | (x<<16); return x; } #endif #ifndef av_bswap64 static inline uint64_t av_const av_bswap64(uint64_t x) { #if 0 x= ((x<< 8)&0xFF00FF00FF00FF00ULL) | ((x>> 8)&0x00FF00FF00FF00FFULL); x= ((x<<16)&0xFFFF0000FFFF0000ULL) | ((x>>16)&0x0000FFFF0000FFFFULL); return (x>>32) | (x<<32); #else union { uint64_t ll; uint32_t l[2]; } w, r; w.ll = x; r.l[0] = av_bswap32 (w.l[1]); r.l[1] = av_bswap32 (w.l[0]); return r.ll; #endif } #endif // be2ne ... big-endian to native-endian // le2ne ... little-endian to native-endian #if AV_HAVE_BIGENDIAN #define av_be2ne16(x) (x) #define av_be2ne32(x) (x) #define av_be2ne64(x) (x) #define av_le2ne16(x) av_bswap16(x) #define av_le2ne32(x) av_bswap32(x) #define av_le2ne64(x) av_bswap64(x) #define AV_BE2NEC(s, x) (x) #define AV_LE2NEC(s, x) AV_BSWAPC(s, x) #else #define av_be2ne16(x) av_bswap16(x) #define av_be2ne32(x) av_bswap32(x) #define av_be2ne64(x) av_bswap64(x) #define av_le2ne16(x) (x) #define av_le2ne32(x) (x) #define av_le2ne64(x) (x) #define AV_BE2NEC(s, x) AV_BSWAPC(s, x) #define AV_LE2NEC(s, x) (x) #endif #define AV_BE2NE16C(x) AV_BE2NEC(16, x) #define AV_BE2NE32C(x) AV_BE2NEC(32, x) #define AV_BE2NE64C(x) AV_BE2NEC(64, x) #define AV_LE2NE16C(x) AV_LE2NEC(16, x) #define AV_LE2NE32C(x) AV_LE2NEC(32, x) #define AV_LE2NE64C(x) AV_LE2NEC(64, x) #endif /* AVUTIL_BSWAP_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/common.h000066400000000000000000000256341317340345000206470ustar00rootroot00000000000000/* * copyright (c) 2006 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * common internal and external API header */ #ifndef AVUTIL_COMMON_H #define AVUTIL_COMMON_H #include #include #include #include #include #include #include #include #include "attributes.h" #include "libavutil/avconfig.h" #if AV_HAVE_BIGENDIAN # define AV_NE(be, le) (be) #else # define AV_NE(be, le) (le) #endif //rounded division & shift #define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b)) /* assume b>0 */ #define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) #define FFUDIV(a,b) (((a)>0 ?(a):(a)-(b)+1) / (b)) #define FFUMOD(a,b) ((a)-(b)*FFUDIV(a,b)) #define FFABS(a) ((a) >= 0 ? (a) : (-(a))) #define FFSIGN(a) ((a) > 0 ? 1 : -1) #define FFMAX(a,b) ((a) > (b) ? (a) : (b)) #define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c) #define FFMIN(a,b) ((a) > (b) ? (b) : (a)) #define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c) #define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0) #define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) #define FFALIGN(x, a) (((x)+(a)-1)&~((a)-1)) /* misc math functions */ extern const uint8_t ff_log2_tab[256]; extern const uint8_t av_reverse[256]; static av_always_inline av_const int av_log2_c(unsigned int v) { int n = 0; if (v & 0xffff0000) { v >>= 16; n += 16; } if (v & 0xff00) { v >>= 8; n += 8; } n += ff_log2_tab[v]; return n; } static av_always_inline av_const int av_log2_16bit_c(unsigned int v) { int n = 0; if (v & 0xff00) { v >>= 8; n += 8; } n += ff_log2_tab[v]; return n; } #ifdef HAVE_AV_CONFIG_H # include "config.h" # include "intmath.h" #endif /* Pull in unguarded fallback defines at the end of this file. */ #include "common.h" /** * Clip a signed integer value into the amin-amax range. * @param a value to clip * @param amin minimum value of the clip range * @param amax maximum value of the clip range * @return clipped value */ static av_always_inline av_const int av_clip_c(int a, int amin, int amax) { if (a < amin) return amin; else if (a > amax) return amax; else return a; } /** * Clip a signed integer value into the 0-255 range. * @param a value to clip * @return clipped value */ static av_always_inline av_const uint8_t av_clip_uint8_c(int a) { if (a&(~0xFF)) return (-a)>>31; else return a; } /** * Clip a signed integer value into the -128,127 range. * @param a value to clip * @return clipped value */ static av_always_inline av_const int8_t av_clip_int8_c(int a) { if ((a+0x80) & ~0xFF) return (a>>31) ^ 0x7F; else return a; } /** * Clip a signed integer value into the 0-65535 range. * @param a value to clip * @return clipped value */ static av_always_inline av_const uint16_t av_clip_uint16_c(int a) { if (a&(~0xFFFF)) return (-a)>>31; else return a; } /** * Clip a signed integer value into the -32768,32767 range. * @param a value to clip * @return clipped value */ static av_always_inline av_const int16_t av_clip_int16_c(int a) { if ((a+0x8000) & ~0xFFFF) return (a>>31) ^ 0x7FFF; else return a; } /** * Clip a signed 64-bit integer value into the -2147483648,2147483647 range. * @param a value to clip * @return clipped value */ static av_always_inline av_const int32_t av_clipl_int32_c(int64_t a) { if ((a+0x80000000u) & ~UINT64_C(0xFFFFFFFF)) return (a>>63) ^ 0x7FFFFFFF; else return a; } /** * Clip a signed integer to an unsigned power of two range. * @param a value to clip * @param p bit position to clip at * @return clipped value */ static av_always_inline av_const unsigned av_clip_uintp2_c(int a, int p) { if (a & ~((1<> 31 & ((1< amax) return amax; else return a; } /** Compute ceil(log2(x)). * @param x value used to compute ceil(log2(x)) * @return computed ceiling of log2(x) */ static av_always_inline av_const int av_ceil_log2_c(int x) { return av_log2((x - 1) << 1); } /** * Count number of bits set to one in x * @param x value to count bits of * @return the number of bits set to one in x */ static av_always_inline av_const int av_popcount_c(uint32_t x) { x -= (x >> 1) & 0x55555555; x = (x & 0x33333333) + ((x >> 2) & 0x33333333); x = (x + (x >> 4)) & 0x0F0F0F0F; x += x >> 8; return (x + (x >> 16)) & 0x3F; } #define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) #define MKBETAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((a) << 24)) /** * Convert a UTF-8 character (up to 4 bytes) to its 32-bit UCS-4 encoded form. * * @param val Output value, must be an lvalue of type uint32_t. * @param GET_BYTE Expression reading one byte from the input. * Evaluated up to 7 times (4 for the currently * assigned Unicode range). With a memory buffer * input, this could be *ptr++. * @param ERROR Expression to be evaluated on invalid input, * typically a goto statement. */ #define GET_UTF8(val, GET_BYTE, ERROR)\ val= GET_BYTE;\ {\ int ones= 7 - av_log2(val ^ 255);\ if(ones==1)\ ERROR\ val&= 127>>ones;\ while(--ones > 0){\ int tmp= GET_BYTE - 128;\ if(tmp>>6)\ ERROR\ val= (val<<6) + tmp;\ }\ } /** * Convert a UTF-16 character (2 or 4 bytes) to its 32-bit UCS-4 encoded form. * * @param val Output value, must be an lvalue of type uint32_t. * @param GET_16BIT Expression returning two bytes of UTF-16 data converted * to native byte order. Evaluated one or two times. * @param ERROR Expression to be evaluated on invalid input, * typically a goto statement. */ #define GET_UTF16(val, GET_16BIT, ERROR)\ val = GET_16BIT;\ {\ unsigned int hi = val - 0xD800;\ if (hi < 0x800) {\ val = GET_16BIT - 0xDC00;\ if (val > 0x3FFU || hi > 0x3FFU)\ ERROR\ val += (hi<<10) + 0x10000;\ }\ }\ /** * @def PUT_UTF8(val, tmp, PUT_BYTE) * Convert a 32-bit Unicode character to its UTF-8 encoded form (up to 4 bytes long). * @param val is an input-only argument and should be of type uint32_t. It holds * a UCS-4 encoded Unicode character that is to be converted to UTF-8. If * val is given as a function it is executed only once. * @param tmp is a temporary variable and should be of type uint8_t. It * represents an intermediate value during conversion that is to be * output by PUT_BYTE. * @param PUT_BYTE writes the converted UTF-8 bytes to any proper destination. * It could be a function or a statement, and uses tmp as the input byte. * For example, PUT_BYTE could be "*output++ = tmp;" PUT_BYTE will be * executed up to 4 times for values in the valid UTF-8 range and up to * 7 times in the general case, depending on the length of the converted * Unicode character. */ #define PUT_UTF8(val, tmp, PUT_BYTE)\ {\ int bytes, shift;\ uint32_t in = val;\ if (in < 0x80) {\ tmp = in;\ PUT_BYTE\ } else {\ bytes = (av_log2(in) + 4) / 5;\ shift = (bytes - 1) * 6;\ tmp = (256 - (256 >> bytes)) | (in >> shift);\ PUT_BYTE\ while (shift >= 6) {\ shift -= 6;\ tmp = 0x80 | ((in >> shift) & 0x3f);\ PUT_BYTE\ }\ }\ } /** * @def PUT_UTF16(val, tmp, PUT_16BIT) * Convert a 32-bit Unicode character to its UTF-16 encoded form (2 or 4 bytes). * @param val is an input-only argument and should be of type uint32_t. It holds * a UCS-4 encoded Unicode character that is to be converted to UTF-16. If * val is given as a function it is executed only once. * @param tmp is a temporary variable and should be of type uint16_t. It * represents an intermediate value during conversion that is to be * output by PUT_16BIT. * @param PUT_16BIT writes the converted UTF-16 data to any proper destination * in desired endianness. It could be a function or a statement, and uses tmp * as the input byte. For example, PUT_BYTE could be "*output++ = tmp;" * PUT_BYTE will be executed 1 or 2 times depending on input character. */ #define PUT_UTF16(val, tmp, PUT_16BIT)\ {\ uint32_t in = val;\ if (in < 0x10000) {\ tmp = in;\ PUT_16BIT\ } else {\ tmp = 0xD800 | ((in - 0x10000) >> 10);\ PUT_16BIT\ tmp = 0xDC00 | ((in - 0x10000) & 0x3FF);\ PUT_16BIT\ }\ }\ #include "mem.h" #ifdef HAVE_AV_CONFIG_H # include "internal.h" #endif /* HAVE_AV_CONFIG_H */ #endif /* AVUTIL_COMMON_H */ /* * The following definitions are outside the multiple inclusion guard * to ensure they are immediately available in intmath.h. */ #ifndef av_log2 # define av_log2 av_log2_c #endif #ifndef av_log2_16bit # define av_log2_16bit av_log2_16bit_c #endif #ifndef av_ceil_log2 # define av_ceil_log2 av_ceil_log2_c #endif #ifndef av_clip # define av_clip av_clip_c #endif #ifndef av_clip_uint8 # define av_clip_uint8 av_clip_uint8_c #endif #ifndef av_clip_int8 # define av_clip_int8 av_clip_int8_c #endif #ifndef av_clip_uint16 # define av_clip_uint16 av_clip_uint16_c #endif #ifndef av_clip_int16 # define av_clip_int16 av_clip_int16_c #endif #ifndef av_clipl_int32 # define av_clipl_int32 av_clipl_int32_c #endif #ifndef av_clip_uintp2 # define av_clip_uintp2 av_clip_uintp2_c #endif #ifndef av_clipf # define av_clipf av_clipf_c #endif #ifndef av_popcount # define av_popcount av_popcount_c #endif IanniX-0.9.20/gui/qffmpeg/libavutil/cpu.h000066400000000000000000000047211317340345000201400ustar00rootroot00000000000000/* * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_CPU_H #define AVUTIL_CPU_H #define AV_CPU_FLAG_FORCE 0x80000000 /* force usage of selected flags (OR) */ /* lower 16 bits - CPU features */ #define AV_CPU_FLAG_MMX 0x0001 ///< standard MMX #define AV_CPU_FLAG_MMX2 0x0002 ///< SSE integer functions or AMD MMX ext #define AV_CPU_FLAG_3DNOW 0x0004 ///< AMD 3DNOW #define AV_CPU_FLAG_SSE 0x0008 ///< SSE functions #define AV_CPU_FLAG_SSE2 0x0010 ///< PIV SSE2 functions #define AV_CPU_FLAG_SSE2SLOW 0x40000000 ///< SSE2 supported, but usually not faster #define AV_CPU_FLAG_3DNOWEXT 0x0020 ///< AMD 3DNowExt #define AV_CPU_FLAG_SSE3 0x0040 ///< Prescott SSE3 functions #define AV_CPU_FLAG_SSE3SLOW 0x20000000 ///< SSE3 supported, but usually not faster #define AV_CPU_FLAG_SSSE3 0x0080 ///< Conroe SSSE3 functions #define AV_CPU_FLAG_ATOM 0x10000000 ///< Atom processor, some SSSE3 instructions are slower #define AV_CPU_FLAG_SSE4 0x0100 ///< Penryn SSE4.1 functions #define AV_CPU_FLAG_SSE42 0x0200 ///< Nehalem SSE4.2 functions #define AV_CPU_FLAG_AVX 0x4000 ///< AVX functions: requires OS support even if YMM registers aren't used #define AV_CPU_FLAG_IWMMXT 0x0100 ///< XScale IWMMXT #define AV_CPU_FLAG_ALTIVEC 0x0001 ///< standard /** * Return the flags which specify extensions supported by the CPU. */ int av_get_cpu_flags(void); /** * Disables cpu detection and forces the specified flags. */ void av_force_cpu_flags(int flags); /* The following CPU-specific functions shall not be called directly. */ int ff_get_cpu_flags_arm(void); int ff_get_cpu_flags_ppc(void); int ff_get_cpu_flags_x86(void); #endif /* AVUTIL_CPU_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/crc.h000066400000000000000000000026651317340345000201250ustar00rootroot00000000000000/* * copyright (c) 2006 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_CRC_H #define AVUTIL_CRC_H #include #include #include "attributes.h" typedef uint32_t AVCRC; typedef enum { AV_CRC_8_ATM, AV_CRC_16_ANSI, AV_CRC_16_CCITT, AV_CRC_32_IEEE, AV_CRC_32_IEEE_LE, /*< reversed bitorder version of AV_CRC_32_IEEE */ AV_CRC_MAX, /*< Not part of public API! Do not use outside libavutil. */ }AVCRCId; int av_crc_init(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size); const AVCRC *av_crc_get_table(AVCRCId crc_id); uint32_t av_crc(const AVCRC *ctx, uint32_t start_crc, const uint8_t *buffer, size_t length) av_pure; #endif /* AVUTIL_CRC_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/dict.h000066400000000000000000000111171317340345000202710ustar00rootroot00000000000000/* * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * Public dictionary API. * @deprecated * AVDictionary is provided for compatibility with libav. It is both in * implementation as well as API inefficient. It does not scale and is * extremely slow with large dictionaries. * It is recommended that new code uses our tree container from tree.c/h * where applicable, which uses AVL trees to achieve O(log n) performance. */ #ifndef AVUTIL_DICT_H #define AVUTIL_DICT_H /** * @defgroup dict_api Public Dictionary API * @{ * Dictionaries are used for storing key:value pairs. To create * an AVDictionary, simply pass an address of a NULL pointer to * av_dict_set(). NULL can be used as an empty dictionary wherever * a pointer to an AVDictionary is required. * Use av_dict_get() to retrieve an entry or iterate over all * entries and finally av_dict_free() to free the dictionary * and all its contents. * * @code * AVDictionary *d = NULL; // "create" an empty dictionary * av_dict_set(&d, "foo", "bar", 0); // add an entry * * char *k = av_strdup("key"); // if your strings are already allocated, * char *v = av_strdup("value"); // you can avoid copying them like this * av_dict_set(&d, k, v, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); * * AVDictionaryEntry *t = NULL; * while (t = av_dict_get(d, "", t, AV_DICT_IGNORE_SUFFIX)) { * <....> // iterate over all entries in d * } * * av_dict_free(&d); * @endcode * * @} */ #define AV_DICT_MATCH_CASE 1 #define AV_DICT_IGNORE_SUFFIX 2 #define AV_DICT_DONT_STRDUP_KEY 4 /**< Take ownership of a key that's been allocated with av_malloc() and children. */ #define AV_DICT_DONT_STRDUP_VAL 8 /**< Take ownership of a value that's been allocated with av_malloc() and chilren. */ #define AV_DICT_DONT_OVERWRITE 16 ///< Don't overwrite existing entries. #define AV_DICT_APPEND 32 /**< If the entry already exists, append to it. Note that no delimiter is added, the strings are simply concatenated. */ typedef struct { char *key; char *value; } AVDictionaryEntry; typedef struct AVDictionary AVDictionary; /** * Get a dictionary entry with matching key. * * @param prev Set to the previous matching element to find the next. * If set to NULL the first matching element is returned. * @param flags Allows case as well as suffix-insensitive comparisons. * @return Found entry or NULL, changing key or value leads to undefined behavior. */ AVDictionaryEntry * av_dict_get(AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags); /** * Set the given entry in *pm, overwriting an existing entry. * * @param pm pointer to a pointer to a dictionary struct. If *pm is NULL * a dictionary struct is allocated and put in *pm. * @param key entry key to add to *pm (will be av_strduped depending on flags) * @param value entry value to add to *pm (will be av_strduped depending on flags). * Passing a NULL value will cause an existing tag to be deleted. * @return >= 0 on success otherwise an error code <0 */ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags); /** * Copy entries from one AVDictionary struct into another. * @param dst pointer to a pointer to a AVDictionary struct. If *dst is NULL, * this function will allocate a struct for you and put it in *dst * @param src pointer to source AVDictionary struct * @param flags flags to use when setting entries in *dst * @note metadata is read using the AV_DICT_IGNORE_SUFFIX flag */ void av_dict_copy(AVDictionary **dst, AVDictionary *src, int flags); /** * Free all the memory allocated for an AVDictionary struct * and all keys and values. */ void av_dict_free(AVDictionary **m); #endif // AVUTIL_DICT_H IanniX-0.9.20/gui/qffmpeg/libavutil/error.h000066400000000000000000000060031317340345000204750ustar00rootroot00000000000000/* * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * error code definitions */ #ifndef AVUTIL_ERROR_H #define AVUTIL_ERROR_H #include #include "avutil.h" /* error handling */ #if EDOM > 0 #define AVERROR(e) (-(e)) ///< Returns a negative error code from a POSIX error code, to return from library functions. #define AVUNERROR(e) (-(e)) ///< Returns a POSIX error code from a library function error return value. #else /* Some platforms have E* and errno already negated. */ #define AVERROR(e) (e) #define AVUNERROR(e) (e) #endif #define AVERROR_BSF_NOT_FOUND (-MKTAG(0xF8,'B','S','F')) ///< Bitstream filter not found #define AVERROR_DECODER_NOT_FOUND (-MKTAG(0xF8,'D','E','C')) ///< Decoder not found #define AVERROR_DEMUXER_NOT_FOUND (-MKTAG(0xF8,'D','E','M')) ///< Demuxer not found #define AVERROR_ENCODER_NOT_FOUND (-MKTAG(0xF8,'E','N','C')) ///< Encoder not found #define AVERROR_EOF (-MKTAG( 'E','O','F',' ')) ///< End of file #define AVERROR_EXIT (-MKTAG( 'E','X','I','T')) ///< Immediate exit was requested; the called function should not be restarted #define AVERROR_FILTER_NOT_FOUND (-MKTAG(0xF8,'F','I','L')) ///< Filter not found #define AVERROR_INVALIDDATA (-MKTAG( 'I','N','D','A')) ///< Invalid data found when processing input #define AVERROR_MUXER_NOT_FOUND (-MKTAG(0xF8,'M','U','X')) ///< Muxer not found #define AVERROR_OPTION_NOT_FOUND (-MKTAG(0xF8,'O','P','T')) ///< Option not found #define AVERROR_PATCHWELCOME (-MKTAG( 'P','A','W','E')) ///< Not yet implemented in FFmpeg, patches welcome #define AVERROR_PROTOCOL_NOT_FOUND (-MKTAG(0xF8,'P','R','O')) ///< Protocol not found #define AVERROR_STREAM_NOT_FOUND (-MKTAG(0xF8,'S','T','R')) ///< Stream not found /** * Put a description of the AVERROR code errnum in errbuf. * In case of failure the global variable errno is set to indicate the * error. Even in case of failure av_strerror() will print a generic * error message indicating the errnum provided to errbuf. * * @param errnum error code to describe * @param errbuf buffer to which description is written * @param errbuf_size the size in bytes of errbuf * @return 0 on success, a negative value if a description for errnum * cannot be found */ int av_strerror(int errnum, char *errbuf, size_t errbuf_size); #endif /* AVUTIL_ERROR_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/eval.h000066400000000000000000000146431317340345000203040ustar00rootroot00000000000000/* * Copyright (c) 2002 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * simple arithmetic expression evaluator */ #ifndef AVUTIL_EVAL_H #define AVUTIL_EVAL_H #include "avutil.h" typedef struct AVExpr AVExpr; /** * Parse and evaluate an expression. * Note, this is significantly slower than av_expr_eval(). * * @param res a pointer to a double where is put the result value of * the expression, or NAN in case of error * @param s expression as a zero terminated string, for example "1+2^3+5*5+sin(2/3)" * @param const_names NULL terminated array of zero terminated strings of constant identifiers, for example {"PI", "E", 0} * @param const_values a zero terminated array of values for the identifiers from const_names * @param func1_names NULL terminated array of zero terminated strings of funcs1 identifiers * @param funcs1 NULL terminated array of function pointers for functions which take 1 argument * @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers * @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 * @param log_ctx parent logging context * @return 0 in case of success, a negative value corresponding to an * AVERROR code otherwise */ int av_expr_parse_and_eval(double *res, const char *s, const char * const *const_names, const double *const_values, const char * const *func1_names, double (* const *funcs1)(void *, double), const char * const *func2_names, double (* const *funcs2)(void *, double, double), void *opaque, int log_offset, void *log_ctx); /** * Parse an expression. * * @param expr a pointer where is put an AVExpr containing the parsed * value in case of successfull parsing, or NULL otherwise. * The pointed to AVExpr must be freed with av_expr_free() by the user * when it is not needed anymore. * @param s expression as a zero terminated string, for example "1+2^3+5*5+sin(2/3)" * @param const_names NULL terminated array of zero terminated strings of constant identifiers, for example {"PI", "E", 0} * @param func1_names NULL terminated array of zero terminated strings of funcs1 identifiers * @param funcs1 NULL terminated array of function pointers for functions which take 1 argument * @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers * @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments * @param log_ctx parent logging context * @return 0 in case of success, a negative value corresponding to an * AVERROR code otherwise */ int av_expr_parse(AVExpr **expr, const char *s, const char * const *const_names, const char * const *func1_names, double (* const *funcs1)(void *, double), const char * const *func2_names, double (* const *funcs2)(void *, double, double), int log_offset, void *log_ctx); /** * Evaluate a previously parsed expression. * * @param const_values a zero terminated array of values for the identifiers from av_expr_parse() const_names * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 * @return the value of the expression */ double av_expr_eval(AVExpr *e, const double *const_values, void *opaque); /** * Free a parsed expression previously created with av_expr_parse(). */ void av_expr_free(AVExpr *e); #if FF_API_OLD_EVAL_NAMES /** * @deprecated Deprecated in favor of av_expr_parse_and_eval(). */ attribute_deprecated int av_parse_and_eval_expr(double *res, const char *s, const char * const *const_names, const double *const_values, const char * const *func1_names, double (* const *funcs1)(void *, double), const char * const *func2_names, double (* const *funcs2)(void *, double, double), void *opaque, int log_offset, void *log_ctx); /** * @deprecated Deprecated in favor of av_expr_parse(). */ attribute_deprecated int av_parse_expr(AVExpr **expr, const char *s, const char * const *const_names, const char * const *func1_names, double (* const *funcs1)(void *, double), const char * const *func2_names, double (* const *funcs2)(void *, double, double), int log_offset, void *log_ctx); /** * @deprecated Deprecated in favor of av_expr_eval(). */ attribute_deprecated double av_eval_expr(AVExpr *e, const double *const_values, void *opaque); /** * @deprecated Deprecated in favor of av_expr_free(). */ attribute_deprecated void av_free_expr(AVExpr *e); #endif /* FF_API_OLD_EVAL_NAMES */ /** * Parse the string in numstr and return its value as a double. If * the string is empty, contains only whitespaces, or does not contain * an initial substring that has the expected syntax for a * floating-point number, no conversion is performed. In this case, * returns a value of zero and the value returned in tail is the value * of numstr. * * @param numstr a string representing a number, may contain one of * the International System number postfixes, for example 'K', 'M', * 'G'. If 'i' is appended after the postfix, powers of 2 are used * instead of powers of 10. The 'B' postfix multiplies the value for * 8, and can be appended after another postfix or used alone. This * allows using for example 'KB', 'MiB', 'G' and 'B' as postfix. * @param tail if non-NULL puts here the pointer to the char next * after the last parsed character */ double av_strtod(const char *numstr, char **tail); #endif /* AVUTIL_EVAL_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/fifo.h000066400000000000000000000104621317340345000202730ustar00rootroot00000000000000/* * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * a very simple circular buffer FIFO implementation */ #ifndef AVUTIL_FIFO_H #define AVUTIL_FIFO_H #include #include "avutil.h" typedef struct AVFifoBuffer { uint8_t *buffer; uint8_t *rptr, *wptr, *end; uint32_t rndx, wndx; } AVFifoBuffer; /** * Initialize an AVFifoBuffer. * @param size of FIFO * @return AVFifoBuffer or NULL in case of memory allocation failure */ AVFifoBuffer *av_fifo_alloc(unsigned int size); /** * Free an AVFifoBuffer. * @param f AVFifoBuffer to free */ void av_fifo_free(AVFifoBuffer *f); /** * Reset the AVFifoBuffer to the state right after av_fifo_alloc, in particular it is emptied. * @param f AVFifoBuffer to reset */ void av_fifo_reset(AVFifoBuffer *f); /** * Return the amount of data in bytes in the AVFifoBuffer, that is the * amount of data you can read from it. * @param f AVFifoBuffer to read from * @return size */ int av_fifo_size(AVFifoBuffer *f); /** * Return the amount of space in bytes in the AVFifoBuffer, that is the * amount of data you can write into it. * @param f AVFifoBuffer to write into * @return size */ int av_fifo_space(AVFifoBuffer *f); /** * Feed data from an AVFifoBuffer to a user-supplied callback. * @param f AVFifoBuffer to read from * @param buf_size number of bytes to read * @param func generic read function * @param dest data destination */ int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int)); /** * Feed data from a user-supplied callback to an AVFifoBuffer. * @param f AVFifoBuffer to write to * @param src data source; non-const since it may be used as a * modifiable context by the function defined in func * @param size number of bytes to write * @param func generic write function; the first parameter is src, * the second is dest_buf, the third is dest_buf_size. * func must return the number of bytes written to dest_buf, or <= 0 to * indicate no more data available to write. * If func is NULL, src is interpreted as a simple byte array for source data. * @return the number of bytes written to the FIFO */ int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, int (*func)(void*, void*, int)); /** * Resize an AVFifoBuffer. * In case of reallocation failure, the old FIFO is kept unchanged. * * @param f AVFifoBuffer to resize * @param size new AVFifoBuffer size in bytes * @return <0 for failure, >=0 otherwise */ int av_fifo_realloc2(AVFifoBuffer *f, unsigned int size); /** * Read and discard the specified amount of data from an AVFifoBuffer. * @param f AVFifoBuffer to read from * @param size amount of data to read in bytes */ void av_fifo_drain(AVFifoBuffer *f, int size); /** * Return a pointer to the data stored in a FIFO buffer at a certain offset. * The FIFO buffer is not modified. * * @param f AVFifoBuffer to peek at, f must be non-NULL * @param offs an offset in bytes, its absolute value must be less * than the used buffer size or the returned pointer will * point outside to the buffer data. * The used buffer size can be checked with av_fifo_size(). */ static inline uint8_t *av_fifo_peek2(const AVFifoBuffer *f, int offs) { uint8_t *ptr = f->rptr + offs; if (ptr >= f->end) ptr = f->buffer + (ptr - f->end); else if (ptr < f->buffer) ptr = f->end - (f->buffer - ptr); return ptr; } #if FF_API_AV_FIFO_PEEK /** * @deprecated Use av_fifo_peek2() instead. */ attribute_deprecated static inline uint8_t av_fifo_peek(AVFifoBuffer *f, int offs) { return *av_fifo_peek2(f, offs); } #endif #endif /* AVUTIL_FIFO_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/file.h000066400000000000000000000033451317340345000202710ustar00rootroot00000000000000/* * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_FILE_H #define AVUTIL_FILE_H #include "avutil.h" /** * @file * Misc file utilities. */ /** * Read the file with name filename, and put its content in a newly * allocated buffer or map it with mmap() when available. * In case of success set *bufptr to the read or mmapped buffer, and * *size to the size in bytes of the buffer in *bufptr. * The returned buffer must be released with av_file_unmap(). * * @param log_offset loglevel offset used for logging * @param log_ctx context used for logging * @return a non negative number in case of success, a negative value * corresponding to an AVERROR error code in case of failure */ int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, int log_offset, void *log_ctx); /** * Unmap or free the buffer bufptr created by av_file_map(). * * @param size size in bytes of bufptr, must be the same as returned * by av_file_map() */ void av_file_unmap(uint8_t *bufptr, size_t size); #endif /* AVUTIL_FILE_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/imgutils.h000066400000000000000000000114241317340345000212040ustar00rootroot00000000000000/* * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_IMGUTILS_H #define AVUTIL_IMGUTILS_H /** * @file * misc image utilities */ #include "avutil.h" #include "pixdesc.h" /** * Compute the max pixel step for each plane of an image with a * format described by pixdesc. * * The pixel step is the distance in bytes between the first byte of * the group of bytes which describe a pixel component and the first * byte of the successive group in the same plane for the same * component. * * @param max_pixsteps an array which is filled with the max pixel step * for each plane. Since a plane may contain different pixel * components, the computed max_pixsteps[plane] is relative to the * component in the plane with the max pixel step. * @param max_pixstep_comps an array which is filled with the component * for each plane which has the max pixel step. May be NULL. */ void av_image_fill_max_pixsteps(int max_pixsteps[4], int max_pixstep_comps[4], const AVPixFmtDescriptor *pixdesc); /** * Compute the size of an image line with format pix_fmt and width * width for the plane plane. * * @return the computed size in bytes */ int av_image_get_linesize(enum PixelFormat pix_fmt, int width, int plane); /** * Fill plane linesizes for an image with pixel format pix_fmt and * width width. * * @param linesizes array to be filled with the linesize for each plane * @return >= 0 in case of success, a negative error code otherwise */ int av_image_fill_linesizes(int linesizes[4], enum PixelFormat pix_fmt, int width); /** * Fill plane data pointers for an image with pixel format pix_fmt and * height height. * * @param data pointers array to be filled with the pointer for each image plane * @param ptr the pointer to a buffer which will contain the image * @param linesizes the array containing the linesize for each * plane, should be filled by av_image_fill_linesizes() * @return the size in bytes required for the image buffer, a negative * error code in case of failure */ int av_image_fill_pointers(uint8_t *data[4], enum PixelFormat pix_fmt, int height, uint8_t *ptr, const int linesizes[4]); /** * Allocate an image with size w and h and pixel format pix_fmt, and * fill pointers and linesizes accordingly. * The allocated image buffer has to be freed by using * av_freep(&pointers[0]). * * @param align the value to use for buffer size alignment * @return the size in bytes required for the image buffer, a negative * error code in case of failure */ int av_image_alloc(uint8_t *pointers[4], int linesizes[4], int w, int h, enum PixelFormat pix_fmt, int align); /** * Copy image plane from src to dst. * That is, copy "height" number of lines of "bytewidth" bytes each. * The first byte of each successive line is separated by *_linesize * bytes. * * @param dst_linesize linesize for the image plane in dst * @param src_linesize linesize for the image plane in src */ void av_image_copy_plane(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize, int bytewidth, int height); /** * Copy image in src_data to dst_data. * * @param dst_linesizes linesizes for the image in dst_data * @param src_linesizes linesizes for the image in src_data */ void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], const uint8_t *src_data[4], const int src_linesizes[4], enum PixelFormat pix_fmt, int width, int height); /** * Check if the given dimension of an image is valid, meaning that all * bytes of the image can be addressed with a signed int. * * @param w the width of the picture * @param h the height of the picture * @param log_offset the offset to sum to the log level for logging with log_ctx * @param log_ctx the parent logging context, it may be NULL * @return >= 0 if valid, a negative error code otherwise */ int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx); int ff_set_systematic_pal2(uint32_t pal[256], enum PixelFormat pix_fmt); #endif /* AVUTIL_IMGUTILS_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/intfloat_readwrite.h000066400000000000000000000025011317340345000232310ustar00rootroot00000000000000/* * copyright (c) 2005 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_INTFLOAT_READWRITE_H #define AVUTIL_INTFLOAT_READWRITE_H #include #include "attributes.h" /* IEEE 80 bits extended float */ typedef struct AVExtFloat { uint8_t exponent[2]; uint8_t mantissa[8]; } AVExtFloat; double av_int2dbl(int64_t v) av_const; float av_int2flt(int32_t v) av_const; double av_ext2dbl(const AVExtFloat ext) av_const; int64_t av_dbl2int(double d) av_const; int32_t av_flt2int(float d) av_const; AVExtFloat av_dbl2ext(double d) av_const; #endif /* AVUTIL_INTFLOAT_READWRITE_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/intreadwrite.h000066400000000000000000000342451317340345000220560ustar00rootroot00000000000000/* * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_INTREADWRITE_H #define AVUTIL_INTREADWRITE_H #include #include "libavutil/avconfig.h" #include "attributes.h" #include "bswap.h" typedef union { uint64_t u64; uint32_t u32[2]; uint16_t u16[4]; uint8_t u8 [8]; double f64; float f32[2]; } av_alias av_alias64; typedef union { uint32_t u32; uint16_t u16[2]; uint8_t u8 [4]; float f32; } av_alias av_alias32; typedef union { uint16_t u16; uint8_t u8 [2]; } av_alias av_alias16; /* * Arch-specific headers can provide any combination of * AV_[RW][BLN](16|24|32|64) and AV_(COPY|SWAP|ZERO)(64|128) macros. * Preprocessor symbols must be defined, even if these are implemented * as inline functions. */ #ifdef HAVE_AV_CONFIG_H #include "config.h" #if ARCH_ARM # include "arm/intreadwrite.h" #elif ARCH_AVR32 # include "avr32/intreadwrite.h" #elif ARCH_MIPS # include "mips/intreadwrite.h" #elif ARCH_PPC # include "ppc/intreadwrite.h" #elif ARCH_TOMI # include "tomi/intreadwrite.h" #elif ARCH_X86 # include "x86/intreadwrite.h" #endif #endif /* HAVE_AV_CONFIG_H */ /* * Map AV_RNXX <-> AV_R[BL]XX for all variants provided by per-arch headers. */ #if AV_HAVE_BIGENDIAN # if defined(AV_RN16) && !defined(AV_RB16) # define AV_RB16(p) AV_RN16(p) # elif !defined(AV_RN16) && defined(AV_RB16) # define AV_RN16(p) AV_RB16(p) # endif # if defined(AV_WN16) && !defined(AV_WB16) # define AV_WB16(p, v) AV_WN16(p, v) # elif !defined(AV_WN16) && defined(AV_WB16) # define AV_WN16(p, v) AV_WB16(p, v) # endif # if defined(AV_RN24) && !defined(AV_RB24) # define AV_RB24(p) AV_RN24(p) # elif !defined(AV_RN24) && defined(AV_RB24) # define AV_RN24(p) AV_RB24(p) # endif # if defined(AV_WN24) && !defined(AV_WB24) # define AV_WB24(p, v) AV_WN24(p, v) # elif !defined(AV_WN24) && defined(AV_WB24) # define AV_WN24(p, v) AV_WB24(p, v) # endif # if defined(AV_RN32) && !defined(AV_RB32) # define AV_RB32(p) AV_RN32(p) # elif !defined(AV_RN32) && defined(AV_RB32) # define AV_RN32(p) AV_RB32(p) # endif # if defined(AV_WN32) && !defined(AV_WB32) # define AV_WB32(p, v) AV_WN32(p, v) # elif !defined(AV_WN32) && defined(AV_WB32) # define AV_WN32(p, v) AV_WB32(p, v) # endif # if defined(AV_RN64) && !defined(AV_RB64) # define AV_RB64(p) AV_RN64(p) # elif !defined(AV_RN64) && defined(AV_RB64) # define AV_RN64(p) AV_RB64(p) # endif # if defined(AV_WN64) && !defined(AV_WB64) # define AV_WB64(p, v) AV_WN64(p, v) # elif !defined(AV_WN64) && defined(AV_WB64) # define AV_WN64(p, v) AV_WB64(p, v) # endif #else /* AV_HAVE_BIGENDIAN */ # if defined(AV_RN16) && !defined(AV_RL16) # define AV_RL16(p) AV_RN16(p) # elif !defined(AV_RN16) && defined(AV_RL16) # define AV_RN16(p) AV_RL16(p) # endif # if defined(AV_WN16) && !defined(AV_WL16) # define AV_WL16(p, v) AV_WN16(p, v) # elif !defined(AV_WN16) && defined(AV_WL16) # define AV_WN16(p, v) AV_WL16(p, v) # endif # if defined(AV_RN24) && !defined(AV_RL24) # define AV_RL24(p) AV_RN24(p) # elif !defined(AV_RN24) && defined(AV_RL24) # define AV_RN24(p) AV_RL24(p) # endif # if defined(AV_WN24) && !defined(AV_WL24) # define AV_WL24(p, v) AV_WN24(p, v) # elif !defined(AV_WN24) && defined(AV_WL24) # define AV_WN24(p, v) AV_WL24(p, v) # endif # if defined(AV_RN32) && !defined(AV_RL32) # define AV_RL32(p) AV_RN32(p) # elif !defined(AV_RN32) && defined(AV_RL32) # define AV_RN32(p) AV_RL32(p) # endif # if defined(AV_WN32) && !defined(AV_WL32) # define AV_WL32(p, v) AV_WN32(p, v) # elif !defined(AV_WN32) && defined(AV_WL32) # define AV_WN32(p, v) AV_WL32(p, v) # endif # if defined(AV_RN64) && !defined(AV_RL64) # define AV_RL64(p) AV_RN64(p) # elif !defined(AV_RN64) && defined(AV_RL64) # define AV_RN64(p) AV_RL64(p) # endif # if defined(AV_WN64) && !defined(AV_WL64) # define AV_WL64(p, v) AV_WN64(p, v) # elif !defined(AV_WN64) && defined(AV_WL64) # define AV_WN64(p, v) AV_WL64(p, v) # endif #endif /* !AV_HAVE_BIGENDIAN */ /* * Define AV_[RW]N helper macros to simplify definitions not provided * by per-arch headers. */ #if defined(__GNUC__) && !defined(__TI_COMPILER_VERSION__) union unaligned_64 { uint64_t l; } __attribute__((packed)) av_alias; union unaligned_32 { uint32_t l; } __attribute__((packed)) av_alias; union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; # define AV_RN(s, p) (((const union unaligned_##s *) (p))->l) # define AV_WN(s, p, v) ((((union unaligned_##s *) (p))->l) = (v)) #elif defined(__DECC) # define AV_RN(s, p) (*((const __unaligned uint##s##_t*)(p))) # define AV_WN(s, p, v) (*((__unaligned uint##s##_t*)(p)) = (v)) #elif AV_HAVE_FAST_UNALIGNED # define AV_RN(s, p) (((const av_alias##s*)(p))->u##s) # define AV_WN(s, p, v) (((av_alias##s*)(p))->u##s = (v)) #else #ifndef AV_RB16 # define AV_RB16(x) \ ((((const uint8_t*)(x))[0] << 8) | \ ((const uint8_t*)(x))[1]) #endif #ifndef AV_WB16 # define AV_WB16(p, d) do { \ ((uint8_t*)(p))[1] = (d); \ ((uint8_t*)(p))[0] = (d)>>8; \ } while(0) #endif #ifndef AV_RL16 # define AV_RL16(x) \ ((((const uint8_t*)(x))[1] << 8) | \ ((const uint8_t*)(x))[0]) #endif #ifndef AV_WL16 # define AV_WL16(p, d) do { \ ((uint8_t*)(p))[0] = (d); \ ((uint8_t*)(p))[1] = (d)>>8; \ } while(0) #endif #ifndef AV_RB32 # define AV_RB32(x) \ (((uint32_t)((const uint8_t*)(x))[0] << 24) | \ (((const uint8_t*)(x))[1] << 16) | \ (((const uint8_t*)(x))[2] << 8) | \ ((const uint8_t*)(x))[3]) #endif #ifndef AV_WB32 # define AV_WB32(p, d) do { \ ((uint8_t*)(p))[3] = (d); \ ((uint8_t*)(p))[2] = (d)>>8; \ ((uint8_t*)(p))[1] = (d)>>16; \ ((uint8_t*)(p))[0] = (d)>>24; \ } while(0) #endif #ifndef AV_RL32 # define AV_RL32(x) \ (((uint32_t)((const uint8_t*)(x))[3] << 24) | \ (((const uint8_t*)(x))[2] << 16) | \ (((const uint8_t*)(x))[1] << 8) | \ ((const uint8_t*)(x))[0]) #endif #ifndef AV_WL32 # define AV_WL32(p, d) do { \ ((uint8_t*)(p))[0] = (d); \ ((uint8_t*)(p))[1] = (d)>>8; \ ((uint8_t*)(p))[2] = (d)>>16; \ ((uint8_t*)(p))[3] = (d)>>24; \ } while(0) #endif #ifndef AV_RB64 # define AV_RB64(x) \ (((uint64_t)((const uint8_t*)(x))[0] << 56) | \ ((uint64_t)((const uint8_t*)(x))[1] << 48) | \ ((uint64_t)((const uint8_t*)(x))[2] << 40) | \ ((uint64_t)((const uint8_t*)(x))[3] << 32) | \ ((uint64_t)((const uint8_t*)(x))[4] << 24) | \ ((uint64_t)((const uint8_t*)(x))[5] << 16) | \ ((uint64_t)((const uint8_t*)(x))[6] << 8) | \ (uint64_t)((const uint8_t*)(x))[7]) #endif #ifndef AV_WB64 # define AV_WB64(p, d) do { \ ((uint8_t*)(p))[7] = (d); \ ((uint8_t*)(p))[6] = (d)>>8; \ ((uint8_t*)(p))[5] = (d)>>16; \ ((uint8_t*)(p))[4] = (d)>>24; \ ((uint8_t*)(p))[3] = (d)>>32; \ ((uint8_t*)(p))[2] = (d)>>40; \ ((uint8_t*)(p))[1] = (d)>>48; \ ((uint8_t*)(p))[0] = (d)>>56; \ } while(0) #endif #ifndef AV_RL64 # define AV_RL64(x) \ (((uint64_t)((const uint8_t*)(x))[7] << 56) | \ ((uint64_t)((const uint8_t*)(x))[6] << 48) | \ ((uint64_t)((const uint8_t*)(x))[5] << 40) | \ ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ (uint64_t)((const uint8_t*)(x))[0]) #endif #ifndef AV_WL64 # define AV_WL64(p, d) do { \ ((uint8_t*)(p))[0] = (d); \ ((uint8_t*)(p))[1] = (d)>>8; \ ((uint8_t*)(p))[2] = (d)>>16; \ ((uint8_t*)(p))[3] = (d)>>24; \ ((uint8_t*)(p))[4] = (d)>>32; \ ((uint8_t*)(p))[5] = (d)>>40; \ ((uint8_t*)(p))[6] = (d)>>48; \ ((uint8_t*)(p))[7] = (d)>>56; \ } while(0) #endif #if AV_HAVE_BIGENDIAN # define AV_RN(s, p) AV_RB##s(p) # define AV_WN(s, p, v) AV_WB##s(p, v) #else # define AV_RN(s, p) AV_RL##s(p) # define AV_WN(s, p, v) AV_WL##s(p, v) #endif #endif /* HAVE_FAST_UNALIGNED */ #ifndef AV_RN16 # define AV_RN16(p) AV_RN(16, p) #endif #ifndef AV_RN32 # define AV_RN32(p) AV_RN(32, p) #endif #ifndef AV_RN64 # define AV_RN64(p) AV_RN(64, p) #endif #ifndef AV_WN16 # define AV_WN16(p, v) AV_WN(16, p, v) #endif #ifndef AV_WN32 # define AV_WN32(p, v) AV_WN(32, p, v) #endif #ifndef AV_WN64 # define AV_WN64(p, v) AV_WN(64, p, v) #endif #if AV_HAVE_BIGENDIAN # define AV_RB(s, p) AV_RN##s(p) # define AV_WB(s, p, v) AV_WN##s(p, v) # define AV_RL(s, p) av_bswap##s(AV_RN##s(p)) # define AV_WL(s, p, v) AV_WN##s(p, av_bswap##s(v)) #else # define AV_RB(s, p) av_bswap##s(AV_RN##s(p)) # define AV_WB(s, p, v) AV_WN##s(p, av_bswap##s(v)) # define AV_RL(s, p) AV_RN##s(p) # define AV_WL(s, p, v) AV_WN##s(p, v) #endif #define AV_RB8(x) (((const uint8_t*)(x))[0]) #define AV_WB8(p, d) do { ((uint8_t*)(p))[0] = (d); } while(0) #define AV_RL8(x) AV_RB8(x) #define AV_WL8(p, d) AV_WB8(p, d) #ifndef AV_RB16 # define AV_RB16(p) AV_RB(16, p) #endif #ifndef AV_WB16 # define AV_WB16(p, v) AV_WB(16, p, v) #endif #ifndef AV_RL16 # define AV_RL16(p) AV_RL(16, p) #endif #ifndef AV_WL16 # define AV_WL16(p, v) AV_WL(16, p, v) #endif #ifndef AV_RB32 # define AV_RB32(p) AV_RB(32, p) #endif #ifndef AV_WB32 # define AV_WB32(p, v) AV_WB(32, p, v) #endif #ifndef AV_RL32 # define AV_RL32(p) AV_RL(32, p) #endif #ifndef AV_WL32 # define AV_WL32(p, v) AV_WL(32, p, v) #endif #ifndef AV_RB64 # define AV_RB64(p) AV_RB(64, p) #endif #ifndef AV_WB64 # define AV_WB64(p, v) AV_WB(64, p, v) #endif #ifndef AV_RL64 # define AV_RL64(p) AV_RL(64, p) #endif #ifndef AV_WL64 # define AV_WL64(p, v) AV_WL(64, p, v) #endif #ifndef AV_RB24 # define AV_RB24(x) \ ((((const uint8_t*)(x))[0] << 16) | \ (((const uint8_t*)(x))[1] << 8) | \ ((const uint8_t*)(x))[2]) #endif #ifndef AV_WB24 # define AV_WB24(p, d) do { \ ((uint8_t*)(p))[2] = (d); \ ((uint8_t*)(p))[1] = (d)>>8; \ ((uint8_t*)(p))[0] = (d)>>16; \ } while(0) #endif #ifndef AV_RL24 # define AV_RL24(x) \ ((((const uint8_t*)(x))[2] << 16) | \ (((const uint8_t*)(x))[1] << 8) | \ ((const uint8_t*)(x))[0]) #endif #ifndef AV_WL24 # define AV_WL24(p, d) do { \ ((uint8_t*)(p))[0] = (d); \ ((uint8_t*)(p))[1] = (d)>>8; \ ((uint8_t*)(p))[2] = (d)>>16; \ } while(0) #endif /* * The AV_[RW]NA macros access naturally aligned data * in a type-safe way. */ #define AV_RNA(s, p) (((const av_alias##s*)(p))->u##s) #define AV_WNA(s, p, v) (((av_alias##s*)(p))->u##s = (v)) #ifndef AV_RN16A # define AV_RN16A(p) AV_RNA(16, p) #endif #ifndef AV_RN32A # define AV_RN32A(p) AV_RNA(32, p) #endif #ifndef AV_RN64A # define AV_RN64A(p) AV_RNA(64, p) #endif #ifndef AV_WN16A # define AV_WN16A(p, v) AV_WNA(16, p, v) #endif #ifndef AV_WN32A # define AV_WN32A(p, v) AV_WNA(32, p, v) #endif #ifndef AV_WN64A # define AV_WN64A(p, v) AV_WNA(64, p, v) #endif /* Parameters for AV_COPY*, AV_SWAP*, AV_ZERO* must be * naturally aligned. They may be implemented using MMX, * so emms_c() must be called before using any float code * afterwards. */ #define AV_COPY(n, d, s) \ (((av_alias##n*)(d))->u##n = ((const av_alias##n*)(s))->u##n) #ifndef AV_COPY16 # define AV_COPY16(d, s) AV_COPY(16, d, s) #endif #ifndef AV_COPY32 # define AV_COPY32(d, s) AV_COPY(32, d, s) #endif #ifndef AV_COPY64 # define AV_COPY64(d, s) AV_COPY(64, d, s) #endif #ifndef AV_COPY128 # define AV_COPY128(d, s) \ do { \ AV_COPY64(d, s); \ AV_COPY64((char*)(d)+8, (char*)(s)+8); \ } while(0) #endif #define AV_SWAP(n, a, b) FFSWAP(av_alias##n, *(av_alias##n*)(a), *(av_alias##n*)(b)) #ifndef AV_SWAP64 # define AV_SWAP64(a, b) AV_SWAP(64, a, b) #endif #define AV_ZERO(n, d) (((av_alias##n*)(d))->u##n = 0) #ifndef AV_ZERO16 # define AV_ZERO16(d) AV_ZERO(16, d) #endif #ifndef AV_ZERO32 # define AV_ZERO32(d) AV_ZERO(32, d) #endif #ifndef AV_ZERO64 # define AV_ZERO64(d) AV_ZERO(64, d) #endif #ifndef AV_ZERO128 # define AV_ZERO128(d) \ do { \ AV_ZERO64(d); \ AV_ZERO64((char*)(d)+8); \ } while(0) #endif #endif /* AVUTIL_INTREADWRITE_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/lfg.h000066400000000000000000000036531317340345000201240ustar00rootroot00000000000000/* * Lagged Fibonacci PRNG * Copyright (c) 2008 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_LFG_H #define AVUTIL_LFG_H typedef struct { unsigned int state[64]; int index; } AVLFG; void av_lfg_init(AVLFG *c, unsigned int seed); /** * Get the next random unsigned 32-bit number using an ALFG. * * Please also consider a simple LCG like state= state*1664525+1013904223, * it may be good enough and faster for your specific use case. */ static inline unsigned int av_lfg_get(AVLFG *c){ c->state[c->index & 63] = c->state[(c->index-24) & 63] + c->state[(c->index-55) & 63]; return c->state[c->index++ & 63]; } /** * Get the next random unsigned 32-bit number using a MLFG. * * Please also consider av_lfg_get() above, it is faster. */ static inline unsigned int av_mlfg_get(AVLFG *c){ unsigned int a= c->state[(c->index-55) & 63]; unsigned int b= c->state[(c->index-24) & 63]; return c->state[c->index++ & 63] = 2*a*b+a+b; } /** * Get the next two numbers generated by a Box-Muller Gaussian * generator using the random numbers issued by lfg. * * @param out array where the two generated numbers are placed */ void av_bmg_get(AVLFG *lfg, double out[2]); #endif /* AVUTIL_LFG_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/log.h000066400000000000000000000121271317340345000201310ustar00rootroot00000000000000/* * copyright (c) 2006 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_LOG_H #define AVUTIL_LOG_H #include #include "avutil.h" #include "attributes.h" /** * Describe the class of an AVClass context structure. That is an * arbitrary struct of which the first field is a pointer to an * AVClass struct (e.g. AVCodecContext, AVFormatContext etc.). */ typedef struct { /** * The name of the class; usually it is the same name as the * context structure type to which the AVClass is associated. */ const char* class_name; /** * A pointer to a function which returns the name of a context * instance ctx associated with the class. */ const char* (*item_name)(void* ctx); /** * a pointer to the first option specified in the class if any or NULL * * @see av_set_default_options() */ const struct AVOption *option; /** * LIBAVUTIL_VERSION with which this structure was created. * This is used to allow fields to be added without requiring major * version bumps everywhere. */ int version; /** * Offset in the structure where log_level_offset is stored. * 0 means there is no such variable */ int log_level_offset_offset; /** * Offset in the structure where a pointer to the parent context for loging is stored. * for example a decoder that uses eval.c could pass its AVCodecContext to eval as such * parent context. And a av_log() implementation could then display the parent context * can be NULL of course */ int parent_log_context_offset; /** * A function for extended searching, e.g. in possible * children objects. */ const struct AVOption* (*opt_find)(void *obj, const char *name, const char *unit, int opt_flags, int search_flags); } AVClass; /* av_log API */ #define AV_LOG_QUIET -8 /** * Something went really wrong and we will crash now. */ #define AV_LOG_PANIC 0 /** * Something went wrong and recovery is not possible. * For example, no header was found for a format which depends * on headers or an illegal combination of parameters is used. */ #define AV_LOG_FATAL 8 /** * Something went wrong and cannot losslessly be recovered. * However, not all future data is affected. */ #define AV_LOG_ERROR 16 /** * Something somehow does not look correct. This may or may not * lead to problems. An example would be the use of '-vstrict -2'. */ #define AV_LOG_WARNING 24 #define AV_LOG_INFO 32 #define AV_LOG_VERBOSE 40 /** * Stuff which is only useful for libav* developers. */ #define AV_LOG_DEBUG 48 /** * Send the specified message to the log if the level is less than or equal * to the current av_log_level. By default, all logging messages are sent to * stderr. This behavior can be altered by setting a different av_vlog callback * function. * * @param avcl A pointer to an arbitrary struct of which the first field is a * pointer to an AVClass struct. * @param level The importance level of the message, lower values signifying * higher importance. * @param fmt The format string (printf-compatible) that specifies how * subsequent arguments are converted to output. * @see av_vlog */ void av_log(void *avcl, int level, const char *fmt, ...) av_printf_format(3, 4); void av_vlog(void *avcl, int level, const char *fmt, va_list); int av_log_get_level(void); void av_log_set_level(int); void av_log_set_callback(void (*)(void*, int, const char*, va_list)); void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl); const char* av_default_item_name(void* ctx); /** * av_dlog macros * Useful to print debug messages that shouldn't get compiled in normally. */ #ifdef DEBUG # define av_dlog(pctx, ...) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__) #else # define av_dlog(pctx, ...) do { if (0) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0) #endif /** * Skip repeated messages, this requires the user app to use av_log() instead of * (f)printf as the 2 would otherwise interfere and lead to * "Last message repeated x times" messages below (f)printf messages with some * bad luck. * Also to receive the last, "last repeated" line if any, the user app must * call av_log(NULL, AV_LOG_QUIET, "%s", ""); at the end */ #define AV_LOG_SKIP_REPEATED 1 void av_log_set_flags(int arg); #endif /* AVUTIL_LOG_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/lzo.h000066400000000000000000000045451317340345000201610ustar00rootroot00000000000000/* * LZO 1x decompression * copyright (c) 2006 Reimar Doeffinger * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_LZO_H #define AVUTIL_LZO_H #include /** @name Error flags returned by av_lzo1x_decode * \{ */ //! end of the input buffer reached before decoding finished #define AV_LZO_INPUT_DEPLETED 1 //! decoded data did not fit into output buffer #define AV_LZO_OUTPUT_FULL 2 //! a reference to previously decoded data was wrong #define AV_LZO_INVALID_BACKPTR 4 //! a non-specific error in the compressed bitstream #define AV_LZO_ERROR 8 /** \} */ #define AV_LZO_INPUT_PADDING 8 #define AV_LZO_OUTPUT_PADDING 12 /** * @brief Decodes LZO 1x compressed data. * @param out output buffer * @param outlen size of output buffer, number of bytes left are returned here * @param in input buffer * @param inlen size of input buffer, number of bytes left are returned here * @return 0 on success, otherwise a combination of the error flags above * * Make sure all buffers are appropriately padded, in must provide * AV_LZO_INPUT_PADDING, out must provide AV_LZO_OUTPUT_PADDING additional bytes. */ int av_lzo1x_decode(void *out, int *outlen, const void *in, int *inlen); /** * @brief deliberately overlapping memcpy implementation * @param dst destination buffer; must be padded with 12 additional bytes * @param back how many bytes back we start (the initial size of the overlapping window) * @param cnt number of bytes to copy, must be >= 0 * * cnt > back is valid, this will copy the bytes we just copied, * thus creating a repeating pattern with a period length of back. */ void av_memcpy_backptr(uint8_t *dst, int back, int cnt); #endif /* AVUTIL_LZO_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/mathematics.h000066400000000000000000000067631317340345000216600ustar00rootroot00000000000000/* * copyright (c) 2005 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_MATHEMATICS_H #define AVUTIL_MATHEMATICS_H #include #include #include "attributes.h" #include "rational.h" #ifndef M_E #define M_E 2.7182818284590452354 /* e */ #endif #ifndef M_LN2 #define M_LN2 0.69314718055994530942 /* log_e 2 */ #endif #ifndef M_LN10 #define M_LN10 2.30258509299404568402 /* log_e 10 */ #endif #ifndef M_LOG2_10 #define M_LOG2_10 3.32192809488736234787 /* log_2 10 */ #endif #ifndef M_PHI #define M_PHI 1.61803398874989484820 /* phi / golden ratio */ #endif #ifndef M_PI #define M_PI 3.14159265358979323846 /* pi */ #endif #ifndef M_SQRT1_2 #define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ #endif #ifndef M_SQRT2 #define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ #endif #ifndef NAN #define NAN (0.0/0.0) #endif #ifndef INFINITY #define INFINITY (1.0/0.0) #endif enum AVRounding { AV_ROUND_ZERO = 0, ///< Round toward zero. AV_ROUND_INF = 1, ///< Round away from zero. AV_ROUND_DOWN = 2, ///< Round toward -infinity. AV_ROUND_UP = 3, ///< Round toward +infinity. AV_ROUND_NEAR_INF = 5, ///< Round to nearest and halfway cases away from zero. }; /** * Return the greatest common divisor of a and b. * If both a and b are 0 or either or both are <0 then behavior is * undefined. */ int64_t av_const av_gcd(int64_t a, int64_t b); /** * Rescale a 64-bit integer with rounding to nearest. * A simple a*b/c isn't possible as it can overflow. */ int64_t av_rescale(int64_t a, int64_t b, int64_t c) av_const; /** * Rescale a 64-bit integer with specified rounding. * A simple a*b/c isn't possible as it can overflow. */ int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding) av_const; /** * Rescale a 64-bit integer by 2 rational numbers. */ int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const; /** * Compare 2 timestamps each in its own timebases. * The result of the function is undefined if one of the timestamps * is outside the int64_t range when represented in the others timebase. * @return -1 if ts_a is before ts_b, 1 if ts_a is after ts_b or 0 if they represent the same position */ int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b); /** * Compare 2 integers modulo mod. * That is we compare integers a and b for which only the least * significant log2(mod) bits are known. * * @param mod must be a power of 2 * @return a negative value if a is smaller than b * a positive value if a is greater than b * 0 if a equals b */ int64_t av_compare_mod(uint64_t a, uint64_t b, uint64_t mod); #endif /* AVUTIL_MATHEMATICS_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/md5.h000066400000000000000000000022321317340345000200310ustar00rootroot00000000000000/* * copyright (c) 2006 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_MD5_H #define AVUTIL_MD5_H #include extern const int av_md5_size; struct AVMD5; void av_md5_init(struct AVMD5 *ctx); void av_md5_update(struct AVMD5 *ctx, const uint8_t *src, const int len); void av_md5_final(struct AVMD5 *ctx, uint8_t *dst); void av_md5_sum(uint8_t *dst, const uint8_t *src, const int len); #endif /* AVUTIL_MD5_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/mem.h000066400000000000000000000112221317340345000201210ustar00rootroot00000000000000/* * copyright (c) 2006 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * memory handling functions */ #ifndef AVUTIL_MEM_H #define AVUTIL_MEM_H #include "attributes.h" #include "avutil.h" #if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 1110 || defined(__SUNPRO_C) #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v #define DECLARE_ASM_CONST(n,t,v) const t __attribute__ ((aligned (n))) v #elif defined(__TI_COMPILER_VERSION__) #define DECLARE_ALIGNED(n,t,v) \ AV_PRAGMA(DATA_ALIGN(v,n)) \ t __attribute__((aligned(n))) v #define DECLARE_ASM_CONST(n,t,v) \ AV_PRAGMA(DATA_ALIGN(v,n)) \ static const t __attribute__((aligned(n))) v #elif defined(__GNUC__) #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v #define DECLARE_ASM_CONST(n,t,v) static const t av_used __attribute__ ((aligned (n))) v #elif defined(_MSC_VER) #define DECLARE_ALIGNED(n,t,v) __declspec(align(n)) t v #define DECLARE_ASM_CONST(n,t,v) __declspec(align(n)) static const t v #else #define DECLARE_ALIGNED(n,t,v) t v #define DECLARE_ASM_CONST(n,t,v) static const t v #endif #if AV_GCC_VERSION_AT_LEAST(3,1) #define av_malloc_attrib __attribute__((__malloc__)) #else #define av_malloc_attrib #endif #if AV_GCC_VERSION_AT_LEAST(4,3) #define av_alloc_size(n) __attribute__((alloc_size(n))) #else #define av_alloc_size(n) #endif /** * Allocate a block of size bytes with alignment suitable for all * memory accesses (including vectors if available on the CPU). * @param size Size in bytes for the memory block to be allocated. * @return Pointer to the allocated block, NULL if the block cannot * be allocated. * @see av_mallocz() */ void *av_malloc(size_t size) av_malloc_attrib av_alloc_size(1); /** * Allocate or reallocate a block of memory. * If ptr is NULL and size > 0, allocate a new block. If * size is zero, free the memory block pointed to by ptr. * @param ptr Pointer to a memory block already allocated with * av_malloc(z)() or av_realloc() or NULL. * @param size Size in bytes for the memory block to be allocated or * reallocated. * @return Pointer to a newly reallocated block or NULL if the block * cannot be reallocated or the function is used to free the memory block. * @see av_fast_realloc() */ void *av_realloc(void *ptr, size_t size) av_alloc_size(2); /** * Free a memory block which has been allocated with av_malloc(z)() or * av_realloc(). * @param ptr Pointer to the memory block which should be freed. * @note ptr = NULL is explicitly allowed. * @note It is recommended that you use av_freep() instead. * @see av_freep() */ void av_free(void *ptr); /** * Allocate a block of size bytes with alignment suitable for all * memory accesses (including vectors if available on the CPU) and * zero all the bytes of the block. * @param size Size in bytes for the memory block to be allocated. * @return Pointer to the allocated block, NULL if it cannot be allocated. * @see av_malloc() */ void *av_mallocz(size_t size) av_malloc_attrib av_alloc_size(1); /** * Duplicate the string s. * @param s string to be duplicated * @return Pointer to a newly allocated string containing a * copy of s or NULL if the string cannot be allocated. */ char *av_strdup(const char *s) av_malloc_attrib; /** * Free a memory block which has been allocated with av_malloc(z)() or * av_realloc() and set the pointer pointing to it to NULL. * @param ptr Pointer to the pointer to the memory block which should * be freed. * @see av_free() */ void av_freep(void *ptr); /** * Add an element to a dynamic array. * * @param tab_ptr Pointer to the array. * @param nb_ptr Pointer to the number of elements in the array. * @param elem Element to be added. */ void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem); #endif /* AVUTIL_MEM_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/opt.h000066400000000000000000000226521317340345000201560ustar00rootroot00000000000000/* * AVOptions * copyright (c) 2005 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_OPT_H #define AVUTIL_OPT_H /** * @file * AVOptions */ #include "rational.h" #include "avutil.h" #include "dict.h" enum AVOptionType{ FF_OPT_TYPE_FLAGS, FF_OPT_TYPE_INT, FF_OPT_TYPE_INT64, FF_OPT_TYPE_DOUBLE, FF_OPT_TYPE_FLOAT, FF_OPT_TYPE_STRING, FF_OPT_TYPE_RATIONAL, FF_OPT_TYPE_BINARY, ///< offset must point to a pointer immediately followed by an int for the length FF_OPT_TYPE_CONST=128, }; /** * AVOption */ typedef struct AVOption { const char *name; /** * short English help text * @todo What about other languages? */ const char *help; /** * The offset relative to the context structure where the option * value is stored. It should be 0 for named constants. */ int offset; enum AVOptionType type; /** * the default value for scalar options */ union { double dbl; const char *str; /* TODO those are unused now */ int64_t i64; AVRational q; } default_val; double min; ///< minimum valid value for the option double max; ///< maximum valid value for the option int flags; #define AV_OPT_FLAG_ENCODING_PARAM 1 ///< a generic parameter which can be set by the user for muxing or encoding #define AV_OPT_FLAG_DECODING_PARAM 2 ///< a generic parameter which can be set by the user for demuxing or decoding #define AV_OPT_FLAG_METADATA 4 ///< some data extracted or inserted into the file like title, comment, ... #define AV_OPT_FLAG_AUDIO_PARAM 8 #define AV_OPT_FLAG_VIDEO_PARAM 16 #define AV_OPT_FLAG_SUBTITLE_PARAM 32 //FIXME think about enc-audio, ... style flags /** * The logical unit to which the option belongs. Non-constant * options and corresponding named constants share the same * unit. May be NULL. */ const char *unit; } AVOption; #if FF_API_FIND_OPT /** * Look for an option in obj. Look only for the options which * have the flags set as specified in mask and flags (that is, * for which it is the case that opt->flags & mask == flags). * * @param[in] obj a pointer to a struct whose first element is a * pointer to an AVClass * @param[in] name the name of the option to look for * @param[in] unit the unit of the option to look for, or any if NULL * @return a pointer to the option found, or NULL if no option * has been found * * @deprecated use av_opt_find. */ attribute_deprecated const AVOption *av_find_opt(void *obj, const char *name, const char *unit, int mask, int flags); #endif /** * Set the field of obj with the given name to value. * * @param[in] obj A struct whose first element is a pointer to an * AVClass. * @param[in] name the name of the field to set * @param[in] val The value to set. If the field is not of a string * type, then the given string is parsed. * SI postfixes and some named scalars are supported. * If the field is of a numeric type, it has to be a numeric or named * scalar. Behavior with more than one scalar and +- infix operators * is undefined. * If the field is of a flags type, it has to be a sequence of numeric * scalars or named flags separated by '+' or '-'. Prefixing a flag * with '+' causes it to be set without affecting the other flags; * similarly, '-' unsets a flag. * @param[out] o_out if non-NULL put here a pointer to the AVOption * found * @param alloc when 1 then the old value will be av_freed() and the * new av_strduped() * when 0 then no av_free() nor av_strdup() will be used * @return 0 if the value has been set, or an AVERROR code in case of * error: * AVERROR_OPTION_NOT_FOUND if no matching option exists * AVERROR(ERANGE) if the value is out of range * AVERROR(EINVAL) if the value is not valid */ int av_set_string3(void *obj, const char *name, const char *val, int alloc, const AVOption **o_out); const AVOption *av_set_double(void *obj, const char *name, double n); const AVOption *av_set_q(void *obj, const char *name, AVRational n); const AVOption *av_set_int(void *obj, const char *name, int64_t n); double av_get_double(void *obj, const char *name, const AVOption **o_out); AVRational av_get_q(void *obj, const char *name, const AVOption **o_out); int64_t av_get_int(void *obj, const char *name, const AVOption **o_out); const char *av_get_string(void *obj, const char *name, const AVOption **o_out, char *buf, int buf_len); const AVOption *av_next_option(void *obj, const AVOption *last); /** * Show the obj options. * * @param req_flags requested flags for the options to show. Show only the * options for which it is opt->flags & req_flags. * @param rej_flags rejected flags for the options to show. Show only the * options for which it is !(opt->flags & req_flags). * @param av_log_obj log context to use for showing the options */ int av_opt_show2(void *obj, void *av_log_obj, int req_flags, int rej_flags); /** * Set the values of all AVOption fields to their default values. * * @param s an AVOption-enabled struct (its first member must be a pointer to AVClass) */ void av_opt_set_defaults(void *s); #if FF_API_OLD_AVOPTIONS attribute_deprecated void av_opt_set_defaults2(void *s, int mask, int flags); #endif /** * Parse the key/value pairs list in opts. For each key/value pair * found, stores the value in the field in ctx that is named like the * key. ctx must be an AVClass context, storing is done using * AVOptions. * * @param opts options string to parse, may be NULL * @param key_val_sep a 0-terminated list of characters used to * separate key from value * @param pairs_sep a 0-terminated list of characters used to separate * two pairs from each other * @return the number of successfully set key/value pairs, or a negative * value corresponding to an AVERROR code in case of error: * AVERROR(EINVAL) if opts cannot be parsed, * the error code issued by av_set_string3() if a key/value pair * cannot be set */ int av_set_options_string(void *ctx, const char *opts, const char *key_val_sep, const char *pairs_sep); /** * Free all string and binary options in obj. */ void av_opt_free(void *obj); /** * Check whether a particular flag is set in a flags field. * * @param field_name the name of the flag field option * @param flag_name the name of the flag to check * @return non-zero if the flag is set, zero if the flag isn't set, * isn't of the right type, or the flags field doesn't exist. */ int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name); /* * Set all the options from a given dictionary on an object. * * @param obj a struct whose first element is a pointer to AVClass * @param options options to process. This dictionary will be freed and replaced * by a new one containing all options not found in obj. * Of course this new dictionary needs to be freed by caller * with av_dict_free(). * * @return 0 on success, a negative AVERROR if some option was found in obj, * but could not be set. * * @see av_dict_copy() */ int av_opt_set_dict(void *obj, struct AVDictionary **options); #define AV_OPT_SEARCH_CHILDREN 0x0001 /**< Search in possible children of the given object first. */ /** * The obj passed to av_opt_find() is fake -- only a double pointer to AVClass * instead of a required pointer to a struct containing AVClass. This is * useful for searching for options without needing to allocate the corresponding * object. */ #define AV_OPT_SEARCH_FAKE_OBJ 0x0002 /** * Look for an option in an object. Consider only options which * have all the specified flags set. * * @param[in] obj A pointer to a struct whose first element is a * pointer to an AVClass. * Alternatively a double pointer to an AVClass, if * AV_OPT_SEARCH_FAKE_OBJ search flag is set. * @param[in] name The name of the option to look for. * @param[in] unit When searching for named constants, name of the unit * it belongs to. * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG). * @param search_flags A combination of AV_OPT_SEARCH_*. * * @return A pointer to the option found, or NULL if no option * was found. * * @note Options found with AV_OPT_SEARCH_CHILDREN flag may not be settable * directly with av_set_string3(). Use special calls which take an options * AVDictionary (e.g. avformat_open_input()) to set options found with this * flag. */ const AVOption *av_opt_find(void *obj, const char *name, const char *unit, int opt_flags, int search_flags); #endif /* AVUTIL_OPT_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/parseutils.h000066400000000000000000000106421317340345000215430ustar00rootroot00000000000000/* * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_PARSEUTILS_H #define AVUTIL_PARSEUTILS_H #include "rational.h" /** * @file * misc parsing utilities */ /** * Parse str and put in width_ptr and height_ptr the detected values. * * @param[in,out] width_ptr pointer to the variable which will contain the detected * width value * @param[in,out] height_ptr pointer to the variable which will contain the detected * height value * @param[in] str the string to parse: it has to be a string in the format * width x height or a valid video size abbreviation. * @return >= 0 on success, a negative error code otherwise */ int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str); /** * Parse str and store the detected values in *rate. * * @param[in,out] rate pointer to the AVRational which will contain the detected * frame rate * @param[in] str the string to parse: it has to be a string in the format * rate_num / rate_den, a float number or a valid video rate abbreviation * @return >= 0 on success, a negative error code otherwise */ int av_parse_video_rate(AVRational *rate, const char *str); /** * Put the RGBA values that correspond to color_string in rgba_color. * * @param color_string a string specifying a color. It can be the name of * a color (case insensitive match) or a [0x|#]RRGGBB[AA] sequence, * possibly followed by "@" and a string representing the alpha * component. * The alpha component may be a string composed by "0x" followed by an * hexadecimal number or a decimal number between 0.0 and 1.0, which * represents the opacity value (0x00/0.0 means completely transparent, * 0xff/1.0 completely opaque). * If the alpha component is not specified then 0xff is assumed. * The string "random" will result in a random color. * @param slen length of the initial part of color_string containing the * color. It can be set to -1 if color_string is a null terminated string * containing nothing else than the color. * @return >= 0 in case of success, a negative value in case of * failure (for example if color_string cannot be parsed). */ int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen, void *log_ctx); /** * Parses timestr and returns in *time a corresponding number of * microseconds. * * @param timeval puts here the number of microseconds corresponding * to the string in timestr. If the string represents a duration, it * is the number of microseconds contained in the time interval. If * the string is a date, is the number of microseconds since 1st of * January, 1970 up to the time of the parsed date. If timestr cannot * be successfully parsed, set *time to INT64_MIN. * @param timestr a string representing a date or a duration. * - If a date the syntax is: * @code * [{YYYY-MM-DD|YYYYMMDD}[T|t| ]]{{HH[:MM[:SS[.m...]]]}|{HH[MM[SS[.m...]]]}}[Z] * now * @endcode * If the value is "now" it takes the current time. * Time is local time unless Z is appended, in which case it is * interpreted as UTC. * If the year-month-day part is not specified it takes the current * year-month-day. * - If a duration the syntax is: * @code * [-]HH[:MM[:SS[.m...]]] * [-]S+[.m...] * @endcode * @param duration flag which tells how to interpret timestr, if not * zero timestr is interpreted as a duration, otherwise as a date * @return 0 in case of success, a negative value corresponding to an * AVERROR code otherwise */ int av_parse_time(int64_t *timeval, const char *timestr, int duration); /** * Attempt to find a specific tag in a URL. * * syntax: '?tag1=val1&tag2=val2...'. Little URL decoding is done. * Return 1 if found. */ int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info); #endif /* AVUTIL_PARSEUTILS_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/pixdesc.h000066400000000000000000000152461317340345000210140ustar00rootroot00000000000000/* * pixel format descriptor * Copyright (c) 2009 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_PIXDESC_H #define AVUTIL_PIXDESC_H #include #include "pixfmt.h" typedef struct AVComponentDescriptor{ uint16_t plane :2; ///< which of the 4 planes contains the component /** * Number of elements between 2 horizontally consecutive pixels minus 1. * Elements are bits for bitstream formats, bytes otherwise. */ uint16_t step_minus1 :3; /** * Number of elements before the component of the first pixel plus 1. * Elements are bits for bitstream formats, bytes otherwise. */ uint16_t offset_plus1 :3; uint16_t shift :3; ///< number of least significant bits that must be shifted away to get the value uint16_t depth_minus1 :4; ///< number of bits in the component minus 1 }AVComponentDescriptor; /** * Descriptor that unambiguously describes how the bits of a pixel are * stored in the up to 4 data planes of an image. It also stores the * subsampling factors and number of components. * * @note This is separate of the colorspace (RGB, YCbCr, YPbPr, JPEG-style YUV * and all the YUV variants) AVPixFmtDescriptor just stores how values * are stored not what these values represent. */ typedef struct AVPixFmtDescriptor{ const char *name; uint8_t nb_components; ///< The number of components each pixel has, (1-4) /** * Amount to shift the luma width right to find the chroma width. * For YV12 this is 1 for example. * chroma_width = -((-luma_width) >> log2_chroma_w) * The note above is needed to ensure rounding up. * This value only refers to the chroma components. */ uint8_t log2_chroma_w; ///< chroma_width = -((-luma_width )>>log2_chroma_w) /** * Amount to shift the luma height right to find the chroma height. * For YV12 this is 1 for example. * chroma_height= -((-luma_height) >> log2_chroma_h) * The note above is needed to ensure rounding up. * This value only refers to the chroma components. */ uint8_t log2_chroma_h; uint8_t flags; /** * Parameters that describe how pixels are packed. If the format * has chroma components, they must be stored in comp[1] and * comp[2]. */ AVComponentDescriptor comp[4]; }AVPixFmtDescriptor; #define PIX_FMT_BE 1 ///< Pixel format is big-endian. #define PIX_FMT_PAL 2 ///< Pixel format has a palette in data[1], values are indexes in this palette. #define PIX_FMT_BITSTREAM 4 ///< All values of a component are bit-wise packed end to end. #define PIX_FMT_HWACCEL 8 ///< Pixel format is an HW accelerated format. /** * The array of all the pixel format descriptors. */ extern const AVPixFmtDescriptor av_pix_fmt_descriptors[]; /** * Read a line from an image, and write the values of the * pixel format component c to dst. * * @param data the array containing the pointers to the planes of the image * @param linesize the array containing the linesizes of the image * @param desc the pixel format descriptor for the image * @param x the horizontal coordinate of the first pixel to read * @param y the vertical coordinate of the first pixel to read * @param w the width of the line to read, that is the number of * values to write to dst * @param read_pal_component if not zero and the format is a paletted * format writes the values corresponding to the palette * component c in data[1] to dst, rather than the palette indexes in * data[0]. The behavior is undefined if the format is not paletted. */ void av_read_image_line(uint16_t *dst, const uint8_t *data[4], const int linesize[4], const AVPixFmtDescriptor *desc, int x, int y, int c, int w, int read_pal_component); /** * Write the values from src to the pixel format component c of an * image line. * * @param src array containing the values to write * @param data the array containing the pointers to the planes of the * image to write into. It is supposed to be zeroed. * @param linesize the array containing the linesizes of the image * @param desc the pixel format descriptor for the image * @param x the horizontal coordinate of the first pixel to write * @param y the vertical coordinate of the first pixel to write * @param w the width of the line to write, that is the number of * values to write to the image line */ void av_write_image_line(const uint16_t *src, uint8_t *data[4], const int linesize[4], const AVPixFmtDescriptor *desc, int x, int y, int c, int w); /** * Return the pixel format corresponding to name. * * If there is no pixel format with name name, then looks for a * pixel format with the name corresponding to the native endian * format of name. * For example in a little-endian system, first looks for "gray16", * then for "gray16le". * * Finally if no pixel format has been found, returns PIX_FMT_NONE. */ enum PixelFormat av_get_pix_fmt(const char *name); /** * Return the short name for a pixel format, NULL in case pix_fmt is * unknown. * * @see av_get_pix_fmt(), av_get_pix_fmt_string() */ const char *av_get_pix_fmt_name(enum PixelFormat pix_fmt); /** * Print in buf the string corresponding to the pixel format with * number pix_fmt, or an header if pix_fmt is negative. * * @param buf the buffer where to write the string * @param buf_size the size of buf * @param pix_fmt the number of the pixel format to print the * corresponding info string, or a negative value to print the * corresponding header. */ char *av_get_pix_fmt_string (char *buf, int buf_size, enum PixelFormat pix_fmt); /** * Return the number of bits per pixel used by the pixel format * described by pixdesc. * * The returned number of bits refers to the number of bits actually * used for storing the pixel information, that is padding bits are * not counted. */ int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); #endif /* AVUTIL_PIXDESC_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/pixfmt.h000066400000000000000000000310501317340345000206530ustar00rootroot00000000000000/* * copyright (c) 2006 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_PIXFMT_H #define AVUTIL_PIXFMT_H /** * @file * pixel format definitions * * @warning This file has to be considered an internal but installed * header, so it should not be directly included in your projects. */ #include "libavutil/avconfig.h" /** * Pixel format. Notes: * * PIX_FMT_RGB32 is handled in an endian-specific manner. An RGBA * color is put together as: * (A << 24) | (R << 16) | (G << 8) | B * This is stored as BGRA on little-endian CPU architectures and ARGB on * big-endian CPUs. * * When the pixel format is palettized RGB (PIX_FMT_PAL8), the palettized * image data is stored in AVFrame.data[0]. The palette is transported in * AVFrame.data[1], is 1024 bytes long (256 4-byte entries) and is * formatted the same as in PIX_FMT_RGB32 described above (i.e., it is * also endian-specific). Note also that the individual RGB palette * components stored in AVFrame.data[1] should be in the range 0..255. * This is important as many custom PAL8 video codecs that were designed * to run on the IBM VGA graphics adapter use 6-bit palette components. * * For all the 8bit per pixel formats, an RGB32 palette is in data[1] like * for pal8. This palette is filled in automatically by the function * allocating the picture. * * Note, make sure that all newly added big endian formats have pix_fmt&1==1 * and that all newly added little endian formats have pix_fmt&1==0 * this allows simpler detection of big vs little endian. */ enum PixelFormat { PIX_FMT_NONE= -1, PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) PIX_FMT_YUYV422, ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr PIX_FMT_RGB24, ///< packed RGB 8:8:8, 24bpp, RGBRGB... PIX_FMT_BGR24, ///< packed RGB 8:8:8, 24bpp, BGRBGR... PIX_FMT_YUV422P, ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) PIX_FMT_YUV444P, ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples) PIX_FMT_YUV410P, ///< planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples) PIX_FMT_YUV411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) PIX_FMT_GRAY8, ///< Y , 8bpp PIX_FMT_MONOWHITE, ///< Y , 1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb PIX_FMT_PAL8, ///< 8 bit with PIX_FMT_RGB32 palette PIX_FMT_YUVJ420P, ///< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV420P and setting color_range PIX_FMT_YUVJ422P, ///< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV422P and setting color_range PIX_FMT_YUVJ444P, ///< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV444P and setting color_range PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing PIX_FMT_XVMC_MPEG2_IDCT, PIX_FMT_UYVY422, ///< packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 PIX_FMT_UYYVYY411, ///< packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3 PIX_FMT_BGR8, ///< packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb) PIX_FMT_BGR4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1B 2G 1R(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits PIX_FMT_BGR4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb) PIX_FMT_RGB8, ///< packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb) PIX_FMT_RGB4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1R 2G 1B(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits PIX_FMT_RGB4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1R 2G 1B(lsb) PIX_FMT_NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) PIX_FMT_NV21, ///< as above, but U and V bytes are swapped PIX_FMT_ARGB, ///< packed ARGB 8:8:8:8, 32bpp, ARGBARGB... PIX_FMT_RGBA, ///< packed RGBA 8:8:8:8, 32bpp, RGBARGBA... PIX_FMT_ABGR, ///< packed ABGR 8:8:8:8, 32bpp, ABGRABGR... PIX_FMT_BGRA, ///< packed BGRA 8:8:8:8, 32bpp, BGRABGRA... PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian PIX_FMT_YUV440P, ///< planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples) PIX_FMT_YUVJ440P, ///< planar YUV 4:4:0 full scale (JPEG), deprecated in favor of PIX_FMT_YUV440P and setting color_range PIX_FMT_YUVA420P, ///< planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples) PIX_FMT_VDPAU_H264,///< H.264 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers PIX_FMT_VDPAU_MPEG1,///< MPEG-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers PIX_FMT_VDPAU_MPEG2,///< MPEG-2 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers PIX_FMT_VDPAU_WMV3,///< WMV3 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers PIX_FMT_VDPAU_VC1, ///< VC-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers PIX_FMT_RGB48BE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as big-endian PIX_FMT_RGB48LE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as little-endian PIX_FMT_RGB565BE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian PIX_FMT_RGB565LE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian PIX_FMT_RGB555BE, ///< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), big-endian, most significant bit to 0 PIX_FMT_RGB555LE, ///< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), little-endian, most significant bit to 0 PIX_FMT_BGR565BE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), big-endian PIX_FMT_BGR565LE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), little-endian PIX_FMT_BGR555BE, ///< packed BGR 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), big-endian, most significant bit to 1 PIX_FMT_BGR555LE, ///< packed BGR 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), little-endian, most significant bit to 1 PIX_FMT_VAAPI_MOCO, ///< HW acceleration through VA API at motion compensation entry-point, Picture.data[3] contains a vaapi_render_state struct which contains macroblocks as well as various fields extracted from headers PIX_FMT_VAAPI_IDCT, ///< HW acceleration through VA API at IDCT entry-point, Picture.data[3] contains a vaapi_render_state struct which contains fields extracted from headers PIX_FMT_VAAPI_VLD, ///< HW decoding through VA API, Picture.data[3] contains a vaapi_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers PIX_FMT_YUV420P16LE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian PIX_FMT_YUV420P16BE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian PIX_FMT_YUV422P16LE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian PIX_FMT_YUV422P16BE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian PIX_FMT_YUV444P16LE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian PIX_FMT_YUV444P16BE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian PIX_FMT_VDPAU_MPEG4, ///< MPEG4 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers PIX_FMT_DXVA2_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer PIX_FMT_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), little-endian, most significant bits to 0 PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), big-endian, most significant bits to 0 PIX_FMT_BGR444LE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), little-endian, most significant bits to 1 PIX_FMT_BGR444BE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), big-endian, most significant bits to 1 PIX_FMT_GRAY8A, ///< 8bit gray, 8bit alpha PIX_FMT_BGR48BE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as big-endian PIX_FMT_BGR48LE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as little-endian //the following 10 formats have the disadvantage of needing 1 format for each bit depth, thus //If you want to support multiple bit depths, then using PIX_FMT_YUV420P16* with the bpp stored seperately //is better PIX_FMT_YUV420P9BE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian PIX_FMT_YUV420P9LE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian PIX_FMT_YUV420P10BE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian PIX_FMT_YUV420P10LE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian PIX_FMT_YUV422P10BE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian PIX_FMT_YUV422P10LE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian PIX_FMT_YUV444P9BE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian PIX_FMT_YUV444P9LE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian PIX_FMT_YUV444P10BE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian PIX_FMT_YUV444P10LE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions }; #define PIX_FMT_Y400A PIX_FMT_GRAY8A #if AV_HAVE_BIGENDIAN # define PIX_FMT_NE(be, le) PIX_FMT_##be #else # define PIX_FMT_NE(be, le) PIX_FMT_##le #endif #define PIX_FMT_RGB32 PIX_FMT_NE(ARGB, BGRA) #define PIX_FMT_RGB32_1 PIX_FMT_NE(RGBA, ABGR) #define PIX_FMT_BGR32 PIX_FMT_NE(ABGR, RGBA) #define PIX_FMT_BGR32_1 PIX_FMT_NE(BGRA, ARGB) #define PIX_FMT_GRAY16 PIX_FMT_NE(GRAY16BE, GRAY16LE) #define PIX_FMT_RGB48 PIX_FMT_NE(RGB48BE, RGB48LE) #define PIX_FMT_RGB565 PIX_FMT_NE(RGB565BE, RGB565LE) #define PIX_FMT_RGB555 PIX_FMT_NE(RGB555BE, RGB555LE) #define PIX_FMT_RGB444 PIX_FMT_NE(RGB444BE, RGB444LE) #define PIX_FMT_BGR48 PIX_FMT_NE(BGR48BE, BGR48LE) #define PIX_FMT_BGR565 PIX_FMT_NE(BGR565BE, BGR565LE) #define PIX_FMT_BGR555 PIX_FMT_NE(BGR555BE, BGR555LE) #define PIX_FMT_BGR444 PIX_FMT_NE(BGR444BE, BGR444LE) #define PIX_FMT_YUV420P9 PIX_FMT_NE(YUV420P9BE , YUV420P9LE) #define PIX_FMT_YUV444P9 PIX_FMT_NE(YUV444P9BE , YUV444P9LE) #define PIX_FMT_YUV420P10 PIX_FMT_NE(YUV420P10BE, YUV420P10LE) #define PIX_FMT_YUV422P10 PIX_FMT_NE(YUV422P10BE, YUV422P10LE) #define PIX_FMT_YUV444P10 PIX_FMT_NE(YUV444P10BE, YUV444P10LE) #define PIX_FMT_YUV420P16 PIX_FMT_NE(YUV420P16BE, YUV420P16LE) #define PIX_FMT_YUV422P16 PIX_FMT_NE(YUV422P16BE, YUV422P16LE) #define PIX_FMT_YUV444P16 PIX_FMT_NE(YUV444P16BE, YUV444P16LE) #endif /* AVUTIL_PIXFMT_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/random_seed.h000066400000000000000000000024571317340345000216350ustar00rootroot00000000000000/* * Copyright (c) 2009 Baptiste Coudurier * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_RANDOM_SEED_H #define AVUTIL_RANDOM_SEED_H #include /** * Get a seed to use in conjunction with random functions. * This function tries to provide a good seed at a best effort bases. * Its possible to call this function multiple times if more bits are needed. * It can be quite slow, which is why it should only be used as seed for a faster * PRNG. The quality of the seed depends on the platform. */ uint32_t av_get_random_seed(void); #endif /* AVUTIL_RANDOM_SEED_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/rational.h000066400000000000000000000071541317340345000211650ustar00rootroot00000000000000/* * rational numbers * Copyright (c) 2003 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * rational numbers * @author Michael Niedermayer */ #ifndef AVUTIL_RATIONAL_H #define AVUTIL_RATIONAL_H #include #include #include "attributes.h" /** * rational number numerator/denominator */ typedef struct AVRational{ int num; ///< numerator int den; ///< denominator } AVRational; /** * Compare two rationals. * @param a first rational * @param b second rational * @return 0 if a==b, 1 if a>b, -1 if a>63)|1; else if(b.den && a.den) return 0; else if(a.num && b.num) return (a.num>>31) - (b.num>>31); else return INT_MIN; } /** * Convert rational to double. * @param a rational to convert * @return (double) a */ static inline double av_q2d(AVRational a){ return a.num / (double) a.den; } /** * Reduce a fraction. * This is useful for framerate calculations. * @param dst_num destination numerator * @param dst_den destination denominator * @param num source numerator * @param den source denominator * @param max the maximum allowed for dst_num & dst_den * @return 1 if exact, 0 otherwise */ int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max); /** * Multiply two rationals. * @param b first rational * @param c second rational * @return b*c */ AVRational av_mul_q(AVRational b, AVRational c) av_const; /** * Divide one rational by another. * @param b first rational * @param c second rational * @return b/c */ AVRational av_div_q(AVRational b, AVRational c) av_const; /** * Add two rationals. * @param b first rational * @param c second rational * @return b+c */ AVRational av_add_q(AVRational b, AVRational c) av_const; /** * Subtract one rational from another. * @param b first rational * @param c second rational * @return b-c */ AVRational av_sub_q(AVRational b, AVRational c) av_const; /** * Convert a double precision floating point number to a rational. * inf is expressed as {1,0} or {-1,0} depending on the sign. * * @param d double to convert * @param max the maximum allowed numerator and denominator * @return (AVRational) d */ AVRational av_d2q(double d, int max) av_const; /** * @return 1 if q1 is nearer to q than q2, -1 if q2 is nearer * than q1, 0 if they have the same distance. */ int av_nearer_q(AVRational q, AVRational q1, AVRational q2); /** * Find the nearest value in q_list to q. * @param q_list an array of rationals terminated by {0, 0} * @return the index of the nearest value found in the array */ int av_find_nearest_q_idx(AVRational q, const AVRational* q_list); #endif /* AVUTIL_RATIONAL_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/samplefmt.h000066400000000000000000000107571317340345000213470ustar00rootroot00000000000000/* * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_SAMPLEFMT_H #define AVUTIL_SAMPLEFMT_H #include "avutil.h" /** * all in native-endian format */ enum AVSampleFormat { AV_SAMPLE_FMT_NONE = -1, AV_SAMPLE_FMT_U8, ///< unsigned 8 bits AV_SAMPLE_FMT_S16, ///< signed 16 bits AV_SAMPLE_FMT_S32, ///< signed 32 bits AV_SAMPLE_FMT_FLT, ///< float AV_SAMPLE_FMT_DBL, ///< double AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically }; /** * Return the name of sample_fmt, or NULL if sample_fmt is not * recognized. */ const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt); /** * Return a sample format corresponding to name, or AV_SAMPLE_FMT_NONE * on error. */ enum AVSampleFormat av_get_sample_fmt(const char *name); /** * Generate a string corresponding to the sample format with * sample_fmt, or a header if sample_fmt is negative. * * @param buf the buffer where to write the string * @param buf_size the size of buf * @param sample_fmt the number of the sample format to print the * corresponding info string, or a negative value to print the * corresponding header. * @return the pointer to the filled buffer or NULL if sample_fmt is * unknown or in case of other errors */ char *av_get_sample_fmt_string(char *buf, int buf_size, enum AVSampleFormat sample_fmt); #if FF_API_GET_BITS_PER_SAMPLE_FMT /** * @deprecated Use av_get_bytes_per_sample() instead. */ attribute_deprecated int av_get_bits_per_sample_fmt(enum AVSampleFormat sample_fmt); #endif /** * Return number of bytes per sample. * * @param sample_fmt the sample format * @return number of bytes per sample or zero if unknown for the given * sample format */ int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt); /** * Fill channel data pointers and linesizes for samples with sample * format sample_fmt. * * The pointers array is filled with the pointers to the samples data: * for planar, set the start point of each plane's data within the buffer, * for packed, set the start point of the entire buffer only. * * The linesize array is filled with the aligned size of each samples * plane, that is linesize[i] will contain the linesize of the plane i, * and will be zero for all the unused planes. All linesize values are * equal. * * @param pointers array to be filled with the pointer for each plane, may be NULL * @param linesizes array to be filled with the linesize, may be NULL * @param buf the pointer to a buffer containing the samples * @param nb_samples the number of samples in a single channel * @param planar 1 if the samples layout is planar, 0 if it is packed * @param nb_channels the number of channels * @return the total size of the buffer, a negative * error code in case of failure */ int av_samples_fill_arrays(uint8_t *pointers[8], int linesizes[8], uint8_t *buf, int nb_channels, int nb_samples, enum AVSampleFormat sample_fmt, int planar, int align); /** * Allocate a samples buffer for nb_samples samples, and * fill pointers and linesizes accordingly. * The allocated samples buffer has to be freed by using * av_freep(&pointers[0]). * * @param nb_channels number of audio channels * @param nb_samples number of samples per channel * @param planar 1 if the samples layout is planar, 0 if packed, * @param align the value to use for buffer size alignment * @return the size in bytes required for the samples buffer, a negative * error code in case of failure * @see av_samples_fill_arrays() */ int av_samples_alloc(uint8_t *pointers[8], int linesizes[8], int nb_channels, int nb_samples, enum AVSampleFormat sample_fmt, int planar, int align); #endif /* AVCORE_SAMPLEFMT_H */ IanniX-0.9.20/gui/qffmpeg/libavutil/sha.h000066400000000000000000000032751317340345000201270ustar00rootroot00000000000000/* * Copyright (C) 2007 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVUTIL_SHA_H #define AVUTIL_SHA_H #include extern const int av_sha_size; struct AVSHA; /** * Initialize SHA-1 or SHA-2 hashing. * * @param context pointer to the function context (of size av_sha_size) * @param bits number of bits in digest (SHA-1 - 160 bits, SHA-2 224 or 256 bits) * @return zero if initialization succeeded, -1 otherwise */ int av_sha_init(struct AVSHA* context, int bits); /** * Update hash value. * * @param context hash function context * @param data input data to update hash with * @param len input data length */ void av_sha_update(struct AVSHA* context, const uint8_t* data, unsigned int len); /** * Finish hashing and output digest value. * * @param context hash function context * @param digest buffer where output digest value is stored */ void av_sha_final(struct AVSHA* context, uint8_t *digest); #endif /* AVUTIL_SHA_H */ IanniX-0.9.20/gui/qffmpeg/libswscale/000077500000000000000000000000001317340345000173315ustar00rootroot00000000000000IanniX-0.9.20/gui/qffmpeg/libswscale/swscale.h000066400000000000000000000302111317340345000211400ustar00rootroot00000000000000/* * Copyright (C) 2001-2003 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SWSCALE_SWSCALE_H #define SWSCALE_SWSCALE_H /** * @file * @brief * external api for the swscale stuff */ #include "libavutil/avutil.h" #include "libavutil/log.h" #include "libavutil/pixfmt.h" #define LIBSWSCALE_VERSION_MAJOR 2 #define LIBSWSCALE_VERSION_MINOR 1 #define LIBSWSCALE_VERSION_MICRO 0 #define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \ LIBSWSCALE_VERSION_MINOR, \ LIBSWSCALE_VERSION_MICRO) #define LIBSWSCALE_VERSION AV_VERSION(LIBSWSCALE_VERSION_MAJOR, \ LIBSWSCALE_VERSION_MINOR, \ LIBSWSCALE_VERSION_MICRO) #define LIBSWSCALE_BUILD LIBSWSCALE_VERSION_INT #define LIBSWSCALE_IDENT "SwS" AV_STRINGIFY(LIBSWSCALE_VERSION) /** * Those FF_API_* defines are not part of public API. * They may change, break or disappear at any time. */ #ifndef FF_API_SWS_GETCONTEXT #define FF_API_SWS_GETCONTEXT (LIBSWSCALE_VERSION_MAJOR < 3) #endif #ifndef FF_API_SWS_CPU_CAPS #define FF_API_SWS_CPU_CAPS (LIBSWSCALE_VERSION_MAJOR < 3) #endif #ifndef FF_API_SWS_FORMAT_NAME #define FF_API_SWS_FORMAT_NAME (LIBSWSCALE_VERSION_MAJOR < 3) #endif /** * Returns the LIBSWSCALE_VERSION_INT constant. */ unsigned swscale_version(void); /** * Returns the libswscale build-time configuration. */ const char *swscale_configuration(void); /** * Returns the libswscale license. */ const char *swscale_license(void); /* values for the flags, the stuff on the command line is different */ #define SWS_FAST_BILINEAR 1 #define SWS_BILINEAR 2 #define SWS_BICUBIC 4 #define SWS_X 8 #define SWS_POINT 0x10 #define SWS_AREA 0x20 #define SWS_BICUBLIN 0x40 #define SWS_GAUSS 0x80 #define SWS_SINC 0x100 #define SWS_LANCZOS 0x200 #define SWS_SPLINE 0x400 #define SWS_SRC_V_CHR_DROP_MASK 0x30000 #define SWS_SRC_V_CHR_DROP_SHIFT 16 #define SWS_PARAM_DEFAULT 123456 #define SWS_PRINT_INFO 0x1000 //the following 3 flags are not completely implemented //internal chrominace subsampling info #define SWS_FULL_CHR_H_INT 0x2000 //input subsampling info #define SWS_FULL_CHR_H_INP 0x4000 #define SWS_DIRECT_BGR 0x8000 #define SWS_ACCURATE_RND 0x40000 #define SWS_BITEXACT 0x80000 #if FF_API_SWS_CPU_CAPS /** * CPU caps are autodetected now, those flags * are only provided for API compatibility. */ #define SWS_CPU_CAPS_MMX 0x80000000 #define SWS_CPU_CAPS_MMX2 0x20000000 #define SWS_CPU_CAPS_3DNOW 0x40000000 #define SWS_CPU_CAPS_ALTIVEC 0x10000000 #define SWS_CPU_CAPS_BFIN 0x01000000 #define SWS_CPU_CAPS_SSE2 0x02000000 #endif #define SWS_MAX_REDUCE_CUTOFF 0.002 #define SWS_CS_ITU709 1 #define SWS_CS_FCC 4 #define SWS_CS_ITU601 5 #define SWS_CS_ITU624 5 #define SWS_CS_SMPTE170M 5 #define SWS_CS_SMPTE240M 7 #define SWS_CS_DEFAULT 5 /** * Returns a pointer to yuv<->rgb coefficients for the given colorspace * suitable for sws_setColorspaceDetails(). * * @param colorspace One of the SWS_CS_* macros. If invalid, * SWS_CS_DEFAULT is used. */ const int *sws_getCoefficients(int colorspace); // when used for filters they must have an odd number of elements // coeffs cannot be shared between vectors typedef struct { double *coeff; ///< pointer to the list of coefficients int length; ///< number of coefficients in the vector } SwsVector; // vectors can be shared typedef struct { SwsVector *lumH; SwsVector *lumV; SwsVector *chrH; SwsVector *chrV; } SwsFilter; struct SwsContext; /** * Returns a positive value if pix_fmt is a supported input format, 0 * otherwise. */ int sws_isSupportedInput(enum PixelFormat pix_fmt); /** * Returns a positive value if pix_fmt is a supported output format, 0 * otherwise. */ int sws_isSupportedOutput(enum PixelFormat pix_fmt); /** * Allocates an empty SwsContext. This must be filled and passed to * sws_init_context(). For filling see AVOptions, options.c and * sws_setColorspaceDetails(). */ struct SwsContext *sws_alloc_context(void); /** * Initializes the swscaler context sws_context. * * @return zero or positive value on success, a negative value on * error */ int sws_init_context(struct SwsContext *sws_context, SwsFilter *srcFilter, SwsFilter *dstFilter); /** * Frees the swscaler context swsContext. * If swsContext is NULL, then does nothing. */ void sws_freeContext(struct SwsContext *swsContext); #if FF_API_SWS_GETCONTEXT /** * Allocates and returns a SwsContext. You need it to perform * scaling/conversion operations using sws_scale(). * * @param srcW the width of the source image * @param srcH the height of the source image * @param srcFormat the source image format * @param dstW the width of the destination image * @param dstH the height of the destination image * @param dstFormat the destination image format * @param flags specify which algorithm and options to use for rescaling * @return a pointer to an allocated context, or NULL in case of error * @note this function is to be removed after a saner alternative is * written * @deprecated Use sws_getCachedContext() instead. */ struct SwsContext *sws_getContext(int srcW, int srcH, enum PixelFormat srcFormat, int dstW, int dstH, enum PixelFormat dstFormat, int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param); #endif /** * Scales the image slice in srcSlice and puts the resulting scaled * slice in the image in dst. A slice is a sequence of consecutive * rows in an image. * * Slices have to be provided in sequential order, either in * top-bottom or bottom-top order. If slices are provided in * non-sequential order the behavior of the function is undefined. * * @param c the scaling context previously created with * sws_getContext() * @param srcSlice the array containing the pointers to the planes of * the source slice * @param srcStride the array containing the strides for each plane of * the source image * @param srcSliceY the position in the source image of the slice to * process, that is the number (counted starting from * zero) in the image of the first row of the slice * @param srcSliceH the height of the source slice, that is the number * of rows in the slice * @param dst the array containing the pointers to the planes of * the destination image * @param dstStride the array containing the strides for each plane of * the destination image * @return the height of the output slice */ int sws_scale(struct SwsContext *c, const uint8_t* const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t* const dst[], const int dstStride[]); /** * @param inv_table the yuv2rgb coefficients, normally ff_yuv2rgb_coeffs[x] * @return -1 if not supported */ int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4], int srcRange, const int table[4], int dstRange, int brightness, int contrast, int saturation); /** * @return -1 if not supported */ int sws_getColorspaceDetails(struct SwsContext *c, int **inv_table, int *srcRange, int **table, int *dstRange, int *brightness, int *contrast, int *saturation); /** * Allocates and returns an uninitialized vector with length coefficients. */ SwsVector *sws_allocVec(int length); /** * Returns a normalized Gaussian curve used to filter stuff * quality=3 is high quality, lower is lower quality. */ SwsVector *sws_getGaussianVec(double variance, double quality); /** * Allocates and returns a vector with length coefficients, all * with the same value c. */ SwsVector *sws_getConstVec(double c, int length); /** * Allocates and returns a vector with just one coefficient, with * value 1.0. */ SwsVector *sws_getIdentityVec(void); /** * Scales all the coefficients of a by the scalar value. */ void sws_scaleVec(SwsVector *a, double scalar); /** * Scales all the coefficients of a so that their sum equals height. */ void sws_normalizeVec(SwsVector *a, double height); void sws_convVec(SwsVector *a, SwsVector *b); void sws_addVec(SwsVector *a, SwsVector *b); void sws_subVec(SwsVector *a, SwsVector *b); void sws_shiftVec(SwsVector *a, int shift); /** * Allocates and returns a clone of the vector a, that is a vector * with the same coefficients as a. */ SwsVector *sws_cloneVec(SwsVector *a); /** * Prints with av_log() a textual representation of the vector a * if log_level <= av_log_level. */ void sws_printVec2(SwsVector *a, AVClass *log_ctx, int log_level); void sws_freeVec(SwsVector *a); SwsFilter *sws_getDefaultFilter(float lumaGBlur, float chromaGBlur, float lumaSharpen, float chromaSharpen, float chromaHShift, float chromaVShift, int verbose); void sws_freeFilter(SwsFilter *filter); /** * Checks if context can be reused, otherwise reallocates a new * one. * * If context is NULL, just calls sws_getContext() to get a new * context. Otherwise, checks if the parameters are the ones already * saved in context. If that is the case, returns the current * context. Otherwise, frees context and gets a new context with * the new parameters. * * Be warned that srcFilter and dstFilter are not checked, they * are assumed to remain the same. */ struct SwsContext *sws_getCachedContext(struct SwsContext *context, int srcW, int srcH, enum PixelFormat srcFormat, int dstW, int dstH, enum PixelFormat dstFormat, int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param); /** * Converts an 8bit paletted frame into a frame with a color depth of 32-bits. * * The output frame will have the same packed format as the palette. * * @param src source frame buffer * @param dst destination frame buffer * @param num_pixels number of pixels to convert * @param palette array with [256] entries, which must match color arrangement (RGB or BGR) of src */ void sws_convertPalette8ToPacked32(const uint8_t *src, uint8_t *dst, int num_pixels, const uint8_t *palette); /** * Converts an 8bit paletted frame into a frame with a color depth of 24 bits. * * With the palette format "ABCD", the destination frame ends up with the format "ABC". * * @param src source frame buffer * @param dst destination frame buffer * @param num_pixels number of pixels to convert * @param palette array with [256] entries, which must match color arrangement (RGB or BGR) of src */ void sws_convertPalette8ToPacked24(const uint8_t *src, uint8_t *dst, int num_pixels, const uint8_t *palette); /** * Get the AVClass for swsContext. It can be used in combination with * AV_OPT_SEARCH_FAKE_OBJ for examining options. * * @see av_opt_find(). */ const AVClass *sws_get_class(void); #endif /* SWSCALE_SWSCALE_H */ IanniX-0.9.20/gui/qjsedit/000077500000000000000000000000001317340345000152175ustar00rootroot00000000000000IanniX-0.9.20/gui/qjsedit/jsedit.cpp000066400000000000000000000740171317340345000172160ustar00rootroot00000000000000/* This file is part of the Ofi Labs X2 project. Copyright (C) 2010 Ariya Hidayat Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "jsedit.h" #include class JSBlockData: public QTextBlockUserData { public: QList bracketPositions; }; class JSHighlighter : public QSyntaxHighlighter { public: JSHighlighter(QTextDocument *parent = 0); void setColor(JSEdit::ColorComponent component, const QColor &color); void mark(const QString &str, Qt::CaseSensitivity caseSensitivity); protected: void highlightBlock(const QString &text); private: QSet m_keywords; QSet m_knownIds; QHash m_colors; QString m_markString; Qt::CaseSensitivity m_markCaseSensitivity; }; JSHighlighter::JSHighlighter(QTextDocument *parent) : QSyntaxHighlighter(parent) , m_markCaseSensitivity(Qt::CaseInsensitive) { // default color scheme m_colors[JSEdit::Normal] = QColor("#000000"); m_colors[JSEdit::Comment] = QColor("#808080"); m_colors[JSEdit::Number] = QColor("#008000"); m_colors[JSEdit::String] = QColor("#800000"); m_colors[JSEdit::Operator] = QColor("#808000"); m_colors[JSEdit::Identifier] = QColor("#000020"); m_colors[JSEdit::Keyword] = QColor("#000080"); m_colors[JSEdit::BuiltIn] = QColor("#008080"); m_colors[JSEdit::Marker] = QColor("#ffff00"); // https://developer.mozilla.org/en/JavaScript/Reference/Reserved_Words m_keywords << "break"; m_keywords << "case"; m_keywords << "catch"; m_keywords << "continue"; m_keywords << "default"; m_keywords << "delete"; m_keywords << "do"; m_keywords << "else"; m_keywords << "finally"; m_keywords << "for"; m_keywords << "function"; m_keywords << "if"; m_keywords << "in"; m_keywords << "instanceof"; m_keywords << "new"; m_keywords << "return"; m_keywords << "switch"; m_keywords << "this"; m_keywords << "throw"; m_keywords << "try"; m_keywords << "typeof"; m_keywords << "var"; m_keywords << "void"; m_keywords << "while"; m_keywords << "with"; m_keywords << "true"; m_keywords << "false"; m_keywords << "null"; // built-in and other popular objects + properties m_knownIds << "Object"; m_knownIds << "prototype"; m_knownIds << "create"; m_knownIds << "defineProperty"; m_knownIds << "defineProperties"; m_knownIds << "getOwnPropertyDescriptor"; m_knownIds << "keys"; m_knownIds << "getOwnPropertyNames"; m_knownIds << "constructor"; m_knownIds << "__parent__"; m_knownIds << "__proto__"; m_knownIds << "__defineGetter__"; m_knownIds << "__defineSetter__"; m_knownIds << "eval"; m_knownIds << "hasOwnProperty"; m_knownIds << "isPrototypeOf"; m_knownIds << "__lookupGetter__"; m_knownIds << "__lookupSetter__"; m_knownIds << "__noSuchMethod__"; m_knownIds << "propertyIsEnumerable"; m_knownIds << "toSource"; m_knownIds << "toLocaleString"; m_knownIds << "toString"; m_knownIds << "unwatch"; m_knownIds << "valueOf"; m_knownIds << "watch"; m_knownIds << "Function"; m_knownIds << "arguments"; m_knownIds << "arity"; m_knownIds << "caller"; m_knownIds << "constructor"; m_knownIds << "length"; m_knownIds << "name"; m_knownIds << "apply"; m_knownIds << "bind"; m_knownIds << "call"; m_knownIds << "String"; m_knownIds << "fromCharCode"; m_knownIds << "length"; m_knownIds << "charAt"; m_knownIds << "charCodeAt"; m_knownIds << "concat"; m_knownIds << "indexOf"; m_knownIds << "lastIndexOf"; m_knownIds << "localCompare"; m_knownIds << "match"; m_knownIds << "quote"; m_knownIds << "replace"; m_knownIds << "search"; m_knownIds << "slice"; m_knownIds << "split"; m_knownIds << "substr"; m_knownIds << "substring"; m_knownIds << "toLocaleLowerCase"; m_knownIds << "toLocaleUpperCase"; m_knownIds << "toLowerCase"; m_knownIds << "toUpperCase"; m_knownIds << "trim"; m_knownIds << "trimLeft"; m_knownIds << "trimRight"; m_knownIds << "Array"; m_knownIds << "isArray"; m_knownIds << "index"; m_knownIds << "input"; m_knownIds << "pop"; m_knownIds << "push"; m_knownIds << "reverse"; m_knownIds << "shift"; m_knownIds << "sort"; m_knownIds << "splice"; m_knownIds << "unshift"; m_knownIds << "concat"; m_knownIds << "join"; m_knownIds << "filter"; m_knownIds << "forEach"; m_knownIds << "every"; m_knownIds << "map"; m_knownIds << "some"; m_knownIds << "reduce"; m_knownIds << "reduceRight"; m_knownIds << "RegExp"; m_knownIds << "global"; m_knownIds << "ignoreCase"; m_knownIds << "lastIndex"; m_knownIds << "multiline"; m_knownIds << "source"; m_knownIds << "exec"; m_knownIds << "test"; m_knownIds << "JSON"; m_knownIds << "parse"; m_knownIds << "stringify"; m_knownIds << "decodeURI"; m_knownIds << "decodeURIComponent"; m_knownIds << "encodeURI"; m_knownIds << "encodeURIComponent"; m_knownIds << "eval"; m_knownIds << "isFinite"; m_knownIds << "isNaN"; m_knownIds << "parseFloat"; m_knownIds << "parseInt"; m_knownIds << "Infinity"; m_knownIds << "NaN"; m_knownIds << "undefined"; m_knownIds << "Math"; m_knownIds << "E"; m_knownIds << "LN2"; m_knownIds << "LN10"; m_knownIds << "LOG2E"; m_knownIds << "LOG10E"; m_knownIds << "PI"; m_knownIds << "SQRT1_2"; m_knownIds << "SQRT2"; m_knownIds << "abs"; m_knownIds << "acos"; m_knownIds << "asin"; m_knownIds << "atan"; m_knownIds << "atan2"; m_knownIds << "ceil"; m_knownIds << "cos"; m_knownIds << "exp"; m_knownIds << "floor"; m_knownIds << "log"; m_knownIds << "max"; m_knownIds << "min"; m_knownIds << "pow"; m_knownIds << "random"; m_knownIds << "round"; m_knownIds << "sin"; m_knownIds << "sqrt"; m_knownIds << "tan"; m_knownIds << "document"; m_knownIds << "window"; m_knownIds << "navigator"; m_knownIds << "userAgent"; m_knownIds << "run"; } void JSHighlighter::setColor(JSEdit::ColorComponent component, const QColor &color) { m_colors[component] = color; rehighlight(); } void JSHighlighter::highlightBlock(const QString &text) { // parsing state enum { Start = 0, Number = 1, Identifier = 2, String = 3, Comment = 4, Regex = 5 }; QList bracketPositions; int blockState = previousBlockState(); int bracketLevel = blockState >> 4; int state = blockState & 15; if (blockState < 0) { bracketLevel = 0; state = Start; } int start = 0; int i = 0; while (i <= text.length()) { QChar ch = (i < text.length()) ? text.at(i) : QChar(); QChar next = (i < text.length() - 1) ? text.at(i + 1) : QChar(); switch (state) { case Start: start = i; if (ch.isSpace()) { ++i; } else if (ch.isDigit()) { ++i; state = Number; } else if (ch.isLetter() || ch == '_') { ++i; state = Identifier; } else if (ch == '\'' || ch == '\"') { ++i; state = String; } else if (ch == '/' && next == '*') { ++i; ++i; state = Comment; } else if (ch == '/' && next == '/') { i = text.length(); setFormat(start, text.length(), m_colors[JSEdit::Comment]); } else if (ch == '/' && next != '*') { ++i; state = Regex; } else { if (!QString("(){}[]").contains(ch)) setFormat(start, 1, m_colors[JSEdit::Operator]); if (ch =='{' || ch == '}') { bracketPositions += i; if (ch == '{') bracketLevel++; else bracketLevel--; } ++i; state = Start; } break; case Number: if (ch.isSpace() || !ch.isDigit()) { setFormat(start, i - start, m_colors[JSEdit::Number]); state = Start; } else { ++i; } break; case Identifier: if (ch.isSpace() || !(ch.isDigit() || ch.isLetter() || ch == '_')) { QString token = text.mid(start, i - start).trimmed(); if (m_keywords.contains(token)) setFormat(start, i - start, m_colors[JSEdit::Keyword]); else if (m_knownIds.contains(token)) setFormat(start, i - start, m_colors[JSEdit::BuiltIn]); state = Start; } else { ++i; } break; case String: if (ch == text.at(start)) { QChar prev = (i > 0) ? text.at(i - 1) : QChar(); if (prev != '\\') { ++i; setFormat(start, i - start, m_colors[JSEdit::String]); state = Start; } else { ++i; } } else { ++i; } break; case Comment: if (ch == '*' && next == '/') { ++i; ++i; setFormat(start, i - start, m_colors[JSEdit::Comment]); state = Start; } else { ++i; } break; case Regex: if (ch == '/') { QChar prev = (i > 0) ? text.at(i - 1) : QChar(); if (prev != '\\') { ++i; setFormat(start, i - start, m_colors[JSEdit::String]); state = Start; } else { ++i; } } else { ++i; } break; default: state = Start; break; } } if (state == Comment) setFormat(start, text.length(), m_colors[JSEdit::Comment]); else state = Start; if (!m_markString.isEmpty()) { int pos = 0; int len = m_markString.length(); QTextCharFormat markerFormat; markerFormat.setBackground(m_colors[JSEdit::Marker]); markerFormat.setForeground(m_colors[JSEdit::Normal]); for (;;) { pos = text.indexOf(m_markString, pos, m_markCaseSensitivity); if (pos < 0) break; setFormat(pos, len, markerFormat); ++pos; } } if (!bracketPositions.isEmpty()) { JSBlockData *blockData = reinterpret_cast(currentBlock().userData()); if (!blockData) { blockData = new JSBlockData; currentBlock().setUserData(blockData); } blockData->bracketPositions = bracketPositions; } blockState = (state & 15) | (bracketLevel << 4); setCurrentBlockState(blockState); } void JSHighlighter::mark(const QString &str, Qt::CaseSensitivity caseSensitivity) { m_markString = str; m_markCaseSensitivity = caseSensitivity; rehighlight(); } struct BlockInfo { int position; int number; bool foldable: 1; bool folded : 1; }; Q_DECLARE_TYPEINFO(BlockInfo, Q_PRIMITIVE_TYPE); class SidebarWidget : public QWidget { public: SidebarWidget(JSEdit *editor); QVector lineNumbers; QColor backgroundColor; QColor lineNumberColor; QColor indicatorColor; QColor foldIndicatorColor; QFont font; int foldIndicatorWidth; QPixmap rightArrowIcon; QPixmap downArrowIcon; protected: void mousePressEvent(QMouseEvent *event); void paintEvent(QPaintEvent *event); }; SidebarWidget::SidebarWidget(JSEdit *editor) : QWidget(editor) , foldIndicatorWidth(0) { backgroundColor = Qt::lightGray; lineNumberColor = Qt::black; indicatorColor = Qt::white; foldIndicatorColor = Qt::lightGray; } void SidebarWidget::mousePressEvent(QMouseEvent *event) { if (foldIndicatorWidth > 0) { int xofs = width() - foldIndicatorWidth; int lineNo = -1; int fh = fontMetrics().lineSpacing(); int ys = event->pos().y(); if (event->pos().x() > xofs) { foreach (BlockInfo ln, lineNumbers) if (ln.position < ys && (ln.position + fh) > ys) { if (ln.foldable) lineNo = ln.number; break; } } if (lineNo >= 0) { JSEdit *editor = qobject_cast(parent()); if (editor) editor->toggleFold(lineNo); } } } void SidebarWidget::paintEvent(QPaintEvent *event) { QPainter p(this); p.fillRect(event->rect(), backgroundColor); p.setPen(lineNumberColor); p.setFont(font); int fh = QFontMetrics(font).height(); foreach (BlockInfo ln, lineNumbers) p.drawText(0, ln.position, width() - 4 - foldIndicatorWidth, fh, Qt::AlignRight, QString::number(ln.number)); if (foldIndicatorWidth > 0) { int xofs = width() - foldIndicatorWidth; p.fillRect(xofs, 0, foldIndicatorWidth, height(), indicatorColor); // initialize (or recreate) the arrow icons whenever necessary if (foldIndicatorWidth != rightArrowIcon.width()) { QPainter iconPainter; QPolygonF polygon; int dim = foldIndicatorWidth; rightArrowIcon = QPixmap(dim, dim); rightArrowIcon.fill(Qt::transparent); downArrowIcon = rightArrowIcon; polygon << QPointF(dim * 0.4, dim * 0.25); polygon << QPointF(dim * 0.4, dim * 0.75); polygon << QPointF(dim * 0.8, dim * 0.5); iconPainter.begin(&rightArrowIcon); iconPainter.setRenderHint(QPainter::Antialiasing); iconPainter.setPen(Qt::NoPen); iconPainter.setBrush(foldIndicatorColor); iconPainter.drawPolygon(polygon); iconPainter.end(); polygon.clear(); polygon << QPointF(dim * 0.25, dim * 0.4); polygon << QPointF(dim * 0.75, dim * 0.4); polygon << QPointF(dim * 0.5, dim * 0.8); iconPainter.begin(&downArrowIcon); iconPainter.setRenderHint(QPainter::Antialiasing); iconPainter.setPen(Qt::NoPen); iconPainter.setBrush(foldIndicatorColor); iconPainter.drawPolygon(polygon); iconPainter.end(); } foreach (BlockInfo ln, lineNumbers) if (ln.foldable) { if (ln.folded) p.drawPixmap(xofs, ln.position, rightArrowIcon); else p.drawPixmap(xofs, ln.position, downArrowIcon); } } } static int findClosingMatch(const QTextDocument *doc, int cursorPosition) { QTextBlock block = doc->findBlock(cursorPosition); JSBlockData *blockData = reinterpret_cast(block.userData()); if (!blockData->bracketPositions.isEmpty()) { int depth = 1; while (block.isValid()) { blockData = reinterpret_cast(block.userData()); if (blockData && !blockData->bracketPositions.isEmpty()) { for (int c = 0; c < blockData->bracketPositions.count(); ++c) { int absPos = block.position() + blockData->bracketPositions.at(c); if (absPos <= cursorPosition) continue; if (doc->characterAt(absPos) == '{') depth++; else depth--; if (depth == 0) return absPos; } } block = block.next(); } } return -1; } static int findOpeningMatch(const QTextDocument *doc, int cursorPosition) { QTextBlock block = doc->findBlock(cursorPosition); JSBlockData *blockData = reinterpret_cast(block.userData()); if (!blockData->bracketPositions.isEmpty()) { int depth = 1; while (block.isValid()) { blockData = reinterpret_cast(block.userData()); if (blockData && !blockData->bracketPositions.isEmpty()) { for (int c = blockData->bracketPositions.count() - 1; c >= 0; --c) { int absPos = block.position() + blockData->bracketPositions.at(c); if (absPos >= cursorPosition - 1) continue; if (doc->characterAt(absPos) == '}') depth++; else depth--; if (depth == 0) return absPos; } } block = block.previous(); } } return -1; } class JSDocLayout: public QPlainTextDocumentLayout { public: JSDocLayout(QTextDocument *doc); void forceUpdate(); }; JSDocLayout::JSDocLayout(QTextDocument *doc) : QPlainTextDocumentLayout(doc) { } void JSDocLayout::forceUpdate() { emit documentSizeChanged(documentSize()); } class JSEditPrivate { public: JSEdit *editor; JSDocLayout *layout; JSHighlighter *highlighter; SidebarWidget *sidebar; bool showLineNumbers; bool textWrap; QColor cursorColor; bool bracketsMatching; QList matchPositions; QColor bracketMatchColor; QList errorPositions; QColor bracketErrorColor; bool codeFolding : 1; }; JSEdit::JSEdit(QWidget *parent) : QPlainTextEdit(parent) , d_ptr(new JSEditPrivate) { d_ptr->editor = this; d_ptr->layout = new JSDocLayout(document()); d_ptr->highlighter = new JSHighlighter(document()); d_ptr->sidebar = new SidebarWidget(this); d_ptr->showLineNumbers = true; d_ptr->textWrap = true; d_ptr->bracketsMatching = true; d_ptr->cursorColor = QColor(255, 255, 192); d_ptr->bracketMatchColor = QColor(180, 238, 180); d_ptr->bracketErrorColor = QColor(224, 128, 128); d_ptr->codeFolding = true; document()->setDocumentLayout(d_ptr->layout); connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateCursor())); connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateSidebar())); connect(this, SIGNAL(updateRequest(QRect, int)), this, SLOT(updateSidebar(QRect, int))); QFont textFont = font(); textFont.setPixelSize(12); #ifdef Q_OS_MAC textFont.setFamily("Monaco"); #endif #ifdef Q_OS_LINUX textFont.setFamily("Monospace"); #endif #ifdef Q_OS_WIN textFont.setFamily("Lucida Console"); #endif setFont(textFont); } JSEdit::~JSEdit() { delete d_ptr->layout; } void JSEdit::setColor(ColorComponent component, const QColor &color) { Q_D(JSEdit); if (component == Background) { QPalette pal = palette(); pal.setColor(QPalette::Base, color); setPalette(pal); d->sidebar->indicatorColor = color; updateSidebar(); } else if (component == Normal) { QPalette pal = palette(); pal.setColor(QPalette::Text, color); setPalette(pal); } else if (component == Sidebar) { d->sidebar->backgroundColor = color; updateSidebar(); } else if (component == LineNumber) { d->sidebar->lineNumberColor = color; updateSidebar(); } else if (component == Cursor) { d->cursorColor = color; updateCursor(); } else if (component == BracketMatch) { d->bracketMatchColor = color; updateCursor(); } else if (component == BracketError) { d->bracketErrorColor = color; updateCursor(); } else if (component == FoldIndicator) { d->sidebar->foldIndicatorColor = color; updateSidebar(); } else { d->highlighter->setColor(component, color); updateCursor(); } } bool JSEdit::isLineNumbersVisible() const { return d_ptr->showLineNumbers; } void JSEdit::setLineNumbersVisible(bool visible) { d_ptr->showLineNumbers = visible; updateSidebar(); } bool JSEdit::isTextWrapEnabled() const { return d_ptr->textWrap; } void JSEdit::setTextWrapEnabled(bool enable) { d_ptr->textWrap = enable; setLineWrapMode(enable ? WidgetWidth : NoWrap); } bool JSEdit::isBracketsMatchingEnabled() const { return d_ptr->bracketsMatching; } void JSEdit::setBracketsMatchingEnabled(bool enable) { d_ptr->bracketsMatching = enable; updateCursor(); } bool JSEdit::isCodeFoldingEnabled() const { return d_ptr->codeFolding; } void JSEdit::setCodeFoldingEnabled(bool enable) { d_ptr->codeFolding = enable; updateSidebar(); } static int findClosingConstruct(const QTextBlock &block) { if (!block.isValid()) return -1; JSBlockData *blockData = reinterpret_cast(block.userData()); if (!blockData) return -1; if (blockData->bracketPositions.isEmpty()) return -1; const QTextDocument *doc = block.document(); int offset = block.position(); foreach (int pos, blockData->bracketPositions) { int absPos = offset + pos; if (doc->characterAt(absPos) == '{') { int matchPos = findClosingMatch(doc, absPos); if (matchPos >= 0) return matchPos; } } return -1; } bool JSEdit::isFoldable(int line) const { int matchPos = findClosingConstruct(document()->findBlockByNumber(line - 1)); if (matchPos >= 0) { QTextBlock matchBlock = document()->findBlock(matchPos); if (matchBlock.isValid() && matchBlock.blockNumber() > line) return true; } return false; } bool JSEdit::isFolded(int line) const { QTextBlock block = document()->findBlockByNumber(line - 1); if (!block.isValid()) return false; block = block.next(); if (!block.isValid()) return false; return !block.isVisible(); } void JSEdit::fold(int line) { QTextBlock startBlock = document()->findBlockByNumber(line - 1); int endPos = findClosingConstruct(startBlock); if (endPos < 0) return; QTextBlock endBlock = document()->findBlock(endPos); QTextBlock block = startBlock.next(); while (block.isValid() && block != endBlock) { block.setVisible(false); block.setLineCount(0); block = block.next(); } document()->markContentsDirty(startBlock.position(), endPos - startBlock.position() + 1); updateSidebar(); update(); JSDocLayout *layout = reinterpret_cast(document()->documentLayout()); layout->forceUpdate(); } void JSEdit::unfold(int line) { QTextBlock startBlock = document()->findBlockByNumber(line - 1); int endPos = findClosingConstruct(startBlock); QTextBlock block = startBlock.next(); while (block.isValid() && !block.isVisible()) { block.setVisible(true); block.setLineCount(block.layout()->lineCount()); endPos = block.position() + block.length(); block = block.next(); } document()->markContentsDirty(startBlock.position(), endPos - startBlock.position() + 1); updateSidebar(); update(); JSDocLayout *layout = reinterpret_cast(document()->documentLayout()); layout->forceUpdate(); } void JSEdit::toggleFold(int line) { if (isFolded(line)) unfold(line); else fold(line); } void JSEdit::resizeEvent(QResizeEvent *e) { QPlainTextEdit::resizeEvent(e); updateSidebar(); } void JSEdit::wheelEvent(QWheelEvent *e) { if (e->modifiers() == Qt::ControlModifier) { int steps = e->delta() / 20; steps = qBound(-3, steps, 3); QFont textFont = font(); int pointSize = textFont.pointSize() + steps; pointSize = qBound(10, pointSize, 40); textFont.setPointSize(pointSize); setFont(textFont); updateSidebar(); e->accept(); return; } QPlainTextEdit::wheelEvent(e); } void JSEdit::updateCursor() { Q_D(JSEdit); if (isReadOnly()) { setExtraSelections(QList()); } else { d->matchPositions.clear(); d->errorPositions.clear(); if (d->bracketsMatching && textCursor().block().userData()) { QTextCursor cursor = textCursor(); int cursorPosition = cursor.position(); if (document()->characterAt(cursorPosition) == '{') { int matchPos = findClosingMatch(document(), cursorPosition); if (matchPos < 0) { d->errorPositions += cursorPosition; } else { d->matchPositions += cursorPosition; d->matchPositions += matchPos; } } if (document()->characterAt(cursorPosition - 1) == '}') { int matchPos = findOpeningMatch(document(), cursorPosition); if (matchPos < 0) { d->errorPositions += cursorPosition - 1; } else { d->matchPositions += cursorPosition - 1; d->matchPositions += matchPos; } } } QTextEdit::ExtraSelection highlight; highlight.format.setBackground(d->cursorColor); highlight.format.setProperty(QTextFormat::FullWidthSelection, true); highlight.cursor = textCursor(); highlight.cursor.clearSelection(); QList extraSelections; extraSelections.append(highlight); for (int i = 0; i < d->matchPositions.count(); ++i) { int pos = d->matchPositions.at(i); QTextEdit::ExtraSelection matchHighlight; matchHighlight.format.setBackground(d->bracketMatchColor); matchHighlight.cursor = textCursor(); matchHighlight.cursor.setPosition(pos); matchHighlight.cursor.setPosition(pos + 1, QTextCursor::KeepAnchor); extraSelections.append(matchHighlight); } for (int i = 0; i < d->errorPositions.count(); ++i) { int pos = d->errorPositions.at(i); QTextEdit::ExtraSelection errorHighlight; errorHighlight.format.setBackground(d->bracketErrorColor); errorHighlight.cursor = textCursor(); errorHighlight.cursor.setPosition(pos); errorHighlight.cursor.setPosition(pos + 1, QTextCursor::KeepAnchor); extraSelections.append(errorHighlight); } setExtraSelections(extraSelections); } } void JSEdit::updateSidebar(const QRect &rect, int d) { Q_UNUSED(rect) if (d != 0) updateSidebar(); } void JSEdit::updateSidebar() { Q_D(JSEdit); if (!d->showLineNumbers && !d->codeFolding) { d->sidebar->hide(); setViewportMargins(0, 0, 0, 0); d->sidebar->setGeometry(3, 0, 0, height()); return; } d->sidebar->foldIndicatorWidth = 0; d->sidebar->font = this->font(); d->sidebar->show(); int sw = 0; if (d->showLineNumbers) { int digits = 2; int maxLines = blockCount(); for (int number = 10; number < maxLines; number *= 10) ++digits; sw += fontMetrics().width('w') * digits; } if (d->codeFolding) { int fh = fontMetrics().lineSpacing(); int fw = fontMetrics().width('w'); d->sidebar->foldIndicatorWidth = qMax(fw, fh); sw += d->sidebar->foldIndicatorWidth; } setViewportMargins(sw, 0, 0, 0); d->sidebar->setGeometry(0, 0, sw, height()); QRectF sidebarRect(0, 0, sw, height()); QTextBlock block = firstVisibleBlock(); int index = 0; while (block.isValid()) { if (block.isVisible()) { QRectF rect = blockBoundingGeometry(block).translated(contentOffset()); if (sidebarRect.intersects(rect)) { if (d->sidebar->lineNumbers.count() >= index) d->sidebar->lineNumbers.resize(index + 1); d->sidebar->lineNumbers[index].position = rect.top(); d->sidebar->lineNumbers[index].number = block.blockNumber() + 1; d->sidebar->lineNumbers[index].foldable = d->codeFolding ? isFoldable(block.blockNumber() + 1) : false; d->sidebar->lineNumbers[index].folded = d->codeFolding ? isFolded(block.blockNumber() + 1) : false; ++index; } if (rect.top() > sidebarRect.bottom()) break; } block = block.next(); } d->sidebar->lineNumbers.resize(index); d->sidebar->update(); } void JSEdit::mark(const QString &str, Qt::CaseSensitivity sens) { d_ptr->highlighter->mark(str, sens); } IanniX-0.9.20/gui/qjsedit/jsedit.h000066400000000000000000000067501317340345000166620ustar00rootroot00000000000000/* This file is part of the Ofi Labs X2 project. Copyright (C) 2010 Ariya Hidayat Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef OFILABS_JSEDIT #define OFILABS_JSEDIT #include #include #include class JSEditPrivate; class JSEdit: public QPlainTextEdit { Q_OBJECT Q_PROPERTY(bool bracketsMatchingEnabled READ isBracketsMatchingEnabled WRITE setBracketsMatchingEnabled) Q_PROPERTY(bool codeFoldingEnabled READ isCodeFoldingEnabled WRITE setCodeFoldingEnabled) Q_PROPERTY(bool lineNumbersVisible READ isLineNumbersVisible WRITE setLineNumbersVisible) Q_PROPERTY(bool textWrapEnabled READ isTextWrapEnabled WRITE setTextWrapEnabled) public: typedef enum { Background, Normal, Comment, Number, String, Operator, Identifier, Keyword, BuiltIn, Sidebar, LineNumber, Cursor, Marker, BracketMatch, BracketError, FoldIndicator } ColorComponent; JSEdit(QWidget *parent = 0); ~JSEdit(); void setColor(ColorComponent component, const QColor &color); bool isBracketsMatchingEnabled() const; bool isCodeFoldingEnabled() const; bool isLineNumbersVisible() const; bool isTextWrapEnabled() const; bool isFoldable(int line) const; bool isFolded(int line) const; public slots: void updateSidebar(); void mark(const QString &str, Qt::CaseSensitivity sens = Qt::CaseInsensitive); void setBracketsMatchingEnabled(bool enable); void setCodeFoldingEnabled(bool enable); void setLineNumbersVisible(bool visible); void setTextWrapEnabled(bool enable); void fold(int line); void unfold(int line); void toggleFold(int line); protected: void resizeEvent(QResizeEvent *e); void wheelEvent(QWheelEvent *e); private slots: void updateCursor(); void updateSidebar(const QRect &rect, int d); private: QScopedPointer d_ptr; Q_DECLARE_PRIVATE(JSEdit); Q_DISABLE_COPY(JSEdit); }; #endif // OFILABS_JSEDIT IanniX-0.9.20/gui/qjsedit/prototype.js000066400000000000000000005005751317340345000176360ustar00rootroot00000000000000/* Prototype JavaScript framework, version 1.7_rc2 * (c) 2005-2010 Sam Stephenson * * Prototype is freely distributable under the terms of an MIT-style license. * For details, see the Prototype web site: http://www.prototypejs.org/ * *--------------------------------------------------------------------------*/ var Prototype = { Version: '1.7_rc2', Browser: (function(){ var ua = navigator.userAgent; var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]'; return { IE: !!window.attachEvent && !isOpera, Opera: isOpera, WebKit: ua.indexOf('AppleWebKit/') > -1, Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1, MobileSafari: /Apple.*Mobile/.test(ua) } })(), BrowserFeatures: { XPath: !!document.evaluate, SelectorsAPI: !!document.querySelector, ElementExtensions: (function() { var constructor = window.Element || window.HTMLElement; return !!(constructor && constructor.prototype); })(), SpecificElementExtensions: (function() { if (typeof window.HTMLDivElement !== 'undefined') return true; var div = document.createElement('div'), form = document.createElement('form'), isSupported = false; if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) { isSupported = true; } div = form = null; return isSupported; })() }, ScriptFragment: ']*>([\\S\\s]*?)<\/script>', JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, emptyFunction: function() { }, K: function(x) { return x } }; if (Prototype.Browser.MobileSafari) Prototype.BrowserFeatures.SpecificElementExtensions = false; var Abstract = { }; var Try = { these: function() { var returnValue; for (var i = 0, length = arguments.length; i < length; i++) { var lambda = arguments[i]; try { returnValue = lambda(); break; } catch (e) { } } return returnValue; } }; /* Based on Alex Arnell's inheritance implementation. */ var Class = (function() { var IS_DONTENUM_BUGGY = (function(){ for (var p in { toString: 1 }) { if (p === 'toString') return false; } return true; })(); function subclass() {}; function create() { var parent = null, properties = $A(arguments); if (Object.isFunction(properties[0])) parent = properties.shift(); function klass() { this.initialize.apply(this, arguments); } Object.extend(klass, Class.Methods); klass.superclass = parent; klass.subclasses = []; if (parent) { subclass.prototype = parent.prototype; klass.prototype = new subclass; parent.subclasses.push(klass); } for (var i = 0, length = properties.length; i < length; i++) klass.addMethods(properties[i]); if (!klass.prototype.initialize) klass.prototype.initialize = Prototype.emptyFunction; klass.prototype.constructor = klass; return klass; } function addMethods(source) { var ancestor = this.superclass && this.superclass.prototype, properties = Object.keys(source); if (IS_DONTENUM_BUGGY) { if (source.toString != Object.prototype.toString) properties.push("toString"); if (source.valueOf != Object.prototype.valueOf) properties.push("valueOf"); } for (var i = 0, length = properties.length; i < length; i++) { var property = properties[i], value = source[property]; if (ancestor && Object.isFunction(value) && value.argumentNames()[0] == "$super") { var method = value; value = (function(m) { return function() { return ancestor[m].apply(this, arguments); }; })(property).wrap(method); value.valueOf = method.valueOf.bind(method); value.toString = method.toString.bind(method); } this.prototype[property] = value; } return this; } return { create: create, Methods: { addMethods: addMethods } }; })(); (function() { var _toString = Object.prototype.toString, NULL_TYPE = 'Null', UNDEFINED_TYPE = 'Undefined', BOOLEAN_TYPE = 'Boolean', NUMBER_TYPE = 'Number', STRING_TYPE = 'String', OBJECT_TYPE = 'Object', BOOLEAN_CLASS = '[object Boolean]', NUMBER_CLASS = '[object Number]', STRING_CLASS = '[object String]', ARRAY_CLASS = '[object Array]', NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON && typeof JSON.stringify === 'function' && JSON.stringify(0) === '0' && typeof JSON.stringify(Prototype.K) === 'undefined'; function Type(o) { switch(o) { case null: return NULL_TYPE; case (void 0): return UNDEFINED_TYPE; } var type = typeof o; switch(type) { case 'boolean': return BOOLEAN_TYPE; case 'number': return NUMBER_TYPE; case 'string': return STRING_TYPE; } return OBJECT_TYPE; } function extend(destination, source) { for (var property in source) destination[property] = source[property]; return destination; } function inspect(object) { try { if (isUndefined(object)) return 'undefined'; if (object === null) return 'null'; return object.inspect ? object.inspect() : String(object); } catch (e) { if (e instanceof RangeError) return '...'; throw e; } } function toJSON(value) { return Str('', { '': value }, []); } function Str(key, holder, stack) { var value = holder[key], type = typeof value; if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') { value = value.toJSON(key); } var _class = _toString.call(value); switch (_class) { case NUMBER_CLASS: case BOOLEAN_CLASS: case STRING_CLASS: value = value.valueOf(); } switch (value) { case null: return 'null'; case true: return 'true'; case false: return 'false'; } type = typeof value; switch (type) { case 'string': return value.inspect(true); case 'number': return isFinite(value) ? String(value) : 'null'; case 'object': for (var i = 0, length = stack.length; i < length; i++) { if (stack[i] === value) { throw new TypeError(); } } stack.push(value); var partial = []; if (_class === ARRAY_CLASS) { for (var i = 0, length = value.length; i < length; i++) { var str = Str(i, value, stack); partial.push(typeof str === 'undefined' ? 'null' : str); } partial = '[' + partial.join(',') + ']'; } else { var keys = Object.keys(value); for (var i = 0, length = keys.length; i < length; i++) { var key = keys[i], str = Str(key, value, stack); if (typeof str !== "undefined") { partial.push(key.inspect(true)+ ':' + str); } } partial = '{' + partial.join(',') + '}'; } stack.pop(); return partial; } } function stringify(object) { return JSON.stringify(object); } function toQueryString(object) { return $H(object).toQueryString(); } function toHTML(object) { return object && object.toHTML ? object.toHTML() : String.interpret(object); } function keys(object) { if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); } var results = []; for (var property in object) { if (object.hasOwnProperty(property)) { results.push(property); } } return results; } function values(object) { var results = []; for (var property in object) results.push(object[property]); return results; } function clone(object) { return extend({ }, object); } function isElement(object) { return !!(object && object.nodeType == 1); } function isArray(object) { return _toString.call(object) === ARRAY_CLASS; } var hasNativeIsArray = (typeof Array.isArray == 'function') && Array.isArray([]) && !Array.isArray({}); if (hasNativeIsArray) { isArray = Array.isArray; } function isHash(object) { return object instanceof Hash; } function isFunction(object) { return typeof object === "function"; } function isString(object) { return _toString.call(object) === STRING_CLASS; } function isNumber(object) { return _toString.call(object) === NUMBER_CLASS; } function isUndefined(object) { return typeof object === "undefined"; } extend(Object, { extend: extend, inspect: inspect, toJSON: NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON, toQueryString: toQueryString, toHTML: toHTML, keys: Object.keys || keys, values: values, clone: clone, isElement: isElement, isArray: isArray, isHash: isHash, isFunction: isFunction, isString: isString, isNumber: isNumber, isUndefined: isUndefined }); })(); Object.extend(Function.prototype, (function() { var slice = Array.prototype.slice; function update(array, args) { var arrayLength = array.length, length = args.length; while (length--) array[arrayLength + length] = args[length]; return array; } function merge(array, args) { array = slice.call(array, 0); return update(array, args); } function argumentNames() { var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1] .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '') .replace(/\s+/g, '').split(','); return names.length == 1 && !names[0] ? [] : names; } function bind(context) { if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; var __method = this, args = slice.call(arguments, 1); return function() { var a = merge(args, arguments); return __method.apply(context, a); } } function bindAsEventListener(context) { var __method = this, args = slice.call(arguments, 1); return function(event) { var a = update([event || window.event], args); return __method.apply(context, a); } } function curry() { if (!arguments.length) return this; var __method = this, args = slice.call(arguments, 0); return function() { var a = merge(args, arguments); return __method.apply(this, a); } } function delay(timeout) { var __method = this, args = slice.call(arguments, 1); timeout = timeout * 1000; return window.setTimeout(function() { return __method.apply(__method, args); }, timeout); } function defer() { var args = update([0.01], arguments); return this.delay.apply(this, args); } function wrap(wrapper) { var __method = this; return function() { var a = update([__method.bind(this)], arguments); return wrapper.apply(this, a); } } function methodize() { if (this._methodized) return this._methodized; var __method = this; return this._methodized = function() { var a = update([this], arguments); return __method.apply(null, a); }; } return { argumentNames: argumentNames, bind: bind, bindAsEventListener: bindAsEventListener, curry: curry, delay: delay, defer: defer, wrap: wrap, methodize: methodize } })()); (function(proto) { function toISOString() { return this.getUTCFullYear() + '-' + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + this.getUTCDate().toPaddedString(2) + 'T' + this.getUTCHours().toPaddedString(2) + ':' + this.getUTCMinutes().toPaddedString(2) + ':' + this.getUTCSeconds().toPaddedString(2) + 'Z'; } function toJSON() { return this.toISOString(); } if (!proto.toISOString) proto.toISOString = toISOString; if (!proto.toJSON) proto.toJSON = toJSON; })(Date.prototype); RegExp.prototype.match = RegExp.prototype.test; RegExp.escape = function(str) { return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); }; var PeriodicalExecuter = Class.create({ initialize: function(callback, frequency) { this.callback = callback; this.frequency = frequency; this.currentlyExecuting = false; this.registerCallback(); }, registerCallback: function() { this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); }, execute: function() { this.callback(this); }, stop: function() { if (!this.timer) return; clearInterval(this.timer); this.timer = null; }, onTimerEvent: function() { if (!this.currentlyExecuting) { try { this.currentlyExecuting = true; this.execute(); this.currentlyExecuting = false; } catch(e) { this.currentlyExecuting = false; throw e; } } } }); Object.extend(String, { interpret: function(value) { return value == null ? '' : String(value); }, specialChar: { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\\': '\\\\' } }); Object.extend(String.prototype, (function() { var NATIVE_JSON_PARSE_SUPPORT = window.JSON && typeof JSON.parse === 'function' && JSON.parse('{"test": true}').test; function prepareReplacement(replacement) { if (Object.isFunction(replacement)) return replacement; var template = new Template(replacement); return function(match) { return template.evaluate(match) }; } function gsub(pattern, replacement) { var result = '', source = this, match; replacement = prepareReplacement(replacement); if (Object.isString(pattern)) pattern = RegExp.escape(pattern); if (!(pattern.length || pattern.source)) { replacement = replacement(''); return replacement + source.split('').join(replacement) + replacement; } while (source.length > 0) { if (match = source.match(pattern)) { result += source.slice(0, match.index); result += String.interpret(replacement(match)); source = source.slice(match.index + match[0].length); } else { result += source, source = ''; } } return result; } function sub(pattern, replacement, count) { replacement = prepareReplacement(replacement); count = Object.isUndefined(count) ? 1 : count; return this.gsub(pattern, function(match) { if (--count < 0) return match[0]; return replacement(match); }); } function scan(pattern, iterator) { this.gsub(pattern, iterator); return String(this); } function truncate(length, truncation) { length = length || 30; truncation = Object.isUndefined(truncation) ? '...' : truncation; return this.length > length ? this.slice(0, length - truncation.length) + truncation : String(this); } function strip() { return this.replace(/^\s+/, '').replace(/\s+$/, ''); } function stripTags() { return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); } function stripScripts() { return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); } function extractScripts() { var matchAll = new RegExp(Prototype.ScriptFragment, 'img'), matchOne = new RegExp(Prototype.ScriptFragment, 'im'); return (this.match(matchAll) || []).map(function(scriptTag) { return (scriptTag.match(matchOne) || ['', ''])[1]; }); } function evalScripts() { return this.extractScripts().map(function(script) { return eval(script) }); } function escapeHTML() { return this.replace(/&/g,'&').replace(//g,'>'); } function unescapeHTML() { return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&'); } function toQueryParams(separator) { var match = this.strip().match(/([^?#]*)(#.*)?$/); if (!match) return { }; return match[1].split(separator || '&').inject({ }, function(hash, pair) { if ((pair = pair.split('='))[0]) { var key = decodeURIComponent(pair.shift()), value = pair.length > 1 ? pair.join('=') : pair[0]; if (value != undefined) value = decodeURIComponent(value); if (key in hash) { if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; hash[key].push(value); } else hash[key] = value; } return hash; }); } function toArray() { return this.split(''); } function succ() { return this.slice(0, this.length - 1) + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); } function times(count) { return count < 1 ? '' : new Array(count + 1).join(this); } function camelize() { return this.replace(/-+(.)?/g, function(match, chr) { return chr ? chr.toUpperCase() : ''; }); } function capitalize() { return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); } function underscore() { return this.replace(/::/g, '/') .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') .replace(/([a-z\d])([A-Z])/g, '$1_$2') .replace(/-/g, '_') .toLowerCase(); } function dasherize() { return this.replace(/_/g, '-'); } function inspect(useDoubleQuotes) { var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) { if (character in String.specialChar) { return String.specialChar[character]; } return '\\u00' + character.charCodeAt().toPaddedString(2, 16); }); if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; return "'" + escapedString.replace(/'/g, '\\\'') + "'"; } function unfilterJSON(filter) { return this.replace(filter || Prototype.JSONFilter, '$1'); } function isJSON() { var str = this; if (str.blank()) return false; str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'); str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'); str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, ''); return (/^[\],:{}\s]*$/).test(str); } function evalJSON(sanitize) { var json = this.unfilterJSON(), cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; if (cx.test(json)) { json = json.replace(cx, function (a) { return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }); } try { if (!sanitize || json.isJSON()) return eval('(' + json + ')'); } catch (e) { } throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); } function parseJSON() { var json = this.unfilterJSON(); return JSON.parse(json); } function include(pattern) { return this.indexOf(pattern) > -1; } function startsWith(pattern) { return this.lastIndexOf(pattern, 0) === 0; } function endsWith(pattern) { var d = this.length - pattern.length; return d >= 0 && this.indexOf(pattern, d) === d; } function empty() { return this == ''; } function blank() { return /^\s*$/.test(this); } function interpolate(object, pattern) { return new Template(this, pattern).evaluate(object); } return { gsub: gsub, sub: sub, scan: scan, truncate: truncate, strip: String.prototype.trim || strip, stripTags: stripTags, stripScripts: stripScripts, extractScripts: extractScripts, evalScripts: evalScripts, escapeHTML: escapeHTML, unescapeHTML: unescapeHTML, toQueryParams: toQueryParams, parseQuery: toQueryParams, toArray: toArray, succ: succ, times: times, camelize: camelize, capitalize: capitalize, underscore: underscore, dasherize: dasherize, inspect: inspect, unfilterJSON: unfilterJSON, isJSON: isJSON, evalJSON: NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON, include: include, startsWith: startsWith, endsWith: endsWith, empty: empty, blank: blank, interpolate: interpolate }; })()); var Template = Class.create({ initialize: function(template, pattern) { this.template = template.toString(); this.pattern = pattern || Template.Pattern; }, evaluate: function(object) { if (object && Object.isFunction(object.toTemplateReplacements)) object = object.toTemplateReplacements(); return this.template.gsub(this.pattern, function(match) { if (object == null) return (match[1] + ''); var before = match[1] || ''; if (before == '\\') return match[2]; var ctx = object, expr = match[3], pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; match = pattern.exec(expr); if (match == null) return before; while (match != null) { var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1]; ctx = ctx[comp]; if (null == ctx || '' == match[3]) break; expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); match = pattern.exec(expr); } return before + String.interpret(ctx); }); } }); Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; var $break = { }; var Enumerable = (function() { function each(iterator, context) { var index = 0; try { this._each(function(value) { iterator.call(context, value, index++); }); } catch (e) { if (e != $break) throw e; } return this; } function eachSlice(number, iterator, context) { var index = -number, slices = [], array = this.toArray(); if (number < 1) return array; while ((index += number) < array.length) slices.push(array.slice(index, index+number)); return slices.collect(iterator, context); } function all(iterator, context) { iterator = iterator || Prototype.K; var result = true; this.each(function(value, index) { result = result && !!iterator.call(context, value, index); if (!result) throw $break; }); return result; } function any(iterator, context) { iterator = iterator || Prototype.K; var result = false; this.each(function(value, index) { if (result = !!iterator.call(context, value, index)) throw $break; }); return result; } function collect(iterator, context) { iterator = iterator || Prototype.K; var results = []; this.each(function(value, index) { results.push(iterator.call(context, value, index)); }); return results; } function detect(iterator, context) { var result; this.each(function(value, index) { if (iterator.call(context, value, index)) { result = value; throw $break; } }); return result; } function findAll(iterator, context) { var results = []; this.each(function(value, index) { if (iterator.call(context, value, index)) results.push(value); }); return results; } function grep(filter, iterator, context) { iterator = iterator || Prototype.K; var results = []; if (Object.isString(filter)) filter = new RegExp(RegExp.escape(filter)); this.each(function(value, index) { if (filter.match(value)) results.push(iterator.call(context, value, index)); }); return results; } function include(object) { if (Object.isFunction(this.indexOf)) if (this.indexOf(object) != -1) return true; var found = false; this.each(function(value) { if (value == object) { found = true; throw $break; } }); return found; } function inGroupsOf(number, fillWith) { fillWith = Object.isUndefined(fillWith) ? null : fillWith; return this.eachSlice(number, function(slice) { while(slice.length < number) slice.push(fillWith); return slice; }); } function inject(memo, iterator, context) { this.each(function(value, index) { memo = iterator.call(context, memo, value, index); }); return memo; } function invoke(method) { var args = $A(arguments).slice(1); return this.map(function(value) { return value[method].apply(value, args); }); } function max(iterator, context) { iterator = iterator || Prototype.K; var result; this.each(function(value, index) { value = iterator.call(context, value, index); if (result == null || value >= result) result = value; }); return result; } function min(iterator, context) { iterator = iterator || Prototype.K; var result; this.each(function(value, index) { value = iterator.call(context, value, index); if (result == null || value < result) result = value; }); return result; } function partition(iterator, context) { iterator = iterator || Prototype.K; var trues = [], falses = []; this.each(function(value, index) { (iterator.call(context, value, index) ? trues : falses).push(value); }); return [trues, falses]; } function pluck(property) { var results = []; this.each(function(value) { results.push(value[property]); }); return results; } function reject(iterator, context) { var results = []; this.each(function(value, index) { if (!iterator.call(context, value, index)) results.push(value); }); return results; } function sortBy(iterator, context) { return this.map(function(value, index) { return { value: value, criteria: iterator.call(context, value, index) }; }).sort(function(left, right) { var a = left.criteria, b = right.criteria; return a < b ? -1 : a > b ? 1 : 0; }).pluck('value'); } function toArray() { return this.map(); } function zip() { var iterator = Prototype.K, args = $A(arguments); if (Object.isFunction(args.last())) iterator = args.pop(); var collections = [this].concat(args).map($A); return this.map(function(value, index) { return iterator(collections.pluck(index)); }); } function size() { return this.toArray().length; } function inspect() { return '#'; } return { each: each, eachSlice: eachSlice, all: all, every: all, any: any, some: any, collect: collect, map: collect, detect: detect, findAll: findAll, select: findAll, filter: findAll, grep: grep, include: include, member: include, inGroupsOf: inGroupsOf, inject: inject, invoke: invoke, max: max, min: min, partition: partition, pluck: pluck, reject: reject, sortBy: sortBy, toArray: toArray, entries: toArray, zip: zip, size: size, inspect: inspect, find: detect }; })(); function $A(iterable) { if (!iterable) return []; if ('toArray' in Object(iterable)) return iterable.toArray(); var length = iterable.length || 0, results = new Array(length); while (length--) results[length] = iterable[length]; return results; } function $w(string) { if (!Object.isString(string)) return []; string = string.strip(); return string ? string.split(/\s+/) : []; } Array.from = $A; (function() { var arrayProto = Array.prototype, slice = arrayProto.slice, _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available function each(iterator) { for (var i = 0, length = this.length; i < length; i++) iterator(this[i]); } if (!_each) _each = each; function clear() { this.length = 0; return this; } function first() { return this[0]; } function last() { return this[this.length - 1]; } function compact() { return this.select(function(value) { return value != null; }); } function flatten() { return this.inject([], function(array, value) { if (Object.isArray(value)) return array.concat(value.flatten()); array.push(value); return array; }); } function without() { var values = slice.call(arguments, 0); return this.select(function(value) { return !values.include(value); }); } function reverse(inline) { return (inline === false ? this.toArray() : this)._reverse(); } function uniq(sorted) { return this.inject([], function(array, value, index) { if (0 == index || (sorted ? array.last() != value : !array.include(value))) array.push(value); return array; }); } function intersect(array) { return this.uniq().findAll(function(item) { return array.detect(function(value) { return item === value }); }); } function clone() { return slice.call(this, 0); } function size() { return this.length; } function inspect() { return '[' + this.map(Object.inspect).join(', ') + ']'; } function indexOf(item, i) { i || (i = 0); var length = this.length; if (i < 0) i = length + i; for (; i < length; i++) if (this[i] === item) return i; return -1; } function lastIndexOf(item, i) { i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; var n = this.slice(0, i).reverse().indexOf(item); return (n < 0) ? n : i - n - 1; } function concat() { var array = slice.call(this, 0), item; for (var i = 0, length = arguments.length; i < length; i++) { item = arguments[i]; if (Object.isArray(item) && !('callee' in item)) { for (var j = 0, arrayLength = item.length; j < arrayLength; j++) array.push(item[j]); } else { array.push(item); } } return array; } Object.extend(arrayProto, Enumerable); if (!arrayProto._reverse) arrayProto._reverse = arrayProto.reverse; Object.extend(arrayProto, { _each: _each, clear: clear, first: first, last: last, compact: compact, flatten: flatten, without: without, reverse: reverse, uniq: uniq, intersect: intersect, clone: clone, toArray: clone, size: size, inspect: inspect }); var CONCAT_ARGUMENTS_BUGGY = (function() { return [].concat(arguments)[0][0] !== 1; })(1,2) if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat; if (!arrayProto.indexOf) arrayProto.indexOf = indexOf; if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf; })(); function $H(object) { return new Hash(object); }; var Hash = Class.create(Enumerable, (function() { function initialize(object) { this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); } function _each(iterator) { for (var key in this._object) { var value = this._object[key], pair = [key, value]; pair.key = key; pair.value = value; iterator(pair); } } function set(key, value) { return this._object[key] = value; } function get(key) { if (this._object[key] !== Object.prototype[key]) return this._object[key]; } function unset(key) { var value = this._object[key]; delete this._object[key]; return value; } function toObject() { return Object.clone(this._object); } function keys() { return this.pluck('key'); } function values() { return this.pluck('value'); } function index(value) { var match = this.detect(function(pair) { return pair.value === value; }); return match && match.key; } function merge(object) { return this.clone().update(object); } function update(object) { return new Hash(object).inject(this, function(result, pair) { result.set(pair.key, pair.value); return result; }); } function toQueryPair(key, value) { if (Object.isUndefined(value)) return key; return key + '=' + encodeURIComponent(String.interpret(value)); } function toQueryString() { return this.inject([], function(results, pair) { var key = encodeURIComponent(pair.key), values = pair.value; if (values && typeof values == 'object') { if (Object.isArray(values)) return results.concat(values.map(toQueryPair.curry(key))); } else results.push(toQueryPair(key, values)); return results; }).join('&'); } function inspect() { return '#'; } function clone() { return new Hash(this); } return { initialize: initialize, _each: _each, set: set, get: get, unset: unset, toObject: toObject, toTemplateReplacements: toObject, keys: keys, values: values, index: index, merge: merge, update: update, toQueryString: toQueryString, inspect: inspect, toJSON: toObject, clone: clone }; })()); Hash.from = $H; Object.extend(Number.prototype, (function() { function toColorPart() { return this.toPaddedString(2, 16); } function succ() { return this + 1; } function times(iterator, context) { $R(0, this, true).each(iterator, context); return this; } function toPaddedString(length, radix) { var string = this.toString(radix || 10); return '0'.times(length - string.length) + string; } function abs() { return Math.abs(this); } function round() { return Math.round(this); } function ceil() { return Math.ceil(this); } function floor() { return Math.floor(this); } return { toColorPart: toColorPart, succ: succ, times: times, toPaddedString: toPaddedString, abs: abs, round: round, ceil: ceil, floor: floor }; })()); function $R(start, end, exclusive) { return new ObjectRange(start, end, exclusive); } var ObjectRange = Class.create(Enumerable, (function() { function initialize(start, end, exclusive) { this.start = start; this.end = end; this.exclusive = exclusive; } function _each(iterator) { var value = this.start; while (this.include(value)) { iterator(value); value = value.succ(); } } function include(value) { if (value < this.start) return false; if (this.exclusive) return value < this.end; return value <= this.end; } return { initialize: initialize, _each: _each, include: include }; })()); var Ajax = { getTransport: function() { return Try.these( function() {return new XMLHttpRequest()}, function() {return new ActiveXObject('Msxml2.XMLHTTP')}, function() {return new ActiveXObject('Microsoft.XMLHTTP')} ) || false; }, activeRequestCount: 0 }; Ajax.Responders = { responders: [], _each: function(iterator) { this.responders._each(iterator); }, register: function(responder) { if (!this.include(responder)) this.responders.push(responder); }, unregister: function(responder) { this.responders = this.responders.without(responder); }, dispatch: function(callback, request, transport, json) { this.each(function(responder) { if (Object.isFunction(responder[callback])) { try { responder[callback].apply(responder, [request, transport, json]); } catch (e) { } } }); } }; Object.extend(Ajax.Responders, Enumerable); Ajax.Responders.register({ onCreate: function() { Ajax.activeRequestCount++ }, onComplete: function() { Ajax.activeRequestCount-- } }); Ajax.Base = Class.create({ initialize: function(options) { this.options = { method: 'post', asynchronous: true, contentType: 'application/x-www-form-urlencoded', encoding: 'UTF-8', parameters: '', evalJSON: true, evalJS: true }; Object.extend(this.options, options || { }); this.options.method = this.options.method.toLowerCase(); if (Object.isHash(this.options.parameters)) this.options.parameters = this.options.parameters.toObject(); } }); Ajax.Request = Class.create(Ajax.Base, { _complete: false, initialize: function($super, url, options) { $super(options); this.transport = Ajax.getTransport(); this.request(url); }, request: function(url) { this.url = url; this.method = this.options.method; var params = Object.isString(this.options.parameters) ? this.options.parameters : Object.toQueryString(this.options.parameters); if (!['get', 'post'].include(this.method)) { params += (params ? '&' : '') + "_method=" + this.method; this.method = 'post'; } if (params) { if (this.method == 'get') this.url += (this.url.include('?') ? '&' : '?') + params; else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='; } this.parameters = params.toQueryParams(); try { var response = new Ajax.Response(this); if (this.options.onCreate) this.options.onCreate(response); Ajax.Responders.dispatch('onCreate', this, response); this.transport.open(this.method.toUpperCase(), this.url, this.options.asynchronous); if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); this.transport.onreadystatechange = this.onStateChange.bind(this); this.setRequestHeaders(); this.body = this.method == 'post' ? (this.options.postBody || params) : null; this.transport.send(this.body); /* Force Firefox to handle ready state 4 for synchronous requests */ if (!this.options.asynchronous && this.transport.overrideMimeType) this.onStateChange(); } catch (e) { this.dispatchException(e); } }, onStateChange: function() { var readyState = this.transport.readyState; if (readyState > 1 && !((readyState == 4) && this._complete)) this.respondToReadyState(this.transport.readyState); }, setRequestHeaders: function() { var headers = { 'X-Requested-With': 'XMLHttpRequest', 'X-Prototype-Version': Prototype.Version, 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' }; if (this.method == 'post') { headers['Content-type'] = this.options.contentType + (this.options.encoding ? '; charset=' + this.options.encoding : ''); /* Force "Connection: close" for older Mozilla browsers to work * around a bug where XMLHttpRequest sends an incorrect * Content-length header. See Mozilla Bugzilla #246651. */ if (this.transport.overrideMimeType && (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) headers['Connection'] = 'close'; } if (typeof this.options.requestHeaders == 'object') { var extras = this.options.requestHeaders; if (Object.isFunction(extras.push)) for (var i = 0, length = extras.length; i < length; i += 2) headers[extras[i]] = extras[i+1]; else $H(extras).each(function(pair) { headers[pair.key] = pair.value }); } for (var name in headers) this.transport.setRequestHeader(name, headers[name]); }, success: function() { var status = this.getStatus(); return !status || (status >= 200 && status < 300); }, getStatus: function() { try { return this.transport.status || 0; } catch (e) { return 0 } }, respondToReadyState: function(readyState) { var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); if (state == 'Complete') { try { this._complete = true; (this.options['on' + response.status] || this.options['on' + (this.success() ? 'Success' : 'Failure')] || Prototype.emptyFunction)(response, response.headerJSON); } catch (e) { this.dispatchException(e); } var contentType = response.getHeader('Content-type'); if (this.options.evalJS == 'force' || (this.options.evalJS && this.isSameOrigin() && contentType && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) this.evalResponse(); } try { (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); } catch (e) { this.dispatchException(e); } if (state == 'Complete') { this.transport.onreadystatechange = Prototype.emptyFunction; } }, isSameOrigin: function() { var m = this.url.match(/^\s*https?:\/\/[^\/]*/); return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ protocol: location.protocol, domain: document.domain, port: location.port ? ':' + location.port : '' })); }, getHeader: function(name) { try { return this.transport.getResponseHeader(name) || null; } catch (e) { return null; } }, evalResponse: function() { try { return eval((this.transport.responseText || '').unfilterJSON()); } catch (e) { this.dispatchException(e); } }, dispatchException: function(exception) { (this.options.onException || Prototype.emptyFunction)(this, exception); Ajax.Responders.dispatch('onException', this, exception); } }); Ajax.Request.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; Ajax.Response = Class.create({ initialize: function(request){ this.request = request; var transport = this.transport = request.transport, readyState = this.readyState = transport.readyState; if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { this.status = this.getStatus(); this.statusText = this.getStatusText(); this.responseText = String.interpret(transport.responseText); this.headerJSON = this._getHeaderJSON(); } if (readyState == 4) { var xml = transport.responseXML; this.responseXML = Object.isUndefined(xml) ? null : xml; this.responseJSON = this._getResponseJSON(); } }, status: 0, statusText: '', getStatus: Ajax.Request.prototype.getStatus, getStatusText: function() { try { return this.transport.statusText || ''; } catch (e) { return '' } }, getHeader: Ajax.Request.prototype.getHeader, getAllHeaders: function() { try { return this.getAllResponseHeaders(); } catch (e) { return null } }, getResponseHeader: function(name) { return this.transport.getResponseHeader(name); }, getAllResponseHeaders: function() { return this.transport.getAllResponseHeaders(); }, _getHeaderJSON: function() { var json = this.getHeader('X-JSON'); if (!json) return null; json = decodeURIComponent(escape(json)); try { return json.evalJSON(this.request.options.sanitizeJSON || !this.request.isSameOrigin()); } catch (e) { this.request.dispatchException(e); } }, _getResponseJSON: function() { var options = this.request.options; if (!options.evalJSON || (options.evalJSON != 'force' && !(this.getHeader('Content-type') || '').include('application/json')) || this.responseText.blank()) return null; try { return this.responseText.evalJSON(options.sanitizeJSON || !this.request.isSameOrigin()); } catch (e) { this.request.dispatchException(e); } } }); Ajax.Updater = Class.create(Ajax.Request, { initialize: function($super, container, url, options) { this.container = { success: (container.success || container), failure: (container.failure || (container.success ? null : container)) }; options = Object.clone(options); var onComplete = options.onComplete; options.onComplete = (function(response, json) { this.updateContent(response.responseText); if (Object.isFunction(onComplete)) onComplete(response, json); }).bind(this); $super(url, options); }, updateContent: function(responseText) { var receiver = this.container[this.success() ? 'success' : 'failure'], options = this.options; if (!options.evalScripts) responseText = responseText.stripScripts(); if (receiver = $(receiver)) { if (options.insertion) { if (Object.isString(options.insertion)) { var insertion = { }; insertion[options.insertion] = responseText; receiver.insert(insertion); } else options.insertion(receiver, responseText); } else receiver.update(responseText); } } }); Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { initialize: function($super, container, url, options) { $super(options); this.onComplete = this.options.onComplete; this.frequency = (this.options.frequency || 2); this.decay = (this.options.decay || 1); this.updater = { }; this.container = container; this.url = url; this.start(); }, start: function() { this.options.onComplete = this.updateComplete.bind(this); this.onTimerEvent(); }, stop: function() { this.updater.options.onComplete = undefined; clearTimeout(this.timer); (this.onComplete || Prototype.emptyFunction).apply(this, arguments); }, updateComplete: function(response) { if (this.options.decay) { this.decay = (response.responseText == this.lastText ? this.decay * this.options.decay : 1); this.lastText = response.responseText; } this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); }, onTimerEvent: function() { this.updater = new Ajax.Updater(this.container, this.url, this.options); } }); function $(element) { if (arguments.length > 1) { for (var i = 0, elements = [], length = arguments.length; i < length; i++) elements.push($(arguments[i])); return elements; } if (Object.isString(element)) element = document.getElementById(element); return Element.extend(element); } if (Prototype.BrowserFeatures.XPath) { document._getElementsByXPath = function(expression, parentElement) { var results = []; var query = document.evaluate(expression, $(parentElement) || document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0, length = query.snapshotLength; i < length; i++) results.push(Element.extend(query.snapshotItem(i))); return results; }; } /*--------------------------------------------------------------------------*/ if (!Node) var Node = { }; if (!Node.ELEMENT_NODE) { Object.extend(Node, { ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5, ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12 }); } (function(global) { var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){ try { var el = document.createElement(''); return el.tagName.toLowerCase() === 'input' && el.name === 'x'; } catch(err) { return false; } })(); var element = global.Element; global.Element = function(tagName, attributes) { attributes = attributes || { }; tagName = tagName.toLowerCase(); var cache = Element.cache; if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) { tagName = '<' + tagName + ' name="' + attributes.name + '">'; delete attributes.name; return Element.writeAttribute(document.createElement(tagName), attributes); } if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); }; Object.extend(global.Element, element || { }); if (element) global.Element.prototype = element.prototype; })(this); Element.idCounter = 1; Element.cache = { }; Element._purgeElement = function(element) { var uid = element._prototypeUID; if (uid) { Element.stopObserving(element); element._prototypeUID = void 0; delete Element.Storage[uid]; } } Element.Methods = { visible: function(element) { return $(element).style.display != 'none'; }, toggle: function(element) { element = $(element); Element[Element.visible(element) ? 'hide' : 'show'](element); return element; }, hide: function(element) { element = $(element); element.style.display = 'none'; return element; }, show: function(element) { element = $(element); element.style.display = ''; return element; }, remove: function(element) { element = $(element); element.parentNode.removeChild(element); return element; }, update: (function(){ var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){ var el = document.createElement("select"), isBuggy = true; el.innerHTML = ""; if (el.options && el.options[0]) { isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION"; } el = null; return isBuggy; })(); var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){ try { var el = document.createElement("table"); if (el && el.tBodies) { el.innerHTML = "test"; var isBuggy = typeof el.tBodies[0] == "undefined"; el = null; return isBuggy; } } catch (e) { return true; } })(); var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () { var s = document.createElement("script"), isBuggy = false; try { s.appendChild(document.createTextNode("")); isBuggy = !s.firstChild || s.firstChild && s.firstChild.nodeType !== 3; } catch (e) { isBuggy = true; } s = null; return isBuggy; })(); function update(element, content) { element = $(element); var purgeElement = Element._purgeElement; var descendants = element.getElementsByTagName('*'), i = descendants.length; while (i--) purgeElement(descendants[i]); if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) return element.update().insert(content); content = Object.toHTML(content); var tagName = element.tagName.toUpperCase(); if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) { element.text = content; return element; } if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) { if (tagName in Element._insertionTranslations.tags) { while (element.firstChild) { element.removeChild(element.firstChild); } Element._getContentFromAnonymousElement(tagName, content.stripScripts()) .each(function(node) { element.appendChild(node) }); } else { element.innerHTML = content.stripScripts(); } } else { element.innerHTML = content.stripScripts(); } content.evalScripts.bind(content).defer(); return element; } return update; })(), replace: function(element, content) { element = $(element); if (content && content.toElement) content = content.toElement(); else if (!Object.isElement(content)) { content = Object.toHTML(content); var range = element.ownerDocument.createRange(); range.selectNode(element); content.evalScripts.bind(content).defer(); content = range.createContextualFragment(content.stripScripts()); } element.parentNode.replaceChild(content, element); return element; }, insert: function(element, insertions) { element = $(element); if (Object.isString(insertions) || Object.isNumber(insertions) || Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) insertions = {bottom:insertions}; var content, insert, tagName, childNodes; for (var position in insertions) { content = insertions[position]; position = position.toLowerCase(); insert = Element._insertionTranslations[position]; if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) { insert(element, content); continue; } content = Object.toHTML(content); tagName = ((position == 'before' || position == 'after') ? element.parentNode : element).tagName.toUpperCase(); childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); if (position == 'top' || position == 'after') childNodes.reverse(); childNodes.each(insert.curry(element)); content.evalScripts.bind(content).defer(); } return element; }, wrap: function(element, wrapper, attributes) { element = $(element); if (Object.isElement(wrapper)) $(wrapper).writeAttribute(attributes || { }); else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); else wrapper = new Element('div', wrapper); if (element.parentNode) element.parentNode.replaceChild(wrapper, element); wrapper.appendChild(element); return wrapper; }, inspect: function(element) { element = $(element); var result = '<' + element.tagName.toLowerCase(); $H({'id': 'id', 'className': 'class'}).each(function(pair) { var property = pair.first(), attribute = pair.last(), value = (element[property] || '').toString(); if (value) result += ' ' + attribute + '=' + value.inspect(true); }); return result + '>'; }, recursivelyCollect: function(element, property, maximumLength) { element = $(element); maximumLength = maximumLength || -1; var elements = []; while (element = element[property]) { if (element.nodeType == 1) elements.push(Element.extend(element)); if (elements.length == maximumLength) break; } return elements; }, ancestors: function(element) { return Element.recursivelyCollect(element, 'parentNode'); }, descendants: function(element) { return Element.select(element, "*"); }, firstDescendant: function(element) { element = $(element).firstChild; while (element && element.nodeType != 1) element = element.nextSibling; return $(element); }, immediateDescendants: function(element) { var results = [], child = $(element).firstChild; while (child) { if (child.nodeType === 1) { results.push(Element.extend(child)); } child = child.nextSibling; } return results; }, previousSiblings: function(element, maximumLength) { return Element.recursivelyCollect(element, 'previousSibling'); }, nextSiblings: function(element) { return Element.recursivelyCollect(element, 'nextSibling'); }, siblings: function(element) { element = $(element); return Element.previousSiblings(element).reverse() .concat(Element.nextSiblings(element)); }, match: function(element, selector) { element = $(element); if (Object.isString(selector)) return Prototype.Selector.match(element, selector); return selector.match(element); }, up: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(element.parentNode); var ancestors = Element.ancestors(element); return Object.isNumber(expression) ? ancestors[expression] : Prototype.Selector.find(ancestors, expression, index); }, down: function(element, expression, index) { element = $(element); if (arguments.length == 1) return Element.firstDescendant(element); return Object.isNumber(expression) ? Element.descendants(element)[expression] : Element.select(element, expression)[index || 0]; }, previous: function(element, expression, index) { element = $(element); if (Object.isNumber(expression)) index = expression, expression = false; if (!Object.isNumber(index)) index = 0; if (expression) { return Prototype.Selector.find(element.previousSiblings(), expression, index); } else { return element.recursivelyCollect("previousSibling", index + 1)[index]; } }, next: function(element, expression, index) { element = $(element); if (Object.isNumber(expression)) index = expression, expression = false; if (!Object.isNumber(index)) index = 0; if (expression) { return Prototype.Selector.find(element.nextSiblings(), expression, index); } else { var maximumLength = Object.isNumber(index) ? index + 1 : 1; return element.recursivelyCollect("nextSibling", index + 1)[index]; } }, select: function(element) { element = $(element); var expressions = Array.prototype.slice.call(arguments, 1).join(', '); return Prototype.Selector.select(expressions, element); }, adjacent: function(element) { element = $(element); var expressions = Array.prototype.slice.call(arguments, 1).join(', '); return Prototype.Selector.select(expressions, element.parentNode).without(element); }, identify: function(element) { element = $(element); var id = Element.readAttribute(element, 'id'); if (id) return id; do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id)); Element.writeAttribute(element, 'id', id); return id; }, readAttribute: function(element, name) { element = $(element); if (Prototype.Browser.IE) { var t = Element._attributeTranslations.read; if (t.values[name]) return t.values[name](element, name); if (t.names[name]) name = t.names[name]; if (name.include(':')) { return (!element.attributes || !element.attributes[name]) ? null : element.attributes[name].value; } } return element.getAttribute(name); }, writeAttribute: function(element, name, value) { element = $(element); var attributes = { }, t = Element._attributeTranslations.write; if (typeof name == 'object') attributes = name; else attributes[name] = Object.isUndefined(value) ? true : value; for (var attr in attributes) { name = t.names[attr] || attr; value = attributes[attr]; if (t.values[attr]) name = t.values[attr](element, value); if (value === false || value === null) element.removeAttribute(name); else if (value === true) element.setAttribute(name, name); else element.setAttribute(name, value); } return element; }, getHeight: function(element) { return Element.getDimensions(element).height; }, getWidth: function(element) { return Element.getDimensions(element).width; }, classNames: function(element) { return new Element.ClassNames(element); }, hasClassName: function(element, className) { if (!(element = $(element))) return; var elementClassName = element.className; return (elementClassName.length > 0 && (elementClassName == className || new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); }, addClassName: function(element, className) { if (!(element = $(element))) return; if (!Element.hasClassName(element, className)) element.className += (element.className ? ' ' : '') + className; return element; }, removeClassName: function(element, className) { if (!(element = $(element))) return; element.className = element.className.replace( new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); return element; }, toggleClassName: function(element, className) { if (!(element = $(element))) return; return Element[Element.hasClassName(element, className) ? 'removeClassName' : 'addClassName'](element, className); }, cleanWhitespace: function(element) { element = $(element); var node = element.firstChild; while (node) { var nextNode = node.nextSibling; if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) element.removeChild(node); node = nextNode; } return element; }, empty: function(element) { return $(element).innerHTML.blank(); }, descendantOf: function(element, ancestor) { element = $(element), ancestor = $(ancestor); if (element.compareDocumentPosition) return (element.compareDocumentPosition(ancestor) & 8) === 8; if (ancestor.contains) return ancestor.contains(element) && ancestor !== element; while (element = element.parentNode) if (element == ancestor) return true; return false; }, scrollTo: function(element) { element = $(element); var pos = Element.cumulativeOffset(element); window.scrollTo(pos[0], pos[1]); return element; }, getStyle: function(element, style) { element = $(element); style = style == 'float' ? 'cssFloat' : style.camelize(); var value = element.style[style]; if (!value || value == 'auto') { var css = document.defaultView.getComputedStyle(element, null); value = css ? css[style] : null; } if (style == 'opacity') return value ? parseFloat(value) : 1.0; return value == 'auto' ? null : value; }, getOpacity: function(element) { return $(element).getStyle('opacity'); }, setStyle: function(element, styles) { element = $(element); var elementStyle = element.style, match; if (Object.isString(styles)) { element.style.cssText += ';' + styles; return styles.include('opacity') ? element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; } for (var property in styles) if (property == 'opacity') element.setOpacity(styles[property]); else elementStyle[(property == 'float' || property == 'cssFloat') ? (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : property] = styles[property]; return element; }, setOpacity: function(element, value) { element = $(element); element.style.opacity = (value == 1 || value === '') ? '' : (value < 0.00001) ? 0 : value; return element; }, makePositioned: function(element) { element = $(element); var pos = Element.getStyle(element, 'position'); if (pos == 'static' || !pos) { element._madePositioned = true; element.style.position = 'relative'; if (Prototype.Browser.Opera) { element.style.top = 0; element.style.left = 0; } } return element; }, undoPositioned: function(element) { element = $(element); if (element._madePositioned) { element._madePositioned = undefined; element.style.position = element.style.top = element.style.left = element.style.bottom = element.style.right = ''; } return element; }, makeClipping: function(element) { element = $(element); if (element._overflow) return element; element._overflow = Element.getStyle(element, 'overflow') || 'auto'; if (element._overflow !== 'hidden') element.style.overflow = 'hidden'; return element; }, undoClipping: function(element) { element = $(element); if (!element._overflow) return element; element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; element._overflow = null; return element; }, cumulativeOffset: function(element) { var valueT = 0, valueL = 0; if (element.parentNode) { do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; } while (element); } return Element._returnOffset(valueL, valueT); }, positionedOffset: function(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; if (element) { if (element.tagName.toUpperCase() == 'BODY') break; var p = Element.getStyle(element, 'position'); if (p !== 'static') break; } } while (element); return Element._returnOffset(valueL, valueT); }, absolutize: function(element) { element = $(element); if (Element.getStyle(element, 'position') == 'absolute') return element; var offsets = Element.positionedOffset(element), top = offsets[1], left = offsets[0], width = element.clientWidth, height = element.clientHeight; element._originalLeft = left - parseFloat(element.style.left || 0); element._originalTop = top - parseFloat(element.style.top || 0); element._originalWidth = element.style.width; element._originalHeight = element.style.height; element.style.position = 'absolute'; element.style.top = top + 'px'; element.style.left = left + 'px'; element.style.width = width + 'px'; element.style.height = height + 'px'; return element; }, relativize: function(element) { element = $(element); if (Element.getStyle(element, 'position') == 'relative') return element; element.style.position = 'relative'; var top = parseFloat(element.style.top || 0) - (element._originalTop || 0), left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); element.style.top = top + 'px'; element.style.left = left + 'px'; element.style.height = element._originalHeight; element.style.width = element._originalWidth; return element; }, cumulativeScrollOffset: function(element) { var valueT = 0, valueL = 0; do { valueT += element.scrollTop || 0; valueL += element.scrollLeft || 0; element = element.parentNode; } while (element); return Element._returnOffset(valueL, valueT); }, getOffsetParent: function(element) { if (element.offsetParent) return $(element.offsetParent); if (element == document.body) return $(element); while ((element = element.parentNode) && element != document.body) if (Element.getStyle(element, 'position') != 'static') return $(element); return $(document.body); }, viewportOffset: function(forElement) { var valueT = 0, valueL = 0, element = forElement; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; if (element.offsetParent == document.body && Element.getStyle(element, 'position') == 'absolute') break; } while (element = element.offsetParent); element = forElement; do { if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { valueT -= element.scrollTop || 0; valueL -= element.scrollLeft || 0; } } while (element = element.parentNode); return Element._returnOffset(valueL, valueT); }, clonePosition: function(element, source) { var options = Object.extend({ setLeft: true, setTop: true, setWidth: true, setHeight: true, offsetTop: 0, offsetLeft: 0 }, arguments[2] || { }); source = $(source); var p = Element.viewportOffset(source), delta = [0, 0], parent = null; element = $(element); if (Element.getStyle(element, 'position') == 'absolute') { parent = Element.getOffsetParent(element); delta = Element.viewportOffset(parent); } if (parent == document.body) { delta[0] -= document.body.offsetLeft; delta[1] -= document.body.offsetTop; } if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; if (options.setWidth) element.style.width = source.offsetWidth + 'px'; if (options.setHeight) element.style.height = source.offsetHeight + 'px'; return element; } }; Object.extend(Element.Methods, { getElementsBySelector: Element.Methods.select, childElements: Element.Methods.immediateDescendants }); Element._attributeTranslations = { write: { names: { className: 'class', htmlFor: 'for' }, values: { } } }; if (Prototype.Browser.Opera) { Element.Methods.getStyle = Element.Methods.getStyle.wrap( function(proceed, element, style) { switch (style) { case 'left': case 'top': case 'right': case 'bottom': if (proceed(element, 'position') === 'static') return null; case 'height': case 'width': if (!Element.visible(element)) return null; var dim = parseInt(proceed(element, style), 10); if (dim !== element['offset' + style.capitalize()]) return dim + 'px'; var properties; if (style === 'height') { properties = ['border-top-width', 'padding-top', 'padding-bottom', 'border-bottom-width']; } else { properties = ['border-left-width', 'padding-left', 'padding-right', 'border-right-width']; } return properties.inject(dim, function(memo, property) { var val = proceed(element, property); return val === null ? memo : memo - parseInt(val, 10); }) + 'px'; default: return proceed(element, style); } } ); Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( function(proceed, element, attribute) { if (attribute === 'title') return element.title; return proceed(element, attribute); } ); } else if (Prototype.Browser.IE) { Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( function(proceed, element) { element = $(element); if (!element.parentNode) return $(document.body); var position = element.getStyle('position'); if (position !== 'static') return proceed(element); element.setStyle({ position: 'relative' }); var value = proceed(element); element.setStyle({ position: position }); return value; } ); $w('positionedOffset viewportOffset').each(function(method) { Element.Methods[method] = Element.Methods[method].wrap( function(proceed, element) { element = $(element); if (!element.parentNode) return Element._returnOffset(0, 0); var position = element.getStyle('position'); if (position !== 'static') return proceed(element); var offsetParent = element.getOffsetParent(); if (offsetParent && offsetParent.getStyle('position') === 'fixed') offsetParent.setStyle({ zoom: 1 }); element.setStyle({ position: 'relative' }); var value = proceed(element); element.setStyle({ position: position }); return value; } ); }); Element.Methods.getStyle = function(element, style) { element = $(element); style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); var value = element.style[style]; if (!value && element.currentStyle) value = element.currentStyle[style]; if (style == 'opacity') { if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) if (value[1]) return parseFloat(value[1]) / 100; return 1.0; } if (value == 'auto') { if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) return element['offset' + style.capitalize()] + 'px'; return null; } return value; }; Element.Methods.setOpacity = function(element, value) { function stripAlpha(filter){ return filter.replace(/alpha\([^\)]*\)/gi,''); } element = $(element); var currentStyle = element.currentStyle; if ((currentStyle && !currentStyle.hasLayout) || (!currentStyle && element.style.zoom == 'normal')) element.style.zoom = 1; var filter = element.getStyle('filter'), style = element.style; if (value == 1 || value === '') { (filter = stripAlpha(filter)) ? style.filter = filter : style.removeAttribute('filter'); return element; } else if (value < 0.00001) value = 0; style.filter = stripAlpha(filter) + 'alpha(opacity=' + (value * 100) + ')'; return element; }; Element._attributeTranslations = (function(){ var classProp = 'className', forProp = 'for', el = document.createElement('div'); el.setAttribute(classProp, 'x'); if (el.className !== 'x') { el.setAttribute('class', 'x'); if (el.className === 'x') { classProp = 'class'; } } el = null; el = document.createElement('label'); el.setAttribute(forProp, 'x'); if (el.htmlFor !== 'x') { el.setAttribute('htmlFor', 'x'); if (el.htmlFor === 'x') { forProp = 'htmlFor'; } } el = null; return { read: { names: { 'class': classProp, 'className': classProp, 'for': forProp, 'htmlFor': forProp }, values: { _getAttr: function(element, attribute) { return element.getAttribute(attribute); }, _getAttr2: function(element, attribute) { return element.getAttribute(attribute, 2); }, _getAttrNode: function(element, attribute) { var node = element.getAttributeNode(attribute); return node ? node.value : ""; }, _getEv: (function(){ var el = document.createElement('div'), f; el.onclick = Prototype.emptyFunction; var value = el.getAttribute('onclick'); if (String(value).indexOf('{') > -1) { f = function(element, attribute) { attribute = element.getAttribute(attribute); if (!attribute) return null; attribute = attribute.toString(); attribute = attribute.split('{')[1]; attribute = attribute.split('}')[0]; return attribute.strip(); }; } else if (value === '') { f = function(element, attribute) { attribute = element.getAttribute(attribute); if (!attribute) return null; return attribute.strip(); }; } el = null; return f; })(), _flag: function(element, attribute) { return $(element).hasAttribute(attribute) ? attribute : null; }, style: function(element) { return element.style.cssText.toLowerCase(); }, title: function(element) { return element.title; } } } } })(); Element._attributeTranslations.write = { names: Object.extend({ cellpadding: 'cellPadding', cellspacing: 'cellSpacing' }, Element._attributeTranslations.read.names), values: { checked: function(element, value) { element.checked = !!value; }, style: function(element, value) { element.style.cssText = value ? value : ''; } } }; Element._attributeTranslations.has = {}; $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; Element._attributeTranslations.has[attr.toLowerCase()] = attr; }); (function(v) { Object.extend(v, { href: v._getAttr2, src: v._getAttr2, type: v._getAttr, action: v._getAttrNode, disabled: v._flag, checked: v._flag, readonly: v._flag, multiple: v._flag, onload: v._getEv, onunload: v._getEv, onclick: v._getEv, ondblclick: v._getEv, onmousedown: v._getEv, onmouseup: v._getEv, onmouseover: v._getEv, onmousemove: v._getEv, onmouseout: v._getEv, onfocus: v._getEv, onblur: v._getEv, onkeypress: v._getEv, onkeydown: v._getEv, onkeyup: v._getEv, onsubmit: v._getEv, onreset: v._getEv, onselect: v._getEv, onchange: v._getEv }); })(Element._attributeTranslations.read.values); if (Prototype.BrowserFeatures.ElementExtensions) { (function() { function _descendants(element) { var nodes = element.getElementsByTagName('*'), results = []; for (var i = 0, node; node = nodes[i]; i++) if (node.tagName !== "!") // Filter out comment nodes. results.push(node); return results; } Element.Methods.down = function(element, expression, index) { element = $(element); if (arguments.length == 1) return element.firstDescendant(); return Object.isNumber(expression) ? _descendants(element)[expression] : Element.select(element, expression)[index || 0]; } })(); } } else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { Element.Methods.setOpacity = function(element, value) { element = $(element); element.style.opacity = (value == 1) ? 0.999999 : (value === '') ? '' : (value < 0.00001) ? 0 : value; return element; }; } else if (Prototype.Browser.WebKit) { Element.Methods.setOpacity = function(element, value) { element = $(element); element.style.opacity = (value == 1 || value === '') ? '' : (value < 0.00001) ? 0 : value; if (value == 1) if (element.tagName.toUpperCase() == 'IMG' && element.width) { element.width++; element.width--; } else try { var n = document.createTextNode(' '); element.appendChild(n); element.removeChild(n); } catch (e) { } return element; }; Element.Methods.cumulativeOffset = function(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; if (element.offsetParent == document.body) if (Element.getStyle(element, 'position') == 'absolute') break; element = element.offsetParent; } while (element); return Element._returnOffset(valueL, valueT); }; } if ('outerHTML' in document.documentElement) { Element.Methods.replace = function(element, content) { element = $(element); if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) { element.parentNode.replaceChild(content, element); return element; } content = Object.toHTML(content); var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); if (Element._insertionTranslations.tags[tagName]) { var nextSibling = element.next(), fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); parent.removeChild(element); if (nextSibling) fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); else fragments.each(function(node) { parent.appendChild(node) }); } else element.outerHTML = content.stripScripts(); content.evalScripts.bind(content).defer(); return element; }; } Element._returnOffset = function(l, t) { var result = [l, t]; result.left = l; result.top = t; return result; }; Element._getContentFromAnonymousElement = function(tagName, html) { var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; if (t) { div.innerHTML = t[0] + html + t[1]; for (var i = t[2]; i--; ) { div = div.firstChild; } } else { div.innerHTML = html; } return $A(div.childNodes); }; Element._insertionTranslations = { before: function(element, node) { element.parentNode.insertBefore(node, element); }, top: function(element, node) { element.insertBefore(node, element.firstChild); }, bottom: function(element, node) { element.appendChild(node); }, after: function(element, node) { element.parentNode.insertBefore(node, element.nextSibling); }, tags: { TABLE: ['', '
    ', 1], TBODY: ['', '
    ', 2], TR: ['', '
    ', 3], TD: ['
    ', '
    ', 4], SELECT: ['', 1] } }; (function() { var tags = Element._insertionTranslations.tags; Object.extend(tags, { THEAD: tags.TBODY, TFOOT: tags.TBODY, TH: tags.TD }); })(); Element.Methods.Simulated = { hasAttribute: function(element, attribute) { attribute = Element._attributeTranslations.has[attribute] || attribute; var node = $(element).getAttributeNode(attribute); return !!(node && node.specified); } }; Element.Methods.ByTag = { }; Object.extend(Element, Element.Methods); (function(div) { if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) { window.HTMLElement = { }; window.HTMLElement.prototype = div['__proto__']; Prototype.BrowserFeatures.ElementExtensions = true; } div = null; })(document.createElement('div')); Element.extend = (function() { function checkDeficiency(tagName) { if (typeof window.Element != 'undefined') { var proto = window.Element.prototype; if (proto) { var id = '_' + (Math.random()+'').slice(2), el = document.createElement(tagName); proto[id] = 'x'; var isBuggy = (el[id] !== 'x'); delete proto[id]; el = null; return isBuggy; } } return false; } function extendElementWith(element, methods) { for (var property in methods) { var value = methods[property]; if (Object.isFunction(value) && !(property in element)) element[property] = value.methodize(); } } var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object'); if (Prototype.BrowserFeatures.SpecificElementExtensions) { if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) { return function(element) { if (element && typeof element._extendedByPrototype == 'undefined') { var t = element.tagName; if (t && (/^(?:object|applet|embed)$/i.test(t))) { extendElementWith(element, Element.Methods); extendElementWith(element, Element.Methods.Simulated); extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]); } } return element; } } return Prototype.K; } var Methods = { }, ByTag = Element.Methods.ByTag; var extend = Object.extend(function(element) { if (!element || typeof element._extendedByPrototype != 'undefined' || element.nodeType != 1 || element == window) return element; var methods = Object.clone(Methods), tagName = element.tagName.toUpperCase(); if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); extendElementWith(element, methods); element._extendedByPrototype = Prototype.emptyFunction; return element; }, { refresh: function() { if (!Prototype.BrowserFeatures.ElementExtensions) { Object.extend(Methods, Element.Methods); Object.extend(Methods, Element.Methods.Simulated); } } }); extend.refresh(); return extend; })(); if (document.documentElement.hasAttribute) { Element.hasAttribute = function(element, attribute) { return element.hasAttribute(attribute); }; } else { Element.hasAttribute = Element.Methods.Simulated.hasAttribute; } Element.addMethods = function(methods) { var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; if (!methods) { Object.extend(Form, Form.Methods); Object.extend(Form.Element, Form.Element.Methods); Object.extend(Element.Methods.ByTag, { "FORM": Object.clone(Form.Methods), "INPUT": Object.clone(Form.Element.Methods), "SELECT": Object.clone(Form.Element.Methods), "TEXTAREA": Object.clone(Form.Element.Methods) }); } if (arguments.length == 2) { var tagName = methods; methods = arguments[1]; } if (!tagName) Object.extend(Element.Methods, methods || { }); else { if (Object.isArray(tagName)) tagName.each(extend); else extend(tagName); } function extend(tagName) { tagName = tagName.toUpperCase(); if (!Element.Methods.ByTag[tagName]) Element.Methods.ByTag[tagName] = { }; Object.extend(Element.Methods.ByTag[tagName], methods); } function copy(methods, destination, onlyIfAbsent) { onlyIfAbsent = onlyIfAbsent || false; for (var property in methods) { var value = methods[property]; if (!Object.isFunction(value)) continue; if (!onlyIfAbsent || !(property in destination)) destination[property] = value.methodize(); } } function findDOMClass(tagName) { var klass; var trans = { "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": "FrameSet", "IFRAME": "IFrame" }; if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; if (window[klass]) return window[klass]; klass = 'HTML' + tagName + 'Element'; if (window[klass]) return window[klass]; klass = 'HTML' + tagName.capitalize() + 'Element'; if (window[klass]) return window[klass]; var element = document.createElement(tagName), proto = element['__proto__'] || element.constructor.prototype; element = null; return proto; } var elementPrototype = window.HTMLElement ? HTMLElement.prototype : Element.prototype; if (F.ElementExtensions) { copy(Element.Methods, elementPrototype); copy(Element.Methods.Simulated, elementPrototype, true); } if (F.SpecificElementExtensions) { for (var tag in Element.Methods.ByTag) { var klass = findDOMClass(tag); if (Object.isUndefined(klass)) continue; copy(T[tag], klass.prototype); } } Object.extend(Element, Element.Methods); delete Element.ByTag; if (Element.extend.refresh) Element.extend.refresh(); Element.cache = { }; }; document.viewport = { getDimensions: function() { return { width: this.getWidth(), height: this.getHeight() }; }, getScrollOffsets: function() { return Element._returnOffset( window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); } }; (function(viewport) { var B = Prototype.Browser, doc = document, element, property = {}; function getRootElement() { if (B.WebKit && !doc.evaluate) return document; if (B.Opera && window.parseFloat(window.opera.version()) < 9.5) return document.body; return document.documentElement; } function define(D) { if (!element) element = getRootElement(); property[D] = 'client' + D; viewport['get' + D] = function() { return element[property[D]] }; return viewport['get' + D](); } viewport.getWidth = define.curry('Width'); viewport.getHeight = define.curry('Height'); })(document.viewport); Element.Storage = { UID: 1 }; Element.addMethods({ getStorage: function(element) { if (!(element = $(element))) return; var uid; if (element === window) { uid = 0; } else { if (typeof element._prototypeUID === "undefined") element._prototypeUID = Element.Storage.UID++; uid = element._prototypeUID; } if (!Element.Storage[uid]) Element.Storage[uid] = $H(); return Element.Storage[uid]; }, store: function(element, key, value) { if (!(element = $(element))) return; if (arguments.length === 2) { Element.getStorage(element).update(key); } else { Element.getStorage(element).set(key, value); } return element; }, retrieve: function(element, key, defaultValue) { if (!(element = $(element))) return; var hash = Element.getStorage(element), value = hash.get(key); if (Object.isUndefined(value)) { hash.set(key, defaultValue); value = defaultValue; } return value; }, clone: function(element, deep) { if (!(element = $(element))) return; var clone = element.cloneNode(deep); clone._prototypeUID = void 0; if (deep) { var descendants = Element.select(clone, '*'), i = descendants.length; while (i--) { descendants[i]._prototypeUID = void 0; } } return Element.extend(clone); }, purge: function(element) { if (!(element = $(element))) return; var purgeElement = Element._purgeElement; purgeElement(element); var descendants = element.getElementsByTagName('*'), i = descendants.length; while (i--) purgeElement(descendants[i]); return null; } }); (function() { function toDecimal(pctString) { var match = pctString.match(/^(\d+)%?$/i); if (!match) return null; return (Number(match[1]) / 100); } function getPixelValue(value, property, context) { var element = null; if (Object.isElement(value)) { element = value; value = element.getStyle(property); } if (value === null) { return null; } if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) { return window.parseFloat(value); } var isPercentage = value.include('%'), isViewport = (context === document.viewport); if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) { var style = element.style.left, rStyle = element.runtimeStyle.left; element.runtimeStyle.left = element.currentStyle.left; element.style.left = value || 0; value = element.style.pixelLeft; element.style.left = style; element.runtimeStyle.left = rStyle; return value; } if (element && isPercentage) { context = context || element.parentNode; var decimal = toDecimal(value); var whole = null; var position = element.getStyle('position'); var isHorizontal = property.include('left') || property.include('right') || property.include('width'); var isVertical = property.include('top') || property.include('bottom') || property.include('height'); if (context === document.viewport) { if (isHorizontal) { whole = document.viewport.getWidth(); } else if (isVertical) { whole = document.viewport.getHeight(); } } else { if (isHorizontal) { whole = $(context).measure('width'); } else if (isVertical) { whole = $(context).measure('height'); } } return (whole === null) ? 0 : whole * decimal; } return 0; } function toCSSPixels(number) { if (Object.isString(number) && number.endsWith('px')) { return number; } return number + 'px'; } function isDisplayed(element) { var originalElement = element; while (element && element.parentNode) { var display = element.getStyle('display'); if (display === 'none') { return false; } element = $(element.parentNode); } return true; } var hasLayout = Prototype.K; if ('currentStyle' in document.documentElement) { hasLayout = function(element) { if (!element.currentStyle.hasLayout) { element.style.zoom = 1; } return element; }; } function cssNameFor(key) { if (key.include('border')) key = key + '-width'; return key.camelize(); } Element.Layout = Class.create(Hash, { initialize: function($super, element, preCompute) { $super(); this.element = $(element); Element.Layout.PROPERTIES.each( function(property) { this._set(property, null); }, this); if (preCompute) { this._preComputing = true; this._begin(); Element.Layout.PROPERTIES.each( this._compute, this ); this._end(); this._preComputing = false; } }, _set: function(property, value) { return Hash.prototype.set.call(this, property, value); }, set: function(property, value) { throw "Properties of Element.Layout are read-only."; }, get: function($super, property) { var value = $super(property); return value === null ? this._compute(property) : value; }, _begin: function() { if (this._prepared) return; var element = this.element; if (isDisplayed(element)) { this._prepared = true; return; } var originalStyles = { position: element.style.position || '', width: element.style.width || '', visibility: element.style.visibility || '', display: element.style.display || '' }; element.store('prototype_original_styles', originalStyles); var position = element.getStyle('position'), width = element.getStyle('width'); var context = (position === 'fixed') ? document.viewport : element.parentNode; element.setStyle({ position: 'absolute', visibility: 'hidden', display: 'block' }); var positionedWidth = element.getStyle('width'); var newWidth; if (width && (positionedWidth === width)) { newWidth = getPixelValue(element, 'width', context); } else if (position === 'absolute' || position === 'fixed') { newWidth = getPixelValue(element, 'width', context); } else { var parent = element.parentNode, pLayout = $(parent).getLayout(); newWidth = pLayout.get('width') - this.get('margin-left') - this.get('border-left') - this.get('padding-left') - this.get('padding-right') - this.get('border-right') - this.get('margin-right'); } element.setStyle({ width: newWidth + 'px' }); this._prepared = true; }, _end: function() { var element = this.element; var originalStyles = element.retrieve('prototype_original_styles'); element.store('prototype_original_styles', null); element.setStyle(originalStyles); this._prepared = false; }, _compute: function(property) { var COMPUTATIONS = Element.Layout.COMPUTATIONS; if (!(property in COMPUTATIONS)) { throw "Property not found."; } return this._set(property, COMPUTATIONS[property].call(this, this.element)); }, toObject: function() { var args = $A(arguments); var keys = (args.length === 0) ? Element.Layout.PROPERTIES : args.join(' ').split(' '); var obj = {}; keys.each( function(key) { if (!Element.Layout.PROPERTIES.include(key)) return; var value = this.get(key); if (value != null) obj[key] = value; }, this); return obj; }, toHash: function() { var obj = this.toObject.apply(this, arguments); return new Hash(obj); }, toCSS: function() { var args = $A(arguments); var keys = (args.length === 0) ? Element.Layout.PROPERTIES : args.join(' ').split(' '); var css = {}; keys.each( function(key) { if (!Element.Layout.PROPERTIES.include(key)) return; if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return; var value = this.get(key); if (value != null) css[cssNameFor(key)] = value + 'px'; }, this); return css; }, inspect: function() { return "#"; } }); Object.extend(Element.Layout, { PROPERTIES: $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'), COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'), COMPUTATIONS: { 'height': function(element) { if (!this._preComputing) this._begin(); var bHeight = this.get('border-box-height'); if (bHeight <= 0) { if (!this._preComputing) this._end(); return 0; } var bTop = this.get('border-top'), bBottom = this.get('border-bottom'); var pTop = this.get('padding-top'), pBottom = this.get('padding-bottom'); if (!this._preComputing) this._end(); return bHeight - bTop - bBottom - pTop - pBottom; }, 'width': function(element) { if (!this._preComputing) this._begin(); var bWidth = this.get('border-box-width'); if (bWidth <= 0) { if (!this._preComputing) this._end(); return 0; } var bLeft = this.get('border-left'), bRight = this.get('border-right'); var pLeft = this.get('padding-left'), pRight = this.get('padding-right'); if (!this._preComputing) this._end(); return bWidth - bLeft - bRight - pLeft - pRight; }, 'padding-box-height': function(element) { var height = this.get('height'), pTop = this.get('padding-top'), pBottom = this.get('padding-bottom'); return height + pTop + pBottom; }, 'padding-box-width': function(element) { var width = this.get('width'), pLeft = this.get('padding-left'), pRight = this.get('padding-right'); return width + pLeft + pRight; }, 'border-box-height': function(element) { if (!this._preComputing) this._begin(); var height = element.offsetHeight; if (!this._preComputing) this._end(); return height; }, 'border-box-width': function(element) { if (!this._preComputing) this._begin(); var width = element.offsetWidth; if (!this._preComputing) this._end(); return width; }, 'margin-box-height': function(element) { var bHeight = this.get('border-box-height'), mTop = this.get('margin-top'), mBottom = this.get('margin-bottom'); if (bHeight <= 0) return 0; return bHeight + mTop + mBottom; }, 'margin-box-width': function(element) { var bWidth = this.get('border-box-width'), mLeft = this.get('margin-left'), mRight = this.get('margin-right'); if (bWidth <= 0) return 0; return bWidth + mLeft + mRight; }, 'top': function(element) { var offset = element.positionedOffset(); return offset.top; }, 'bottom': function(element) { var offset = element.positionedOffset(), parent = element.getOffsetParent(), pHeight = parent.measure('height'); var mHeight = this.get('border-box-height'); return pHeight - mHeight - offset.top; }, 'left': function(element) { var offset = element.positionedOffset(); return offset.left; }, 'right': function(element) { var offset = element.positionedOffset(), parent = element.getOffsetParent(), pWidth = parent.measure('width'); var mWidth = this.get('border-box-width'); return pWidth - mWidth - offset.left; }, 'padding-top': function(element) { return getPixelValue(element, 'paddingTop'); }, 'padding-bottom': function(element) { return getPixelValue(element, 'paddingBottom'); }, 'padding-left': function(element) { return getPixelValue(element, 'paddingLeft'); }, 'padding-right': function(element) { return getPixelValue(element, 'paddingRight'); }, 'border-top': function(element) { return getPixelValue(element, 'borderTopWidth'); }, 'border-bottom': function(element) { return getPixelValue(element, 'borderBottomWidth'); }, 'border-left': function(element) { return getPixelValue(element, 'borderLeftWidth'); }, 'border-right': function(element) { return getPixelValue(element, 'borderRightWidth'); }, 'margin-top': function(element) { return getPixelValue(element, 'marginTop'); }, 'margin-bottom': function(element) { return getPixelValue(element, 'marginBottom'); }, 'margin-left': function(element) { return getPixelValue(element, 'marginLeft'); }, 'margin-right': function(element) { return getPixelValue(element, 'marginRight'); } } }); if ('getBoundingClientRect' in document.documentElement) { Object.extend(Element.Layout.COMPUTATIONS, { 'right': function(element) { var parent = hasLayout(element.getOffsetParent()); var rect = element.getBoundingClientRect(), pRect = parent.getBoundingClientRect(); return (pRect.right - rect.right).round(); }, 'bottom': function(element) { var parent = hasLayout(element.getOffsetParent()); var rect = element.getBoundingClientRect(), pRect = parent.getBoundingClientRect(); return (pRect.bottom - rect.bottom).round(); } }); } Element.Offset = Class.create({ initialize: function(left, top) { this.left = left.round(); this.top = top.round(); this[0] = this.left; this[1] = this.top; }, relativeTo: function(offset) { return new Element.Offset( this.left - offset.left, this.top - offset.top ); }, inspect: function() { return "#".interpolate(this); }, toString: function() { return "[#{left}, #{top}]".interpolate(this); }, toArray: function() { return [this.left, this.top]; } }); function getLayout(element, preCompute) { return new Element.Layout(element, preCompute); } function measure(element, property) { return $(element).getLayout().get(property); } function getDimensions(element) { element = $(element); var display = Element.getStyle(element, 'display'); if (display && display !== 'none') { return { width: element.offsetWidth, height: element.offsetHeight }; } var style = element.style; var originalStyles = { visibility: style.visibility, position: style.position, display: style.display }; var newStyles = { visibility: 'hidden', display: 'block' }; if (originalStyles.position !== 'fixed') newStyles.position = 'absolute'; Element.setStyle(element, newStyles); var dimensions = { width: element.offsetWidth, height: element.offsetHeight }; Element.setStyle(element, originalStyles); return dimensions; } function getOffsetParent(element) { if (isDetached(element)) return $(document.body); var isInline = (Element.getStyle(element, 'display') === 'inline'); if (!isInline && element.offsetParent) return $(element.offsetParent); if (element === document.body) return $(element); while ((element = element.parentNode) && element !== document.body) { if (Element.getStyle(element, 'position') !== 'static') { return (element.nodeName === 'HTML') ? $(document.body) : $(element); } } return $(document.body); } function cumulativeOffset(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; } while (element); return new Element.Offset(valueL, valueT); } function positionedOffset(element) { var layout = element.getLayout(); var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; if (element) { if (isBody(element)) break; var p = Element.getStyle(element, 'position'); if (p !== 'static') break; } } while (element); valueL -= layout.get('margin-top'); valueT -= layout.get('margin-left'); return new Element.Offset(valueL, valueT); } function cumulativeScrollOffset(element) { var valueT = 0, valueL = 0; do { valueT += element.scrollTop || 0; valueL += element.scrollLeft || 0; element = element.parentNode; } while (element); return new Element.Offset(valueL, valueT); } function viewportOffset(forElement) { var valueT = 0, valueL = 0, docBody = document.body; var element = forElement; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; if (element.offsetParent == docBody && Element.getStyle(element, 'position') == 'absolute') break; } while (element = element.offsetParent); element = forElement; do { if (element != docBody) { valueT -= element.scrollTop || 0; valueL -= element.scrollLeft || 0; } } while (element = element.parentNode); return new Element.Offset(valueL, valueT); } function absolutize(element) { element = $(element); if (Element.getStyle(element, 'position') === 'absolute') { return element; } var offsetParent = getOffsetParent(element); var eOffset = element.viewportOffset(), pOffset = offsetParent.viewportOffset(); var offset = eOffset.relativeTo(pOffset); var layout = element.getLayout(); element.store('prototype_absolutize_original_styles', { left: element.getStyle('left'), top: element.getStyle('top'), width: element.getStyle('width'), height: element.getStyle('height') }); element.setStyle({ position: 'absolute', top: offset.top + 'px', left: offset.left + 'px', width: layout.get('width') + 'px', height: layout.get('height') + 'px' }); return element; } function relativize(element) { element = $(element); if (Element.getStyle(element, 'position') === 'relative') { return element; } var originalStyles = element.retrieve('prototype_absolutize_original_styles'); if (originalStyles) element.setStyle(originalStyles); return element; } Element.addMethods({ getLayout: getLayout, measure: measure, getDimensions: getDimensions, getOffsetParent: getOffsetParent, cumulativeOffset: cumulativeOffset, positionedOffset: positionedOffset, cumulativeScrollOffset: cumulativeScrollOffset, viewportOffset: viewportOffset, absolutize: absolutize, relativize: relativize }); function isBody(element) { return element.nodeName.toUpperCase() === 'BODY'; } function isDetached(element) { return element !== document.body && !Element.descendantOf(element, document.body); } if ('getBoundingClientRect' in document.documentElement) { Element.addMethods({ viewportOffset: function(element) { element = $(element); if (isDetached(element)) return new Element.Offset(0, 0); var rect = element.getBoundingClientRect(), docEl = document.documentElement; return new Element.Offset(rect.left - docEl.clientLeft, rect.top - docEl.clientTop); }, positionedOffset: function(element) { element = $(element); var parent = element.getOffsetParent(); if (isDetached(element)) return new Element.Offset(0, 0); if (element.offsetParent && element.offsetParent.nodeName.toUpperCase() === 'HTML') { return positionedOffset(element); } var eOffset = element.viewportOffset(), pOffset = isBody(parent) ? viewportOffset(parent) : parent.viewportOffset(); var retOffset = eOffset.relativeTo(pOffset); var layout = element.getLayout(); var top = retOffset.top - layout.get('margin-top'); var left = retOffset.left - layout.get('margin-left'); return new Element.Offset(left, top); } }); } })(); window.$$ = function() { var expression = $A(arguments).join(', '); return Prototype.Selector.select(expression, document); }; Prototype.Selector = (function() { function select() { throw new Error('Method "Prototype.Selector.select" must be defined.'); } function match() { throw new Error('Method "Prototype.Selector.match" must be defined.'); } function find(elements, expression, index) { index = index || 0; var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i; for (i = 0; i < length; i++) { if (match(elements[i], expression) && index == matchIndex++) { return Element.extend(elements[i]); } } } function extendElements(elements) { for (var i = 0, length = elements.length; i < length; i++) { Element.extend(elements[i]); } return elements; } var K = Prototype.K; return { select: select, match: match, find: find, extendElements: (Element.extend === K) ? K : extendElements, extendElement: Element.extend }; })(); Prototype._original_property = window.Sizzle; /*! * Sizzle CSS Selector Engine - v1.0 * Copyright 2009, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * More information: http://sizzlejs.com/ */ (function(){ var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, done = 0, toString = Object.prototype.toString, hasDuplicate = false, baseHasDuplicate = true; [0, 0].sort(function(){ baseHasDuplicate = false; return 0; }); var Sizzle = function(selector, context, results, seed) { results = results || []; var origContext = context = context || document; if ( context.nodeType !== 1 && context.nodeType !== 9 ) { return []; } if ( !selector || typeof selector !== "string" ) { return results; } var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), soFar = selector; while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { soFar = m[3]; parts.push( m[1] ); if ( m[2] ) { extra = m[3]; break; } } if ( parts.length > 1 && origPOS.exec( selector ) ) { if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { set = posProcess( parts[0] + parts[1], context ); } else { set = Expr.relative[ parts[0] ] ? [ context ] : Sizzle( parts.shift(), context ); while ( parts.length ) { selector = parts.shift(); if ( Expr.relative[ selector ] ) selector += parts.shift(); set = posProcess( selector, set ); } } } else { if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { var ret = Sizzle.find( parts.shift(), context, contextXML ); context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; } if ( context ) { var ret = seed ? { expr: parts.pop(), set: makeArray(seed) } : Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; if ( parts.length > 0 ) { checkSet = makeArray(set); } else { prune = false; } while ( parts.length ) { var cur = parts.pop(), pop = cur; if ( !Expr.relative[ cur ] ) { cur = ""; } else { pop = parts.pop(); } if ( pop == null ) { pop = context; } Expr.relative[ cur ]( checkSet, pop, contextXML ); } } else { checkSet = parts = []; } } if ( !checkSet ) { checkSet = set; } if ( !checkSet ) { throw "Syntax error, unrecognized expression: " + (cur || selector); } if ( toString.call(checkSet) === "[object Array]" ) { if ( !prune ) { results.push.apply( results, checkSet ); } else if ( context && context.nodeType === 1 ) { for ( var i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { results.push( set[i] ); } } } else { for ( var i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && checkSet[i].nodeType === 1 ) { results.push( set[i] ); } } } } else { makeArray( checkSet, results ); } if ( extra ) { Sizzle( extra, origContext, results, seed ); Sizzle.uniqueSort( results ); } return results; }; Sizzle.uniqueSort = function(results){ if ( sortOrder ) { hasDuplicate = baseHasDuplicate; results.sort(sortOrder); if ( hasDuplicate ) { for ( var i = 1; i < results.length; i++ ) { if ( results[i] === results[i-1] ) { results.splice(i--, 1); } } } } return results; }; Sizzle.matches = function(expr, set){ return Sizzle(expr, null, null, set); }; Sizzle.find = function(expr, context, isXML){ var set, match; if ( !expr ) { return []; } for ( var i = 0, l = Expr.order.length; i < l; i++ ) { var type = Expr.order[i], match; if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { var left = match[1]; match.splice(1,1); if ( left.substr( left.length - 1 ) !== "\\" ) { match[1] = (match[1] || "").replace(/\\/g, ""); set = Expr.find[ type ]( match, context, isXML ); if ( set != null ) { expr = expr.replace( Expr.match[ type ], "" ); break; } } } } if ( !set ) { set = context.getElementsByTagName("*"); } return {set: set, expr: expr}; }; Sizzle.filter = function(expr, set, inplace, not){ var old = expr, result = [], curLoop = set, match, anyFound, isXMLFilter = set && set[0] && isXML(set[0]); while ( expr && set.length ) { for ( var type in Expr.filter ) { if ( (match = Expr.match[ type ].exec( expr )) != null ) { var filter = Expr.filter[ type ], found, item; anyFound = false; if ( curLoop == result ) { result = []; } if ( Expr.preFilter[ type ] ) { match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); if ( !match ) { anyFound = found = true; } else if ( match === true ) { continue; } } if ( match ) { for ( var i = 0; (item = curLoop[i]) != null; i++ ) { if ( item ) { found = filter( item, match, i, curLoop ); var pass = not ^ !!found; if ( inplace && found != null ) { if ( pass ) { anyFound = true; } else { curLoop[i] = false; } } else if ( pass ) { result.push( item ); anyFound = true; } } } } if ( found !== undefined ) { if ( !inplace ) { curLoop = result; } expr = expr.replace( Expr.match[ type ], "" ); if ( !anyFound ) { return []; } break; } } } if ( expr == old ) { if ( anyFound == null ) { throw "Syntax error, unrecognized expression: " + expr; } else { break; } } old = expr; } return curLoop; }; var Expr = Sizzle.selectors = { order: [ "ID", "NAME", "TAG" ], match: { ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ }, leftMatch: {}, attrMap: { "class": "className", "for": "htmlFor" }, attrHandle: { href: function(elem){ return elem.getAttribute("href"); } }, relative: { "+": function(checkSet, part, isXML){ var isPartStr = typeof part === "string", isTag = isPartStr && !/\W/.test(part), isPartStrNotTag = isPartStr && !isTag; if ( isTag && !isXML ) { part = part.toUpperCase(); } for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { if ( (elem = checkSet[i]) ) { while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? elem || false : elem === part; } } if ( isPartStrNotTag ) { Sizzle.filter( part, checkSet, true ); } }, ">": function(checkSet, part, isXML){ var isPartStr = typeof part === "string"; if ( isPartStr && !/\W/.test(part) ) { part = isXML ? part : part.toUpperCase(); for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { var parent = elem.parentNode; checkSet[i] = parent.nodeName === part ? parent : false; } } } else { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { checkSet[i] = isPartStr ? elem.parentNode : elem.parentNode === part; } } if ( isPartStr ) { Sizzle.filter( part, checkSet, true ); } } }, "": function(checkSet, part, isXML){ var doneName = done++, checkFn = dirCheck; if ( !/\W/.test(part) ) { var nodeCheck = part = isXML ? part : part.toUpperCase(); checkFn = dirNodeCheck; } checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); }, "~": function(checkSet, part, isXML){ var doneName = done++, checkFn = dirCheck; if ( typeof part === "string" && !/\W/.test(part) ) { var nodeCheck = part = isXML ? part : part.toUpperCase(); checkFn = dirNodeCheck; } checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); } }, find: { ID: function(match, context, isXML){ if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); return m ? [m] : []; } }, NAME: function(match, context, isXML){ if ( typeof context.getElementsByName !== "undefined" ) { var ret = [], results = context.getElementsByName(match[1]); for ( var i = 0, l = results.length; i < l; i++ ) { if ( results[i].getAttribute("name") === match[1] ) { ret.push( results[i] ); } } return ret.length === 0 ? null : ret; } }, TAG: function(match, context){ return context.getElementsByTagName(match[1]); } }, preFilter: { CLASS: function(match, curLoop, inplace, result, not, isXML){ match = " " + match[1].replace(/\\/g, "") + " "; if ( isXML ) { return match; } for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { if ( elem ) { if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { if ( !inplace ) result.push( elem ); } else if ( inplace ) { curLoop[i] = false; } } } return false; }, ID: function(match){ return match[1].replace(/\\/g, ""); }, TAG: function(match, curLoop){ for ( var i = 0; curLoop[i] === false; i++ ){} return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); }, CHILD: function(match){ if ( match[1] == "nth" ) { var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); match[2] = (test[1] + (test[2] || 1)) - 0; match[3] = test[3] - 0; } match[0] = done++; return match; }, ATTR: function(match, curLoop, inplace, result, not, isXML){ var name = match[1].replace(/\\/g, ""); if ( !isXML && Expr.attrMap[name] ) { match[1] = Expr.attrMap[name]; } if ( match[2] === "~=" ) { match[4] = " " + match[4] + " "; } return match; }, PSEUDO: function(match, curLoop, inplace, result, not){ if ( match[1] === "not" ) { if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { match[3] = Sizzle(match[3], null, null, curLoop); } else { var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); if ( !inplace ) { result.push.apply( result, ret ); } return false; } } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { return true; } return match; }, POS: function(match){ match.unshift( true ); return match; } }, filters: { enabled: function(elem){ return elem.disabled === false && elem.type !== "hidden"; }, disabled: function(elem){ return elem.disabled === true; }, checked: function(elem){ return elem.checked === true; }, selected: function(elem){ elem.parentNode.selectedIndex; return elem.selected === true; }, parent: function(elem){ return !!elem.firstChild; }, empty: function(elem){ return !elem.firstChild; }, has: function(elem, i, match){ return !!Sizzle( match[3], elem ).length; }, header: function(elem){ return /h\d/i.test( elem.nodeName ); }, text: function(elem){ return "text" === elem.type; }, radio: function(elem){ return "radio" === elem.type; }, checkbox: function(elem){ return "checkbox" === elem.type; }, file: function(elem){ return "file" === elem.type; }, password: function(elem){ return "password" === elem.type; }, submit: function(elem){ return "submit" === elem.type; }, image: function(elem){ return "image" === elem.type; }, reset: function(elem){ return "reset" === elem.type; }, button: function(elem){ return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; }, input: function(elem){ return /input|select|textarea|button/i.test(elem.nodeName); } }, setFilters: { first: function(elem, i){ return i === 0; }, last: function(elem, i, match, array){ return i === array.length - 1; }, even: function(elem, i){ return i % 2 === 0; }, odd: function(elem, i){ return i % 2 === 1; }, lt: function(elem, i, match){ return i < match[3] - 0; }, gt: function(elem, i, match){ return i > match[3] - 0; }, nth: function(elem, i, match){ return match[3] - 0 == i; }, eq: function(elem, i, match){ return match[3] - 0 == i; } }, filter: { PSEUDO: function(elem, match, i, array){ var name = match[1], filter = Expr.filters[ name ]; if ( filter ) { return filter( elem, i, match, array ); } else if ( name === "contains" ) { return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; } else if ( name === "not" ) { var not = match[3]; for ( var i = 0, l = not.length; i < l; i++ ) { if ( not[i] === elem ) { return false; } } return true; } }, CHILD: function(elem, match){ var type = match[1], node = elem; switch (type) { case 'only': case 'first': while ( (node = node.previousSibling) ) { if ( node.nodeType === 1 ) return false; } if ( type == 'first') return true; node = elem; case 'last': while ( (node = node.nextSibling) ) { if ( node.nodeType === 1 ) return false; } return true; case 'nth': var first = match[2], last = match[3]; if ( first == 1 && last == 0 ) { return true; } var doneName = match[0], parent = elem.parentNode; if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { var count = 0; for ( node = parent.firstChild; node; node = node.nextSibling ) { if ( node.nodeType === 1 ) { node.nodeIndex = ++count; } } parent.sizcache = doneName; } var diff = elem.nodeIndex - last; if ( first == 0 ) { return diff == 0; } else { return ( diff % first == 0 && diff / first >= 0 ); } } }, ID: function(elem, match){ return elem.nodeType === 1 && elem.getAttribute("id") === match; }, TAG: function(elem, match){ return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; }, CLASS: function(elem, match){ return (" " + (elem.className || elem.getAttribute("class")) + " ") .indexOf( match ) > -1; }, ATTR: function(elem, match){ var name = match[1], result = Expr.attrHandle[ name ] ? Expr.attrHandle[ name ]( elem ) : elem[ name ] != null ? elem[ name ] : elem.getAttribute( name ), value = result + "", type = match[2], check = match[4]; return result == null ? type === "!=" : type === "=" ? value === check : type === "*=" ? value.indexOf(check) >= 0 : type === "~=" ? (" " + value + " ").indexOf(check) >= 0 : !check ? value && result !== false : type === "!=" ? value != check : type === "^=" ? value.indexOf(check) === 0 : type === "$=" ? value.substr(value.length - check.length) === check : type === "|=" ? value === check || value.substr(0, check.length + 1) === check + "-" : false; }, POS: function(elem, match, i, array){ var name = match[2], filter = Expr.setFilters[ name ]; if ( filter ) { return filter( elem, i, match, array ); } } } }; var origPOS = Expr.match.POS; for ( var type in Expr.match ) { Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source ); } var makeArray = function(array, results) { array = Array.prototype.slice.call( array, 0 ); if ( results ) { results.push.apply( results, array ); return results; } return array; }; try { Array.prototype.slice.call( document.documentElement.childNodes, 0 ); } catch(e){ makeArray = function(array, results) { var ret = results || []; if ( toString.call(array) === "[object Array]" ) { Array.prototype.push.apply( ret, array ); } else { if ( typeof array.length === "number" ) { for ( var i = 0, l = array.length; i < l; i++ ) { ret.push( array[i] ); } } else { for ( var i = 0; array[i]; i++ ) { ret.push( array[i] ); } } } return ret; }; } var sortOrder; if ( document.documentElement.compareDocumentPosition ) { sortOrder = function( a, b ) { if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { if ( a == b ) { hasDuplicate = true; } return 0; } var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; if ( ret === 0 ) { hasDuplicate = true; } return ret; }; } else if ( "sourceIndex" in document.documentElement ) { sortOrder = function( a, b ) { if ( !a.sourceIndex || !b.sourceIndex ) { if ( a == b ) { hasDuplicate = true; } return 0; } var ret = a.sourceIndex - b.sourceIndex; if ( ret === 0 ) { hasDuplicate = true; } return ret; }; } else if ( document.createRange ) { sortOrder = function( a, b ) { if ( !a.ownerDocument || !b.ownerDocument ) { if ( a == b ) { hasDuplicate = true; } return 0; } var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); aRange.setStart(a, 0); aRange.setEnd(a, 0); bRange.setStart(b, 0); bRange.setEnd(b, 0); var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); if ( ret === 0 ) { hasDuplicate = true; } return ret; }; } (function(){ var form = document.createElement("div"), id = "script" + (new Date).getTime(); form.innerHTML = ""; var root = document.documentElement; root.insertBefore( form, root.firstChild ); if ( !!document.getElementById( id ) ) { Expr.find.ID = function(match, context, isXML){ if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; } }; Expr.filter.ID = function(elem, match){ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); return elem.nodeType === 1 && node && node.nodeValue === match; }; } root.removeChild( form ); root = form = null; // release memory in IE })(); (function(){ var div = document.createElement("div"); div.appendChild( document.createComment("") ); if ( div.getElementsByTagName("*").length > 0 ) { Expr.find.TAG = function(match, context){ var results = context.getElementsByTagName(match[1]); if ( match[1] === "*" ) { var tmp = []; for ( var i = 0; results[i]; i++ ) { if ( results[i].nodeType === 1 ) { tmp.push( results[i] ); } } results = tmp; } return results; }; } div.innerHTML = ""; if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && div.firstChild.getAttribute("href") !== "#" ) { Expr.attrHandle.href = function(elem){ return elem.getAttribute("href", 2); }; } div = null; // release memory in IE })(); if ( document.querySelectorAll ) (function(){ var oldSizzle = Sizzle, div = document.createElement("div"); div.innerHTML = "

    "; if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { return; } Sizzle = function(query, context, extra, seed){ context = context || document; if ( !seed && context.nodeType === 9 && !isXML(context) ) { try { return makeArray( context.querySelectorAll(query), extra ); } catch(e){} } return oldSizzle(query, context, extra, seed); }; for ( var prop in oldSizzle ) { Sizzle[ prop ] = oldSizzle[ prop ]; } div = null; // release memory in IE })(); if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ var div = document.createElement("div"); div.innerHTML = "
    "; if ( div.getElementsByClassName("e").length === 0 ) return; div.lastChild.className = "e"; if ( div.getElementsByClassName("e").length === 1 ) return; Expr.order.splice(1, 0, "CLASS"); Expr.find.CLASS = function(match, context, isXML) { if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { return context.getElementsByClassName(match[1]); } }; div = null; // release memory in IE })(); function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { var sibDir = dir == "previousSibling" && !isXML; for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { if ( sibDir && elem.nodeType === 1 ){ elem.sizcache = doneName; elem.sizset = i; } elem = elem[dir]; var match = false; while ( elem ) { if ( elem.sizcache === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 && !isXML ){ elem.sizcache = doneName; elem.sizset = i; } if ( elem.nodeName === cur ) { match = elem; break; } elem = elem[dir]; } checkSet[i] = match; } } } function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { var sibDir = dir == "previousSibling" && !isXML; for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { if ( sibDir && elem.nodeType === 1 ) { elem.sizcache = doneName; elem.sizset = i; } elem = elem[dir]; var match = false; while ( elem ) { if ( elem.sizcache === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 ) { if ( !isXML ) { elem.sizcache = doneName; elem.sizset = i; } if ( typeof cur !== "string" ) { if ( elem === cur ) { match = true; break; } } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { match = elem; break; } } elem = elem[dir]; } checkSet[i] = match; } } } var contains = document.compareDocumentPosition ? function(a, b){ return a.compareDocumentPosition(b) & 16; } : function(a, b){ return a !== b && (a.contains ? a.contains(b) : true); }; var isXML = function(elem){ return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; }; var posProcess = function(selector, context){ var tmpSet = [], later = "", match, root = context.nodeType ? [context] : context; while ( (match = Expr.match.PSEUDO.exec( selector )) ) { later += match[0]; selector = selector.replace( Expr.match.PSEUDO, "" ); } selector = Expr.relative[selector] ? selector + "*" : selector; for ( var i = 0, l = root.length; i < l; i++ ) { Sizzle( selector, root[i], tmpSet ); } return Sizzle.filter( later, tmpSet ); }; window.Sizzle = Sizzle; })(); ;(function(engine) { var extendElements = Prototype.Selector.extendElements; function select(selector, scope) { return extendElements(engine(selector, scope || document)); } function match(element, selector) { return engine.matches(selector, [element]).length == 1; } Prototype.Selector.engine = engine; Prototype.Selector.select = select; Prototype.Selector.match = match; })(Sizzle); window.Sizzle = Prototype._original_property; delete Prototype._original_property; var Form = { reset: function(form) { form = $(form); form.reset(); return form; }, serializeElements: function(elements, options) { if (typeof options != 'object') options = { hash: !!options }; else if (Object.isUndefined(options.hash)) options.hash = true; var key, value, submitted = false, submit = options.submit, accumulator, initial; if (options.hash) { initial = {}; accumulator = function(result, key, value) { if (key in result) { if (!Object.isArray(result[key])) result[key] = [result[key]]; result[key].push(value); } else result[key] = value; return result; }; } else { initial = ''; accumulator = function(result, key, value) { return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + encodeURIComponent(value); } } return elements.inject(initial, function(result, element) { if (!element.disabled && element.name) { key = element.name; value = $(element).getValue(); if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && submit !== false && (!submit || key == submit) && (submitted = true)))) { result = accumulator(result, key, value); } } return result; }); } }; Form.Methods = { serialize: function(form, options) { return Form.serializeElements(Form.getElements(form), options); }, getElements: function(form) { var elements = $(form).getElementsByTagName('*'), element, arr = [ ], serializers = Form.Element.Serializers; for (var i = 0; element = elements[i]; i++) { arr.push(element); } return arr.inject([], function(elements, child) { if (serializers[child.tagName.toLowerCase()]) elements.push(Element.extend(child)); return elements; }) }, getInputs: function(form, typeName, name) { form = $(form); var inputs = form.getElementsByTagName('input'); if (!typeName && !name) return $A(inputs).map(Element.extend); for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { var input = inputs[i]; if ((typeName && input.type != typeName) || (name && input.name != name)) continue; matchingInputs.push(Element.extend(input)); } return matchingInputs; }, disable: function(form) { form = $(form); Form.getElements(form).invoke('disable'); return form; }, enable: function(form) { form = $(form); Form.getElements(form).invoke('enable'); return form; }, findFirstElement: function(form) { var elements = $(form).getElements().findAll(function(element) { return 'hidden' != element.type && !element.disabled; }); var firstByIndex = elements.findAll(function(element) { return element.hasAttribute('tabIndex') && element.tabIndex >= 0; }).sortBy(function(element) { return element.tabIndex }).first(); return firstByIndex ? firstByIndex : elements.find(function(element) { return /^(?:input|select|textarea)$/i.test(element.tagName); }); }, focusFirstElement: function(form) { form = $(form); form.findFirstElement().activate(); return form; }, request: function(form, options) { form = $(form), options = Object.clone(options || { }); var params = options.parameters, action = form.readAttribute('action') || ''; if (action.blank()) action = window.location.href; options.parameters = form.serialize(true); if (params) { if (Object.isString(params)) params = params.toQueryParams(); Object.extend(options.parameters, params); } if (form.hasAttribute('method') && !options.method) options.method = form.method; return new Ajax.Request(action, options); } }; /*--------------------------------------------------------------------------*/ Form.Element = { focus: function(element) { $(element).focus(); return element; }, select: function(element) { $(element).select(); return element; } }; Form.Element.Methods = { serialize: function(element) { element = $(element); if (!element.disabled && element.name) { var value = element.getValue(); if (value != undefined) { var pair = { }; pair[element.name] = value; return Object.toQueryString(pair); } } return ''; }, getValue: function(element) { element = $(element); var method = element.tagName.toLowerCase(); return Form.Element.Serializers[method](element); }, setValue: function(element, value) { element = $(element); var method = element.tagName.toLowerCase(); Form.Element.Serializers[method](element, value); return element; }, clear: function(element) { $(element).value = ''; return element; }, present: function(element) { return $(element).value != ''; }, activate: function(element) { element = $(element); try { element.focus(); if (element.select && (element.tagName.toLowerCase() != 'input' || !(/^(?:button|reset|submit)$/i.test(element.type)))) element.select(); } catch (e) { } return element; }, disable: function(element) { element = $(element); element.disabled = true; return element; }, enable: function(element) { element = $(element); element.disabled = false; return element; } }; /*--------------------------------------------------------------------------*/ var Field = Form.Element; var $F = Form.Element.Methods.getValue; /*--------------------------------------------------------------------------*/ Form.Element.Serializers = { input: function(element, value) { switch (element.type.toLowerCase()) { case 'checkbox': case 'radio': return Form.Element.Serializers.inputSelector(element, value); default: return Form.Element.Serializers.textarea(element, value); } }, inputSelector: function(element, value) { if (Object.isUndefined(value)) return element.checked ? element.value : null; else element.checked = !!value; }, textarea: function(element, value) { if (Object.isUndefined(value)) return element.value; else element.value = value; }, select: function(element, value) { if (Object.isUndefined(value)) return this[element.type == 'select-one' ? 'selectOne' : 'selectMany'](element); else { var opt, currentValue, single = !Object.isArray(value); for (var i = 0, length = element.length; i < length; i++) { opt = element.options[i]; currentValue = this.optionValue(opt); if (single) { if (currentValue == value) { opt.selected = true; return; } } else opt.selected = value.include(currentValue); } } }, selectOne: function(element) { var index = element.selectedIndex; return index >= 0 ? this.optionValue(element.options[index]) : null; }, selectMany: function(element) { var values, length = element.length; if (!length) return null; for (var i = 0, values = []; i < length; i++) { var opt = element.options[i]; if (opt.selected) values.push(this.optionValue(opt)); } return values; }, optionValue: function(opt) { return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; } }; /*--------------------------------------------------------------------------*/ Abstract.TimedObserver = Class.create(PeriodicalExecuter, { initialize: function($super, element, frequency, callback) { $super(callback, frequency); this.element = $(element); this.lastValue = this.getValue(); }, execute: function() { var value = this.getValue(); if (Object.isString(this.lastValue) && Object.isString(value) ? this.lastValue != value : String(this.lastValue) != String(value)) { this.callback(this.element, value); this.lastValue = value; } } }); Form.Element.Observer = Class.create(Abstract.TimedObserver, { getValue: function() { return Form.Element.getValue(this.element); } }); Form.Observer = Class.create(Abstract.TimedObserver, { getValue: function() { return Form.serialize(this.element); } }); /*--------------------------------------------------------------------------*/ Abstract.EventObserver = Class.create({ initialize: function(element, callback) { this.element = $(element); this.callback = callback; this.lastValue = this.getValue(); if (this.element.tagName.toLowerCase() == 'form') this.registerFormCallbacks(); else this.registerCallback(this.element); }, onElementEvent: function() { var value = this.getValue(); if (this.lastValue != value) { this.callback(this.element, value); this.lastValue = value; } }, registerFormCallbacks: function() { Form.getElements(this.element).each(this.registerCallback, this); }, registerCallback: function(element) { if (element.type) { switch (element.type.toLowerCase()) { case 'checkbox': case 'radio': Event.observe(element, 'click', this.onElementEvent.bind(this)); break; default: Event.observe(element, 'change', this.onElementEvent.bind(this)); break; } } } }); Form.Element.EventObserver = Class.create(Abstract.EventObserver, { getValue: function() { return Form.Element.getValue(this.element); } }); Form.EventObserver = Class.create(Abstract.EventObserver, { getValue: function() { return Form.serialize(this.element); } }); (function() { var Event = { KEY_BACKSPACE: 8, KEY_TAB: 9, KEY_RETURN: 13, KEY_ESC: 27, KEY_LEFT: 37, KEY_UP: 38, KEY_RIGHT: 39, KEY_DOWN: 40, KEY_DELETE: 46, KEY_HOME: 36, KEY_END: 35, KEY_PAGEUP: 33, KEY_PAGEDOWN: 34, KEY_INSERT: 45, cache: {} }; var docEl = document.documentElement; var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl && 'onmouseleave' in docEl; var _isButton; if (Prototype.Browser.IE) { var buttonMap = { 0: 1, 1: 4, 2: 2 }; _isButton = function(event, code) { return event.button === buttonMap[code]; }; } else if (Prototype.Browser.WebKit) { _isButton = function(event, code) { switch (code) { case 0: return event.which == 1 && !event.metaKey; case 1: return event.which == 1 && event.metaKey; default: return false; } }; } else { _isButton = function(event, code) { return event.which ? (event.which === code + 1) : (event.button === code); }; } function isLeftClick(event) { return _isButton(event, 0) } function isMiddleClick(event) { return _isButton(event, 1) } function isRightClick(event) { return _isButton(event, 2) } function element(event) { event = Event.extend(event); var node = event.target, type = event.type, currentTarget = event.currentTarget; if (currentTarget && currentTarget.tagName) { if (type === 'load' || type === 'error' || (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' && currentTarget.type === 'radio')) node = currentTarget; } if (node.nodeType == Node.TEXT_NODE) node = node.parentNode; return Element.extend(node); } function findElement(event, expression) { var element = Event.element(event); if (!expression) return element; while (element) { if (Object.isElement(element) && Prototype.Selector.match(element, expression)) { return Element.extend(element); } element = element.parentNode; } } function pointer(event) { return { x: pointerX(event), y: pointerY(event) }; } function pointerX(event) { var docElement = document.documentElement, body = document.body || { scrollLeft: 0 }; return event.pageX || (event.clientX + (docElement.scrollLeft || body.scrollLeft) - (docElement.clientLeft || 0)); } function pointerY(event) { var docElement = document.documentElement, body = document.body || { scrollTop: 0 }; return event.pageY || (event.clientY + (docElement.scrollTop || body.scrollTop) - (docElement.clientTop || 0)); } function stop(event) { Event.extend(event); event.preventDefault(); event.stopPropagation(); event.stopped = true; } Event.Methods = { isLeftClick: isLeftClick, isMiddleClick: isMiddleClick, isRightClick: isRightClick, element: element, findElement: findElement, pointer: pointer, pointerX: pointerX, pointerY: pointerY, stop: stop }; var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { m[name] = Event.Methods[name].methodize(); return m; }); if (Prototype.Browser.IE) { function _relatedTarget(event) { var element; switch (event.type) { case 'mouseover': element = event.fromElement; break; case 'mouseout': element = event.toElement; break; default: return null; } return Element.extend(element); } Object.extend(methods, { stopPropagation: function() { this.cancelBubble = true }, preventDefault: function() { this.returnValue = false }, inspect: function() { return '[object Event]' } }); Event.extend = function(event, element) { if (!event) return false; if (event._extendedByPrototype) return event; event._extendedByPrototype = Prototype.emptyFunction; var pointer = Event.pointer(event); Object.extend(event, { target: event.srcElement || element, relatedTarget: _relatedTarget(event), pageX: pointer.x, pageY: pointer.y }); return Object.extend(event, methods); }; } else { Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__; Object.extend(Event.prototype, methods); Event.extend = Prototype.K; } function _createResponder(element, eventName, handler) { var registry = Element.retrieve(element, 'prototype_event_registry'); if (Object.isUndefined(registry)) { CACHE.push(element); registry = Element.retrieve(element, 'prototype_event_registry', $H()); } var respondersForEvent = registry.get(eventName); if (Object.isUndefined(respondersForEvent)) { respondersForEvent = []; registry.set(eventName, respondersForEvent); } if (respondersForEvent.pluck('handler').include(handler)) return false; var responder; if (eventName.include(":")) { responder = function(event) { if (Object.isUndefined(event.eventName)) return false; if (event.eventName !== eventName) return false; Event.extend(event, element); handler.call(element, event); }; } else { if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED && (eventName === "mouseenter" || eventName === "mouseleave")) { if (eventName === "mouseenter" || eventName === "mouseleave") { responder = function(event) { Event.extend(event, element); var parent = event.relatedTarget; while (parent && parent !== element) { try { parent = parent.parentNode; } catch(e) { parent = element; } } if (parent === element) return; handler.call(element, event); }; } } else { responder = function(event) { Event.extend(event, element); handler.call(element, event); }; } } responder.handler = handler; respondersForEvent.push(responder); return responder; } function _destroyCache() { for (var i = 0, length = CACHE.length; i < length; i++) { Event.stopObserving(CACHE[i]); CACHE[i] = null; } } var CACHE = []; if (Prototype.Browser.IE) window.attachEvent('onunload', _destroyCache); if (Prototype.Browser.WebKit) window.addEventListener('unload', Prototype.emptyFunction, false); var _getDOMEventName = Prototype.K, translations = { mouseenter: "mouseover", mouseleave: "mouseout" }; if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) { _getDOMEventName = function(eventName) { return (translations[eventName] || eventName); }; } function observe(element, eventName, handler) { element = $(element); var responder = _createResponder(element, eventName, handler); if (!responder) return element; if (eventName.include(':')) { if (element.addEventListener) element.addEventListener("dataavailable", responder, false); else { element.attachEvent("ondataavailable", responder); element.attachEvent("onlosecapture", responder); } } else { var actualEventName = _getDOMEventName(eventName); if (element.addEventListener) element.addEventListener(actualEventName, responder, false); else element.attachEvent("on" + actualEventName, responder); } return element; } function stopObserving(element, eventName, handler) { element = $(element); var registry = Element.retrieve(element, 'prototype_event_registry'); if (!registry) return element; if (!eventName) { registry.each( function(pair) { var eventName = pair.key; stopObserving(element, eventName); }); return element; } var responders = registry.get(eventName); if (!responders) return element; if (!handler) { responders.each(function(r) { stopObserving(element, eventName, r.handler); }); return element; } var responder = responders.find( function(r) { return r.handler === handler; }); if (!responder) return element; if (eventName.include(':')) { if (element.removeEventListener) element.removeEventListener("dataavailable", responder, false); else { element.detachEvent("ondataavailable", responder); element.detachEvent("onlosecapture", responder); } } else { var actualEventName = _getDOMEventName(eventName); if (element.removeEventListener) element.removeEventListener(actualEventName, responder, false); else element.detachEvent('on' + actualEventName, responder); } registry.set(eventName, responders.without(responder)); return element; } function fire(element, eventName, memo, bubble) { element = $(element); if (Object.isUndefined(bubble)) bubble = true; if (element == document && document.createEvent && !element.dispatchEvent) element = document.documentElement; var event; if (document.createEvent) { event = document.createEvent('HTMLEvents'); event.initEvent('dataavailable', bubble, true); } else { event = document.createEventObject(); event.eventType = bubble ? 'ondataavailable' : 'onlosecapture'; } event.eventName = eventName; event.memo = memo || { }; if (document.createEvent) element.dispatchEvent(event); else element.fireEvent(event.eventType, event); return Event.extend(event); } Event.Handler = Class.create({ initialize: function(element, eventName, selector, callback) { this.element = $(element); this.eventName = eventName; this.selector = selector; this.callback = callback; this.handler = this.handleEvent.bind(this); }, start: function() { Event.observe(this.element, this.eventName, this.handler); return this; }, stop: function() { Event.stopObserving(this.element, this.eventName, this.handler); return this; }, handleEvent: function(event) { var element = event.findElement(this.selector); if (element) this.callback.call(this.element, event, element); } }); function on(element, eventName, selector, callback) { element = $(element); if (Object.isFunction(selector) && Object.isUndefined(callback)) { callback = selector, selector = null; } return new Event.Handler(element, eventName, selector, callback).start(); } Object.extend(Event, Event.Methods); Object.extend(Event, { fire: fire, observe: observe, stopObserving: stopObserving, on: on }); Element.addMethods({ fire: fire, observe: observe, stopObserving: stopObserving, on: on }); Object.extend(document, { fire: fire.methodize(), observe: observe.methodize(), stopObserving: stopObserving.methodize(), on: on.methodize(), loaded: false }); if (window.Event) Object.extend(window.Event, Event); else window.Event = Event; })(); (function() { /* Support for the DOMContentLoaded event is based on work by Dan Webb, Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ var timer; function fireContentLoadedEvent() { if (document.loaded) return; if (timer) window.clearTimeout(timer); document.loaded = true; document.fire('dom:loaded'); } function checkReadyState() { if (document.readyState === 'complete') { document.stopObserving('readystatechange', checkReadyState); fireContentLoadedEvent(); } } function pollDoScroll() { try { document.documentElement.doScroll('left'); } catch(e) { timer = pollDoScroll.defer(); return; } fireContentLoadedEvent(); } if (document.addEventListener) { document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false); } else { document.observe('readystatechange', checkReadyState); if (window == top) timer = pollDoScroll.defer(); } Event.observe(window, 'load', fireContentLoadedEvent); })(); Element.addMethods(); /*------------------------------- DEPRECATED -------------------------------*/ Hash.toQueryString = Object.toQueryString; var Toggle = { display: Element.toggle }; Element.Methods.childOf = Element.Methods.descendantOf; var Insertion = { Before: function(element, content) { return Element.insert(element, {before:content}); }, Top: function(element, content) { return Element.insert(element, {top:content}); }, Bottom: function(element, content) { return Element.insert(element, {bottom:content}); }, After: function(element, content) { return Element.insert(element, {after:content}); } }; var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); var Position = { includeScrollOffsets: false, prepare: function() { this.deltaX = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0; this.deltaY = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; }, within: function(element, x, y) { if (this.includeScrollOffsets) return this.withinIncludingScrolloffsets(element, x, y); this.xcomp = x; this.ycomp = y; this.offset = Element.cumulativeOffset(element); return (y >= this.offset[1] && y < this.offset[1] + element.offsetHeight && x >= this.offset[0] && x < this.offset[0] + element.offsetWidth); }, withinIncludingScrolloffsets: function(element, x, y) { var offsetcache = Element.cumulativeScrollOffset(element); this.xcomp = x + offsetcache[0] - this.deltaX; this.ycomp = y + offsetcache[1] - this.deltaY; this.offset = Element.cumulativeOffset(element); return (this.ycomp >= this.offset[1] && this.ycomp < this.offset[1] + element.offsetHeight && this.xcomp >= this.offset[0] && this.xcomp < this.offset[0] + element.offsetWidth); }, overlap: function(mode, element) { if (!mode) return 0; if (mode == 'vertical') return ((this.offset[1] + element.offsetHeight) - this.ycomp) / element.offsetHeight; if (mode == 'horizontal') return ((this.offset[0] + element.offsetWidth) - this.xcomp) / element.offsetWidth; }, cumulativeOffset: Element.Methods.cumulativeOffset, positionedOffset: Element.Methods.positionedOffset, absolutize: function(element) { Position.prepare(); return Element.absolutize(element); }, relativize: function(element) { Position.prepare(); return Element.relativize(element); }, realOffset: Element.Methods.cumulativeScrollOffset, offsetParent: Element.Methods.getOffsetParent, page: Element.Methods.viewportOffset, clone: function(source, target, options) { options = options || { }; return Element.clonePosition(target, source, options); } }; /*--------------------------------------------------------------------------*/ if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){ function iter(name) { return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]"; } instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ? function(element, className) { className = className.toString().strip(); var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className); return cond ? document._getElementsByXPath('.//*' + cond, element) : []; } : function(element, className) { className = className.toString().strip(); var elements = [], classNames = (/\s/.test(className) ? $w(className) : null); if (!classNames && !className) return elements; var nodes = $(element).getElementsByTagName('*'); className = ' ' + className + ' '; for (var i = 0, child, cn; child = nodes[i]; i++) { if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) || (classNames && classNames.all(function(name) { return !name.toString().blank() && cn.include(' ' + name + ' '); })))) elements.push(Element.extend(child)); } return elements; }; return function(className, parentElement) { return $(parentElement || document.body).getElementsByClassName(className); }; }(Element.Methods); /*--------------------------------------------------------------------------*/ Element.ClassNames = Class.create(); Element.ClassNames.prototype = { initialize: function(element) { this.element = $(element); }, _each: function(iterator) { this.element.className.split(/\s+/).select(function(name) { return name.length > 0; })._each(iterator); }, set: function(className) { this.element.className = className; }, add: function(classNameToAdd) { if (this.include(classNameToAdd)) return; this.set($A(this).concat(classNameToAdd).join(' ')); }, remove: function(classNameToRemove) { if (!this.include(classNameToRemove)) return; this.set($A(this).without(classNameToRemove).join(' ')); }, toString: function() { return $A(this).join(' '); } }; Object.extend(Element.ClassNames.prototype, Enumerable); /*--------------------------------------------------------------------------*/ (function() { window.Selector = Class.create({ initialize: function(expression) { this.expression = expression.strip(); }, findElements: function(rootElement) { return Prototype.Selector.select(this.expression, rootElement); }, match: function(element) { return Prototype.Selector.match(element, this.expression); }, toString: function() { return this.expression; }, inspect: function() { return "#"; } }); Object.extend(Selector, { matchElements: function(elements, expression) { var match = Prototype.Selector.match, results = []; for (var i = 0, length = elements.length; i < length; i++) { var element = elements[i]; if (match(element, expression)) { results.push(Element.extend(element)); } } return results; }, findElement: function(elements, expression, index) { index = index || 0; var matchIndex = 0, element; for (var i = 0, length = elements.length; i < length; i++) { element = elements[i]; if (Prototype.Selector.match(element, expression) && index === matchIndex++) { return Element.extend(element); } } }, findChildElements: function(element, expressions) { var selector = expressions.toArray().join(', '); return Prototype.Selector.select(selector, element || document); } }); })(); IanniX-0.9.20/gui/uihelp.cpp000066400000000000000000000435341317340345000155570ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #include "uihelp.h" #include "ui_uihelp.h" quint16 UiHelp::oscPort = 0; UiHelp *UiHelp::statusHelpWidget = 0; UiHelp::UiHelp(QWidget *parent) : QWidget(parent), ui(new Ui::UiHelp) { ui->setupUi(this); statusRefresh = false; currentCombo = 0; currentTextEdit = 0; visibility = true; if(parent == 0) { statusHelpWidget = this; setWindowFlags(Qt::Dialog); setWindowFlag(Qt::WindowMaximizeButtonHint, false); setWindowFlag(Qt::WindowMinimizeButtonHint, false); setWindowOpacity(0.9); } startTimer(150); } UiHelp::~UiHelp() { delete ui; } void UiHelp::timerEvent(QTimerEvent *) { if(statusRefresh) statusHelp(); statusRefresh = false; } void UiHelp::showEvent(QShowEvent *e) { visibility = true; QWidget::showEvent(e); if(parent() == 0) statusRefresh = true; } void UiHelp::closeEvent(QCloseEvent *e) { visibility = false; QWidget::closeEvent(e); } void UiHelp::statusHelp(const QWidget *widget) { if((statusHelpWidget) && (widget)) statusHelpWidget->statusHelp(widget->statusTip()); } void UiHelp::statusHelp(QString _statusText) { if((isVisible()) && (!_statusText.isEmpty()) && (statusTextOld != _statusText)) { statusTextOld = _statusText; qint16 splitIndex = _statusText.indexOf("|"); statusTexts.clear(); if(splitIndex < 0) statusTexts.append(_statusText.replace("\\n", "
    ")); else { statusTexts.append(_statusText.left(splitIndex).toUpper()); statusTexts.append(_statusText.mid(splitIndex+1).replace("\\n ", "
    ").replace("\\n", "
    ")); } statusRefresh = true; } } void UiHelp::messageHelp(QString _messageText) { if(isVisible()) { _messageText = _messageText.replace("\\n", "
    "); QStringList messageTextsArguments = _messageText.split(" ", QString::SkipEmptyParts); quint16 radix = 0; HelpInfo helpInfo = Help::getHelpFor(messageTextsArguments.first()); QStringList syntaxes = helpInfo.syntax.split(" <"); QString radixMessage; for(quint16 i = 0 ; i < syntaxes.count() ; i++) { if((syntaxes.at(i) == "") || (syntaxes.at(i) == "point_index>")) radix = i+1; } for(quint16 i = 0 ; i < messageTextsArguments.count() ; i++) { if(i <= radix) radixMessage += messageTextsArguments.at(i) + " "; else break; } if((messageTexts.count()) && messageTexts.last().first.startsWith(radixMessage)) messageTexts[messageTexts.count()-1] = qMakePair(_messageText, helpInfo); else messageTexts.append(qMakePair(_messageText, helpInfo)); while(messageTexts.count() > 10) messageTexts.removeFirst(); statusRefresh = true; } } void UiHelp::statusHelp() { if((isVisible()) && (statusTexts.count())) { QString html = ""; html += ""; html += "

    "; if(statusTexts.count() == 2) html += QString("

    %1

    ").arg(statusTexts.first()); else html += QString("

    %1

    ").arg(tr("INTERACTIVE HELP")); html += statusTexts.last(); if(messageTexts.count()) { html += QString("

    %1

    ").arg(tr("GUI MESSAGES")); html += QString("

    %1

    ").arg(tr("You've just performed action through graphical user interface. Here are the messages you have to use if you want to control IannIX from another software or interface.")); html += QString("

    "); for(quint16 i = 0 ; i < messageTexts.count() ; i++) { const QString messageText = messageTexts.at(i).first.trimmed(); QString messageDescription = messageTexts.at(i).second.description.trimmed(); QString messageSyntax = messageTexts.at(i).second.syntax.trimmed(); QStringList messageTextsArguments = messageText.split(" ", QString::SkipEmptyParts); QString messageVerbose = messageText; messageVerbose = messageVerbose.replace(" selection ", " <object id or group> "); QString parametersMessage = ""; quint16 messageTextsArgumentIndex = 0; bool paramOk = false; foreach(const QString &messageTextsArgument, messageTextsArguments) { bool added = false; if(!paramOk) { bool ok = false; messageTextsArgument.toDouble(&ok); if(ok) { if(((messageTextsArgumentIndex == 1) && (messageTextsArgumentIndex == (messageTextsArguments.count()-1))) || ((messageTextsArgumentIndex == 2) && (messageTextsArgumentIndex == (messageTextsArguments.count()-1))) || (messageTextsArgumentIndex > 2)) { parametersMessage += "$1 "; added = true; paramOk = true; } } } if(!added) parametersMessage += messageTextsArgument + " "; messageTextsArgumentIndex++; } parametersMessage.chop(1); QString codeMessage = ""; foreach(const QString &messageTextsArgument, messageTextsArguments) { bool ok = false; messageTextsArgument.toDouble(&ok); if(ok) codeMessage += messageTextsArgument + ", "; else codeMessage += "\"" + messageTextsArgument + "\", "; } codeMessage.chop(2); html += QString("%1
    ").arg(messageDescription.replace("\n", "
    ")); html += messageVerbose; html += ""; qint64 clipboardsKey; clipboardsKey = QDateTime::currentMSecsSinceEpoch(); clipboards.insert(clipboardsKey, QString("%1 | Copied to clipboard! You can now paste this message in a script (through run() function) or in an OSC message.").arg(messageText)); html += QString("  > Copy").arg(clipboardsKey); clipboardsKey--; clipboards.insert(clipboardsKey, QString("%1 | Copied to clipboard! Open a Max patch and choose Edit > Paste. It will automatically create objects to interact with IanniX.").arg(QString("{ \"boxes\" : [ { \"box\" : { \"maxclass\" : \"flonum\", \"outlettype\" : [ \"float\", \"bang\" ], \"fontname\" : \"Arial\", \"numinlets\" : 1, \"patching_rect\" : [ 37.0, 58.0, 50.0, 20.0 ], \"fontsize\" : 12.0, \"id\" : \"obj-5\", \"numoutlets\" : 2, \"parameter_enable\" : 0 } } , { \"box\" : { \"maxclass\" : \"message\", \"text\" : \"/iannix/%1\", \"outlettype\" : [ \"\" ], \"fontname\" : \"Arial\", \"numinlets\" : 2, \"patching_rect\" : [ 37.0, 85.0, 95.0, 18.0 ], \"fontsize\" : 12.0, \"id\" : \"obj-3\", \"numoutlets\" : 1 } } , { \"box\" : { \"maxclass\" : \"newobj\", \"text\" : \"udpsend 127.0.0.1 %2\", \"fontname\" : \"Arial\", \"numinlets\" : 1, \"patching_rect\" : [ 37.0, 110.0, 140.0, 20.0 ], \"fontsize\" : 12.0, \"id\" : \"obj-1\", \"numoutlets\" : 0 } } ], \"lines\" : [ { \"patchline\" : { \"source\" : [ \"obj-5\", 0 ], \"destination\" : [ \"obj-3\", 0 ], \"hidden\" : 0, \"disabled\" : 0 } } , { \"patchline\" : { \"source\" : [ \"obj-3\", 0 ], \"destination\" : [ \"obj-1\", 0 ], \"hidden\" : 0, \"disabled\" : 0 } } ], \"appversion\" : { \"major\" : 6, \"minor\" : 0, \"revision\" : 8 } } ").arg(parametersMessage).arg(oscPort))); html += QString(" / > for MaxMSP").arg(clipboardsKey); clipboardsKey--; clipboards.insert(clipboardsKey, QString("%1 | Copied to clipboard! Open a Processing sketch with IanniX class (provided with IanniX). Paste the code where you want to interact with IanniX.").arg(QString("iannix.send(%1);").arg(codeMessage))); html += QString(" / > for Processing").arg(clipboardsKey); html += "
    "; html += QString("%1 %2
    ").arg(messageTexts.at(i).second.keyword).arg(messageSyntax.replace(">", ">").replace("<", "<").replace("\n", "
    ")); html += "
    "; } html += QString("

    "); } html += ""; qreal currenScrollValue = ui->html->verticalScrollBar()->value() / (qreal)ui->html->verticalScrollBar()->maximum(); ui->html->setHtml(html); ui->html->verticalScrollBar()->setValue(currenScrollValue * ui->html->verticalScrollBar()->maximum()); } } void UiHelp::scriptHelp(QPlainTextEdit *textEdit, const QStringList &lookCategories) { currentTextEdit = textEdit; currentCombo = 0; scriptHelp(currentTextEdit->textCursor().block().text(), lookCategories); } void UiHelp::scriptHelp(QComboBox *comboBox, const QStringList &lookCategories) { currentTextEdit = 0; currentCombo = comboBox; scriptHelp(currentCombo->currentText(), lookCategories); } void UiHelp::scriptHelp(const QString &looking, const QStringList &lookCategories) { if(isVisible()) { QString html = ""; html += ""; html += "

    "; bool foundInfo = false; QList > htmlCategories; for(quint16 i = 0 ; i < 3 ; i++) { foreach(const QString &category, lookCategories) { QString htmlCategory = ""; HelpCategory helpCategory = Help::categories.value(category); foreach(const HelpInfo &info, helpCategory.infos) { if(((i == 0) && (looking.toLower().contains(info.keyword.toLower()))) || ((i == 1) && (looking.toLower().contains(info.keyword.toLower().left(5)))) || ((i == 2) && (looking.toLower().contains(info.keyword.toLower().left(3))))) { QString keyword = info.keyword, title = info.title.toUpper(), syntax = info.syntax, description = info.description.trimmed(); if(category == "commands") syntax = keyword + " " + syntax; syntax = syntax. replace(">", ">").replace("<", "<").replace("\n", "
    "); description = description.replace(">", ">").replace("<", "<").replace("\n", "
    "); if(!description.isEmpty()) { htmlCategory += QString("

    %1 — %2

    ").arg(keyword).arg(title); if(!description.isEmpty()) htmlCategory += QString("%1
    %2


    ").arg(title).arg(description); if(!syntax.isEmpty()) htmlCategory += QString("%3
    %1
    %4


    ").arg(syntax).arg(info.keyword + " " + info.syntax).arg(tr("SYNTAX")).arg(tr("IMPLEMENT IN SCRIPT")); htmlCategory += QString("
    "); } else { if(syntax.isEmpty()) syntax = keyword; htmlCategory += QString("

    %1 — %2

    ").arg(keyword).arg(title).arg(syntax); } foundInfo = true; } } if(!htmlCategory.isEmpty()) htmlCategories << qMakePair(QString("

    —  %1  —

    ").arg(helpCategory.category.toUpper()), htmlCategory); } if(foundInfo) break; } if(!foundInfo) { foreach(const QString &category, lookCategories) { QString htmlCategory; HelpCategory helpCategory = Help::categories.value(category); foreach(const HelpInfo &info, helpCategory.infos) { QString keyword = info.keyword, title = info.title.toUpper(), syntax = info.syntax; if(syntax.isEmpty()) syntax = keyword; htmlCategory += QString("

    %1 — %2

    ").arg(keyword).arg(title).arg(syntax); } if(!htmlCategory.isEmpty()) htmlCategories << qMakePair(QString("

    —  %1  —

    ").arg(helpCategory.category.toUpper()), htmlCategory); } } for(quint16 i = 0 ; i < htmlCategories.count() ; i++) { if(htmlCategories.count() > 1) html += htmlCategories.at(i).first; html += htmlCategories.at(i).second; } html += ""; ui->html->setHtml(html); } } void UiHelp::linkClicked(const QUrl &url) { QString urlString = url.toString(); if(urlString.startsWith("clipboard")) { qint64 clipboardsKey = urlString.remove("clipboard").toLongLong(); if(clipboards.contains(clipboardsKey)) { QStringList clips = clipboards.value(clipboardsKey).split("|"); if(clips.length()) { if((currentTextEdit) || (currentCombo)) { if(currentTextEdit) currentTextEdit->textCursor().insertText(clips.at(0).trimmed()); if(currentCombo) currentCombo->setEditText(currentCombo->currentText() + clips.at(0).trimmed()); } else QApplication::clipboard()->setText(clips.at(0).trimmed()); if(clips.length()) (new UiMessageBox())->display(tr("Help Center"), clips.at(1).trimmed()); } } else qDebug("Big error… %lld", clipboardsKey); } } IanniX-0.9.20/gui/uihelp.h000066400000000000000000000045711317340345000152220ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #ifndef UIHELP_H #define UIHELP_H #include #include #include #include #include #include #include #include #include #include #include "gui/uimessagebox.h" #include "misc/help.h" #include "misc/options.h" namespace Ui { class UiHelp; } class UiHelp : public QWidget { Q_OBJECT private: QPlainTextEdit *currentTextEdit; QComboBox *currentCombo; QStringList statusTexts; QList< QPair > messageTexts; QString statusTextOld; bool statusRefresh; public: static quint16 oscPort; static UiHelp *statusHelpWidget; public: explicit UiHelp(QWidget *parent = 0); ~UiHelp(); public: static void statusHelp(const QWidget *widget); void statusHelp(); void scriptHelp(QPlainTextEdit *textEdit, const QStringList &lookCategories); void scriptHelp(QComboBox *textEdit, const QStringList &lookCategories); void scriptHelp(const QString &looking, const QStringList &lookCategories); public: UiBool visibility; QHash clipboards; public slots: void statusHelp(QString _statusText); void messageHelp(QString _messageText); void linkClicked(const QUrl &); protected: void timerEvent(QTimerEvent *); void showEvent(QShowEvent *); void closeEvent(QCloseEvent *); private: Ui::UiHelp *ui; }; #endif // UIHELP_H IanniX-0.9.20/gui/uihelp.ui000066400000000000000000000024711317340345000154050ustar00rootroot00000000000000 UiHelp 0 0 530 305 IanniX Helper 0 0 Qt::NoFocus Qt::ScrollBarAlwaysOff false html anchorClicked(QUrl) UiHelp linkClicked(QUrl) 319 188 359 496 linkClicked(QUrl) IanniX-0.9.20/gui/uiinspector.cpp000066400000000000000000001622371317340345000166370ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #include "uiinspector.h" #include "ui_uiinspector.h" UiInspector::UiInspector(QWidget *parent) : QWidget(parent), ui(new Ui::UiInspector) { ui->setupUi(this); slidersLock = false; toolbarButton = 0; lastTabBeforeRessources = 0; mouseDisplay = false; Help::syncHelpWith(ui->positionX, COMMAND_POS_X); Help::syncHelpWith(ui->positionY, COMMAND_POS_Y); Help::syncHelpWith(ui->positionZ, COMMAND_POS_Z); Help::syncHelpWith(ui->activityCheck, COMMAND_ACTIVE); Help::syncHelpWith(ui->labelLine, COMMAND_LABEL); Help::syncHelpWith(ui->sizeSpin, COMMAND_SIZE); Help::syncHelpWith(ui->messagesButton, COMMAND_MESSAGE); Help::syncHelpWith(ui->messagesSpin, COMMAND_MESSAGE_INTERVAL); Help::syncHelpWith(ui->widthSpin, COMMAND_CURSOR_WIDTH); Help::syncHelpWith(ui->depthSpin, COMMAND_CURSOR_DEPTH); Help::syncHelpWith(ui->speedFSpin, COMMAND_CURSOR_SPEEDF); Help::syncHelpWith(ui->speedSpin, COMMAND_CURSOR_SPEED); Help::syncHelpWith(ui->intertiaSpin, COMMAND_CURVE_INERTIE); Help::syncHelpWith(ui->cursorLengthSpin, COMMAND_CURSOR_SPEED); Help::syncHelpWith(ui->triggerOffSpin, COMMAND_TRIGGER_OFF); Help::syncHelpWith(ui->equationPoints, COMMAND_CURVE_EQUATION_POINTS); Help::syncHelpWith(ui->cursorSourceMode0, COMMAND_CURSOR_BOUNDS_SOURCE_MODE); Help::syncHelpWith(ui->cursorSourceMode1, COMMAND_CURSOR_BOUNDS_SOURCE_MODE); Help::syncHelpWith(ui->cursorSourceMode2, COMMAND_CURSOR_BOUNDS_SOURCE_MODE); Help::syncHelpWith(ui->cursorSourceMode3, COMMAND_CURSOR_BOUNDS_SOURCE_MODE); Help::syncHelpWith(ui->cursorSourceX1, COMMAND_CURSOR_BOUNDS_SOURCE); Help::syncHelpWith(ui->cursorSourceY1, COMMAND_CURSOR_BOUNDS_SOURCE); Help::syncHelpWith(ui->cursorSourceZ1, COMMAND_CURSOR_BOUNDS_SOURCE); Help::syncHelpWith(ui->cursorSourceX2, COMMAND_CURSOR_BOUNDS_SOURCE); Help::syncHelpWith(ui->cursorSourceY2, COMMAND_CURSOR_BOUNDS_SOURCE); Help::syncHelpWith(ui->cursorSourceZ2, COMMAND_CURSOR_BOUNDS_SOURCE); Help::syncHelpWith(ui->cursorTargetX1, COMMAND_CURSOR_BOUNDS_TARGET); Help::syncHelpWith(ui->cursorTargetY1, COMMAND_CURSOR_BOUNDS_TARGET); Help::syncHelpWith(ui->cursorTargetZ1, COMMAND_CURSOR_BOUNDS_TARGET); Help::syncHelpWith(ui->cursorTargetX2, COMMAND_CURSOR_BOUNDS_TARGET); Help::syncHelpWith(ui->cursorTargetY2, COMMAND_CURSOR_BOUNDS_TARGET); Help::syncHelpWith(ui->cursorTargetZ2, COMMAND_CURSOR_BOUNDS_TARGET); Help::syncHelpWith(ui->equationEdit, COMMAND_CURVE_EQUATION); Help::syncHelpWith(ui->groupIdButton, COMMAND_GROUP); Help::syncHelpWith(ui->newIdButton, COMMAND_ID); //Help::syncHelpWith(ui->pointsLists, COMMAND_CURVE_EDITOR); Help::syncHelpWith(ui->offsetInitialSpin, COMMAND_CURSOR_OFFSET); Help::syncHelpWith(ui->offsetStartSpin, COMMAND_CURSOR_OFFSET); Help::syncHelpWith(ui->offsetEndSpin, COMMAND_CURSOR_OFFSET); Help::syncHelpWith(ui->sizeWSpin, COMMAND_RESIZE); Help::syncHelpWith(ui->sizeHSpin, COMMAND_RESIZE); Help::syncHelpWith(ui->easingCombo, COMMAND_CURSOR_START); Help::syncHelpWith(ui->patternLine, COMMAND_CURSOR_START); Help::syncHelpWith(ui->fireTriggers, COMMAND_CURSOR_FIRE); Help::syncHelpWith(ui->colorCombo1, COMMAND_COLOR_ACTIVE); Help::syncHelpWith(ui->colorCombo1, COMMAND_COLOR_ACTIVE_HUE); Help::syncHelpWith(ui->colorCombo2, COMMAND_COLOR_INACTIVE); Help::syncHelpWith(ui->colorCombo2, COMMAND_COLOR_INACTIVE_HUE); Help::syncHelpWith(ui->colorComboMultiply,COMMAND_COLOR_MULTIPLY); Help::syncHelpWith(ui->colorComboMultiply,COMMAND_COLOR_MULTIPLY_HUE); Help::syncHelpWith(ui->textureCombo1, COMMAND_TEXTURE_ACTIVE); Help::syncHelpWith(ui->textureCombo1, COMMAND_TEXTURE_INACTIVE); Help::syncHelpWith(ui->ressourcesTextures,COMMAND_TEXTURE); Help::syncHelpWith(ui->ressourcesColors, COMMAND_GLOBAL_COLOR); Help::syncHelpWith(ui->ressourcesColors, COMMAND_GLOBAL_COLOR_HUE); Application::objectsAutosize.setAction(ui->autoresizeSlider, "guiObjectsAutosize"); MessageManager::setInterfaces(0, 0, ui->spaceForMessageLog); ui->ressourcesTextures->showImport(true); ui->ressourcesTextures->showNew(false); ui->ressourcesTextures->showDuplicate(false); Render::textures->configure(tr("Textures"), ui->ressourcesTextures); Render::colors->configure(tr("Score colors"), ui->ressourcesColors); ui->ressourcesColors->showDuplicate(false); ui->files->importAsFiles = false; UiFileItem::configure(ui->files); UiFileItem::syncWith(QFileInfoList() << QFileInfo(Application::pathApplication.absoluteFilePath() + "/Examples/") << QFileInfo(Application::pathDocuments.absoluteFilePath() + "/"), ui->files->getTree()); ui->files->getTree()->collapseAll(); for(quint16 i = 0 ; i < ui->files->getTree()->topLevelItemCount() ; i++) { UiFileItem *searchItem = ((UiFileItem*)ui->files->getTree()->topLevelItem(i))->find(Application::pathApplication.absoluteFilePath() + "/IanniX/"); if(searchItem) ui->files->getTree()->expandItem(searchItem); } ui->files->showNewRoot(true); ui->files->showOpen(true); //UiRenderOptions::texturesWidget = ui->ressourcesTextures; /* UiRenderOptions::texturesWidget->setColumnWidth(0, 100); UiRenderOptions::texturesWidget->setColumnWidth(1, 55); UiRenderOptions::texturesWidget->setColumnWidth(2, 55); UiRenderOptions::texturesWidget->setColumnWidth(3, 55); UiRenderOptions::texturesWidget->setColumnWidth(4, 55); */ ui->ccView->setColumnWidth(0, 105); ui->ccView->setColumnWidth(1, 25); ui->ccView->setColumnWidth(2, 25); ui->ccView->setColumnWidth(3, 40); //ui->ssTabInfo->setTabEnabled(4, false); ui->ssTabInfo->setCurrentIndex(lastTabBeforeRessources); render = 0; Application::followId .setAction(ui->followId, "scoreFollowId"); Application::paintCurvesOpacity.setAction(ui->viewCurveOpacityCheck, "guiPaintCurvesOpacity"); Render::cameraPerspective .setAction(ui->viewCameraModeCheck, "guiCameraMode"); ui->followId->setValue(-1); ui->ccView->expandAll(); ui->ccView->sortByColumn(0, Qt::AscendingOrder); ui->colorCombo1->clear(); ui->colorCombo2->clear(); ui->colorComboMultiply->clear(); ui->textureCombo1->clear(); ui->textureCombo2->clear(); actionInfoLock = true; ui->easingCombo->clear(); NxEasing easing; for(quint16 type = 0 ; type < 45 ; type++) { easing.setType(type); ui->easingCombo->addItem(QIcon(easing.getPixmap()), tr("Easing") + QString(" %1").arg(type)); } //Templates ui->equationTemplate->clear(); addEquationTemplate("Templates", "", true); addEquationTemplate("--", ""); QFileInfoList files = QDir(Application::pathApplication.absoluteFilePath() + "/Tools/Templates/").entryInfoList(QStringList() << "*.txt", QDir::Files | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase); files << QDir(Application::pathDocuments.absoluteFilePath() + "/Templates/").entryInfoList(QStringList() << "*.txt", QDir::Files | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase); bool firstTemplate = true; QString title; foreach(const QFileInfo &file, files) { QString header; QHash params; QFile templateFile(file.absoluteFilePath()); if(templateFile.open(QFile::ReadOnly)) { QStringList templatesLong = QString(templateFile.readAll()).split("\n", QString::SkipEmptyParts); foreach(const QString &templateLong, templatesLong) { if(templateLong.startsWith("[")) header = templateLong.toLower(); else if(header == "[general]") { QStringList templateLongSplit = templateLong.split("="); if(templateLongSplit.count() > 1) { QString key = templateLongSplit.at(0).toLower(), value = templateLongSplit.at(1); params.insert(key, value); if(key == "name") title = value; } } else if(header == "[equations]") { if(!title.isEmpty()) { if(!firstTemplate) addEquationTemplate("--", ""); firstTemplate = false; addEquationTemplate(title, ""); title.clear(); } QStringList templateLongSplited = templateLong.trimmed().split(" | "); addEquationTemplate(" " + templateLongSplited.at(qMax(1, templateLongSplited.count()-1)), templateLongSplited.first(), true); } } } } //needRefresh = true; startTimer(100); refresh(); refreshIp(); } void UiInspector::addEquationTemplate(const QString &text, const QString &valeur, bool enabled) { if(text.trimmed() == "--") ui->equationTemplate->insertSeparator(ui->equationTemplate->count()); else ui->equationTemplate->addItem(text, valeur); if(!enabled) qobject_cast(ui->equationTemplate->model())->item(ui->equationTemplate->count()-1)->setEnabled(false); } void UiInspector::addInterfaces() { QHashIterator interfacesIterator(MessageManager::interfaces); while (interfacesIterator.hasNext()) { interfacesIterator.next(); if(interfacesIterator.key() == MessagesTypeSerial) ui->ssTabConfigArduinoLayout->addWidget(interfacesIterator.value()); else if(interfacesIterator.key() == MessagesTypeMidi) ui->ssTabConfigMIDILayout->addWidget(interfacesIterator.value()); else if((interfacesIterator.key() == MessagesTypeOsc) || (interfacesIterator.key() == MessagesTypeUdp) || (interfacesIterator.key() == MessagesTypeTcp) || (interfacesIterator.key() == MessagesTypeHttp)) ui->ssTabConfigNetworkLayout->addWidget(interfacesIterator.value()); else if((interfacesIterator.key() == MessagesTypeSyphon) || (interfacesIterator.key() == MessagesTypeDirect)) ui->ssTabConfigSyphonLayout->addWidget(interfacesIterator.value()); } } UiInspector::~UiInspector() { delete ui; } void UiInspector::showEvent(QShowEvent *e) { if(toolbarButton) toolbarButton->setChecked(true); QWidget::showEvent(e); } void UiInspector::closeEvent(QCloseEvent *e) { if(toolbarButton) toolbarButton->setChecked(false); QWidget::closeEvent(e); } void UiInspector::changeEvent(QEvent *e) { QWidget::changeEvent(e); switch (e->type()) { case QEvent::LanguageChange: ui->retranslateUi(this); break; default: break; } } void UiInspector::keyPressEvent(QKeyEvent *e) { if(e->key() == Qt::Key_Escape) setFocus(); } UiTreeView* UiInspector::getFileWidget() const { return ui->files; } void UiInspector::actionCCButton() { if(sender() == ui->unmuteGroups) { emit(actionUnmuteGroups()); actionCC(); } else if(sender() == ui->unmuteObjects) { emit(actionUnmuteObjects()); actionCC(); } else if(sender() == ui->unsoloGroups) { emit(actionUnsoloGroups()); actionCC(); } else if(sender() == ui->unsoloObjects) { emit(actionUnsoloObjects()); actionCC(); } else if(sender() == ui->followIdClear) ui->followId->setValue(-1); } void UiInspector::actionInfo() { if(!slidersLock) { slidersLock = true; if(sender() == ui->equationParamReset) { ui->equationParam1Value ->setValue(0.5); ui->equationParam2Value ->setValue(0.5); ui->equationParam3Value ->setValue(0.5); ui->equationParam4Value ->setValue(0.5); ui->equationParam5Value ->setValue(0.5); ui->equationParam1Slider->setValue(500); ui->equationParam2Slider->setValue(500); ui->equationParam3Slider->setValue(500); ui->equationParam4Slider->setValue(500); ui->equationParam5Slider->setValue(500); } if(sender() == ui->equationParam1Slider) ui->equationParam1Value->setValue(ui->equationParam1Slider->value() / 1000.); if(sender() == ui->equationParam2Slider) ui->equationParam2Value->setValue(ui->equationParam2Slider->value() / 1000.); if(sender() == ui->equationParam3Slider) ui->equationParam3Value->setValue(ui->equationParam3Slider->value() / 1000.); if(sender() == ui->equationParam4Slider) ui->equationParam4Value->setValue(ui->equationParam4Slider->value() / 1000.); if(sender() == ui->equationParam5Slider) ui->equationParam5Value->setValue(ui->equationParam5Slider->value() / 1000.); if(sender() == ui->equationParam1Value) ui->equationParam1Slider->setValue(ui->equationParam1Value->value() * 1000.); if(sender() == ui->equationParam2Value) ui->equationParam2Slider->setValue(ui->equationParam2Value->value() * 1000.); if(sender() == ui->equationParam3Value) ui->equationParam3Slider->setValue(ui->equationParam3Value->value() * 1000.); if(sender() == ui->equationParam4Value) ui->equationParam4Slider->setValue(ui->equationParam4Value->value() * 1000.); if(sender() == ui->equationParam5Value) ui->equationParam5Slider->setValue(ui->equationParam5Value->value() * 1000.); slidersLock = false; } if(!actionInfoLock) { Application::current->pushSnapshot(); if(ui->positionX == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_POS_X).arg(ui->positionX->value()), ExecuteSourceGui); else if(ui->positionY == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_POS_Y).arg(ui->positionY->value()), ExecuteSourceGui); else if(ui->positionZ == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_POS_Z).arg(ui->positionZ->value()), ExecuteSourceGui); else if(ui->activityCheck == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_ACTIVE).arg(ui->activityCheck->isChecked()), ExecuteSourceGui); else if(ui->labelLine == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_LABEL).arg(ui->labelLine->text()), ExecuteSourceGui); else if(ui->sizeSpin == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_SIZE).arg(ui->sizeSpin->value()), ExecuteSourceGui); else if(ui->messagesSpin == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_MESSAGE_INTERVAL).arg(ui->messagesSpin->value()), ExecuteSourceGui); else if(ui->widthSpin == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_CURSOR_WIDTH).arg(ui->widthSpin->value()), ExecuteSourceGui); else if(ui->depthSpin == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_CURSOR_DEPTH).arg(ui->depthSpin->value()), ExecuteSourceGui); else if(ui->speedFSpin == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_CURSOR_SPEEDF).arg(ui->speedFSpin->value()), ExecuteSourceGui); else if(ui->speedSpin == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_CURSOR_SPEED).arg(ui->speedSpin->value()), ExecuteSourceGui); else if(ui->intertiaSpin == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_CURVE_INERTIE).arg(ui->intertiaSpin->value()), ExecuteSourceGui); else if(ui->triggerOffSpin == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_TRIGGER_OFF).arg(ui->triggerOffSpin->value()), ExecuteSourceGui); else if(ui->pointsLists == sender()) Application::current->execute(QString("%1 selection 1").arg(COMMAND_CURVE_EDITOR), ExecuteSourceGui); else if(ui->pointsResample == sender()) Application::current->execute(QString("%1 selection 1").arg(COMMAND_CURVE_RESAMPLE), ExecuteSourceGui); else if(ui->cursorSourceX1 == sender()) Application::current->execute(QString("%1 selection 0 %2").arg(COMMAND_CURSOR_BOUNDS_SOURCE).arg(ui->cursorSourceX1->value()), ExecuteSourceGui); else if(ui->cursorSourceY1 == sender()) Application::current->execute(QString("%1 selection 1 %2").arg(COMMAND_CURSOR_BOUNDS_SOURCE).arg(ui->cursorSourceY1->value()), ExecuteSourceGui); else if(ui->cursorSourceZ1 == sender()) Application::current->execute(QString("%1 selection 2 %2").arg(COMMAND_CURSOR_BOUNDS_SOURCE).arg(ui->cursorSourceZ1->value()), ExecuteSourceGui); else if(ui->cursorSourceX2 == sender()) Application::current->execute(QString("%1 selection 3 %2").arg(COMMAND_CURSOR_BOUNDS_SOURCE).arg(ui->cursorSourceX2->value()), ExecuteSourceGui); else if(ui->cursorSourceY2 == sender()) Application::current->execute(QString("%1 selection 4 %2").arg(COMMAND_CURSOR_BOUNDS_SOURCE).arg(ui->cursorSourceY2->value()), ExecuteSourceGui); else if(ui->cursorSourceZ2 == sender()) Application::current->execute(QString("%1 selection 5 %2").arg(COMMAND_CURSOR_BOUNDS_SOURCE).arg(ui->cursorSourceZ2->value()), ExecuteSourceGui); else if(ui->cursorTargetX1 == sender()) Application::current->execute(QString("%1 selection 0 %2").arg(COMMAND_CURSOR_BOUNDS_TARGET).arg(ui->cursorTargetX1->value()), ExecuteSourceGui); else if(ui->cursorTargetY1 == sender()) Application::current->execute(QString("%1 selection 1 %2").arg(COMMAND_CURSOR_BOUNDS_TARGET).arg(ui->cursorTargetY1->value()), ExecuteSourceGui); else if(ui->cursorTargetZ1 == sender()) Application::current->execute(QString("%1 selection 2 %2").arg(COMMAND_CURSOR_BOUNDS_TARGET).arg(ui->cursorTargetZ1->value()), ExecuteSourceGui); else if(ui->cursorTargetX2 == sender()) Application::current->execute(QString("%1 selection 3 %2").arg(COMMAND_CURSOR_BOUNDS_TARGET).arg(ui->cursorTargetX2->value()), ExecuteSourceGui); else if(ui->cursorTargetY2 == sender()) Application::current->execute(QString("%1 selection 4 %2").arg(COMMAND_CURSOR_BOUNDS_TARGET).arg(ui->cursorTargetY2->value()), ExecuteSourceGui); else if(ui->cursorTargetZ2 == sender()) Application::current->execute(QString("%1 selection 5 %2").arg(COMMAND_CURSOR_BOUNDS_TARGET).arg(ui->cursorTargetZ2->value()), ExecuteSourceGui); else if(ui->equationPoints == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_CURVE_EQUATION_POINTS).arg(ui->equationPoints->value()), ExecuteSourceGui); else if(ui->equationParam1Value == sender()) Application::current->execute(QString("%1 selection param1 %2").arg(COMMAND_CURVE_EQUATION_PARAM).arg(ui->equationParam1Value->value()), ExecuteSourceGui); else if(ui->equationParam2Value == sender()) Application::current->execute(QString("%1 selection param2 %2").arg(COMMAND_CURVE_EQUATION_PARAM).arg(ui->equationParam2Value->value()), ExecuteSourceGui); else if(ui->equationParam3Value == sender()) Application::current->execute(QString("%1 selection param3 %2").arg(COMMAND_CURVE_EQUATION_PARAM).arg(ui->equationParam3Value->value()), ExecuteSourceGui); else if(ui->equationParam4Value == sender()) Application::current->execute(QString("%1 selection param4 %2").arg(COMMAND_CURVE_EQUATION_PARAM).arg(ui->equationParam4Value->value()), ExecuteSourceGui); else if(ui->equationParam5Value == sender()) Application::current->execute(QString("%1 selection param5 %2").arg(COMMAND_CURVE_EQUATION_PARAM).arg(ui->equationParam5Value->value()), ExecuteSourceGui); else if(ui->cursorSourceMode0 == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_CURSOR_BOUNDS_SOURCE_MODE).arg(0), ExecuteSourceGui); else if(ui->cursorSourceMode1 == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_CURSOR_BOUNDS_SOURCE_MODE).arg(1), ExecuteSourceGui); else if(ui->cursorSourceMode2 == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_CURSOR_BOUNDS_SOURCE_MODE).arg(2), ExecuteSourceGui); else if(ui->cursorSourceMode3 == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_CURSOR_BOUNDS_SOURCE_MODE).arg(3), ExecuteSourceGui); else if((ui->cursorLengthSpin == sender()) || (ui->cursorSpeedLock == sender())) { if(ui->cursorSpeedLock->isChecked()) Application::current->execute(QString("%1 selection autolock %2").arg(COMMAND_CURSOR_SPEED).arg(ui->cursorLengthSpin->value()), ExecuteSourceGui); else Application::current->execute(QString("%1 selection auto %2").arg(COMMAND_CURSOR_SPEED).arg(ui->cursorLengthSpin->value()), ExecuteSourceGui); } else if((ui->equationType0 == sender()) || (ui->equationType1 == sender()) || (ui->equationEdit == sender())) { if(ui->equationType0->isChecked()) Application::current->execute(QString("%1 selection cartesian %2").arg(COMMAND_CURVE_EQUATION).arg(ui->equationEdit->toPlainText().remove("\n").trimmed()), ExecuteSourceGui); else Application::current->execute(QString("%1 selection polar %2").arg(COMMAND_CURVE_EQUATION).arg(ui->equationEdit->toPlainText().remove("\n").trimmed()), ExecuteSourceGui); } else if((ui->offsetInitialSpin == sender()) || (ui->offsetStartSpin == sender()) || (ui->offsetEndSpin == sender())) Application::current->execute(QString("%1 selection %2 %3 %4").arg(COMMAND_CURSOR_OFFSET).arg(ui->offsetInitialSpin->value()).arg(ui->offsetStartSpin->value()).arg(ui->offsetEndSpin->value()), ExecuteSourceGui); else if((ui->sizeWSpin == sender()) || (ui->sizeHSpin == sender())) Application::current->execute(QString("%1 selection %2 %3").arg(COMMAND_RESIZE).arg(ui->sizeWSpin->value()).arg(ui->sizeHSpin->value()), ExecuteSourceGui); else if((ui->patternLine == sender()) || (ui->easingCombo == sender())) Application::current->execute(QString("%1 selection %2 0 %3").arg(COMMAND_CURSOR_START).arg(ui->easingCombo->currentIndex()).arg(ui->patternLine->currentText().split(" - ").at(0)), ExecuteSourceGui); else if(ui->fireTriggers == sender()) { QString action = ""; if(ui->fireTriggers->currentIndex() == 0) action = "none"; else if(ui->fireTriggers->currentIndex() == 1) action = "group"; else if(ui->fireTriggers->currentIndex() == 2) action = "all"; Application::current->execute(QString("%1 selection %2").arg(COMMAND_CURSOR_FIRE).arg(action), ExecuteSourceGui); } else if((ui->equationTemplate == sender()) && (!ui->equationTemplate->itemData(ui->equationTemplate->currentIndex()).toString().isEmpty())) Application::current->execute(QString("%1 selection %2").arg(COMMAND_CURVE_EQUATION).arg(ui->equationTemplate->itemData(ui->equationTemplate->currentIndex()).toString()), ExecuteSourceGui); refresh(); } } void UiInspector::actionColor() { if(!actionInfoLock) { QComboBox *combo = (QComboBox*)sender(); QString val = combo->currentText(); QStringList oldValStr = combo->currentText().split(" ", QString::SkipEmptyParts); if(combo->currentText() == tr("Choose…")) { QColor oldVal = Qt::white; if(oldValStr.count() == 4) oldVal = QColor(oldValStr.at(0).toUInt(), oldValStr.at(1).toUInt(), oldValStr.at(2).toUInt(), oldValStr.at(3).toUInt()); QColor valColor = QColorDialog::getColor(oldVal, 0, tr("IanniX Color Inspector"), QColorDialog::ShowAlphaChannel); val = QString("%1 %2 %3 %4").arg(valColor.red()).arg(valColor.green()).arg(valColor.blue()).arg(valColor.alpha()); } Application::current->pushSnapshot(); if(ui->colorCombo1 == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_COLOR_ACTIVE).arg(val), ExecuteSourceGui); else if(ui->colorCombo2 == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_COLOR_INACTIVE).arg(val), ExecuteSourceGui); else if(ui->colorComboMultiply == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_COLOR_MULTIPLY).arg(val), ExecuteSourceGui); refresh(); } } void UiInspector::actionTexture() { if(!actionInfoLock) { QComboBox *combo = (QComboBox*)sender(); QString val = combo->currentText(); Application::current->pushSnapshot(); if(ui->textureCombo1 == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_TEXTURE_ACTIVE).arg(val), ExecuteSourceGui); else if(ui->textureCombo2 == sender()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_TEXTURE_INACTIVE).arg(val), ExecuteSourceGui); refresh(); } } void UiInspector::actionInfoID() { bool ok = false; quint16 oldId = ui->newIdButton->text().toInt(); quint16 newId = (new UiMessageBox())->getDouble(tr("Object ID"), tr("Enter the new ID:"), oldId, 0, 32767, 1, 0, "", &ok); if((ok) && (oldId != newId)) { if(Application::current->getObjectById(newId)) (new UiMessageBox())->display(tr("Object ID"), tr("Another object has this ID.\nTry deleting that object, or change its ID.")); else { Application::current->pushSnapshot(); Application::current->execute(QString("%1 %2 %3").arg(COMMAND_ID).arg(oldId).arg(newId), ExecuteSourceGui); needRefresh = true; } } } void UiInspector::actionInfoGroup() { bool ok = false; QString groupeId = (new UiMessageBox())->getText(tr("Object Group ID"), tr("Enter the name of the desired group:"), ui->groupIdButton->text(), &ok); if(ok) { Application::current->pushSnapshot(); Application::current->execute(QString("%1 selection %2").arg(COMMAND_GROUP).arg(groupeId), ExecuteSourceGui); needRefresh = true; } } void UiInspector::actionMessages() { if(render->getSelection()->count()) { Application::current->pushSnapshot(); ExtOscPatternAsk *ask = new ExtOscPatternAsk(Application::current->getMainWindow(), render->getSelection()); if(!ask->onlyCurves) if(ask->exec()) { if(ask->getMessagePatterns().length()) Application::current->execute(QString("%1 selection %2").arg(COMMAND_MESSAGE).arg(ask->getMessagePatterns()), ExecuteSourceGui); else Application::current->execute(QString("%1 selection -").arg(COMMAND_MESSAGE), ExecuteSourceGui); } } } void UiInspector::setMousePos(const NxPoint & pos) { mousePos = tr("MOUSE:") + QString(" %1 s. / %2 s.").arg(pos.x(), 0, 'f', 3).arg(pos.y(), 0, 'f', 3); mouseDisplay = true; } void UiInspector::setMouseZoom(qreal zoom) { mouseZoom = tr("ZOOM:") + QString(" %1%").arg(zoom, 0, 'f', 1); mouseDisplay = true; } void UiInspector:: setRotationAngles(const NxPoint &angles) { rotationAngles = tr("ANGLES:") + QString(" %1° / %2°").arg(angles.y(), 0, 'f', 3).arg(angles.z(), 0, 'f', 3); mouseDisplay = true; } void UiInspector::actionTabChange(int) { if(ui->tab->currentIndex() == 1) askRefresh(); else if((ui->tab->currentIndex() == 3) && (ui->ssTabConfig->currentIndex() == 0)) MessageManager::setLogVisibility(true); else MessageManager::setLogVisibility(false); } void UiInspector::timerEvent(QTimerEvent *) { if(needRefresh) refresh(); if(mouseDisplay) { ui->mouseLabel->setText(mousePos); ui->zoomLabel->setText(mouseZoom); ui->rotationLabel->setText(rotationAngles); mouseDisplay = false; } } void UiInspector::refreshIp() { //IPs QStringList ipsName; foreach(const QNetworkInterface &interf, QNetworkInterface::allInterfaces()) { foreach(const QNetworkAddressEntry &addressEntry, interf.addressEntries()) { bool ok = false; QString ipName; if(addressEntry.ip().toIPv4Address() > 0) { ipName += QString(" - %1 (%2)").arg(addressEntry.ip().toString()).arg(interf.humanReadableName()); ok = true; } if((ok) && (addressEntry.broadcast().toIPv4Address() > 0)) ipName += QString(", broadcast on %1").arg(addressEntry.broadcast().toString()); if(ok) { ipsName << ipName; } } } if(ipsName.count()) { QString ipNameTotal; foreach(const QString &ipName, ipsName) ipNameTotal += ipName + "\n"; ipNameTotal.chop(1); if(ui->myIP->toPlainText() != ipNameTotal) ui->myIP->setPlainText(ipNameTotal); ui->myIP->setVisible(true); ui->myIPLabel->setVisible(true); } else { ui->myIP->setVisible(false); ui->myIPLabel->setVisible(false); } QTimer::singleShot(5000, this, SLOT(refreshIp())); } void UiInspector::refresh() { needRefresh = false; if(!Application::current) return; MessageManager::transportNbTriggers = Application::current->getCount(ObjectsTypeTrigger); MessageManager::transportNbCursors = Application::current->getCount(ObjectsTypeCursor); MessageManager::transportNbCurves = Application::current->getCount(ObjectsTypeCurve); MessageManager::transportNbGroups = Application::current->getCount(-2); actionInfoLock = true; quint16 counterTriggers = 0, counterCurves = 0, counterCurvePoints = 0, counterCurveEllipse = 0, counterCurveEquation = 0, counterCursors = 0, counterCursorsCurve = 0; if((render) && (ui->tab->currentIndex() == 1)) { UiRenderSelection *objects = render->getSelection(); NxObject *objectsHover = 0; if((objects->count() == 0) && (render->getSelectedHover())) objectsHover = render->getSelectedHover(); NxCursor *prevCursor = 0; NxTrigger *prevTrigger = 0; NxObject *prevObject = 0; NxCurve *prevCurve = 0; if(!ui->colorCombo1->hasFocus()) { ui->colorCombo1->clear(); colorComboAdd(ui->colorCombo1, Render::colors->keys()); colorComboAdd(ui->colorCombo1, QStringList() << tr("Choose…")); } if(!ui->colorCombo2->hasFocus()) { ui->colorCombo2->clear(); colorComboAdd(ui->colorCombo2, Render::colors->keys()); colorComboAdd(ui->colorCombo2, QStringList() << tr("Choose…")); } if(!ui->colorComboMultiply->hasFocus()) { ui->colorComboMultiply->clear(); colorComboAdd(ui->colorComboMultiply, QStringList() << tr("Choose…")); } ui->textureCombo1->clear(); ui->textureCombo2->clear(); textureComboAdd(ui->textureCombo1, QStringList() << ""); textureComboAdd(ui->textureCombo2, QStringList() << ""); textureComboAdd(ui->textureCombo1, Render::textures->keys()); textureComboAdd(ui->textureCombo2, Render::textures->keys()); for(quint16 indexObject = 0 ; indexObject < objects->count()+1 ; indexObject++) { NxObject *object = 0; if(indexObject == objects->count()) object = objectsHover; else object = objects->at(indexObject); if(!object) continue; if(prevObject == 0) prevObject = object; if(object->getType() == ObjectsTypeCursor) counterCursors++; else if(object->getType() == ObjectsTypeCurve) counterCurves++; else if(object->getType() == ObjectsTypeTrigger) counterTriggers++; if((object->getType() == ObjectsTypeCursor) && (((NxCursor*)object)->getCurve())) counterCursorsCurve++; if((object->getType() == ObjectsTypeCurve) && (((NxCurve*)object)->getCurveType() == CurveTypePoints)) counterCurvePoints++; if((object->getType() == ObjectsTypeCurve) && (((NxCurve*)object)->getCurveType() == CurveTypeEllipse)) counterCurveEllipse++; if((object->getType() == ObjectsTypeCurve) && ((((NxCurve*)object)->getCurveType() == CurveTypeEquationCartesian) || (((NxCurve*)object)->getCurveType() == CurveTypeEquationPolar))) counterCurveEquation++; if (objects->count() > 1) ////CG//// Don't allow ID change if more than one object selected ui->newIdButton->setDisabled(true); else ui->newIdButton->setDisabled(false); QString thisID = QString::number(object->getId()); QString prevID = QString::number(prevObject->getId()); change(indexObject, ui->newIdButton, thisID , prevID); change(indexObject, ui->groupIdButton, object->getGroupId(), prevObject->getGroupId()); change(indexObject, ui->positionX, object->getPos().x(), prevObject->getPos().x()); change(indexObject, ui->positionY, object->getPos().y(), prevObject->getPos().y()); change(indexObject, ui->positionZ, object->getPos().z(), prevObject->getPos().z()); change(indexObject, ui->activityCheck, object->getActive(), prevObject->getActive()); change(indexObject, ui->labelLine, object->getLabel(), prevObject->getLabel()); change(indexObject, ui->colorCombo1, object->getColorActiveVerbose(), prevObject->getColorActiveVerbose(), true); change(indexObject, ui->colorCombo2, object->getColorInactiveVerbose(), prevObject->getColorInactiveVerbose(), true); change(indexObject, ui->colorComboMultiply, object->getColorMultiplyVerbose(), prevObject->getColorMultiplyVerbose(), true); change(indexObject, ui->sizeSpin, object->getSize(), prevObject->getSize()); if(object->getType() == ObjectsTypeCursor) { NxCursor *cursor = (NxCursor*)object; if(prevCursor == 0) prevCursor = cursor; change(indexObject, ui->widthSpin, cursor->getWidth(), prevCursor->getWidth()); change(indexObject, ui->depthSpin, cursor->getDepth(), prevCursor->getDepth()); if(sender() != ui->patternLine) change(indexObject, ui->patternLine, cursor->getStart().mid(4), prevCursor->getStart().mid(4), false); change(indexObject, ui->easingCombo, cursor->getEasing(), prevCursor->getEasing()); change(indexObject, ui->fireTriggers, cursor->getFireValue(), prevCursor->getFireValue()); change(indexObject, ui->speedSpin, cursor->getTimeFactor(), prevCursor->getTimeFactor()); change(indexObject, ui->speedFSpin, cursor->getTimeFactorF(), prevCursor->getTimeFactorF()); change(indexObject, ui->cursorSpeedLock, cursor->getLockPathLength(), prevCursor->getLockPathLength()); change(indexObject, ui->offsetInitialSpin, cursor->getTimeInitialOffset(), prevCursor->getTimeInitialOffset()); change(indexObject, ui->offsetStartSpin, cursor->getTimeStartOffset(), prevCursor->getTimeStartOffset()); change(indexObject, ui->offsetEndSpin, cursor->getTimeEndOffset(), prevCursor->getTimeEndOffset()); change(indexObject, ui->cursorSourceX1, cursor->getBoundsRect(0, true), prevCursor->getBoundsRect(0, true)); change(indexObject, ui->cursorSourceY1, cursor->getBoundsRect(1, true), prevCursor->getBoundsRect(1, true)); change(indexObject, ui->cursorSourceZ1, cursor->getBoundsRect(2, true), prevCursor->getBoundsRect(2, true)); change(indexObject, ui->cursorSourceX2, cursor->getBoundsRect(3, true), prevCursor->getBoundsRect(3, true)); change(indexObject, ui->cursorSourceY2, cursor->getBoundsRect(4, true), prevCursor->getBoundsRect(4, true)); change(indexObject, ui->cursorSourceZ2, cursor->getBoundsRect(5, true), prevCursor->getBoundsRect(5, true)); change(indexObject, ui->cursorTargetX1, cursor->getBoundsRect(0, false), prevCursor->getBoundsRect(0, false)); change(indexObject, ui->cursorTargetY1, cursor->getBoundsRect(1, false), prevCursor->getBoundsRect(1, false)); change(indexObject, ui->cursorTargetZ1, cursor->getBoundsRect(2, false), prevCursor->getBoundsRect(2, false)); change(indexObject, ui->cursorTargetX2, cursor->getBoundsRect(3, false), prevCursor->getBoundsRect(3, false)); change(indexObject, ui->cursorTargetY2, cursor->getBoundsRect(4, false), prevCursor->getBoundsRect(4, false)); change(indexObject, ui->cursorTargetZ2, cursor->getBoundsRect(5, false), prevCursor->getBoundsRect(5, false)); change(indexObject, ui->cursorSourceMode0, cursor->getBoundsSourceMode()==0, prevCursor->getBoundsSourceMode()==0); change(indexObject, ui->cursorSourceMode1, cursor->getBoundsSourceMode()==1, prevCursor->getBoundsSourceMode()==1); change(indexObject, ui->cursorSourceMode2, cursor->getBoundsSourceMode()==2, prevCursor->getBoundsSourceMode()==2); change(indexObject, ui->cursorSourceMode3, cursor->getBoundsSourceMode()==3, prevCursor->getBoundsSourceMode()==3); change(indexObject, ui->textureCombo1, cursor->getTextureActive(), prevCursor->getTextureActive(), false); change(indexObject, ui->textureCombo2, cursor->getTextureInactive(), prevCursor->getTextureInactive(), false); change(indexObject, ui->messagesSpin, object->getMessageTimeInterval(), prevObject->getMessageTimeInterval()); if(cursor->getCurve()) { change(indexObject, ui->speedSpin, cursor->getTimeFactor(), prevCursor->getTimeFactor()); change(indexObject, ui->cursorLengthSpin, cursor->getCurve()->getPathLength() / cursor->getTimeFactor(), prevCursor->getCurve()->getPathLength() / prevCursor->getTimeFactor()); } prevCursor = cursor; } else if(object->getType() == ObjectsTypeCurve) { NxCurve *curve = (NxCurve*)object; if(prevCurve == 0) prevCurve = curve; change(indexObject, ui->sizeWSpin, curve->getResize().width(), prevCurve->getResize().width()); change(indexObject, ui->sizeHSpin, curve->getResize().height(), prevCurve->getResize().height()); change(indexObject, ui->intertiaSpin, curve->getInertie(), prevCurve->getInertie()); change(indexObject, ui->equationPoints, curve->getEquationPoints(), prevCurve->getEquationPoints()); change(indexObject, ui->equationType0, curve->getEquationType()==0, prevCurve->getEquationType()==0); change(indexObject, ui->equationType1, curve->getEquationType()==1, prevCurve->getEquationType()==1); change(indexObject, ui->equationEdit, curve->getEquation(true), prevCurve->getEquation(true)); change(indexObject, ui->equationParam1Value, curve->getEquationParam("param1"), prevCurve->getEquationParam("param1")); change(indexObject, ui->equationParam2Value, curve->getEquationParam("param2"), prevCurve->getEquationParam("param2")); change(indexObject, ui->equationParam3Value, curve->getEquationParam("param3"), prevCurve->getEquationParam("param3")); change(indexObject, ui->equationParam4Value, curve->getEquationParam("param4"), prevCurve->getEquationParam("param4")); change(indexObject, ui->equationParam5Value, curve->getEquationParam("param5"), prevCurve->getEquationParam("param5")); prevCurve = curve; } else if(object->getType() == ObjectsTypeTrigger) { NxTrigger *trigger = (NxTrigger*)object; if(prevTrigger == 0) prevTrigger = trigger; change(indexObject, ui->triggerOffSpin, trigger->getTriggerOff(), prevTrigger->getTriggerOff()); change(indexObject, ui->textureCombo1, trigger->getTextureActive(), prevTrigger->getTextureActive(), false); change(indexObject, ui->textureCombo2, trigger->getTextureInactive(), prevTrigger->getTextureInactive(), false); prevTrigger = trigger; } prevObject = object; } } ui->typeLabel->setText(""); QString typeLabelText; if(counterTriggers == 1) typeLabelText += QString::number(counterTriggers) + tr(" TRIGGER, "); else if(counterTriggers > 1) typeLabelText += QString::number(counterTriggers) + tr(" TRIGGERS, "); if(counterCurves == 1) typeLabelText += QString::number(counterCurves) + tr(" CURVE, "); else if(counterCurves > 1) typeLabelText += QString::number(counterCurves) + tr(" CURVES, "); if(counterCursors == 1) typeLabelText += QString::number(counterCursors) + tr(" CURSOR, "); else if(counterCursors > 1) typeLabelText += QString::number(counterCursors) + tr(" CURSORS, "); typeLabelText.chop(2); ui->typeLabel->setText(typeLabelText); bool showCursorInfo = false, showTriggerInfo = false, showCurveInfo = false, showCurvePointsInfo = false, showCurveEllipseInfo = false, showCursorCurveInfo = false, showGenericInfo = false, showCurveEquationInfo = false; if(counterCurves > 0) showCurveInfo = true; if(counterCursors > 0) showCursorInfo = true; if(counterTriggers > 0) showTriggerInfo = true; if(counterCurveEllipse > 0) showCurveEllipseInfo = true; if(counterCursorsCurve > 0) showCursorCurveInfo = true; if(counterCurvePoints > 0) showCurvePointsInfo = true; if(counterCurveEquation > 0) showCurveEquationInfo = true; if((counterCursors + counterCurves + counterTriggers) > 0) showGenericInfo = true; ui->newIdButton->setVisible(showGenericInfo); ui->IDLabel->setVisible(showGenericInfo); ui->groupIdButton->setVisible(showGenericInfo); ui->groupIdLabel->setVisible(showGenericInfo); ui->positionX->setVisible(showCurveInfo | showTriggerInfo); ui->positionY->setVisible(showCurveInfo | showTriggerInfo); ui->positionZ->setVisible(showCurveInfo | showTriggerInfo); ui->positionLabel->setVisible(showCurveInfo | showTriggerInfo); ui->activityCheck->setVisible(showGenericInfo); ui->activityLabel->setVisible(showGenericInfo); ui->messagesButton->setVisible(showCursorInfo | showTriggerInfo); ui->messagesSpin->setVisible(showCursorInfo); ui->sizeSpin->setVisible(showGenericInfo); ui->sizeLabel2->setVisible(showGenericInfo); ui->labelLabel->setVisible(showGenericInfo); ui->labelLine->setVisible(showGenericInfo); ui->colorLabel1->setVisible(showGenericInfo); ui->colorLabel2->setVisible(showGenericInfo); ui->colorCombo1->setVisible(showGenericInfo); ui->colorCombo2->setVisible(showGenericInfo); ui->colorComboMultiply->setVisible(showGenericInfo); ui->textureLabel1->setVisible(showCursorInfo | showTriggerInfo); ui->textureLabel2->setVisible(showCursorInfo | showTriggerInfo); ui->textureCombo1->setVisible(showCursorInfo | showTriggerInfo); ui->textureCombo2->setVisible(showCursorInfo | showTriggerInfo); ui->widthSpin->setVisible(showCursorInfo); ui->depthSpin->setVisible(showCursorInfo); ui->widthLabel->setVisible(showCursorInfo); ui->patternLine->setVisible(showCursorInfo); ui->easingLabel->setVisible(showCursorInfo); ui->easingCombo->setVisible(showCursorInfo); ui->fireTriggers->setVisible(showCursorInfo); ui->patternLabel->setVisible(showCursorInfo); ui->offsetInitialSpin->setVisible(showCursorCurveInfo); ui->offsetStartSpin->setVisible(showCursorCurveInfo); ui->offsetEndSpin->setVisible(showCursorCurveInfo); ui->offsetLabel->setVisible(showCursorCurveInfo); ui->offsetLabel1->setVisible(showCursorCurveInfo); ui->offsetLabel2->setVisible(showCursorCurveInfo); ui->offsetLabel2_2->setVisible(showCursorCurveInfo); ui->offsetLabel3->setVisible(showCursorCurveInfo); ui->cursorLengthSpin->setVisible(showCursorCurveInfo); ui->cursorSpeedLabel->setVisible(showCursorCurveInfo); ui->cursorSpeedLock->setVisible(showCursorCurveInfo); if(ui->cursorSpeedLock->isChecked()) { ui->cursorSpeedLabel_2->setVisible(false); ui->speedSpin->setVisible(false); } else { ui->speedSpin->setVisible(showCursorCurveInfo); ui->cursorSpeedLabel_2->setVisible(showCursorCurveInfo); } ui->cursorTargetX1->setVisible(showCursorCurveInfo); ui->cursorTargetX2->setVisible(showCursorCurveInfo); ui->cursorTargetY1->setVisible(showCursorCurveInfo); ui->cursorTargetY2->setVisible(showCursorCurveInfo); ui->cursorTargetZ1->setVisible(showCursorCurveInfo); ui->cursorTargetZ2->setVisible(showCursorCurveInfo); if(!ui->cursorSourceMode3->isChecked()) { ui->cursorSourceX1->setVisible(false); ui->cursorSourceY1->setVisible(false); ui->cursorSourceZ1->setVisible(false); ui->cursorSourceX2->setVisible(false); ui->cursorSourceY2->setVisible(false); ui->cursorSourceZ2->setVisible(false); ui->cursorTargetLabel1->setVisible(false); ui->cursorTargetLabel2->setVisible(false); ui->cursorTargetLabel5->setVisible(false); ui->cursorTargetLabel6->setVisible(false); ui->cursorTargetLabel11->setVisible(false); ui->cursorTargetLabel13->setVisible(false); } else { ui->cursorSourceX1->setVisible(showCursorCurveInfo); ui->cursorSourceX2->setVisible(showCursorCurveInfo); ui->cursorSourceY1->setVisible(showCursorCurveInfo); ui->cursorSourceY2->setVisible(showCursorCurveInfo); ui->cursorSourceZ1->setVisible(showCursorCurveInfo); ui->cursorSourceZ2->setVisible(showCursorCurveInfo); ui->cursorTargetLabel1->setVisible(showCursorCurveInfo); ui->cursorTargetLabel2->setVisible(showCursorCurveInfo); ui->cursorTargetLabel5->setVisible(showCursorCurveInfo); ui->cursorTargetLabel6->setVisible(showCursorCurveInfo); ui->cursorTargetLabel11->setVisible(showCursorCurveInfo); ui->cursorTargetLabel13->setVisible(showCursorCurveInfo); } ui->cursorTargetLabel3->setVisible(showCursorCurveInfo); ui->cursorTargetLabel4->setVisible(showCursorCurveInfo); ui->cursorTargetLabel7->setVisible(showCursorCurveInfo); ui->cursorTargetLabel8->setVisible(showCursorCurveInfo); ui->cursorTargetLabel12->setVisible(showCursorCurveInfo); ui->cursorTargetLabel14->setVisible(showCursorCurveInfo); ui->cursorSourceMode->setVisible(showCursorCurveInfo); ui->speedFLabel->setVisible(showCursorCurveInfo); ui->speedFSpin->setVisible(showCursorCurveInfo); ui->triggerOffLabel->setVisible(showTriggerInfo); ui->triggerOffSpin->setVisible(showTriggerInfo); ui->sizeHSpin->setVisible(showCurvePointsInfo || showCurveEllipseInfo); ui->sizeWSpin->setVisible(showCurvePointsInfo || showCurveEllipseInfo); ui->sizeLabel->setVisible(showCurvePointsInfo || showCurveEllipseInfo); ui->intertiaSpin->setVisible(showCurvePointsInfo); ui->intertiaLabel->setVisible(showCurvePointsInfo); ui->pointsLabel->setVisible(showCurveInfo); ui->pointsResample->setVisible(showCurveInfo); ui->pointsLists->setVisible(showCurvePointsInfo); ui->equationTemplate->setVisible(showCurveEquationInfo); ui->equationLabel->setVisible(showCurveEquationInfo); ui->equationType->setVisible(showCurveEquationInfo); ui->equationPoints->setVisible(showCurveEquationInfo); ui->equationEdit->setVisible(showCurveEquationInfo); ui->equationParam1Label->setVisible(showCurveEquationInfo); ui->equationParam1Slider->setVisible(showCurveEquationInfo); ui->equationParam1Value->setVisible(showCurveEquationInfo); ui->equationParam2Label->setVisible(showCurveEquationInfo); ui->equationParam2Slider->setVisible(showCurveEquationInfo); ui->equationParam2Value->setVisible(showCurveEquationInfo); ui->equationParam3Label->setVisible(showCurveEquationInfo); ui->equationParam3Slider->setVisible(showCurveEquationInfo); ui->equationParam3Value->setVisible(showCurveEquationInfo); ui->equationParam4Label->setVisible(showCurveEquationInfo); ui->equationParam4Slider->setVisible(showCurveEquationInfo); ui->equationParam4Value->setVisible(showCurveEquationInfo); ui->equationParam5Label->setVisible(showCurveEquationInfo); ui->equationParam5Slider->setVisible(showCurveEquationInfo); ui->equationParam5Value->setVisible(showCurveEquationInfo); ui->equationParamReset->setVisible(showCurveEquationInfo); if((!showGenericInfo) && (ui->ssTabInfo->currentIndex() != 4)) lastTabBeforeRessources = ui->ssTabInfo->currentIndex(); ui->ssTabInfo->setTabEnabled(0, showGenericInfo); ui->ssTabInfo->setTabEnabled(1, showGenericInfo); ui->ssTabInfo->setTabEnabled(2, showCursorInfo | showTriggerInfo); ui->ssTabInfo->setTabEnabled(3, showCursorInfo | showTriggerInfo); if((ui->ssTabInfo->currentIndex() == 4) && (showGenericInfo)) { if(ui->ssTabInfo->isTabEnabled(lastTabBeforeRessources)) ui->ssTabInfo->setCurrentIndex(lastTabBeforeRessources); else if(ui->ssTabInfo->isTabEnabled(lastTabBeforeRessources-1)) ui->ssTabInfo->setCurrentIndex(lastTabBeforeRessources -1); else if(ui->ssTabInfo->isTabEnabled(lastTabBeforeRessources-2)) ui->ssTabInfo->setCurrentIndex(lastTabBeforeRessources -2); } actionInfoLock = false; } void UiInspector::change(quint16 indexObject, QRadioButton *spin, bool val, bool prevVal) { if(indexObject == 0) { if(spin->styleSheet() != "") spin->setStyleSheet(""); if(!spin->hasFocus()) spin->setChecked(val); } else if((spin->styleSheet() == "") && (prevVal != val)) { spin->setStyleSheet("color: gray;"); } } void UiInspector::change(quint16 indexObject, QDoubleSpinBox *spin, qreal val, qreal prevVal) { if(indexObject == 0) { if(spin->styleSheet() != "") spin->setStyleSheet(""); if(!spin->hasFocus()) spin->setValue(val); } else if((spin->styleSheet() == "") && (prevVal != val)) { spin->setStyleSheet("color: gray;"); } } void UiInspector::change(quint16 indexObject, QSpinBox *spin, qint32 val, qint32 prevVal) { if(indexObject == 0) { if(spin->styleSheet() != "") spin->setStyleSheet(""); if(!spin->hasFocus()) spin->setValue(val); } else if((spin->styleSheet() == "") && (prevVal != val)) { spin->setStyleSheet("color: gray;"); } } void UiInspector::change(quint16 indexObject, QPushButton *spin, const QString & val, const QString & prevVal) { if(indexObject == 0) { if(spin->styleSheet() != "") spin->setStyleSheet(""); if(!spin->hasFocus()) spin->setText(val); } else if((spin->styleSheet() == "") && (prevVal != val)) { spin->setStyleSheet("color: gray;"); } } void UiInspector::change(quint16 indexObject, QCheckBox *spin, quint8 val, quint8 prevVal) { if(indexObject == 0) { if(spin->styleSheet() != "") spin->setStyleSheet(""); if(!spin->hasFocus()) spin->setChecked(val); } else if((spin->styleSheet() == "") && (prevVal != val)) { spin->setStyleSheet("QCheckBox::indicator { background-color: rgba(50, 237, 255, 128); }"); } } void UiInspector::change(quint16 indexObject, QLineEdit *spin, const QString & val, const QString & prevVal) { if(indexObject == 0) { if(spin->styleSheet() != "") spin->setStyleSheet(""); if(!spin->hasFocus()) spin->setText(val); } else if((spin->styleSheet() == "") && (prevVal != val)) { spin->setStyleSheet("QCheckBox::indicator { background-color: rgba(50, 237, 255, 128); }"); } } void UiInspector::change(quint16 indexObject, QPlainTextEdit *spin, const QString & val, const QString & prevVal) { if(indexObject == 0) { if(spin->styleSheet() != "") spin->setStyleSheet(""); if(!spin->hasFocus()) spin->setPlainText(val); } else if((spin->styleSheet() == "") && (prevVal != val)) { spin->setStyleSheet("QCheckBox::indicator { background-color: rgba(50, 237, 255, 128); }"); } } void UiInspector::change(quint16 indexObject, QComboBox *spin, const QString & val, const QString & prevVal, bool isColor) { if(!isColor) { if((!spin->hasFocus()) && (spin->isEditable())) spin->setEditText(val); } if(indexObject == 0) { qint16 indexVal = spin->findText(val); if(!spin->hasFocus()) { if(indexVal < 0) { if(isColor) colorComboAdd(spin, QStringList() << val); else spin->addItem(val); indexVal = spin->count()-1; } spin->setCurrentIndex(indexVal); //spin->setEditText(val); } } else if(prevVal != val) { if((isColor) && (spin->currentIndex() >= 0)) spin->setCurrentIndex(-1); } } void UiInspector::change(quint16 indexObject, QComboBox *spin, qint16 val, qint16 prevVal) { if(indexObject == 0) { if(!spin->hasFocus()) spin->setCurrentIndex(val); } else if((spin->styleSheet() == "") && (prevVal != val)) { if(spin->currentIndex() >= 0) spin->setCurrentIndex(-1); } } void UiInspector::colorComboAdd(QComboBox *spin, QStringList values) { foreach(const QString & value, values) { QString colorName = value; QPixmap icon(32, 32); QColor color = Qt::gray; QStringList valueSplit = colorName.split(" ", QString::SkipEmptyParts); if(valueSplit.count() == 4) color = QColor(valueSplit.at(0).toUInt(), valueSplit.at(1).toUInt(), valueSplit.at(2).toUInt(), valueSplit.at(3).toUInt()); else if((colorName.startsWith(Application::colorsPrefix(0))) || (colorName.startsWith(Application::colorsPrefix(1)))) { if((!colorName.contains("_gui_")) && (((colorName.startsWith(Application::colorsPrefix(0))) && (Application::colorsPrefix() == Application::colorsPrefix(0))) || ((colorName.startsWith(Application::colorsPrefix(1))) && (Application::colorsPrefix() == Application::colorsPrefix(1))))) { color = Render::colors->value(colorName); colorName = colorName.remove(Application::colorsPrefix()); } else continue; } else color = Render::colors->value(colorName); icon.fill(color); if(colorName != tr("Choose…")) spin->addItem(QIcon(icon), colorName); else spin->addItem(colorName); } } void UiInspector::textureComboAdd(QComboBox *spin, QStringList values) { foreach(const QString & value, values) { if((value.isEmpty()) || (Render::textures->value(value)->loaded)) spin->addItem(value); } } QTreeWidgetItem* UiInspector::getObjectRootItem() const { return ui->ccView->invisibleRootItem(); } QPair< QList, UiRenderSelection> UiInspector::getSelectedCCObject() const { UiRenderSelection objects; QList groups; foreach(const QTreeWidgetItem* item, ui->ccView->selectedItems()) if(item->text(0) == tr("GROUP")) groups .append((NxGroup*) item); else objects.append((NxObject*)item); return qMakePair(groups, objects); } void UiInspector::showSpaceTab() { ui->tab->setCurrentIndex(1); ui->ssTabInfo->setCurrentIndex(1); } void UiInspector::showRessourcesTab(const QString &) { ui->tab->setCurrentIndex(1); ui->ssTabInfo->setTabEnabled(4, true); ui->ssTabInfo->setCurrentIndex(4); } void UiInspector::showConfigTab() { ui->tab->setCurrentIndex(3); } void UiInspector::clearCCselections() { ui->ccView->clearSelection(); } IanniX-0.9.20/gui/uiinspector.h000066400000000000000000000105001317340345000162650ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #ifndef INSPECTOR_H #define INSPECTOR_H #include #include #include "misc/application.h" #include "gui/uimessagebox.h" #include "render/uirender.h" #include "interfaces/extoscpatternask.h" #include "messages/messagemanager.h" namespace Ui { class UiInspector; } class UiInspector : public QWidget { Q_OBJECT public: explicit UiInspector(QWidget *parent = 0); ~UiInspector(); protected: void changeEvent(QEvent *e); private: bool actionInfoLock; bool slidersLock; bool mouseDisplay; QString mousePos, mouseZoom, rotationAngles; public slots: void addInterfaces(); void setMousePos(const NxPoint & pos); void setMouseZoom(qreal zoom); void setRotationAngles(const NxPoint & pos); void actionTabChange(int tab); void actionCC(QTreeWidgetItem* item,int col) { emit(actionRouteCC(item, col)); } void actionCC() { emit(actionRouteCC(0, 0)); } void actionCCButton(); void actionInfo(); void actionInfoID(); void actionColor(); void actionTexture(); void actionInfoGroup(); void actionMessages(); QPair, UiRenderSelection> getSelectedCCObject() const; QTreeWidgetItem *getObjectRootItem() const; UiTreeView* getFileWidget() const; private: void timerEvent(QTimerEvent *); void addEquationTemplate(const QString &text, const QString &valeur, bool enabled = false); bool needRefresh; public slots: void refreshIp(); void showRessourcesTab(const QString &value); void showSpaceTab(); void showConfigTab(); void clearCCselections(); void refresh(); void askRefresh() { needRefresh = true; } void change(quint16 indexObject, QRadioButton *spin, bool val, bool prevVal); void change(quint16 indexObject, QDoubleSpinBox *spin, qreal val, qreal prevVal); void change(quint16 indexObject, QSpinBox *spin, qint32 val, qint32 prevVal); void change(quint16 indexObject, QPushButton *spin, const QString & val, const QString & prevVal); void change(quint16 indexObject, QCheckBox *spin, quint8 val, quint8 prevVal); void change(quint16 indexObject, QLineEdit *spin, const QString & val, const QString & prevVal); void change(quint16 indexObject, QPlainTextEdit *spin, const QString & val, const QString & prevVal); void change(quint16 indexObject, QComboBox *spin, const QString & val, const QString & prevVal, bool isColor = true); void change(quint16 indexObject, QComboBox *spin, qint16 val, qint16 prevVal); void colorComboAdd(QComboBox *spin, QStringList values); void textureComboAdd(QComboBox *spin, QStringList values); signals: void actionRouteCC(QTreeWidgetItem*,int); void actionRouteProjectFiles(); void actionRouteProjectScripts(); void actionUnsoloGroups(); void actionUnsoloObjects(); void actionUnmuteGroups(); void actionUnmuteObjects(); private: UiRender *render; quint16 lastTabBeforeRessources; public: inline void setRender(UiRender *_render) { render = _render; } public: QAction *toolbarButton; protected: void showEvent(QShowEvent *); void closeEvent(QCloseEvent *); void keyPressEvent(QKeyEvent *); private: Ui::UiInspector *ui; }; #endif // INSPECTOR_H IanniX-0.9.20/gui/uiinspector.ui000066400000000000000000007062341317340345000164730ustar00rootroot00000000000000 UiInspector 0 0 387 562 390 16777215 IanniX — Inspector QTabWidget, QLabel, QCheckBox, QLineEdit, QPlainTextEdit, QPushButton, QSpinBox, QDoubleSpinBox, QTreeView, QHeaderView, QTabBar, QComboBox, QFrame#globalFrame, QTabBar::tab, QTreeView, QHeaderView, QDockWidget, QStatusBar, QRadioButton, QToolButton { font: 10px "Museo Sans", "Museo Sans 500", "Arial"; padding: 0px; margin: 0px; min-height: 20px; color: white; border: 0px solid black; icon-size: 14px; } QPushButton, QSpinBox, QDoubleSpinBox, QLineEdit, QPlainTextEdit, QCheckBox::indicator, QRadioButton::indicator, QTreeView::indicator, QComboBox, QTreeView, QHeaderView { border: 1px solid rgb(55, 55, 55); border-radius: 2px; background-color: rgb(70, 70, 70); } QSpinBox, QDoubleSpinBox, QLineEdit, QPlainTextEdit, QCheckBox { margin-top: 4px; margin-bottom: 4px; } QFrame#globalFrame, QFrame#transportFrame, QFrame#timeFrame, QFrame#optionFrame, QFrame#speedFrame, QFrame#logoFrame, QFrame#perfFrame, QDialog { background-color: rgb(40, 40, 40); } QLabel, QCheckBox, QRadioButton { color: rgb(210, 210, 210); } QTabWidget::pane { border: 1px solid rgb(50, 50, 50); } QTabWidget::tab-bar { left: 0px; } QTabWidget#tab { color: red; } QTabBar::tab { min-height: 25px; /* FIX IN SS-TAB */ background-color: rgb(110, 110, 110); border-top-left-radius: 4px; border-top-right-radius: 4px; margin-right: 2px; padding-left: 5px; padding-right: 5px; color: rgb(220, 220, 220); } QTabBar::tab:selected { background-color: rgb(242, 241, 237); color: black; } QTabBar::tab:hover { color: black; } QTabBar::tab:!selected { margin-top: 2px; } QTabBar::tab:disabled { color: gray; } QPushButton { margin-left: 6px; padding-left: 3px; padding-right: 3px; } QPushButton:hover { border: 1px solid rgb(28, 124, 195); background-color: rgb(21, 91, 143); } QPushButton::checked, QPushButton:pressed, QCheckBox::indicator:checked, QTreeView::indicator:checked, QRadioButton::indicator:checked { background-color: rgb(0, 187, 255); } QCheckBox, QRadioButton { spacing: 5px; } QCheckBox::indicator, QTreeView::indicator, QRadioButton::indicator { width: 10px; height: 10px; } QSpinBox, QDoubleSpinBox, QLineEdit { padding-left : 5px; } QSpinBox::up-button, QDoubleSpinBox::up-button, QSpinBox::down-button, QDoubleSpinBox::down-button { width: 5px; padding: 2px; padding-left: 3px; background-color: rgb(60, 60, 60); border: 0px solid black; border-left: 1px solid rgb(70, 70, 70); } QSpinBox::up-button, QDoubleSpinBox::up-button { image: url(:/icons/res_icon_plus.png); border-bottom: 1px solid rgb(70, 70, 70); } QSpinBox::down-button, QDoubleSpinBox::down-button { image: url(:/icons/res_icon_minus.png); } QComboBox { background: rgb(242, 241, 237); color: black; margin-left: 3px; border-radius: 3px; selection-color: black; padding-left: 5px; } QComboBox::drop-down { width: 10px; padding: 2px; border: 0px solid black; background-color: rgb(70, 70, 70); image: url(:/icons/res_icon_down.png); } QTreeView { background: rgb(50, 50, 50); alternate-background-color: rgb(55, 55, 55); selection-background-color: rgb(0, 187, 255); gridline-color: rgb(60, 60, 60); icon-size: 14px; } QHeaderView { background: transparent; border: 0px solid black; color: rgb(200, 200, 200); min-height: 14px; } QHeaderView::section { background: rgb(90, 90, 90); padding-left: 5px; border-top-left-radius: 3px; border-top-right-radius: 3px; margin-right: 1px; font: 9px "Arial"; } QTreeView::item { min-height: 20px; } QTreeView::branch:has-children:!has-siblings:closed, QTreeView::branch:closed:has-children:has-siblings { border-image: none; image: url(:/items/res_tree_close.png); } QTreeView::branch:open:has-children:!has-siblings, QTreeView::branch:open:has-children:has-siblings { border-image: none; image: url(:/items/res_tree_open.png); } QScrollBar:vertical, QScrollBar:horizontal { border: 0px solid black; background: rgba(255, 255, 255, 32); } QScrollBar::handle:vertical, QScrollBar::handle:horizontal { border: 0px solid black; background: rgb(161, 161, 161); border-radius: 3px; } QScrollBar:vertical { width: 8px; } QScrollBar:horizontal { height: 8px; } QScrollBar::handle:vertical { min-height: 8px; } QScrollBar::handle:horizontal { min-width: 8px; } QScrollBar::add-line:vertical, QScrollBar::add-line:hozirontal, QScrollBar::sub-line:vertical, QScrollBar::sub-line:horizontal, QScrollBar::up-arrow:vertical, QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:vertical, QScrollBar::down-arrow:horizontal { border: 0px solid black; background: transparent; width: 1px; height: 1px; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical, QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: none; } QSlider:horizontal { min-width: 100px; } QSlider::groove:horizontal { border: 0px solid transparent; background-color: rgb(70, 70, 70); height: 3px; } QSlider::handle:horizontal { width: 11px; height: 10px; border-radius: 5px; margin-top: -4px; margin-bottom: -4px; border: 0px solid black; background-color: rgb(0, 187, 250); } QSplitter::handle { background: rgb(255, 255, 255, 30); } QSplitter::handle:pressed { background: rgb(0, 187, 255); } QSplitter::handle:horizontal { width: 4px; } QSplitter::handle:vertical { height: 4px; } QDockWidget { } QDockWidget::title { text-align: center; background-color: rgb(70, 70, 70); } QToolBar { background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(247, 247, 247, 255), stop:1 rgba(222, 222, 222, 255)); border: 1px solid rgba(202, 202, 202, 255); spacing: 0px; } QToolButton { border: 0px solid black; color: black; border-radius: 3px; margin: 3px; } QToolButton:pressed, QToolButton:checked { background-color: rgba(0, 0, 0, 20); } QStatusBar { color: rgb(210, 210, 210); border-top: 1px solid rgb(50, 50, 50); background-color: rgb(30, 30, 30); } /*TRANSPORT*/ QFrame#transportFrame, QFrame#timeFrame, QFrame#optionFrame, QFrame#speedFrame, QFrame#logoFrame, QFrame#perfFrame{ border: 0px solid black; border-left: 1px solid rgb(50, 50, 50); } QWIdget { margin: 0px; padding: 0px; } QWidget#speedSlider { margin-top: 7px; } QWidget#timeEdit, QWidget#perfCpuEdit, QWidget#perfOpenGLEdit, QWidget#perfSchedulerEdit { background-color: transparent; border: 0px solid black; font: 9px; color: rgb(140, 140, 140); } QLineEdit#timeEdit { font: 40px "Lucida Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida"; color: rgb(0, 187, 255); } QPushButton#logoButton { border: 0px solid black; background-color: transparent; } QPushButton:hover#logoButton { border: 1px solid rgb(28, 124, 195); background-color: rgb(21, 91, 143); } QPushButton#ffButton, QPushButton#playButton { min-width: 40px; min-height: 40px; border-radius: 20px; padding: 0px; } QPushButton#logoButton { margin: -2px; } /* ---- */ /* INSPECTEUR */ QWidget#ssTabInfoGeneral, QWidget#ssTabInfoSpace, QWidget#ssTabInfoTime, QWidget#ssTabInfoMessage, QWidget#ssTabConfigLog, QWidget#ssTabConfigNetwork, QWidget#ssTabConfigMIDI, QWidget#ssTabConfigArduino, QWidget#ssTabConfigSyphon, QWidget#ssTabConfigWeb, QWidget#ssTabRessource { background-color: rgb(50, 50, 50) } QWidget#tabProject, QWidget#tabView, QWidget#tabInfo, QWidget#tabControlCenter, QWidget#tabConfig { background-color: transparent; } QWidget#equationEdit { font: 10px "Lucida Console", "Monaco", "Monospace"; } /* ----- */ /* MAIN */ QWidget#centralwidget { background-color: black; } /* ----- */ /* DIALOG */ QDialogButtonBox QPushButton { padding-left: 10px; padding-right: 10px; min-height: 25px; margin: 5px; } /* ------ */ 0 0 0 0 QFrame::StyledPanel QFrame::Raised 0 3 3 3 3 0 24 24 Scores file|Scores are stored in files containing three parts:\n- objects edited through graphical user interface\n- script code\n- received messages from external software :/general/res_icon_inspector_project.png:/general/res_icon_inspector_project.png FILES 6 6 6 6 0 150 :/general/res_icon_inspector_info.png:/general/res_icon_inspector_info.png INFOS 10 6 6 6 6 0 0 color: white; font: 12px; TRIGGER QTabBar::tab { min-height: 20px; } 0 GENERAL 3 10 10 10 10 Objects identification|An object in IanniX is defined by two identifiers:\n- the ID is a unique number in the score (two objects cannot have the same ID). IDs are used in sent messages to know who was the sender; they are used in received messages to control a targer a specific object\n- the group ID is a string allowing a group control of objects in received messages. In sent messages, it can also be used as a human readable ID.\n\nIf an object is disabled ("active" checkbox), it will not be used in the score (no sent messages). 3 0 0 0 0 10 100 20 100 16777215 ID Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true newIdButton 206 22 206 16777215 Changes the object ID ID Qt::Horizontal 40 20 10 100 20 100 16777215 GROUP ID Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true newIdButton 206 22 206 16777215 Changes the group ID GROUP Qt::Horizontal 40 20 10 100 20 100 16777215 ACTIVE Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true activityCheck Enables or disables the object in the socre padding-left: 2px; Objects style|Objects can have different graphical behaviours:\n - you can change the colors and texture (images - only for triggers)\n - size or thickness of the object is customisable\n - a label can be set to add human readable information to the object 3 0 0 0 0 10 100 20 100 16777215 THICKNESS / SIZE Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true sizeSpin 80 30 80 16777215 Changes the tickness or size of objects 3 0.000000000000000 999999.000000000000000 0.100000000000000 Qt::Horizontal 40 1 10 100 20 100 16777215 LABEL Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true labelLine 200 30 200 16777215 Changes the label of objects Qt::Horizontal 40 1 10 100 20 100 16777215 COLOR if ACTIVE Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true colorCombo1 203 22 203 16777215 Changes the color of active objects by using a color in the palette or a custom color QComboBox QAbstractItemView { min-height: 100px; } true QComboBox::AdjustToContents Qt::Horizontal 40 1 10 100 20 100 16777215 COLOR if INACTIVE Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true colorCombo1 203 22 203 16777215 Changes the color of inactive objects by using a color in the palette or a custom color QComboBox QAbstractItemView { min-height: 100px; } true QComboBox::AdjustToContents Qt::Horizontal 40 1 10 100 20 100 16777215 COLOR MULTIPLICATION Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true colorCombo1 203 22 203 16777215 Multiplies the color of objects by another color in the palette or a custom color QComboBox QAbstractItemView { min-height: 100px; } true QComboBox::AdjustToContents Qt::Horizontal 40 1 10 100 20 100 16777215 TEXTURE if ACTIVE Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true colorCombo1 203 22 203 16777215 Changes the texture (image) of active objects QComboBox QAbstractItemView { min-height: 100px; } QComboBox::AdjustToContents Qt::Horizontal 40 1 10 100 20 100 16777215 TEXTURE if INACTIVE Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true colorCombo1 203 22 203 16777215 Changes the texture (image) of inactive objects QComboBox QAbstractItemView { min-height: 100px; } QComboBox::AdjustToContents Qt::Horizontal 40 1 Qt::Vertical 20 1 Objects and 3D space|Objects are positioned in a 3D space. These options allows you to control how objects interact with space:\n - absolute position\n - size of curves\n - playhead cursor size\n - curve trajectory points (manual or mathematical edition) 3D SPACE 5 10 10 10 10 10 85 20 85 16777215 3D POSITION (X / Y / Z) Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true positionX 70 30 70 16777215 Changes the absolute X-position of object s 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 70 30 70 16777215 Changes the absolute Y-position of object s 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 70 30 70 16777215 Changes the absolute Z-position of object s 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 Qt::Horizontal 40 1 10 85 20 85 16777215 3D CURVE SIZE (W / H) Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true sizeWSpin 70 30 70 16777215 Resizes the object width s 3 0.000000000000000 999999.000000000000000 0.100000000000000 70 30 70 16777215 Resizes the object height s 3 0.000000000000000 999999.000000000000000 0.100000000000000 Qt::Horizontal 40 1 10 85 20 85 16777215 ELASTICITY FACTOR Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true sizeWSpin 70 30 70 16777215 Set a factor of elasticity making the curve "elastic" while moving points 2 0.000000000000000 999999.000000000000000 0.100000000000000 Qt::Horizontal 40 1 10 85 20 85 16777215 CURSOR WIDTH / DEPTH Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true widthSpin 70 30 70 16777215 Changes the width of cursor playhead s 3 999999.000000000000000 0.100000000000000 70 30 70 16777215 Changes the depth of cursor playhead s 3 999999.000000000000000 0.100000000000000 Qt::Horizontal 40 1 10 85 20 85 16777215 CURVE POINTS Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 103 22 Click here to manually edit curve points RESAMPLE 103 22 Click here to manually edit curve points EDIT POINTS Qt::Horizontal 40 1 0 10 0 203 22 203 16777215 QComboBox QAbstractItemView { min-height: 100px; } Templates Qt::Vertical QSizePolicy::Fixed 20 10 Qt::Horizontal 35 17 Qt::Horizontal 40 20 85 20 85 16777215 CURVE EQUATION Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 0 30 16777215 120 Changes the 3D mathematical equation of the curve 1 , 3 , 5 5 0 0 0 0 Cartesian coordinates (x, y, z) true Polar coordinates (r, phi, theta) 0 50 QFrame#frame { border: 0px solid black; } QWidget { padding-top: 0px; padding-bottom: 0px; margin-top: -2px; margin-bottom: -2px; } QFrame::StyledPanel QFrame::Raised 0 0 0 0 0 10 45 16 54 16777215 PARAM1 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true positionX 1000 50 Qt::Horizontal 50 18 50 16777215 Changes the absolute Y-position of object 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 10 45 16 54 16777215 PARAM2 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true positionX 1000 50 Qt::Horizontal 50 18 50 16777215 Changes the absolute Y-position of object 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 10 45 16 54 16777215 PARAM3 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true positionX 1000 50 Qt::Horizontal 50 18 50 16777215 Changes the absolute Y-position of object 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 10 45 16 54 16777215 PARAM4 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true positionX 1000 50 Qt::Horizontal 50 18 50 16777215 Changes the absolute Y-position of object 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 10 45 16 54 16777215 PARAM5 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true positionX 1000 50 Qt::Horizontal 50 18 50 16777215 Changes the absolute Y-position of object 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 margin-top:5px; margin-bottom:0px; RESET PARAMETERS TO DEFAULT 203 30 203 16777215 Defines the number of points used to calculate the 3D mathematical equation points with a precision of 2 9999 Qt::Vertical 20 54 Objects and time|Cursors moves according to time. You can set up:\n - speed of progression of cursors on curves\n - how cursors loops on curve (in terms of speed and position/time)\n - variation of speed (acceleration, multiple speeds according to loops)\n\n Last option is for triggers event duration. Typically, this duration is used for MIDI notes off (duration of note). TIME 3 10 10 10 10 10 85 20 85 16777215 TRIGGER DURATION Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true triggerOffSpin 80 30 80 16777215 Changes the duration of a trigger event s 3 999999.000000000000000 0.100000000000000 Qt::Horizontal 40 1 10 85 20 85 16777215 CURSOR SPEED or LENGTH Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true speedSpin 60 30 60 16777215 Changes the cursor speed in terms of factor of global playback speed (1.00 = score playback speed) 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 10 20 10 16777215 = 60 30 60 16777215 Changes the duration of one run of the cursor on its curve s 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 Locks cursor speed to a specific duration on curve (even if curve length changes in the future) LOCK false Qt::Horizontal 40 1 10 85 20 85 16777215 CURSOR MASTER SPEED Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true speedFSpin 80 30 80 16777215 Applies a last factor on cursor speed (1.00 = no changes) 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 Qt::Horizontal 40 1 10 85 20 85 16777215 CURSOR LOOP PATTERN Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true patternLine 200 22 200 16777215 Defines the "speed pattern" of the cursor. Speeds are applied consecutively on each loop or run of the cursor on the curve. true QComboBox::AdjustToContents 1 0 - One run on curve 1 - Loop on curve 1 -1 0 - Single roundtrip on curve 1 -1 - Loop roundtrip on curve 1 2 0 - One normal run, another at double speed Qt::Horizontal 40 1 10 85 20 85 16777215 CURSOR EASING CURVE Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true patternLine 200 22 200 16777215 Manages cursor acceleration on the curve (beta) Qt::Horizontal 40 1 10 85 20 85 16777215 IMPACT ON TRIGGERS Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true patternLine 200 22 200 16777215 Defines the "speed pattern" of the cursor. Speeds are applied consecutively on each loop or run of the cursor on the curve. true QComboBox::AdjustToContents Doesn't fire triggers Fires only triggers of the same group Fires all triggers Qt::Horizontal 40 1 10 85 20 85 16777215 CURSOR OFFSETS Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true offsetInitialSpin 0 5 0 0 75 20 130 16777215 INITIALLY STARTS FROM 60 30 80 16777215 Changes initial position/time of the cursor on the curve for the first run. Negative value is a delay before starting the run. s 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 0 0 35 20 35 16777215 THEN false Qt::Horizontal 40 1 5 0 0 70 20 60 16777215 LOOPS FROM false 60 30 80 16777215 Changes loop starting position/time of the cursor on the curve for each run s 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 20 20 20 16777215 TO Qt::AlignCenter 60 30 80 16777215 Changes loop ending position/time of the cursor on the curve for each run the end s 3 0.000000000000000 9999999.000000000000000 0.100000000000000 Qt::Horizontal 40 1 Qt::Vertical 20 96 Objects and messages|Cursors emit periodically messages containing especially their position on score. This panel allows you to set up some options:\n - you can edit the messages (protocol, what kind of values are sent...) and the amount of messages sent each second\n - you can configure the mapping of coordinates. This fundamental option makes a translation between coordinates in score 3D space to the desired value ranges needed by the receiver (for example, you can translate coordinates to frequencies, or coordinates to MIDI velocities)\n\n Triggers will also emit messages each time cursor playheads will hit them. MESSAGES 3 10 10 10 10 20 120 22 120 16777215 Changes the object sent messages margin: 0px; EDIT MESSAGE(S) Qt::Horizontal 40 20 160 30 80 16777215 Changes the amount of messages sent by objects (small values may be CPU and network intensive) Messages are sent immediately Messages are sent each ms 0 0.000000000000000 999999.000000000000000 1.000000000000000 0.000000000000000 10 0 0 Qt::Vertical QSizePolicy::Fixed 20 20 5 0 0 0 0 Changes the cursor mapping to match the curve bounding rectangle Mapped on curves bounding rectangle Changes the cursor mapping to match the curve+cursor bounding rectangle Mapped on curves bounding rectangle including cursor size Changes the cursor mapping to match the score bounding rectangle Mapped on global score bounding rectangle Changes the cursor mapping to your own coordinates mapping Custom mapping 5 5 0 100 20 100 16777215 X-COORDINATE GOING FROM Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 60 30 60 16777215 Sets starting range for X absolute coordinates s 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 20 20 15 16777215 TO Qt::AlignCenter 60 30 60 16777215 Sets starting range for X absolute coordinates s 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 100 20 100 16777215 X-OUTPUT FROM Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 60 30 60 16777215 Sets mapped range for X coordinates 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 20 20 15 16777215 TO Qt::AlignCenter 60 30 60 16777215 Sets mapped range for X coordinates 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 Qt::Horizontal 40 20 5 5 0 100 20 100 16777215 Y-COORDINATE GOING FROM Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 60 30 60 16777215 Sets starting range for Y absolute coordinates s 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 20 20 15 16777215 TO Qt::AlignCenter 60 30 60 16777215 Sets starting range for Y absolute coordinates s 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 100 20 100 16777215 Y-OUTPUT FROM Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 60 30 60 16777215 Sets mapped range for Y coordinates 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 20 20 15 16777215 TO Qt::AlignCenter 60 30 60 16777215 Sets mapped range for Y coordinates 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 Qt::Horizontal 40 20 5 0 100 20 100 16777215 Z-COORDINATE GOING FROM Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 60 30 60 16777215 Sets starting range for Z absolute coordinates s 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 20 20 15 16777215 TO Qt::AlignCenter 60 30 60 16777215 Sets starting range for Z absolute coordinates s 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 100 20 100 16777215 Z-OUTPUT FROM Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 60 30 60 16777215 Sets mapped range for Z coordinates 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 20 20 15 16777215 TO Qt::AlignCenter 60 30 60 16777215 Sets mapped range for Z coordinates 3 -999999.000000000000000 999999.000000000000000 0.100000000000000 Qt::Horizontal 40 20 Qt::Vertical 20 93 Score resources|These two lists allow you to add external files (image file for triggers appearance or score background) or to create a color palette for your score. Each resource is identified by a unique string. Once edited, your new resources will be available in the first tab if you want to apply them on objects. RESOURCES 10 10 10 10 10 TEXTURES 0 150 Loads/initializes textures (images) for the current score COLORS 0 150 Loads/initializes global colors (color palette) for the current score Qt::Vertical 20 168 Objects panel|This panel allows you to control the objects behaviour regarding to the score. You can mute some of them, turn objects in solo mode… :/general/res_icon_inspector_view.png:/general/res_icon_inspector_view.png OBJECTS 6 6 6 6 Qt::Vertical 5 0 Lists all objects of the score true QAbstractItemView::ExtendedSelection true true true TYPE M S ID GROUP ID 15 0 22 16777215 16777215 Switch on all objects Switch on all objects 0 22 16777215 16777215 Disable solo for all objects Disable solo for all objects 15 0 22 16777215 16777215 Switch on all groups Switch on all groups 0 22 16777215 16777215 Disable solo for all groups Disable solo for all groups Gives a small opacity on curves which has no cursor running on LIGHT OFF UNUSED CURVES false Gives a small opacity on curves which has no cursor running on CAMERA IN PERSPECTIVE MODE false 10 0 0 CAMERA FOLLOWS OBJECT ID followId 80 30 80 16777215 Camera point of view can be controlled by an object. Type here the ID of this object. no objects -1 999999 -1 Resets camera follow object ID QPushButton { min-width: 14px; min-height: 14px; max-width: 14px; max-height: 14px; width: 14px; height: 14px; border-radius: 7px; margin: 0px; padding: 0px; } X Qt::Horizontal 40 20 Autoresize option|This options will adapt the size of objects according to the current zoom. When you zoom or unzoom very far, objects like triggers may be very big or invisible. This feature allows you to have a clear and homogenous vision of your score by resizing objects to a reasonable size. 0 0 0 0 0 OBJECTS SIZE ACCORDING TO ZOOM Qt::AlignCenter 10 0 0 BASIC SIZE Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter followId Rescales objects size according to zoom 100 Qt::Horizontal 0 0 FIXED SIZE followId :/general/res_icon_inspector_osc.png:/general/res_icon_inspector_osc.png CONFIG 6 6 20 6 6 QTabBar::tab { min-height: 20px; } 0 MESSAGE LOG 5 5 5 5 5 NETWORK 0 10 5 10 5 My IP: 0 20 background-color: transparent; border: 0px solid transparent; margin: 0px; padding: 0px; QPlainTextEdit::NoWrap true 5 Qt::Vertical 20 40 MIDI 10 10 10 10 10 20 Qt::Vertical 20 247 ARDUINO 10 10 10 10 10 20 Qt::Vertical 20 339 SOFTWARE 10 10 10 10 10 20 Qt::Vertical 20 339 0 150 20 150 20 Current mouse position on score MOUSE: 0.000 s. / 0.000 s. 150 20 150 20 Current score zoom font: 10px; ANGLES: 0.000° / 0.000° 85 20 Current score zoom ZOOM: 100% UiTreeView QWidget
    items/uitreeview.h
    1
    tab newIdButton groupIdButton sizeSpin labelLine activityCheck colorCombo1 colorCombo2 ccView unmuteObjects unsoloObjects unmuteGroups unsoloGroups followId tab currentChanged(int) UiInspector actionTabChange(int) 241 42 221 0 groupIdButton released() UiInspector actionInfoGroup() 337 149 0 33 activityCheck stateChanged(int) UiInspector actionInfo() 215 182 0 186 labelLine textChanged(QString) UiInspector actionInfo() 331 252 0 391 ccView currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*) UiInspector actionCC() 93 56 0 230 labelLine returnPressed() UiInspector actionInfo() 331 252 375 156 colorCombo1 currentIndexChanged(QString) UiInspector actionColor() 334 280 375 122 colorCombo2 currentIndexChanged(QString) UiInspector actionColor() 334 309 0 322 sizeSpin valueChanged(double) UiInspector actionInfo() 211 217 375 43 ccView itemClicked(QTreeWidgetItem*,int) UiInspector actionCC(QTreeWidgetItem*,int) 93 56 0 187 newIdButton released() UiInspector actionInfoID() 260 112 375 109 unmuteObjects released() UiInspector actionCCButton() 62 321 55 505 unsoloObjects released() UiInspector actionCCButton() 382 321 199 505 unsoloGroups released() UiInspector actionCCButton() 382 350 282 505 unmuteGroups released() UiInspector actionCCButton() 62 350 78 0 followId valueChanged(int) UiInspector actionCCButton() 245 467 34 0 positionX valueChanged(double) UiInspector actionInfo() 111 130 390 178 positionY valueChanged(double) UiInspector actionInfo() 130 130 390 135 positionZ valueChanged(double) UiInspector actionInfo() 150 130 390 80 sizeWSpin valueChanged(double) UiInspector actionInfo() 117 133 390 206 sizeHSpin valueChanged(double) UiInspector actionInfo() 143 133 390 170 widthSpin valueChanged(double) UiInspector actionInfo() 117 138 390 279 depthSpin valueChanged(double) UiInspector actionInfo() 143 138 390 266 triggerOffSpin valueChanged(double) UiInspector actionInfo() 140 121 390 126 cursorLengthSpin valueChanged(double) UiInspector actionInfo() 128 132 390 101 speedSpin valueChanged(double) UiInspector actionInfo() 97 132 390 377 speedFSpin valueChanged(QString) UiInspector actionInfo() 140 134 390 462 patternLine currentIndexChanged(int) UiInspector actionInfo() 260 128 390 455 patternLine editTextChanged(QString) UiInspector actionInfo() 260 128 390 411 easingCombo currentIndexChanged(int) UiInspector actionInfo() 260 130 390 446 offsetInitialSpin valueChanged(double) UiInspector actionInfo() 137 143 390 476 offsetStartSpin valueChanged(double) UiInspector actionInfo() 135 143 390 468 offsetEndSpin valueChanged(QString) UiInspector actionInfo() 150 143 390 436 messagesButton released() UiInspector actionMessages() 140 112 390 80 messagesSpin valueChanged(double) UiInspector actionInfo() 240 130 390 335 cursorSourceX1 valueChanged(double) UiInspector actionInfo() 102 128 390 139 cursorSourceX2 valueChanged(double) UiInspector actionInfo() 139 128 390 48 cursorTargetX1 valueChanged(double) UiInspector actionInfo() 102 126 390 318 cursorTargetX2 valueChanged(double) UiInspector actionInfo() 139 126 390 152 cursorSourceY2 valueChanged(double) UiInspector actionInfo() 102 127 390 362 cursorSourceY1 valueChanged(double) UiInspector actionInfo() 139 127 390 202 cursorTargetY2 valueChanged(double) UiInspector actionInfo() 102 125 390 440 cursorTargetY1 valueChanged(double) UiInspector actionInfo() 139 125 390 242 cursorSourceZ1 valueChanged(double) UiInspector actionInfo() 102 127 390 490 cursorSourceZ2 valueChanged(double) UiInspector actionInfo() 139 127 390 427 cursorTargetZ1 valueChanged(double) UiInspector actionInfo() 102 127 390 407 cursorTargetZ2 valueChanged(double) UiInspector actionInfo() 139 127 390 444 cursorSpeedLock released() UiInspector actionInfo() 89 130 390 58 equationEdit textChanged() UiInspector actionInfo() 99 142 602 407 pointsLists released() UiInspector actionInfo() 176 132 553 164 equationPoints valueChanged(int) UiInspector actionInfo() 261 143 560 203 textureCombo1 currentIndexChanged(int) UiInspector actionTexture() 334 367 493 296 textureCombo2 currentIndexChanged(int) UiInspector actionTexture() 334 396 503 330 equationType0 released() UiInspector actionInfo() 85 133 497 233 equationType1 released() UiInspector actionInfo() 85 137 499 223 cursorSourceMode0 released() UiInspector actionInfo() 98 117 488 151 cursorSourceMode1 released() UiInspector actionInfo() 98 118 488 103 cursorSourceMode2 released() UiInspector actionInfo() 98 119 519 127 cursorSourceMode3 released() UiInspector actionInfo() 98 120 512 50 ssTabConfig currentChanged(int) UiInspector actionTabChange(int) 97 61 537 115 followIdClear released() UiInspector actionCCButton() 271 460 693 322 autoresizeSlider valueChanged(int) UiInspector actionCCButton() 185 521 520 436 equationTemplate currentIndexChanged(int) UiInspector actionInfo() 261 135 702 233 colorComboMultiply currentIndexChanged(QString) UiInspector actionColor() 334 338 698 201 colorCombo1 editTextChanged(QString) UiInspector actionColor() 334 280 656 104 colorCombo2 editTextChanged(QString) UiInspector actionColor() 334 309 773 158 colorComboMultiply editTextChanged(QString) UiInspector actionColor() 334 338 815 105 pointsResample released() UiInspector actionInfo() 150 132 677 195 equationParam1Slider valueChanged(int) UiInspector actionInfo() 176 119 1157 275 equationParam2Slider valueChanged(int) UiInspector actionInfo() 176 128 1160 326 equationParam3Slider valueChanged(int) UiInspector actionInfo() 176 137 1125 307 equationParam4Slider valueChanged(int) UiInspector actionInfo() 176 146 1147 241 equationParam5Slider valueChanged(int) UiInspector actionInfo() 176 155 1112 248 equationParam1Value valueChanged(double) UiInspector actionInfo() 142 131 859 297 equationParam2Value valueChanged(double) UiInspector actionInfo() 142 140 825 34 equationParam3Value valueChanged(double) UiInspector actionInfo() 142 149 755 65 equationParam4Value valueChanged(double) UiInspector actionInfo() 142 158 665 46 equationParam5Value valueChanged(double) UiInspector actionInfo() 142 167 624 513 equationParamReset released() UiInspector actionInfo() 99 182 551 400 intertiaSpin valueChanged(double) UiInspector actionInfo() 130 135 794 132 fireTriggers currentIndexChanged(int) UiInspector actionInfo() 260 131 504 286 fireTriggers editTextChanged(QString) UiInspector actionInfo() 260 131 560 269 actionTabChange(int) actionViewChange() actionCC() actionInfo() actionInfoGroup() actionMessages() actionGtext(QPoint) actionNetwork() actionColor() actionInfoID() actionCCButton() actionCC(QTreeWidgetItem*,int) actionTexture()
    IanniX-0.9.20/gui/uimessagebox.cpp000066400000000000000000000144071317340345000167610ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #include "uimessagebox.h" #include "ui_uimessagebox.h" #include "misc/application.h" UiMessageBox::UiMessageBox(QWidget *parent) : QDialog(parent, Qt::Tool), ui(new Ui::UiMessageBox) { ui->setupUi(this); setStyleSheet(Application::current->getMainWindow()->styleSheet()); } UiMessageBox::~UiMessageBox() { delete ui; } QPair UiMessageBox::getCheckboxes() { return qMakePair(ui->checkSmooth->isChecked(), ui->checkTrigger->isChecked()); } qreal UiMessageBox::getDouble(const QString &title, const QString &description, qreal value, qreal min, qreal max, qreal step, quint16 decimals, const QString &suffix, bool *ok) { setUpdatesEnabled(false); ui->choices->setCurrentIndex(0); ui->spinLabel->setText(description); setWindowTitle(title); ui->spinSpin->setMinimum(min); ui->spinSpin->setMaximum(max); ui->spinSpin->setDecimals(decimals); ui->spinSpin->setSingleStep(step); ui->spinSpin->setValue(value); ui->spinSpin->setSuffix(" " + suffix); ui->spinSpin->setFocus(); setUpdatesEnabled(true); show(); QRect screen = QApplication::desktop()->screenGeometry(); move(screen.center() - QPoint(200, 100)); exec(); if(ok) { if(result()) *ok = true; else *ok = false; } qreal ret = ui->spinSpin->value(); delete this; return ret; } qreal UiMessageBox::getDouble(const QString &title, const QString &description, const QPixmap &pixmap, qreal value, qreal min, qreal max, qreal step, quint16 decimals, const QString &suffix, bool resample, bool *ok) { setUpdatesEnabled(false); ui->choices->setCurrentIndex(1); ui->checkSmooth->setVisible(resample); ui->checkTrigger->setVisible(resample); ui->spinpLabel->setText(description); setWindowTitle(title); ui->spinpSpin->setMinimum(min); ui->spinpSpin->setMaximum(max); ui->spinpSpin->setDecimals(decimals); ui->spinpSpin->setSingleStep(step); ui->spinpSpin->setValue(value); ui->spinpPicture->resize(pixmap.size()/2); ui->spinpPicture->setMinimumSize(pixmap.size()/2); ui->spinpPicture->setPixmap(pixmap); ui->spinpPicture->setScaledContents(true); ui->spinpSpin->setSuffix(" " + suffix); ui->spinpSpin->setFocus(); setUpdatesEnabled(true); updateGeometry(); QRect screen = QApplication::desktop()->screenGeometry(); move(screen.center() - QPoint(200, 100)); exec(); if(ok) { if(result()) *ok = true; else *ok = false; } qreal ret = ui->spinpSpin->value(); if(!resample) delete this; return ret; } int UiMessageBox::display(const QString &title, const QString &description, QDialogButtonBox::StandardButtons buttons, bool *ok) { setUpdatesEnabled(false); ui->choices->setCurrentIndex(2); ui->messageLabel->setText(description); ui->messageButtons->setStandardButtons(buttons); setWindowTitle(title); setUpdatesEnabled(true); updateGeometry(); QRect screen = QApplication::desktop()->screenGeometry(); move(screen.center() - QPoint(200, 100)); exec(); if(ok) { if(result()) *ok = true; else *ok = false; } int ret = result(); delete this; return ret; } void UiMessageBox::display(const QString &title, const QString &description) { setUpdatesEnabled(false); ui->choices->setCurrentIndex(2); ui->messageLabel->setText(description); ui->messageButtons->setStandardButtons(QDialogButtonBox::Ok); setWindowTitle(title); setUpdatesEnabled(true); updateGeometry(); QRect screen = QApplication::desktop()->screenGeometry(); move(screen.center() - QPoint(200, 100)); show(); raise(); } QString UiMessageBox::getText(const QString &title, const QString &description, const QString &value, bool *ok) { setUpdatesEnabled(false); ui->choices->setCurrentIndex(3); ui->textLabel->setText(description); setWindowTitle(title); ui->textEdit->setText(value); setUpdatesEnabled(true); updateGeometry(); QRect screen = QApplication::desktop()->screenGeometry(); move(screen.center() - QPoint(200, 100)); exec(); if(ok) { if(result()) *ok = true; else *ok = false; } QString ret = ui->textEdit->text(); delete this; return ret; } int UiMessageBox::display(const QString &title, const QString &description1, const QString &description2, const QString &description3, const QPixmap &pixmap, QDialogButtonBox::StandardButtons buttons, bool *ok) { setUpdatesEnabled(false); ui->choices->setCurrentIndex(4); ui->updateLabel->setText(description1); ui->updatePlain->setMinimumSize(0, 200); ui->updatePlain->setPlainText(description2); ui->updateLabel2->setText(description3); ui->updatePicture->setMinimumSize(pixmap.size()/2); ui->updatePicture->resize(pixmap.size()/2); ui->updatePicture->setPixmap(pixmap); ui->updatePicture->setScaledContents(true); ui->messageButtons->setStandardButtons(buttons); setWindowTitle(title); setUpdatesEnabled(true); updateGeometry(); QRect screen = QApplication::desktop()->screenGeometry(); move(screen.center() - QPoint(200, 300)); exec(); if(ok) { if(result()) *ok = true; else *ok = false; } int ret = result(); delete this; return ret; } IanniX-0.9.20/gui/uimessagebox.h000066400000000000000000000043651317340345000164300ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #ifndef UIMESSAGEBOX_H #define UIMESSAGEBOX_H #include #include #include #include namespace Ui { class UiMessageBox; } class UiMessageBox : public QDialog { Q_OBJECT public: explicit UiMessageBox(QWidget *parent = 0); ~UiMessageBox(); public: QPair getCheckboxes(); public: qreal getDouble(const QString &title, const QString &description, qreal value, qreal min, qreal max, qreal step, quint16 decimals, const QString &suffix, bool *ok = 0); qreal getDouble(const QString &title, const QString &description, const QPixmap &pixmap, qreal value, qreal min, qreal max, qreal step, quint16 decimals, const QString &suffix, bool resample, bool *ok = 0); QString getText(const QString &title, const QString &description, const QString &value, bool *ok = 0); int display(const QString &title, const QString &description1, const QString &description2, const QString &description3, const QPixmap &pixmap, QDialogButtonBox::StandardButtons buttons, bool *ok = 0); int display(const QString &title, const QString &description, QDialogButtonBox::StandardButtons buttons, bool *ok = 0); void display(const QString &title, const QString &description); private: Ui::UiMessageBox *ui; }; #endif // UIMESSAGEBOX_H IanniX-0.9.20/gui/uimessagebox.ui000066400000000000000000000326031317340345000166120ustar00rootroot00000000000000 UiMessageBox 0 0 339 204 IanniX true 12 12 12 12 12 1 15 0 0 0 0 Qt::Horizontal 40 20 ENTER A VALUE FOR Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 0 30 16777215 24 Qt::AlignCenter Qt::Horizontal 40 20 5 0 0 0 0 Qt::Horizontal 0 0 PICTURE true Qt::AlignCenter Qt::Horizontal 0 0 15 Qt::Horizontal 40 20 ENTER A VALUE FOR spinpSpin 0 30 16777215 24 Qt::AlignCenter Qt::Horizontal 40 20 Make a smooth curve true Generate triggers instead of resampling curve 0 0 0 0 0 ENTER A VALUE FOR Qt::AlignCenter 15 0 0 0 0 Qt::Horizontal 40 20 ENTER A VALUE FOR Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter textEdit 100 30 16777215 24 Qt::AlignCenter Qt::Horizontal 40 20 5 0 0 0 0 Qt::Horizontal 40 20 PICTURE Qt::Horizontal 40 20 Title of popup updatePlain Qt::NoFocus true Question QDialogButtonBox::Cancel|QDialogButtonBox::Ok spinSpin spinpSpin textEdit updatePlain messageButtons messageButtons accepted() UiMessageBox accept() 159 104 -7 279 messageButtons rejected() UiMessageBox reject() 90 110 23 253 IanniX-0.9.20/gui/uisplashscreen.cpp000066400000000000000000000042301317340345000173070ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #include "uisplashscreen.h" UiSplashScreen::UiSplashScreen(const QPixmap &_pixmap) : QFrame(0, Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint) { pixmap = _pixmap; setAttribute(Qt::WA_TranslucentBackground); setFixedSize(pixmap.size()/2); QRect screen = QApplication::desktop()->screenGeometry(); move(screen.center() - rect().center()); QFont textFont("Arial"); textFont.setPixelSize(13); showMessage(tr("version") + " " + QString(QCoreApplication::applicationVersion()) + " " + tr("beta"), textFont, Qt::AlignCenter, QColor(255, 255, 255, 150)); show(); QCoreApplication::processEvents(); } void UiSplashScreen::showMessage(const QString& _message, const QFont &_font, int _messageAlignement, const QColor& _messageColor) { message = _message; messageAlignment = _messageAlignement; messageColor = _messageColor; messageFont = _font; repaint(); } void UiSplashScreen::paintEvent(QPaintEvent*) { QRect textRect(QRect(QPoint(115, 435), QSize(285, 70))); QPainter painter(this); painter.drawPixmap(rect(), pixmap); painter.setPen(messageColor); painter.setFont(messageFont); painter.drawText(textRect, messageAlignment, message); } IanniX-0.9.20/gui/uisplashscreen.h000066400000000000000000000031411317340345000167540ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #ifndef UISPLASHSCREEN_H #define UISPLASHSCREEN_H #include #include #include #include #include class UiSplashScreen : public QFrame { Q_OBJECT public: explicit UiSplashScreen(const QPixmap&); public: void showMessage(const QString& _message, const QFont &_font, int _messageAlignment = Qt::AlignCenter, const QColor& _messageColor = Qt::white); private: void paintEvent(QPaintEvent* e); QPixmap pixmap; QString message; int messageAlignment; QColor messageColor; QFont messageFont; signals: public slots: }; #endif // UISPLASHSCREEN_H IanniX-0.9.20/gui/uiview.cpp000066400000000000000000000717441317340345000156050ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #include "uiview.h" #include "ui_uiview.h" UiView::UiView(QWidget *parent) : QMainWindow(parent), ui(new Ui::UiView) { ui->setupUi(this); isFullScreen = false; freehandCurveId = freehandCurveIndex = 0; Help::syncHelpWith(ui->actionImport_Text, COMMAND_CURVE_TXT); Help::syncHelpWith(ui->actionImport_SVG, COMMAND_CURVE_PATH); #ifndef Q_OS_MAC ui->actionDelete->setShortcut(QApplication::trUtf8("UiView", "Delete")); #endif //About about = new UiAbout(); //Helper help = new UiHelp(); connect(&help->visibility, SIGNAL(triggered(bool)), SLOT(showHelp())); connect(ui->statusBar, SIGNAL(messageChanged(QString)), help, SLOT(statusHelp(QString))); ui->statusBar->setVisible(false); help->visibility.setAction(ui->actionShowHelp, "showHelp"); ui->render->defaultStatusTip = ui->render->statusTip(); ui->render->curveStatusTip = ui->actionDrawFreeCurve->statusTip().remove(tr("\nPress ESC or click again on the toolbar button to stop edition.")); ui->render->cursorStatusTip = ui->actionAddFreeCursor->statusTip().remove(tr("\nPress ESC or click again on the toolbar button to stop edition.")); ui->render->triggerStatusTip = ui->actionDrawTriggers ->statusTip().remove(tr("\nPress ESC or click again on the toolbar button to stop edition.")); QRect screen = QApplication::desktop()->screenGeometry(); move(screen.center() - rect().center()); connect(ui->render, SIGNAL(editingMove(NxPoint,bool,bool)), SLOT(editingMove(NxPoint,bool,bool))); connect(ui->render, SIGNAL(editingStart(NxPoint)), SLOT(editingStart(NxPoint))); connect(ui->render, SIGNAL(editingStop()), SLOT(editingStop())); connect(ui->actionNew, SIGNAL(triggered()), ui->render, SLOT(actionNew())); connect(ui->actionClose_score, SIGNAL(triggered()), ui->render, SLOT(actionNew())); connect(ui->actionOpen, SIGNAL(triggered()), ui->render, SLOT(actionOpen())); connect(ui->actionSave, SIGNAL(triggered()), ui->render, SLOT(actionSave())); connect(ui->actionSave_score_as, SIGNAL(triggered()), ui->render, SLOT(actionSave_as())); connect(ui->actionImport_SVG, SIGNAL(triggered()), SLOT(actionImportSVG())); connect(ui->actionImport_Background, SIGNAL(triggered()), SLOT(actionImportBackground())); connect(ui->actionImport_Text, SIGNAL(triggered()), SLOT(actionImportText())); connect(ui->actionRedo, SIGNAL(triggered()), ui->render, SLOT(actionRedo())); connect(ui->actionUndo, SIGNAL(triggered()), ui->render, SLOT(actionUndo())); connect(ui->actionCopy, SIGNAL(triggered()), ui->render, SLOT(actionCopy())); connect(ui->actionPaste, SIGNAL(triggered()), ui->render, SLOT(actionPaste())); connect(ui->actionDuplicate, SIGNAL(triggered()), ui->render, SLOT(actionDuplicate())); connect(ui->actionCut, SIGNAL(triggered()), ui->render, SLOT(actionCut())); connect(ui->actionSelect_all, SIGNAL(triggered()), ui->render, SLOT(actionSelect_all())); connect(ui->actionDelete, SIGNAL(triggered()), ui->render, SLOT(actionDelete())); connect(ui->actionResize, SIGNAL(triggered()), SLOT(actionResize())); connect(ui->actionSnapshot, SIGNAL(triggered()), SLOT(actionSnapshot())); connect(ui->actionZoom_in, SIGNAL(triggered()), ui->render, SLOT(zoomIn())); connect(ui->actionZoom_out, SIGNAL(triggered()), ui->render, SLOT(zoomOut())); connect(ui->actionZoom_initial, SIGNAL(triggered()), ui->render, SLOT(zoomInitial())); connect(ui->actionAbout, SIGNAL(triggered()), about, SLOT(show())); connect(ui->actionPreferences, SIGNAL(triggered()), ui->inspector, SLOT(showConfigTab())); connect(ui->actionQuit, SIGNAL(triggered()), SLOT(close())); connect(ui->actionToggle_Inspector, SIGNAL(triggered()), SLOT(showInspector())); connect(ui->actionToggle_Transport, SIGNAL(triggered()), SLOT(showTransport())); connect(ui->actionPatchesFolder, SIGNAL(triggered()), SLOT(actionPatchesFolder())); connect(ui->actionLockPos, SIGNAL(triggered()), SLOT(editingStop())); Application::colorTheme .setAction(ui->actionLight, "guiColorTheme"); Application::paintAxisGrid .setAction(ui->actionGrid, "guiPaintAxisGrid"); Application::paintLabel .setAction(ui->actionToggleLabel, "guiPaintLabel"); Application::mouseSnapX .setAction(ui->actionSnapXGrid); Application::mouseSnapY .setAction(ui->actionSnapYGrid); Application::allowLockPos .setAction(ui->actionLockPos, "guiAllowLockPos"); Application::allowSelectionCursors .setAction(ui->actionAllow_cursors_selection, "guiAllowSelectionCursors"); Application::allowSelectionCurves .setAction(ui->actionAllow_curves_selection, "guiAllowSelectionCurves"); Application::allowSelectionTriggers.setAction(ui->actionAllow_triggers_selection, "guiAllowSelectionTriggers"); Application::allowPlaySelected .setAction(ui->actionPlaySelected, "guiAllowPlaySelected"); connect(ui->actionFullscreen, SIGNAL(triggered()), SLOT(goToFullscreen())); connect(ui->actionPerformance, SIGNAL(triggered()), SLOT(actionPerformance())); connect(ui->actionPlay_pause, SIGNAL(triggered()), SLOT(actionPlay_pause())); connect(ui->actionFast_rewind, SIGNAL(triggered()), SLOT(actionFast_rewind())); connect(ui->actionDrawFreeCurve, SIGNAL(triggered()), SLOT(actionDrawFreeCurve())); connect(ui->actionDrawPointCurve, SIGNAL(triggered()), SLOT(actionDrawPointCurve())); connect(ui->actionDrawFreeCurveSimple, SIGNAL(triggered()), SLOT(actionDrawFreeCurveSimple())); connect(ui->actionDrawPointCurveSimple, SIGNAL(triggered()), SLOT(actionDrawPointCurveSimple())); connect(ui->actionDrawTriggers, SIGNAL(triggered()), SLOT(actionDrawTriggers())); connect(ui->actionAddFreeCursor, SIGNAL(triggered()), SLOT(actionAddFreeCursor())); connect(ui->actionAddCircleCurve, SIGNAL(triggered()), SLOT(actionCircleCurve())); connect(ui->actionAddMathCurve, SIGNAL(triggered()), SLOT(actionAddMathCurve())); connect(ui->actionAddMathCurveSimple, SIGNAL(triggered()), SLOT(actionAddMathCurveSimple())); connect(ui->actionAddTimeline, SIGNAL(triggered()), SLOT(actionAddTimeline())); connect(ui->actionShowEditor, SIGNAL(triggered()), SLOT(showEditor())); connect(ui->actionShowTimer, SIGNAL(triggered()), SLOT(showTimer())); connect(ui->actionReloadScript, SIGNAL(triggered()), SLOT(actionReloadScript())); connect(ui->action10Seconds, SIGNAL(triggered()), SLOT(gridChange())); connect(ui->action1second, SIGNAL(triggered()), SLOT(gridChange())); connect(ui->action500Milliseconds, SIGNAL(triggered()), SLOT(gridChange())); connect(ui->action100Milliseconds, SIGNAL(triggered()), SLOT(gridChange())); connect(ui->action10Milliseconds, SIGNAL(triggered()), SLOT(gridChange())); connect(ui->actionCustomValue, SIGNAL(triggered()), SLOT(gridChange())); connect(ui->actionAlign_bottom, SIGNAL(triggered()), SLOT(actionAlign_bottom())); connect(ui->actionAlign_center, SIGNAL(triggered()), SLOT(actionAlign_center())); connect(ui->actionAlign_left, SIGNAL(triggered()), SLOT(actionAlign_left())); connect(ui->actionAlign_middle, SIGNAL(triggered()), SLOT(actionAlign_middle())); connect(ui->actionAlign_right, SIGNAL(triggered()), SLOT(actionAlign_right())); connect(ui->actionAlign_top, SIGNAL(triggered()), SLOT(actionAlign_top())); connect(ui->actionDistributeH, SIGNAL(triggered()), SLOT(actionDistributeH())); connect(ui->actionDistributeV, SIGNAL(triggered()), SLOT(actionDistributeV())); connect(ui->actionAlign_circle, SIGNAL(triggered()), SLOT(actionAlign_circle())); connect(ui->actionAlign_ellipse, SIGNAL(triggered()), SLOT(actionAlign_ellipse())); delete ui->renderPreview; ui->renderPreview = 0; ui->renderPreview = new UiRenderPreview(ui->pagePerf, ui->render); ui->pagePerf->layout()->addWidget(ui->renderPreview); fullscreenDisplays = QApplication::desktop(); connect(fullscreenDisplays, SIGNAL(screenCountChanged(int)), SLOT(fullscreenDisplaysCountChanged())); fullscreenDisplaysCountChanged(); //delete ui->actionPerformance; ui->render->setFocus(); } UiView::~UiView() { delete ui; } void UiView::toggleFullscreen(bool val) { ui->actionFullscreen->setChecked(val); } void UiView::changeEvent(QEvent *e) { QMainWindow::changeEvent(e); switch (e->type()) { case QEvent::LanguageChange: ui->retranslateUi(this); break; default: break; } } UiRender* UiView::getRender() const { return ui->render; } Transport* UiView::getTransport() const { return ui->transport; } UiInspector* UiView::getInspector() const { return ui->inspector; } UiRenderPreview* UiView::getRenderPreview() const { return ui->renderPreview; } bool UiView::getPerformancePreview() const { return ui->performancePreview->isChecked(); } void UiView::keyPressEvent(QKeyEvent *event) { ui->render->keyPressEvent(event); } void UiView::closeEvent(QCloseEvent *event) { emit(actionRouteCloseEvent(event)); if(about) about->close(); if(help) help->close(); } void UiView::fullscreenDisplaysCountChanged() { foreach(QPushButton *fullscreenButton, fullscreenButtons) delete fullscreenButton; fullscreenButtons.clear(); for(quint8 fullscreenDisplayIndex = 0 ; fullscreenDisplayIndex < fullscreenDisplays->screenCount() ; fullscreenDisplayIndex++) { QPushButton *fullscreenButton = new QPushButton(tr("DISPLAY %1 (%2 x %3)").arg(fullscreenDisplayIndex+1).arg(fullscreenDisplays->screenGeometry(fullscreenDisplayIndex).width()).arg(fullscreenDisplays->screenGeometry(fullscreenDisplayIndex).height()), ui->pagePerf); fullscreenButton->setToolTip(tr("Moves the render window on this video output and switches to fullscreen")); ui->performanceLayout->addWidget(fullscreenButton); connect(fullscreenButton, SIGNAL(released()), SLOT(fullscreenDisplaysSelected())); fullscreenButtons.append(fullscreenButton); } } void UiView::fullscreenDisplaysSelected() { qint8 index = fullscreenButtons.indexOf((QPushButton*)sender()); if(index >= 0) goToFullscreen(index); } void UiView::goToFullscreen() { if(ui->render->parent()) goToFullscreen(fullscreenDisplays->screenNumber(pos())); else goToFullscreen(fullscreenDisplays->screenNumber(ui->render->pos())); } void UiView::goToFullscreen(quint8 screenIndex) { if(ui->render->parent()) { if(isFullScreen) { setWindowState(windowState() & ~Qt::WindowFullScreen); ui->render->setCursor(Qt::ArrowCursor); ui->toolBarAdd->setVisible(true); ui->toolBarView->setVisible(true); ui->toolBarWindow->setVisible(true); ui->inspector->parentWidget()->setVisible(wasInspectorVisible); ui->transport->parentWidget()->setVisible(wasTransportVisible); ui->menubar->setVisible(true); isFullScreen = false; toggleFullscreen(isFullScreen); } else { setWindowState(windowState() | Qt::WindowFullScreen); ui->render->setCursor(Qt::BlankCursor); ui->toolBarAdd->setVisible(false); ui->toolBarView->setVisible(false); ui->toolBarWindow->setVisible(false); wasInspectorVisible = ui->inspecteurDock->isVisible(); wasTransportVisible = ui->transportDock->isVisible(); ui->menubar->setVisible(false); ui->inspector->parentWidget()->hide(); ui->transport->parentWidget()->hide(); isFullScreen = true; toggleFullscreen(isFullScreen); } //activateWindow(); } else { ui->render->hide(); if(isFullScreen) { ui->render->setWindowState(windowState() & ~Qt::WindowFullScreen); ui->render->move(previousPos); ui->render->setCursor(Qt::ArrowCursor); isFullScreen = false; toggleFullscreen(isFullScreen); } else { previousPos = ui->render->pos(); //previousSize = ui->render->size(); ui->render->move(fullscreenDisplays->screenGeometry(screenIndex).topLeft()); ui->render->setWindowState(windowState() | Qt::WindowFullScreen); ui->render->setCursor(Qt::BlankCursor); isFullScreen = true; toggleFullscreen(isFullScreen); } ui->render->show(); //ui->render->activateWindow(); } ui->render->selectionClear(true); } void UiView::escFullscreen() { if(isFullScreen) goToFullscreen(); } void UiView::actionPlay_pause() { if(Transport::timerOk) Application::current->execute(QString("%1").arg(COMMAND_STOP), ExecuteSourceGui); else Application::current->execute(QString("%1").arg(COMMAND_PLAY), ExecuteSourceGui); } void UiView::actionFast_rewind() { Application::current->execute(QString("%1").arg(COMMAND_FF), ExecuteSourceGui); } void UiView::actionPerformance() { if(ui->actionPerformance->isChecked()) { fullscreenDisplaysCountChanged(); ui->render->setPerformanceMode(true); ui->stackedWidget->setCurrentIndex(1); } else { ui->render->setPerformanceMode(false); ui->stackedWidget->widget(0)->layout()->addWidget(ui->render); ui->stackedWidget->setCurrentIndex(0); } } void UiView::actionImportSVG() { QString fileName = QFileDialog::getOpenFileName(0, tr("Select a SVG file…"), QDir::currentPath(), tr("SVG Files") + " (*.svg)"); if(!fileName.isEmpty()) emit(actionRouteImportSVG(fileName)); } void UiView::actionImportBackground() { QString fileName = QFileDialog::getOpenFileName(0, tr("Select an image…"), QDir::currentPath(), tr("Images") + " (*.png *.jpg *.jpeg)"); if(!fileName.isEmpty()) emit(actionRouteImportBackground(fileName)); } void UiView::actionImportText() { QString font = ""; QString text = (new UiMessageBox())->getText(tr("Text Import"), tr("Type a character or some text to import in IanniX:"), ""); if(!text.isEmpty()) emit(actionRouteImportText(font, text)); } void UiView::actionSnapshot() { bool ok = false; qreal scaleFactor = (new UiMessageBox())->getDouble(tr("Score Snapshot"), tr("Snapshot will be saved on your desktop.\nPlease enter a scale factor:"), QPixmap(":/infos/res_info_export.png"), 4, 0.1, 30, 0.25, 2, "times current screen size", false, &ok); if(ok) ui->render->capture(scaleFactor); } void UiView::showTimer() { ui->transport->bigTimer->toolbarButton = ui->actionShowTimer; if(ui->transport->bigTimer->isVisible()) ui->transport->bigTimer->close(); else ui->transport->bigTimer->show(); } void UiView::showHelp() { if(help->visibility) { if(help->pos() == QPoint(0, 0)) help->move(QPoint(qMax(0, geometry().left() - help->width()), geometry().center().y() - help->height())); UiHelp::statusHelp(ui->render); help->show(); } else help->close(); } void UiView::showEditor() { ui->transport->editor->toolbarButton = ui->actionShowEditor; if(ui->transport->editor->isVisible()) ui->transport->editor->close(); else ui->transport->editor->show(); } void UiView::showTransport() { ui->transport->toolbarButton = ui->actionToggle_Transport; if(ui->transport->isVisible()) ui->transport->parentWidget()->close(); else ui->transport->parentWidget()->show(); } void UiView::showInspector() { ui->inspector->toolbarButton = ui->actionToggle_Inspector; if(ui->inspector->isVisible()) ui->inspector->parentWidget()->close(); else ui->inspector->parentWidget()->show(); } void UiView::unToogleDraw(quint16 id) { if(id == 1) { ui->actionDrawFreeCurve->setChecked(false); ui->actionDrawFreeCurveSimple->setChecked(false); } else if(id == 2) { ui->actionDrawPointCurve->setChecked(false); ui->actionDrawPointCurveSimple->setChecked(false); } else if(id == 3) { ui->actionDrawTriggers->setChecked(false); } else if(id == 4) { ui->actionAddCircleCurve->setChecked(false); } else { ui->actionDrawTriggers->setChecked(false); ui->actionDrawFreeCurve->setChecked(false); ui->actionDrawFreeCurveSimple->setChecked(false); ui->actionDrawPointCurve->setChecked(false); ui->actionDrawPointCurveSimple->setChecked(false); ui->actionAddCircleCurve->setChecked(false); } } void UiView::gridChange() { QAction *action = (QAction*)sender(); bool ok = true; if(action == ui->action10Seconds) Render::axisGrid = 10; else if(action == ui->action1second) Render::axisGrid = 1; else if(action == ui->action500Milliseconds) Render::axisGrid = 0.5; else if(action == ui->action100Milliseconds) Render::axisGrid = 0.1; else if(action == ui->action10Milliseconds) Render::axisGrid = 0.01; else if(action == ui->actionCustomValue) { qreal val = (new UiMessageBox())->getDouble(tr("Custom grid value"), tr("Enter the desired grid time value in seconds:"), 0.500, 0.001, 999, 0.1, 3, "seconds", &ok); if(ok) { ui->actionCustomValue->setText(tr("Custom value:") + QString(" %1 ").arg(val) + tr("sec")); Render::axisGrid = val; } } if(ok) { ui->action10Seconds->setChecked(false); ui->action1second->setChecked(false); ui->action500Milliseconds->setChecked(false); ui->action100Milliseconds->setChecked(false); ui->action10Milliseconds->setChecked(false); ui->actionCustomValue->setChecked(false); action->setChecked(true); } } void UiView::actionResize() { QSize currentSize = ui->render->size(); QStringList newSizes = (new UiMessageBox())->getText(tr("Viewport Resize"), tr("New viewport size:"), tr("%1 x %2").arg(currentSize.width()).arg(currentSize.height())).split("x", QString::SkipEmptyParts); if(newSizes.count() == 2) { QSize newSize(newSizes.at(0).toUInt(), newSizes.at(1).toUInt()); if((newSize.width() > 0) && (newSize.height() > 0)) actionResize(newSize); } } void UiView::actionResize(QSize newSize) { resize(size() + newSize - ui->render->size()); } void UiView::actionDrawFreeCurve(bool cursor) { if((Render::editingMode == EditingModeFree) && (Render::editing)) editingStop(); else { freehandCurveId = freehandCurveIndex = 0; freehandCurveNeedsCursor = cursor; unToogleDraw(2); unToogleDraw(3); unToogleDraw(4); ui->render->setEditingMode(EditingModeFree); } } void UiView::actionDrawPointCurve(bool cursor) { if((Render::editingMode == EditingModePoint) && (Render::editing)) editingStop(); else { freehandCurveId = freehandCurveIndex = 0; freehandCurveNeedsCursor = cursor; unToogleDraw(1); unToogleDraw(3); unToogleDraw(4); ui->render->setEditingMode(EditingModePoint); } } void UiView::actionDrawTriggers() { if((Render::editingMode == EditingModeTriggers) && (Render::editing)) editingStop(); else { unToogleDraw(1); unToogleDraw(2); unToogleDraw(4); ui->render->setEditingMode(EditingModeTriggers); } } void UiView::actionAddTimeline() { unToogleDraw(1); unToogleDraw(2); unToogleDraw(3); unToogleDraw(4); ui->render->selectionClear(true); quint16 id1 = Application::current->execute("add curve auto", ExecuteSourceGui).toUInt(); Application::current->execute("setpointat " + QString::number(id1) + " 0 -5 0", ExecuteSourceGui); Application::current->execute("setpointat " + QString::number(id1) + " 1 5 0", ExecuteSourceGui); quint16 id2 = Application::current->execute("add cursor auto", ExecuteSourceGui).toUInt(); Application::current->execute("setwidth " + QString::number(id2) + " 5", ExecuteSourceGui); Application::current->execute("setcurve " + QString::number(id2) + " lastCurve", ExecuteSourceGui); Application::current->execute("setboundssourcemode " + QString::number(id2) + " 1", ExecuteSourceGui); Application::current->execute("setmessage " + QString::number(id2) + " 20, " + Application::defaultMessageCurve, ExecuteSourceGui); ui->render->selectionAdd((NxObject*)Application::current->getObjectById(id1)); ui->render->selectionAdd((NxObject*)Application::current->getObjectById(id2)); } void UiView::actionAddMathCurve() { unToogleDraw(1); unToogleDraw(2); unToogleDraw(3); unToogleDraw(4); ui->render->selectionClear(true); quint16 id = Application::current->execute("add curve auto", ExecuteSourceGui).toUInt(); Application::current->execute("setequation " + QString::number(id) + " cartesian 10*param1*t , sin(param2*20*t*PI) * exp(1-4*param3*t) , 2*param5*cos(8*param4*t*PI)", ExecuteSourceGui); ui->render->selectionAdd((NxObject*)Application::current->getObjectById(id)); ui->inspector->showSpaceTab(); id = Application::current->execute("add cursor auto", ExecuteSourceGui).toUInt(); Application::current->execute("setcurve " + QString::number(id) + " lastCurve", ExecuteSourceGui); } void UiView::actionAddMathCurveSimple() { unToogleDraw(1); unToogleDraw(2); unToogleDraw(3); unToogleDraw(4); ui->render->selectionClear(true); quint16 id = Application::current->execute("add curve auto", ExecuteSourceGui).toUInt(); Application::current->execute("setequation " + QString::number(id) + " cartesian 10*param1*t , sin(param2*20*t*PI) * exp(1-4*param3*t) , 0", ExecuteSourceGui); ui->render->selectionAdd((NxObject*)Application::current->getObjectById(id)); ui->inspector->showSpaceTab(); } void UiView::actionAddFreeCursor() { bool freeCursor = true; unToogleDraw(1); unToogleDraw(2); unToogleDraw(3); unToogleDraw(4); freehandCurveNeedsCursor = false; editingStop(); Application::current->pushSnapshot(); foreach(const NxObject *object, *(ui->render->getSelection())) { if(object->getType() == ObjectsTypeCurve) { freeCursor = false; NxCurve *curve = (NxCurve*)object; quint16 cursorId = Application::current->execute(QString("add cursor auto"), ExecuteSourceGui).toUInt(); Application::current->execute(QString("%1 %2 %3").arg(COMMAND_CURSOR_CURVE).arg(cursorId).arg(curve->getId()), ExecuteSourceGui); Application::current->execute(QString("%1 %2 %3 0 end").arg(COMMAND_CURSOR_OFFSET).arg(cursorId).arg(curve->getMaxOffset() / 2), ExecuteSourceGui); } } if(freeCursor) Application::current->execute(QString("add cursor auto"), ExecuteSourceGui).toUInt(); } void UiView::actionCircleCurve() { if((Render::editingMode == EditingModeCircle) && (Render::editing)) editingStop(); else { unToogleDraw(1); unToogleDraw(2); unToogleDraw(3); ui->render->setEditingMode(EditingModeCircle); } } void UiView::editingStart(const NxPoint & point) { if(Render::editing) { if((Render::editingMode == EditingModeFree) || (Render::editingMode == EditingModePoint)) { editingStartPoint = point; freehandCurveIndex = 1; Application::current->pushSnapshot(); freehandCurveId = Application::current->execute("add curve auto", ExecuteSourceGui).toUInt(); Application::current->execute(QString("%1 %2 %3 %4 0").arg(COMMAND_POS).arg(freehandCurveId).arg(editingStartPoint.x()).arg(editingStartPoint.y()), ExecuteSourceGui); if(Render::editingMode == EditingModeFree) Application::current->execute(QString("%1 %2 0 0 0 0").arg(COMMAND_CURVE_POINT_SMOOTH).arg(freehandCurveId), ExecuteSourceGui); else Application::current->execute(QString("%1 %2 0 0 0 0").arg(COMMAND_CURVE_POINT).arg(freehandCurveId), ExecuteSourceGui); } else if(Render::editingMode == EditingModeTriggers) { Application::current->pushSnapshot(); quint16 triggerId = Application::current->execute("add trigger auto", ExecuteSourceGui).toUInt(); Application::current->execute(QString("%1 %2 %3 %4 0").arg(COMMAND_POS).arg(triggerId).arg(point.x()).arg(point.y()), ExecuteSourceGui); } else if(Render::editingMode == EditingModeCircle) { Application::current->pushSnapshot(); quint16 curveId = Application::current->execute(QString("add curve auto"), ExecuteSourceGui).toUInt(); Application::current->execute(QString("%1 %2 %3 %4 0").arg(COMMAND_POS).arg(curveId).arg(point.x()).arg(point.y()), ExecuteSourceGui); Application::current->execute(QString("%1 %2 2 2").arg(COMMAND_CURVE_ELL).arg(curveId), ExecuteSourceGui); quint16 cursorId = Application::current->execute(QString("add cursor auto"), ExecuteSourceGui).toUInt(); Application::current->execute(QString("%1 %2 %3").arg(COMMAND_CURSOR_CURVE).arg(cursorId).arg(curveId), ExecuteSourceGui); Application::current->execute(QString("%1 %2 0 0 1").arg(COMMAND_CURSOR_START).arg(cursorId), ExecuteSourceGui); } } } void UiView::editingStop() { if((Render::editing) && ((Render::editingMode == EditingModeFree) || (Render::editingMode == EditingModePoint))) { if(freehandCurveIndex > 0) { Application::current->execute(QString("%1 %2 %3").arg(COMMAND_CURVE_POINT_RMV).arg(freehandCurveId).arg(freehandCurveIndex), ExecuteSourceSystem); freehandCurveIndex--; } } editingStopWithoutRemoval(); } void UiView::editingStopWithoutRemoval(bool isLoop) { if(freehandCurveIndex > 0) { if(freehandCurveNeedsCursor) { quint16 cursorId = Application::current->execute(QString("add cursor auto"), ExecuteSourceGui).toUInt(); Application::current->execute(QString("%1 %2 %3").arg(COMMAND_CURSOR_CURVE).arg(cursorId).arg(freehandCurveId), ExecuteSourceGui); if(isLoop) Application::current->execute(QString("%1 %2 0 0 1").arg(COMMAND_CURSOR_START).arg(cursorId), ExecuteSourceGui); } } else Application::current->execute(QString("%1 %2").arg(COMMAND_REMOVE).arg(freehandCurveId), ExecuteSourceSystem); freehandCurveId = 0; freehandCurveIndex = 0; freehandCurveNeedsCursor = false; unToogleDraw(0); ui->render->unsetEditing(); } void UiView::editingMove(const NxPoint & point, bool add, bool mouseState) { bool isLoop = false; NxPoint newPoint = point - editingStartPoint; if((!mouseState) && (freehandCurveIndex > 1) && ((qAbs(newPoint.x()) < (0.25 * Render::zoomLinear)) && (qAbs(newPoint.y()) < (0.25 * Render::zoomLinear)) && (qAbs(newPoint.z()) < (0.25 * Render::zoomLinear)))) { isLoop = true; newPoint = NxPoint(); } if((Render::editing) && (Render::editingMode == EditingModeFree)) { Application::current->execute(QString("%1 %2 %3 %4 %5").arg(COMMAND_CURVE_POINT_SMOOTH).arg(freehandCurveId).arg(freehandCurveIndex).arg(newPoint.x()).arg(newPoint.y()), ExecuteSourceGui); if(add) freehandCurveIndex++; } else if((Render::editing) && (Render::editingMode == EditingModePoint)) { Application::current->execute(QString("%1 %2 %3 %4 %5").arg(COMMAND_CURVE_POINT).arg(freehandCurveId).arg(freehandCurveIndex).arg(newPoint.x()).arg(newPoint.y()), ExecuteSourceGui); if(add) freehandCurveIndex++; } if((isLoop) && (add)) { freehandCurveIndex--; editingStopWithoutRemoval(isLoop); } } IanniX-0.9.20/gui/uiview.h000066400000000000000000000107031317340345000152360ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #ifndef UIVIEW_H #define UIVIEW_H #include #include "uiinspector.h" #include "transport/uiabout.h" #include "gui/uihelp.h" namespace Ui { class UiView; } class UiView : public QMainWindow { Q_OBJECT public: explicit UiView(QWidget *parent = 0); ~UiView(); public: UiHelp *help; private: UiAbout *about; bool wasInspectorVisible, wasTransportVisible, isFullScreen; QPoint previousPos; QSize previousSize; QDesktopWidget *fullscreenDisplays; QList fullscreenButtons; public: UiRender* getRender() const; Transport* getTransport() const; UiInspector* getInspector() const; UiRenderPreview* getRenderPreview() const; bool getPerformancePreview() const; public slots: void fullscreenDisplaysCountChanged(); void fullscreenDisplaysSelected(); void showTimer(); void showHelp(); void showTransport(); void showInspector(); void showEditor(); void toggleFullscreen(bool); void goToFullscreen(); void goToFullscreen(quint8 screenIndex); void escFullscreen(); void actionPlay_pause(); void actionFast_rewind(); void actionPerformance(); void actionReloadScript() { emit(actionRouteReloadScript()); } void actionImportSVG(); void actionImportBackground(); void actionImportText(); void actionAlign_top() { emit(arrangeObjects(0)); } void actionAlign_left() { emit(arrangeObjects(1)); } void actionAlign_bottom() { emit(arrangeObjects(2)); } void actionAlign_right() { emit(arrangeObjects(3)); } void actionAlign_middle() { emit(arrangeObjects(4)); } void actionAlign_center() { emit(arrangeObjects(5)); } void actionDistributeH() { emit(arrangeObjects(6)); } void actionDistributeV() { emit(arrangeObjects(7)); } void actionAlign_circle() { emit(arrangeObjects(8)); } void actionAlign_ellipse() { emit(arrangeObjects(9)); } void actionSnapshot(); void actionResize(); void actionResize(QSize size); void gridChange(); void actionPatchesFolder() { QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(Application::pathApplication.absoluteFilePath() + "/Patches/").absoluteFilePath())); } private: quint16 freehandCurveId; qint16 freehandCurveIndex; bool freehandCurveNeedsCursor; NxPoint editingStartPoint; public slots: void unToogleDraw(quint16 id = 0); void actionDrawFreeCurveSimple() { actionDrawFreeCurve (false); } void actionDrawPointCurveSimple() { actionDrawPointCurve(false); } void actionDrawFreeCurve(bool cursor = true); void actionDrawPointCurve(bool cursor = true); void actionDrawTriggers(); void actionAddTimeline(); void actionAddFreeCursor(); void actionCircleCurve(); void actionAddMathCurve(); void actionAddMathCurveSimple(); void editingStart(const NxPoint &); void editingStop(); void editingStopWithoutRemoval(bool isLoop = false); void editingMove(const NxPoint &, bool add, bool mouseState); signals: void forceGoto(qreal,bool); void arrangeObjects(quint16 type); void actionRouteReloadScript(); void actionRouteImportSVG(QString); void actionRouteImportBackground(QString); void actionRouteImportText(QString,QString); void actionRouteCloseEvent(QCloseEvent*); protected: void changeEvent(QEvent *e); void keyPressEvent(QKeyEvent *event); void closeEvent(QCloseEvent *); private: Ui::UiView *ui; }; #endif // UIVIEW_H IanniX-0.9.20/gui/uiview.ui000066400000000000000000002025461317340345000154340ustar00rootroot00000000000000 UiView 0 0 1094 740 IanniX — View QTabWidget, QLabel, QCheckBox, QLineEdit, QPlainTextEdit, QPushButton, QSpinBox, QDoubleSpinBox, QTreeView, QHeaderView, QTabBar, QComboBox, QFrame#globalFrame, QTabBar::tab, QTreeView, QHeaderView, QDockWidget, QStatusBar, QRadioButton, QToolButton { font: 10px "Museo Sans", "Museo Sans 500", "Arial"; padding: 0px; margin: 0px; min-height: 20px; color: white; border: 0px solid black; } QPushButton, QSpinBox, QDoubleSpinBox, QLineEdit, QPlainTextEdit, QCheckBox::indicator, QRadioButton::indicator, QTreeView::indicator, QComboBox, QTreeView, QHeaderView { border: 1px solid rgb(55, 55, 55); border-radius: 2px; background-color: rgb(70, 70, 70); } QSpinBox, QDoubleSpinBox, QLineEdit, QPlainTextEdit, QCheckBox { margin-top: 4px; margin-bottom: 4px; } QFrame#globalFrame, QFrame#transportFrame, QFrame#timeFrame, QFrame#optionFrame, QFrame#speedFrame, QFrame#logoFrame, QFrame#perfFrame, QDialog { background-color: rgb(40, 40, 40); } QLabel, QCheckBox, QRadioButton { color: rgb(210, 210, 210); } QTabWidget::pane { border: 1px solid rgb(50, 50, 50); } QTabWidget::tab-bar { left: 0px; } QTabWidget#tab { color: red; } QTabBar::tab { min-height: 25px; /* FIX IN SS-TAB */ background-color: rgb(110, 110, 110); border-top-left-radius: 4px; border-top-right-radius: 4px; margin-right: 2px; padding-left: 5px; padding-right: 5px; color: rgb(220, 220, 220); } QTabBar::tab:selected { background-color: rgb(242, 241, 237); color: black; } QTabBar::tab:hover { color: black; } QTabBar::tab:!selected { margin-top: 2px; } QTabBar::tab:disabled { color: gray; } QPushButton { margin-left: 6px; padding-left: 3px; padding-right: 3px; } QPushButton:hover { border: 1px solid rgb(28, 124, 195); background-color: rgb(21, 91, 143); } QPushButton::checked, QPushButton:pressed, QCheckBox::indicator:checked, QTreeView::indicator:checked, QRadioButton::indicator:checked { background-color: rgb(0, 187, 255); } QCheckBox, QRadioButton { spacing: 5px; } QCheckBox::indicator, QTreeView::indicator, QRadioButton::indicator { width: 10px; height: 10px; } QSpinBox, QDoubleSpinBox, QLineEdit { padding-left : 5px; } QSpinBox::up-button, QDoubleSpinBox::up-button, QSpinBox::down-button, QDoubleSpinBox::down-button { width: 5px; padding: 2px; padding-left: 3px; background-color: rgb(60, 60, 60); border: 0px solid black; border-left: 1px solid rgb(70, 70, 70); } QSpinBox::up-button, QDoubleSpinBox::up-button { image: url(:/icons/res_icon_plus.png); border-bottom: 1px solid rgb(70, 70, 70); } QSpinBox::down-button, QDoubleSpinBox::down-button { image: url(:/icons/res_icon_minus.png); } QComboBox { background: rgb(242, 241, 237); color: black; margin-left: 3px; border-radius: 3px; selection-color: black; padding-left: 5px; } QComboBox::drop-down { width: 10px; padding: 2px; border: 0px solid black; background-color: rgb(70, 70, 70); image: url(:/icons/res_icon_down.png); } QTreeView { background: rgb(50, 50, 50); alternate-background-color: rgb(55, 55, 55); selection-background-color: rgb(0, 187, 255); gridline-color: rgb(60, 60, 60); } QHeaderView { background: transparent; border: 0px solid black; color: rgb(200, 200, 200); min-height: 14px; } QHeaderView::section { background: rgb(90, 90, 90); padding-left: 5px; border-top-left-radius: 3px; border-top-right-radius: 3px; margin-right: 1px; font: 9px "Arial"; } QTreeView::item { min-height: 20px; } QTreeView::branch:has-children:!has-siblings:closed, QTreeView::branch:closed:has-children:has-siblings { border-image: none; image: url(:/items/res_tree_close.png); } QTreeView::branch:open:has-children:!has-siblings, QTreeView::branch:open:has-children:has-siblings { border-image: none; image: url(:/items/res_tree_open.png); } QScrollBar:vertical, QScrollBar:horizontal { border: 0px solid black; background: rgba(255, 255, 255, 32); } QScrollBar::handle:vertical, QScrollBar::handle:horizontal { border: 0px solid black; background: rgb(161, 161, 161); border-radius: 3px; } QScrollBar:vertical { width: 8px; } QScrollBar:horizontal { height: 8px; } QScrollBar::handle:vertical { min-height: 8px; } QScrollBar::handle:horizontal { min-width: 8px; } QScrollBar::add-line:vertical, QScrollBar::add-line:hozirontal, QScrollBar::sub-line:vertical, QScrollBar::sub-line:horizontal, QScrollBar::up-arrow:vertical, QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:vertical, QScrollBar::down-arrow:horizontal { border: 0px solid black; background: transparent; width: 1px; height: 1px; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical, QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: none; } QSlider:horizontal { min-width: 100px; } QSlider::groove:horizontal { border: 0px solid transparent; background-color: rgb(70, 70, 70); height: 3px; } QSlider::handle:horizontal { width: 11px; height: 10px; border-radius: 5px; margin-top: -4px; margin-bottom: -4px; border: 0px solid black; background-color: rgb(0, 187, 250); } QSplitter::handle { background: rgb(255, 255, 255, 30); } QSplitter::handle:pressed { background: rgb(0, 187, 255); } QSplitter::handle:horizontal { width: 4px; } QSplitter::handle:vertical { height: 4px; } QDockWidget { } QDockWidget::title { text-align: center; background-color: rgb(70, 70, 70); } QToolBar { background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(247, 247, 247, 255), stop:1 rgba(222, 222, 222, 255)); border: 1px solid rgba(202, 202, 202, 255); spacing: 0px; } QToolButton { border: 0px solid black; color: black; border-radius: 3px; margin: 3px; width: 22px; height: 22px; } QToolButton:pressed, QToolButton:checked { background-color: rgba(0, 0, 0, 20); } QToolButton#actionPlaySelected:pressed, QToolButton#actionPlaySelected:checked { background-color: red; } QToolButton#actionLockPos:pressed, QToolButton#actionLockPos:checked { background-color: red; } QStatusBar { color: rgb(210, 210, 210); border-top: 1px solid rgb(50, 50, 50); background-color: rgb(30, 30, 30); } /*TRANSPORT*/ QFrame#transportFrame, QFrame#timeFrame, QFrame#optionFrame, QFrame#speedFrame, QFrame#logoFrame, QFrame#perfFrame{ border: 0px solid black; border-left: 1px solid rgb(50, 50, 50); } QWIdget { margin: 0px; padding: 0px; } QWidget#speedSlider { margin-top: 7px; } QWidget#timeEdit, QWidget#perfCpuEdit, QWidget#perfOpenGLEdit, QWidget#perfSchedulerEdit { background-color: transparent; border: 0px solid black; font: 9px; color: rgb(140, 140, 140); } QLineEdit#timeEdit { font: 40px "Lucida Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida"; color: rgb(0, 187, 255); } QPushButton#logoButton { border: 0px solid black; background-color: transparent; } QPushButton:hover#logoButton { border: 1px solid rgb(28, 124, 195); background-color: rgb(21, 91, 143); } QPushButton#ffButton, QPushButton#playButton { min-width: 40px; min-height: 40px; border-radius: 20px; padding: 0px; } QPushButton#logoButton { margin: -2px; } /* ---- */ /* INSPECTEUR */ QWidget#ssTabInfoGeneral, QWidget#ssTabInfoSpace, QWidget#ssTabInfoTime, QWidget#ssTabInfoMessage, QWidget#ssTabConfigLog, QWidget#ssTabConfigNetwork, QWidget#ssTabConfigMIDI, QWidget#ssTabConfigArduino, QWidget#ssTabConfigSyphon, QWidget#ssTabConfigWeb, QWidget#ssTabRessource { background-color: rgb(50, 50, 50) } QWidget#tabProject, QWidget#tabView, QWidget#tabInfo, QWidget#tabControlCenter, QWidget#tabConfig { background-color: transparent; } QWidget#equationEdit { font: 10px "Lucida Console", "Monaco", "Monospace"; } /* ----- */ /* MAIN */ QWidget#centralwidget { background-color: black; } /* ----- */ /* DIALOG */ QDialogButtonBox QPushButton { padding-left: 10px; padding-right: 10px; min-height: 25px; margin: 5px; } /* ------ */ 0 0 0 0 0 0 0 0 0 0 0 Performance preview|While in performance mode, you can take benefits of the multiple display outputs. For example, you can make a video projection of the score on the second video output while keeping a preview and a control of your score on your laptop main display. 0 15 Allows you to keep a video thumbnail in the IanniX main window REFRESH THIS PREVIEW true Qt::Horizontal 40 20 0 0 1094 22 Edit File Display Grid resolution Playback Arrange objects Align horizontally Align vertically 54 38 QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable Qt::BottomDockWidgetArea Transport 8 370 38 QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea Inspector 2 Objects creation 32 32 TopToolBarArea false View options 32 32 TopToolBarArea false Window options 32 32 TopToolBarArea false Undo Undo last action Ctrl+Z Qt::ApplicationShortcut Redo Redo last action Ctrl+Y Qt::ApplicationShortcut Copy Copies selected objects to clipboard Ctrl+C Qt::ApplicationShortcut Paste Pastes copied objects from clipboard Ctrl+V Qt::ApplicationShortcut Cut Copies to clipboard and deletes selected objects Ctrl+X Qt::ApplicationShortcut Select all Selects all the selectable objects in the score Ctrl+A Qt::ApplicationShortcut Delete Deletes selected objects Backspace Qt::ApplicationShortcut New score Creates a new empty score Ctrl+N Qt::ApplicationShortcut Open a score… Opens a IanniX project Ctrl+O Qt::ApplicationShortcut Save score Saves the current score Ctrl+S Quit Quits IanniX Ctrl+Q Qt::ApplicationShortcut true false :/actions/res_icon_fullscreen.png:/actions/res_icon_fullscreen.png Fullscreen Fullscreen Switches score to fullscreen Ctrl+F Qt::ApplicationShortcut true true :/actions/res_icon_inspector.png:/actions/res_icon_inspector.png Inspector panel Shows/hides the inspector panel Inspector panel|The inspector panel allows you to configure your objects, scores and settings. All the actions and options are in this very important area. Ctrl+Alt+I Qt::ApplicationShortcut true true :/actions/res_icon_transport.png:/actions/res_icon_transport.png Transport panel Shows/hides the transport panel Transport panel|The transport panel allows you to start, stop or set up the playback of your score. Ctrl+Alt+T Qt::ApplicationShortcut Play/pause Plays or pauses the playback Play/pause|Press this button to start or pause the playback Space Qt::ApplicationShortcut Rewind score Rewind score Rewinds the playback Fast rewind|By pressing the button, IanniX will play or pause the score playback. If nothing happened, be sure the score speed is positive! F Qt::ApplicationShortcut true true :/actions/res_icon_grid.png:/actions/res_icon_grid.png Grid && axis Grid & axis Shows/hides score grid and axis Ctrl+G Qt::ApplicationShortcut Duplicate Duplicates selected objects Ctrl+D Qt::ApplicationShortcut Zoom in Zooms in Ctrl++ Qt::ApplicationShortcut Zoom out Zooms out Ctrl+- Qt::ApplicationShortcut Reset zoom (100%) Restores initial zoom Ctrl+Shift+0 Qt::ApplicationShortcut true :/actions/res_icon_curveFree.png:/actions/res_icon_curveFree.png Draw a smooth curve with a cursor Draw a smooth curve with a cursor Draws a smooth curve with a cursor Curves|In IanniX vocabulary, a curve is a spatial trajectory. A curve can have two functions: first, it is a support for cursors, defining where they are going on; secondly, it can be a variation of values read by cursors (intersection of cursor with the curve). Curves can be circular, segments of lines, Bézier curves or math equations.\n\nAfter creating a curve, you can edit it:\n- Double click on the path to add a point\n- Control+double click on a point of the curve to remove it (Command key for Mac users)\n- Double-click on a point to enable or disable smoothing\n\nPress ESC or click again on the toolbar button to stop edition. Ctrl+Shift+F Qt::ApplicationShortcut true :/actions/res_icon_curvePoint.png:/actions/res_icon_curvePoint.png Draw straight curve with a cursor Draw straight curve with a cursor Draws straight curve with a cursor Curves|In IanniX vocabulary, a curve is a spatial trajectory. A curve can have two functions: first, it is a support for cursors, defining where they are going on; secondly, it can be a variation of values read by cursors (intersection of cursor with the curve). Curves can be circular, segments of lines, Bézier curves or math equations.\n\nAfter creating a curve, you can edit it:\n- Double click on the path to add a point\n- Control+click on a point of the curve to remove it (Command key for Mac users)\n- Double-click on a point to enable or disable smoothing\n- Shift+double-click to resample curve (it means you transform the curve into many segments)\n\nPress ESC or click again on the toolbar button to stop edition. Ctrl+Shift+G Qt::ApplicationShortcut true :/actions/res_icon_trigger.png:/actions/res_icon_trigger.png Add triggers Add triggers Adds triggers Triggers|In IanniX vocabulary, a trigger is an event that is fired by cursors. It is very similar to a note in music, but of course IanniX allows you to fire any kind of event, depending on the software linked with your score.\n\nDouble click on a trigger to change the sent messages when fired.\nPress ESC or click again on the toolbar button to stop edition. Ctrl+Shift+T Qt::ApplicationShortcut :/actions/res_icon_cursor.png:/actions/res_icon_cursor.png Add a cursor Add a cursor Adds a cursor on the selected curves Cursors|In IanniX vocabulary, a cursor is a playhead. While running on a curve, it can fire triggers, sends its position or reads curve values. If the cursor is not linked to a curve, it will not move automatically, but you can control it from another software or hardware (sensors…).\n\nDouble click on a cursor to change the sent messages. Qt::ApplicationShortcut true 10 seconds Changes the grid base unit to 10 seconds Qt::ApplicationShortcut true true 1 second Changes the grid base unit to 1 second Qt::ApplicationShortcut true 500 milliseconds Changes the grid base unit to 500 milliseconds Qt::ApplicationShortcut true 100 milliseconds Changes the grid base unit to 100 milliseconds Qt::ApplicationShortcut true 10 milliseconds Changes the grid base unit to 10 milliseconds Qt::ApplicationShortcut true Custom value Changes the grid base unit to a custom value Qt::ApplicationShortcut true :/actions/res_icon_curveCircle.png:/actions/res_icon_curveCircle.png Add circular curves with cursors Add circular curves with cursors Adds circular curves with cursors Curves|In IanniX vocabulary, a curve is a spatial trajectory. A curve can have two functions: first, it is a support for cursors, defining where they are going on; secondly, it can be a variation of values read by cursors (intersection of cursor with the curve). Curves can be circular, segments of lines, Bézier curves or math equations.\n\nAfter creating a curve, you can edit it:\n- Double click on the path to add a point\n- Control+double click on a point of the curve to remove it (Command key for Mac users)\n- Double-click on a point to enable or disable smoothing\n\nPress ESC or click again on the toolbar button to stop edition. Ctrl+Shift+R Qt::ApplicationShortcut true :/actions/res_icon_grid_snapX.png:/actions/res_icon_grid_snapX.png Snap to X-grid Snap to X-grid Snaps mouse actions on vertical grid Qt::ApplicationShortcut true :/actions/res_icon_lock.png:/actions/res_icon_lock.png Lock objects position Lock objects position Locks objects position Locking objects|Activate this option if you only want to navigate safely (without moving objects accidentally) in the score. Qt::ApplicationShortcut true true :/actions/res_icon_label.png:/actions/res_icon_label.png Objects labels Objects labels Show/hides objects labels Objects labels|Disable this option if you don't want to display object labels (if you've set labels in inspector) on the score. Displaying label may be CPU intensive so disabling them may increase video frame rate. Qt::ApplicationShortcut :/actions/res_icon_patches_folder.png:/actions/res_icon_patches_folder.png Third party software examples Third party software examples Opens a folder where you can find third party software examples Third party software examples|IanniX only sequences events and values to other software or hardware. Click on this button to open examples using third party software that are compatible with IanniX.\nBe aware that these represent just samples, many other software tools are compatible with IanniX! Have a look at the configuration tab in inspector panel to see all the available interfaces. Qt::ApplicationShortcut About IanniX Opens About IanniX window About IanniX|IanniX is open source and developed by volunteers. Discover who they are! Qt::ApplicationShortcut QAction::AboutRole Import SVG file… Imports SVG file to score SVG files|IanniX can import SVG files (open vectorial format). Be aware that IanniX tries to make the best it can to import data from SVG, but some of SVG features are not compatible with IanniX philosophy.\nFinaly, SVG is based on print or display units whereas IanniX is based on seconds; you may need to rescale the imported data. Qt::ApplicationShortcut Import text… Imports glyphs (characters) to score Text import|IanniX can import glyphs (characters) from fonts. Note that font sizes are based on print or display units whereas IanniX is based on seconds; you may need to rescale the imported data. Qt::ApplicationShortcut true false :/actions/res_icon_editor.png:/actions/res_icon_editor.png Script editor window Script editor window Shows/hides script editor window Script editor window|The script editor window allows you to add code to your score. Scripts are based on the Javascript language and some special methods allows you to control IanniX. Have a look at examples to start working with scripts! Ctrl+E Qt::ApplicationShortcut Reload score Reloads the current script if you made changes with an external editor Ctrl+R Qt::ApplicationShortcut true true :/actions/res_icon_light.png:/actions/res_icon_light.png Lighter color theme Lighter color theme Changes the color theme Color themes|IanniX comes with two color themes: one is bright (for editing, with colors inspired by paper and pencil), the other is dark (for performance, not dazzling on stage, in lighting desk or sound controls) Qt::ApplicationShortcut Import a background image… Imports a background image Background picture|Background picture is not only an esthetical feature, it also allows you to trace curves manually from the image.\nNote that pictures are based on pixels whereas IanniX is based on seconds; you may need to rescale the picture in inspector panel. Qt::ApplicationShortcut true true :/general/res_icon_trigger_select.png:/general/res_icon_trigger_select.png Allow triggers selection Allow triggers selection Allows triggers selection Objects selection|Use these options to enable or disable selection of objects regarding their nature. It can be very useful if you need to change for example all the messages of the triggers. Qt::ApplicationShortcut true true :/general/res_icon_curve_select.png:/general/res_icon_curve_select.png Allow curves selection Allow curves selection Allows curves selection Objects selection|Use these options to enable or disable selection of objects regarding their nature. It can be very useful if you need to change for example all the messages of the triggers. Qt::ApplicationShortcut true true :/general/res_icon_cursor_select.png:/general/res_icon_cursor_select.png Allow cursors selection Allow cursors selection Allows cursors selection Objects selection|Use these options to enable or disable selection of objects regarding their nature. It can be very useful if you need to change for example all the messages of the triggers. Qt::ApplicationShortcut true :/actions/res_icon_grid_snapY.png:/actions/res_icon_grid_snapY.png Snap to Y-grid Snap to Y-grid Snaps mouse actions on horizontal grid Qt::ApplicationShortcut Distribute horizontally Distributes objects horizontally from the leftmost object to the rightmost object Qt::ApplicationShortcut Distribute vertically Distributes objects vertically from the topmost object to the bottommost object Qt::ApplicationShortcut Align left Aligns objects on the leftmost object Qt::ApplicationShortcut Align center Aligns objects on the horizontal center of the selection Qt::ApplicationShortcut Align right Aligns objects on the rightmost object Qt::ApplicationShortcut Align top Aligns objects on the topmost object Qt::ApplicationShortcut Align middle Aligns objects on the vertical center of the selection Qt::ApplicationShortcut Align bottom Aligns objects on the bottommost object Qt::ApplicationShortcut Distribute circulary Aligns objects as a circle Qt::ApplicationShortcut Distribute on ellipse Aligns objects as an ellipse Qt::ApplicationShortcut Make a high resolution snapshot Generates a high resolution picture of the score on your desktop Ctrl+Shift+P Qt::ApplicationShortcut Resize viewport Resizes score viewport to specific dimensions Qt::ApplicationShortcut true false :/actions/res_icon_timer.png:/actions/res_icon_timer.png Timer window Timer window Shows/hides the timer window Timer window|The timer window is useful if you need a big readable timer on stage for performance. Ctrl+T Qt::ApplicationShortcut true :/actions/res_icon_performance.png:/actions/res_icon_performance.png Performance mode Performance mode Switches to performance mode Performance mode|While in performance mode, you can take benefits of the multiple display outputs. For example, you can make a video projection of the score on the second video output while keeping a preview and a control of your score on your laptop main display. Ctrl+P Qt::ApplicationShortcut :/actions/res_icon_timeline.png:/actions/res_icon_timeline.png Add a timeline Add a timeline Adds a timeline Timeline|A timeline is just a classical horizontal curve with a cursor reading curves values. This feature only adds a curve with a cursor that has a pre-configured message for curve value reading (intersection of cursor with the curves) true :/actions/res_icon_play_selected.png:/actions/res_icon_play_selected.png Only play selected objects Only play selected objects If checked, only selected objects will output messages true :/actions/res_icon_curveFree_simple.png:/actions/res_icon_curveFree_simple.png Draw a smooth curve Draw a smooth curve Draws a smooth curve Curves|In IanniX vocabulary, a curve is a spatial trajectory. A curve can have two functions: first, it is a support for cursors, defining where they are going on; secondly, it can be a variation of values read by cursors (intersection of cursor with the curve). Curves can be circular, segments of lines, Bézier curves or math equations.\n\nAfter creating a curve, you can edit it:\n- Double click on the path to add a point\n- Control+double click on a point of the curve to remove it (Command key for Mac users)\n- Double-click on a point to enable or disable smoothing\n\nPress ESC or click again on the toolbar button to stop edition. Qt::ApplicationShortcut true :/actions/res_icon_curvePoint_simple.png:/actions/res_icon_curvePoint_simple.png Draw straight curve Draw straight curve Draws straight curve Curves|In IanniX vocabulary, a curve is a spatial trajectory. A curve can have two functions: first, it is a support for cursors, defining where they are going on; secondly, it can be a variation of values read by cursors (intersection of cursor with the curve). Curves can be circular, segments of lines, Bézier curves or math equations.\n\nAfter creating a curve, you can edit it:\n- Double click on the path to add a point\n- Control+double click on a point of the curve to remove it (Command key for Mac users)\n- Double-click on a point to enable or disable smoothing\n\nPress ESC or click again on the toolbar button to stop edition. Qt::ApplicationShortcut :/actions/res_icon_curveEq_simple.png:/actions/res_icon_curveEq_simple.png Add a math curve Add a math curve Adds a math curve Curves|In IanniX vocabulary, a curve is a spatial trajectory. A curve can have two functions: first, it is a support for cursors, defining where they are going on; secondly, it can be a variation of values read by cursors (intersection of cursor with the curve). Curves can be circular, segments of lines, Bézier curves or math equations.\n\nAfter creating a curve, you can edit it:\n- Double click on the path to add a point\n- Control+double click on a point of the curve to remove it (Command key for Mac users)\n- Double-click on a point to enable or disable smoothing\n\nPress ESC or click again on the toolbar button to stop edition. Qt::ApplicationShortcut :/actions/res_icon_curveEq.png:/actions/res_icon_curveEq.png Add a math curve with a cursor Add a math curve with a cursor Adds a math curve with a cursor Curves|In IanniX vocabulary, a curve is a spatial trajectory. A curve can have two functions: first, it is a support for cursors, defining where they are going on; secondly, it can be a variation of values read by cursors (intersection of cursor with the curve). Curves can be circular, segments of lines, Bézier curves or math equations.\n\nAfter creating a curve, you can edit it:\n- Double click on the path to add a point\n- Control+double click on a point of the curve to remove it (Command key for Mac users)\n- Double-click on a point to enable or disable smoothing\n\nPress ESC or click again on the toolbar button to stop edition. Ctrl+Shift+M Qt::ApplicationShortcut true true :/actions/res_icon_help.png:/actions/res_icon_help.png Help window Help window Shows/hides the help window Ctrl+H Qt::ApplicationShortcut Preferences Opens the Config tab in Inspector Save score as… Ctrl+Shift+S Close score Ctrl+W UiRender QWidget
    render/uirender.h
    1
    Transport QWidget
    transport/transport.h
    1
    UiInspector QWidget
    gui/uiinspector.h
    1
    UiRenderPreview QWidget
    render/uirenderpreview.h
    1
    fullscreenDisplaysSelected()
    IanniX-0.9.20/iannix.cpp000066400000000000000000001620251317340345000147700ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #include "iannix.h" IanniX::IanniX(const QString &_projectToLoad, QObject *parent) : ApplicationCurrent(parent) { projectToLoad = _projectToLoad; projectIsLoaded = false; iconAppPlay = QIcon(":icons/res_appicon_pause.png"); iconAppPause = QIcon(":icons/res_appicon_play.png"); NxObject::widgetIconActiveOff = QIcon(":gui/res_icon_check_active_off.png"); NxObject::widgetIconActiveOn = QIcon(":gui/res_icon_check_active_on.png"); NxObject::widgetIconSoloOff = QIcon(":gui/res_icon_check_solo_off.png"); NxObject::widgetIconSoloOn = QIcon(":gui/res_icon_check_solo_on.png"); #ifdef QT5 OpenGlDrawing::dpi = QWindow().devicePixelRatio(); qApp->setAttribute(Qt::AA_UseHighDpiPixmaps); #endif Render::textures = new UiTextureItems(); Render::colors = new UiColorItems(); #ifdef Q_OS_MAC Application::renderFont = QFont("Museo Sans"); #else Application::renderFont = QFont("Museo Sans 500"); #endif Application::renderFont.setPixelSize(20); //Updates forceUpdate = false; forbidUpdate = !projectToLoad.isEmpty(); //Default values setCurrentDocument(0); iniSettings = 0; updateManager = 0; isGroupSoloActive = false; isObjectSoloActive = false; waitingForMessageValue = false; scriptDir = QDir::current(); //Create basic workspace QDir().mkpath(Application::pathDocuments.absoluteFilePath() + "/"); QDir().mkpath(Application::pathDocuments.absoluteFilePath() + "/Templates/"); //View view = new UiView(0); render = view->getRender(); Application::setInterfaces(this, render); Application::render = render; Application::render->setZoom(100); Application::render->rotateTo(NxPoint(0, 0, 0)); inspector = view->getInspector(); inspector->setRender(render); transport = view->getTransport(); connect(view, SIGNAL(forceGoto(qreal,bool)), SLOT(forceGoto(qreal,bool))); connect(view, SIGNAL(actionRouteReloadScript()), SLOT(actionReloadScript())); connect(view, SIGNAL(actionRouteCloseEvent(QCloseEvent*)), SLOT(actionCloseEvent(QCloseEvent*))); connect(render, SIGNAL(actionRoutePaste()), SLOT(actionPaste())); connect(render, SIGNAL(actionRouteCopy()), SLOT(actionCopy())); //Imports connect(view, SIGNAL(actionRouteImportSVG(QString)), SLOT(actionImportSVG(QString))); connect(render, SIGNAL(actionRouteImportSVG(QString)), SLOT(actionImportSVG(QString))); connect(render, SIGNAL(actionRouteImportBackground(QString)), SLOT(actionImportBackground(QString))); connect(view, SIGNAL(actionRouteImportBackground(QString)), SLOT(actionImportBackground(QString))); connect(render, SIGNAL(actionRouteImportText(QString,QString)), SLOT(actionImportText(QString,QString))); connect(view, SIGNAL(actionRouteImportText(QString,QString)), SLOT(actionImportText(QString,QString))); //Transport connect(transport, SIGNAL(forceOpenGLtimer(qreal)), SLOT(forceOpenGLTimer(qreal))); connect(transport, SIGNAL(forceSchedulerTimer(qreal)), SLOT(forceSchedulerTimer(qreal))); connect(Transport::editor, SIGNAL(askSave()), SLOT(actionSaveAndReload())); //connect(Transport::editor, SIGNAL(askSave()), SLOT(actionReloadScript())); connect(Transport::editor, SIGNAL(askRefresh()), SLOT(actionRefresh())); //Inspector connect(inspector, SIGNAL(actionRouteCC(QTreeWidgetItem*,int)), SLOT(actionCC(QTreeWidgetItem*,int))); connect(inspector, SIGNAL(actionUnmuteGroups()), SLOT(actionUnmuteGroups())); connect(inspector, SIGNAL(actionUnmuteObjects()), SLOT(actionUnmuteObjects())); connect(inspector, SIGNAL(actionUnsoloGroups()), SLOT(actionUnsoloGroups())); connect(inspector, SIGNAL(actionUnsoloObjects()), SLOT(actionUnsoloObjects())); connect(inspector->getFileWidget(), SIGNAL(currentDocumentChanged(UiSyncItem*)), SLOT(currentDocumentChanged(UiSyncItem*))); //Render connect(render, SIGNAL(mousePosChanged(NxPoint)), inspector, SLOT(setMousePos(NxPoint))); connect(render, SIGNAL(mouseZoomChanged(qreal)), inspector, SLOT(setMouseZoom(qreal))); connect(render, SIGNAL(mouseRotationChanged(NxPoint)),inspector,SLOT(setRotationAngles(NxPoint))); connect(render, SIGNAL(selectionChanged()), inspector, SLOT(askRefresh())); connect(render, SIGNAL(escFullscreen()), view, SLOT(escFullscreen())); connect(render, SIGNAL(actionRouteNew()), SLOT(actionNew())); connect(render, SIGNAL(actionRouteOpen()), SLOT(actionOpen())); connect(render, SIGNAL(actionRouteSave()), SLOT(actionSave())); connect(render, SIGNAL(actionRouteSave_as()), SLOT(actionSave_as())); connect(render, SIGNAL(actionRouteUndo()), SLOT(actionUndo())); connect(render, SIGNAL(actionRouteRedo()), SLOT(actionRedo())); connect(view, SIGNAL(arrangeObjects(quint16)), render, SLOT(arrangeObjects(quint16))); render->setZoom(); render->rotateTo(NxPoint(0, 0, 0)); inspector->setMousePos(NxPoint(0, 0)); //Interfaces interfaceOsc = new InterfaceOsc(); MessageManager::addNetworkInterface(MessagesTypeOsc, interfaceOsc); MessageManager::addNetworkInterface(MessagesTypeDirect, new InterfaceDirect()); MessageManager::addNetworkInterface(MessagesTypeUdp, new InterfaceUdp ()); MessageManager::addNetworkInterface(MessagesTypeTcp, new InterfaceTcp ()); MessageManager::addNetworkInterface(MessagesTypeHttp, new InterfaceHttp ()); MessageManager::addNetworkInterface(MessagesTypeSerial, new InterfaceSerial()); MessageManager::addNetworkInterface(MessagesTypeMidi, new InterfaceMidi ()); #ifdef SYPHON_INSTALLED MessageManager::addNetworkInterface(MessagesTypeSyphon, render->interfaceSyphon); #endif inspector->addInterfaces(); //Message script engine QScriptValue messageScript = messageScriptEngine.globalObject(); messageScript = messageScriptEngine.evaluate(NxDocument::loadLibrary()); //Special objects MessageManager::setInterfaces(this, &messageScriptEngine, 0, transport->getLogMini()); MessageManager::transportObject = new NxTrigger(this, 0); MessageManager::syncObject = new NxTrigger(this, 0); //Other experimental components #ifdef WACOM_INSTALLED wacom = new ExtWacomManager(); #endif #ifdef KINECT_INSTALLED kinect = new ExtKinectManager(); #endif //Special settings UiOptions::add(&Render::axisGrid, "guiGrid"); UiOptions::add(&Application::defaultMessage, "defaultMessage"); UiOptions::add(&Application::defaultMessageCursor, "defaultMessageCursor"); UiOptions::add(&Application::defaultMessageCurve, "defaultMessageCurve"); UiOptions::add(&Application::defaultMessageSync, "defaultMessageSync"); UiOptions::add(&Application::defaultMessageTransport, "defaultMessageTransport"); UiOptions::add(&Application::defaultMessageTrigger, "defaultMessageTrigger"); NxDocument::restoreDefaults(); //Global settings creation if needed globalSettings = new QSettings(); if((globalSettings) && (!globalSettings->childKeys().contains("id"))) { qsrand(QDateTime::currentDateTime().toTime_t()); updateAnonymousId = QString::number(qrand()); globalSettings->setValue("id", updateAnonymousId); globalSettings->setValue("updatePeriod", 1); globalSettings->setValue("lastUpdate", QDateTime(QDate(2000, 01, 01))); } //Local settings creation if needed QString settingsFilename = Application::pathDocuments.absoluteFilePath() + "/Settings.ini"; if(!QFile(settingsFilename).exists()) { iniSettings = new QSettings(settingsFilename, QSettings::IniFormat); //UiOptions foreach(UiOption *option, UiOptions::options) iniSettings->setValue(option->settingName, option->variant()); //Colors iniSettings->beginGroup("Colors"); QMapIterator colorIterator(*Render::colors); while (colorIterator.hasNext()) { colorIterator.next(); iniSettings->setValue(colorIterator.key(), colorIterator.value()); } iniSettings->endGroup(); delete iniSettings; } //Read settings if(QFile(settingsFilename).exists()) { iniSettings = new QSettings(settingsFilename, QSettings::IniFormat); QString iniAppVersion = iniSettings->value("appVersion").toString(); if(iniAppVersion == QApplication::applicationVersion()) { //UiOptions foreach(UiOption *option, UiOptions::options) if(iniSettings->childKeys().contains(option->settingName)) option->setVariant(iniSettings->value(option->settingName)); } //Colors iniSettings->beginGroup("Colors"); QStringList settingsKeys = iniSettings->childKeys(); foreach(const QString &settingsKey, settingsKeys) Render::colors->insert(settingsKey, iniSettings->value(settingsKey).value()); iniSettings->endGroup(); } Render::colors->update(); //Update management if((globalSettings) && (globalSettings->childKeys().contains("id"))) { QDateTime updateLastDate = globalSettings->value("lastUpdate") .toDateTime(); quint16 updatePeriod = globalSettings->value("updatePeriod").toUInt(); updateAnonymousId = globalSettings->value("id") .toString(); qDebug("Last update : %s (should update each %d day(s))", qPrintable(updateLastDate.toString("dd/MM/yyyy hh:mm:ss")), updatePeriod); if((!forbidUpdate) && ((updateLastDate.daysTo(QDateTime::currentDateTime()) >= updatePeriod) || (forceUpdate))) checkForUpdates(); } //Apply specials settings ((NxTrigger*)MessageManager::transportObject)->setMessagePatterns("1," + Application::defaultMessageTransport); ((NxTrigger*)MessageManager::syncObject) ->setMessagePatterns("1," + Application::defaultMessageSync); //Scheduler timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(timerTick())); timer->setInterval(5); timer->start(); forceGoto(0); //Show view->show(); if(Application::current) Application::current->readyToStart(); } void IanniX::readyToStart() { if(!hasStarted) { hasStarted = true; qDebug("Ready to start!"); //Projet par défault loadProject(projectToLoad); forceGoto(0); timerTime = startTimer(50); timerPerf = startTimer(500); render->startRenderTimer(); Application::splash->close(); } } void IanniX::actionImportSVG(const QString &filename) { qreal scale = 0.01; QDomDocument xmlDoc; QFile svgFile(filename); if(svgFile.open(QFile::ReadOnly)) { render->selectionClear(true); xmlDoc.setContent(svgFile.readAll()); actionImportSVG(xmlDoc.documentElement(), scale); svgFile.close(); inspector->showSpaceTab(); } } void IanniX::actionImportSVG(const QDomElement &xmlElement, qreal scale) { QDomNode xmlNode = xmlElement.firstChild(); while(!xmlNode.isNull()) { QDomElement xmlData = xmlNode.toElement(); if((!xmlData.isNull()) && (xmlData.tagName() == "path")) { quint16 id = execute(QString(COMMAND_ADD) + " curve auto", ExecuteSourceGui).toUInt(); execute(QString(COMMAND_CURVE_PATH) + " " + QString::number(id) + " " + QString::number(scale) + " " + xmlData.attribute("d"), ExecuteSourceGui); render->selectionAdd(getCurrentDocument()->getObject(id)); } else if((!xmlData.isNull()) && (xmlData.tagName() == "polyline")) { quint16 id = execute(QString(COMMAND_ADD) + " curve auto", ExecuteSourceGui).toUInt();; execute(QString(COMMAND_CURVE_LINES) + " " + QString::number(id) + " " + QString::number(scale) + " " + xmlData.attribute("points"), ExecuteSourceGui); render->selectionAdd(getCurrentDocument()->getObject(id)); } actionImportSVG(xmlData, scale); xmlNode = xmlNode.nextSibling(); } } void IanniX::actionImportBackground(const QString &filename) { QPixmap pixmap(filename); if(!pixmap.isNull()) { qreal scale = qMin(8 / (qreal)pixmap.width(), 8 / (qreal)pixmap.height()); execute(QString(COMMAND_TEXTURE) + " background " + QString("%1 %2 %3 %4").arg(-scale * pixmap.width() / 2).arg(scale * pixmap.height() / 2).arg(scale * pixmap.width() / 2).arg(-scale * pixmap.height() / 2) + " " + filename, ExecuteSourceGui); inspector->showRessourcesTab("background"); } } void IanniX::actionImportText(const QString &font, const QString &text) { qreal scale = 0.1; bool ok = false; QString fontReal = font; if(fontReal.isEmpty()) { ok = false; QFont fontFont = QFontDialog::getFont(&ok); if(ok) fontReal = fontFont.family(); else return; } fontReal = fontReal.replace(" ", "_"); render->selectionClear(true); quint16 id = execute(QString(COMMAND_ADD) + " curve auto", ExecuteSourceGui).toUInt(); execute(QString(COMMAND_CURVE_TXT) + " " + QString::number(id) + " " + QString::number(scale) + " " + fontReal + " " + text, ExecuteSourceGui); render->selectionAdd(getCurrentDocument()->getObject(id)); inspector->showSpaceTab(); } void IanniX::setScheduler(SchedulerActivity _schedulerActivity) { MessageManager::messagesCache.clear(); schedulerActivity = _schedulerActivity; if(schedulerActivity != SchedulerOff) { Transport::timerOk = true; Transport::renderMeasureAbsoluteValOld = 0; Transport::renderMeasureAbsolute.start(); } else Transport::timerOk = false; if(view->isVisible()) { if(Transport::timerOk) QApplication::setWindowIcon(iconAppPause); else QApplication::setWindowIcon(iconAppPlay); } } const QString IanniX::serialize() const { return transport->serialize() + getCurrentDocument()->serialize(); } void IanniX::timerEvent(QTimerEvent *event) { if(transport) { if(event->timerId() == timerTime) transport->refreshTime(); else if(event->timerId() == timerPerf) transport->refreshPerformances(); } } void IanniX::timerTick() { timerTick(false); } void IanniX::timerTick(bool force) { interfaceOsc->parseOSC(); qreal renderMeasureAbsoluteVal = Transport::renderMeasureAbsolute.elapsed() / 1000.0F; qreal delta = renderMeasureAbsoluteVal - Transport::renderMeasureAbsoluteValOld; Transport::renderMeasureAbsoluteValOld = renderMeasureAbsoluteVal; //Parse MIDI if(!force) MessageManager::networkManualParsing(); //Tick ! if((force) || (Transport::timerOk)) timerTick(delta); } void IanniX::timerTick(qreal delta) { Transport::currentMSecsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); if(Transport::forceTimeLocal) { delta = 0; if(schedulerActivity == SchedulerOneShot) setScheduler(SchedulerOff); } Transport::timeLocal += delta * Transport::scoreSpeed; if(Transport::timeLocal < 0) { Transport::forceTimeLocal = true; Transport::timeLocal = 0; return; } Transport::perfSchedulerRefreshTime += delta; Transport::perfSchedulerCounterTime++; //Open a bundle if necessary MessageManager::networkBundle(true); //Browse documents QHashIterator documentIterator(documents); while (documentIterator.hasNext()) { documentIterator.next(); NxDocument *document = documentIterator.value(); //Browse groups if(document) { foreach(const NxGroup *group, document->groups) { //Browse active/inactive objects for(quint16 activityIterator = 0 ; activityIterator < ObjectsActivityLenght ; activityIterator++) { //Browse active cursors QHashIterator cursorIterator(group->objects[activityIterator][ObjectsTypeCursor]); while (cursorIterator.hasNext()) { cursorIterator.next(); NxCursor *cursor = (NxCursor*)cursorIterator.value(); NxCurve *curve = cursor->getCurve(); //Calculate curve if(curve) curve->update(); //Cursor reset if(Transport::forceTimeLocal) { cursor->setTimeLocal(Transport::timeLocal); cursor->setMessageId(0); } //Set time for a cursor cursor->setTime(delta * Transport::scoreSpeed); //Is cursor active ? if((!Transport::forceTimeLocal) && (cursor->getActive()) && (((!isGroupSoloActive) && (group->isNotMuted())) || ((isGroupSoloActive) && (group->isSolo()))) && (((!isObjectSoloActive) && (cursor->isNotMuted())) || ((isObjectSoloActive) && (cursor->isSolo())))) timerTrig(cursor); } } } } } //Close the bundle if necessary MessageManager::networkBundle(false); if(Transport::forceTimeLocal) Transport::forceTimeLocal = false; } void IanniX::timerTrig(void *object, bool force) { NxCursor *cursor = (NxCursor*)object; //Messages if((!Application::allowPlaySelected) || (!render->isSelection()) || ((Application::allowPlaySelected) && (cursor->getSelected()))) cursor->trig(force); //Browse documents if(cursor->getFireValue() > CURSOR_FIRE_NONE) { QHashIterator documentIterator(documents); while (documentIterator.hasNext()) { documentIterator.next(); NxDocument *document = documentIterator.value(); //Browse groups foreach(const NxGroup *group, document->groups) { //Test if group is the right on if((cursor->getFireValue() == CURSOR_FIRE_ALL) || ((cursor->getFireValue() == CURSOR_FIRE_GROUP) && (cursor->getGroupId() == group->getId()))) { //Browse active triggers QHashIterator triggerIterator(group->objects[ObjectsActivityActive][ObjectsTypeTrigger]); while (triggerIterator.hasNext()) { triggerIterator.next(); NxTrigger *trigger = (NxTrigger*)triggerIterator.value(); //Check the collision if((cursor->contains(trigger)) && (((!isObjectSoloActive) && (trigger->isNotMuted())) || ((isObjectSoloActive) && (trigger->isSolo()))) && ((!Application::allowPlaySelected) || (!render->isSelection()) || ((Application::allowPlaySelected) && (trigger->getSelected())))) trigger->trig(cursor); } //Browse active curbes if(cursor->getPerformCollision()) { QHashIterator curveIterator(group->objects[ObjectsActivityActive][ObjectsTypeCurve]); while (curveIterator.hasNext()) { curveIterator.next(); NxCurve *objectCurve = (NxCurve*)curveIterator.value(); //Check the collision if((!Application::allowPlaySelected) || (!render->isSelection()) || ((Application::allowPlaySelected) && (objectCurve->getSelected()))) cursor->trig((NxCurve*)objectCurve); } } } } } } } void IanniX::checkForUpdates() { updateManager = new QNetworkAccessManager(this); connect(updateManager, SIGNAL(finished(QNetworkReply*)), SLOT(checkForUpdatesFinished(QNetworkReply*))); QString url = "http://www.iannix.org/download/updates.php?id=" + updateAnonymousId + "&package=" + (QCoreApplication::applicationName() + "__" + QCoreApplication::applicationVersion()).toLower().replace(" ", "_").replace(".", "_"); qDebug("Checking for updates %s", qPrintable(url)); updateManager->get(QNetworkRequest(QUrl(url, QUrl::TolerantMode))); } void IanniX::checkForUpdatesFinished(QNetworkReply *reply) { if(reply->error() != QNetworkReply::NoError) qDebug("Network error. %s", qPrintable(reply->errorString())); else { if(globalSettings) globalSettings->setValue("lastUpdate", QDateTime::currentDateTime()); QString info = reply->readAll().trimmed(); if((info.length() > 0) || (forceUpdate)) { int rep = (new UiMessageBox())->display(tr("IanniX Update Center"), tr("A new version of IanniX is available"), info, tr("Would you like to update IanniX with the new version ?"), QPixmap(":/infos/res_info_update.png"), QDialogButtonBox::Yes | QDialogButtonBox::No); if(rep) QDesktopServices::openUrl(QUrl("http://www.iannix.org/", QUrl::TolerantMode)); } } } void IanniX::actionPlayPause() { if(Transport::timerOk) { setScheduler(SchedulerOff); MessageManager::networkSynchro(false); } else { setScheduler(SchedulerOn); MessageManager::networkSynchro(true); } } void IanniX::forceGoto(qreal gotoTime, bool) { if(gotoTime == 0) { Transport::forceTimeLocal = true; Transport::timeLocal = 0; setScheduler(SchedulerOneShot); } else { Transport::timeLocal = gotoTime; Transport::forceTimeLocal = true; if(schedulerActivity == SchedulerOff) setScheduler(SchedulerOneShot); } MessageManager::networkSynchro(false); } void IanniX::forceSchedulerTimer(qreal val) { timer->setInterval(val); } void IanniX::forceOpenGLTimer(qreal val) { render->setInterval(1000.0F/(qreal)val); } void IanniX::actionCC(QTreeWidgetItem *item, int col) { if((item) && (col)) { if(item->text(0) == tr("GROUP")) ((NxGroup*)item) ->widgetClick(col); else ((NxObject*)item)->widgetClick(col); } if(col == 0) { QPair< QList, UiRenderSelection > elements = inspector->getSelectedCCObject(); NxPoint center; quint16 centerCounter = 0; render->selectionClear(true); foreach(NxObject* object, elements.second) { render->selectionAdd(object); center += object->getPos(); centerCounter++; } foreach(const NxGroup* group, elements.first) { //Browse active/inactive objects for(quint16 activityIterator = 0 ; activityIterator < ObjectsActivityLenght ; activityIterator++) { //Browse all types of objects for(quint16 typeIterator = 0 ; typeIterator < ObjectsTypeLength ; typeIterator++) { //Browse objects foreach(NxObject *object, group->objects[activityIterator][typeIterator]) { render->selectionAdd(object); center += object->getPos(); centerCounter++; } } } } center /= centerCounter; //render->centerOn(center); } //Is solo active ? isGroupSoloActive = false; isObjectSoloActive = false; if(getCurrentDocument()) { //Is solo active ? foreach(const NxGroup *group, getCurrentDocument()->groups) if(group->isSolo()) { isGroupSoloActive = true; break; } foreach(const NxGroup* group, getCurrentDocument()->groups) { //Browse active/inactive objects for(quint16 activityIterator = 0 ; activityIterator < ObjectsActivityLenght ; activityIterator++) { //Browse all types of objects for(quint16 typeIterator = 0 ; typeIterator < ObjectsTypeLength ; typeIterator++) { //Browse objects foreach(const NxObject *object, group->objects[activityIterator][typeIterator]) { if(object->isSolo()) { isObjectSoloActive = true; return; } } } } } } } void IanniX::currentDocumentChanged(UiSyncItem *item) { if(currentDocument) delete currentDocument; setCurrentDocument(new NxDocument(this, (UiFileItem*)item)); render->setDocument(getCurrentDocument()); getCurrentDocument()->askFileOpen(); } void IanniX::actionNew() { inspector->getFileWidget()->askNew(); } void IanniX::actionOpen() { QString filename = QFileDialog::getOpenFileName(0, tr("Open IanniX Score"), Application::pathDocuments.absoluteFilePath() + "/"); if(!filename.isEmpty()) loadProject(filename); } void IanniX::actionSave() { inspector->getFileWidget()->askSave(); } void IanniX::actionSaveAndReload() { inspector->getFileWidget()->askSave(); actionReloadScript(); } void IanniX::actionSave_as() { inspector->getFileWidget()->askSave(true); } void IanniX::actionRefresh() { getCurrentDocument()->updateCode(false, false); } void IanniX::loadProject(const QString & _projectFile) { QFileInfo projectFile(_projectFile); if(projectFile.isDir()) UiFileItem::syncWith(QFileInfoList() << QFileInfo(projectFile.absoluteFilePath() + "/"), inspector->getFileWidget()->getTree()); else if(projectFile.isFile()) { UiFileItem::syncWith(QFileInfoList() << QFileInfo(projectFile.absolutePath() + "/"), inspector->getFileWidget()->getTree()); inspector->getFileWidget()->askImport(QStringList() << projectFile.absoluteFilePath()); inspector->getFileWidget()->askOpen(); } else inspector->getFileWidget()->askNew(); projectIsLoaded = true; } void IanniX::setCurrentDocument(NxDocument *_currentDocument) { documents.clear(); workingDocument = currentDocument = _currentDocument; documents.insert("current", currentDocument); } NxGroup* IanniX::addGroup(const QString & groupId) { NxDocument *document = getWorkingDocument(); if(document->groups.contains(groupId)) return document->groups.value(groupId); else { NxGroup *group = new NxGroup(this, inspector->getObjectRootItem()); group->setId(groupId); document->groups.insert(groupId, group); document->setCurrentGroup(group); return group; } } void IanniX::setObjectActivity(void *_object, quint8 activeOld) { NxDocument *document = getWorkingDocument(); if(!document) return; //Extract object NxObject *object = (NxObject*)_object; NxGroup *group = addGroup(object->getGroupId()); //Move object group->objects[activeOld] [object->getType()].remove(object->getId()); group->objects[object->getActive()][object->getType()].insert(object->getId(), object); } void IanniX::setObjectGroupId(void *_object, const QString & groupIdOld) { NxDocument *document = getWorkingDocument(); if(!document) return; //Extract object NxObject *object = (NxObject*)_object; NxGroup *group = addGroup(object->getGroupId()); //Move object group->objects[object->getActive()][object->getType()].insert(object->getId(), object); if(document->groups.contains(groupIdOld)) document->groups[groupIdOld]->objects[object->getActive()][object->getType()].remove(object->getId()); //Remove a group if empty /* if(currentDocument->groups.value(groupIdOld)->getCount() == 0) { NxGroup *group = currentDocument->groups[object->getGroupId()]; currentDocument->groups.remove(groupIdOld); delete group; } */ } void IanniX::setObjectId(void *_object, quint16 idOld) { //Extract object NxDocument *document = getWorkingDocument(); NxObject *object = (NxObject*)_object; NxGroup *group = addGroup(object->getGroupId()); //Move object group->objects[object->getActive()][object->getType()].insert(object->getId(), object); group->objects[object->getActive()][object->getType()].remove(idOld); document->objects.insert(object->getId(), object); document->objects.remove(idOld); } quint16 IanniX::getCount(qint8 objectType) { quint16 count = 0; NxDocument *document = getWorkingDocument(); if(document) { if(objectType == -2) return document->groups.count(); else foreach(NxGroup *group, document->groups) count += group->getCount(objectType); } return count; } void IanniX::removeObject(NxObject *object) { NxDocument *document = getWorkingDocument(); if(object) { if(render) render->flagIsRemoving(); //Remove the object document->groups[object->getGroupId()]->objects[object->getActive()][object->getType()].remove(object->getId()); document->objects.remove(object->getId()); //Clear selection inspector->clearCCselections(); if(document->getCurrentObject() == object) document->setCurrentObject(0); render->selectionClear(true); if(object->getType() == ObjectsTypeCurve) { NxCurve *curve = (NxCurve*)object; QStringList commands; foreach(const NxObject *object, curve->getCursors()) commands << QString(COMMAND_REMOVE) + " " + QString::number(object->getId()) + COMMAND_END; foreach(const QString & command, commands) execute(command, ExecuteSourceSystem); } else if(object->getType() == ObjectsTypeCursor) { NxCurve *curve = ((NxCursor*)object)->getCurve(); if(curve) curve->removeCursor(object); } //Remove groups if((document->groups.contains(object->getGroupId())) && (document->groups.value(object->getGroupId())->getCount() == 0)) { NxGroup *group = document->groups[object->getGroupId()]; document->groups.remove(object->getGroupId()); delete group; } delete object; if(render) render->flagIsRemoving(false); } } const QVariant IanniX::execute(const MessageIncomming &command, bool createNewObjectIfExists, bool needOutput) { if(waitingForMessageValue) { waitingForMessageValue = false; waitForMessageValue = command.getVerboseMessage(true); emit(waitForMessageArrived()); } return execute(command.command, ExecuteSourceNetwork, createNewObjectIfExists, needOutput); } const QVariant IanniX::execute(const QString &command, ExecuteSource source, bool createNewObjectIfExists, bool needOutput) { //qDebug("=> (%d) %s", source, qPrintable(command)); if(((source == ExecuteSourceGui) || (source == ExecuteSourceInformative)) && (view->help)) view->help->messageHelp(command); if(source == ExecuteSourceInformative) return QVariant(); NxObjectDispatchProperty::source = source; NxDocument *document = getWorkingDocument(); QStringList argv = command.split(" ", QString::SkipEmptyParts); quint16 argc = argv.count(); if(argc > 0) { QString commande = argv.at(0).toLower(); if((argc > 2) && (commande == COMMAND_ADD)) { bool ok = false; qint16 id = argv.at(2).toUInt(&ok); NxObject *parentObject = 0; if(ok) { parentObject = document->getObject(id); if(parentObject) { if(createNewObjectIfExists) { id = document->nextAvailableId(); } else { id = parentObject->getId(); //removeObject(parentObject); parentObject = 0; } } } else id = document->nextAvailableId(); NxObject *object = 0; QString type = argv.at(1).toLower(); if(type == "curve") object = new NxCurve(this, inspector->getObjectRootItem()); else if(type == "cursor") object = new NxCursor(this, inspector->getObjectRootItem()); else object = new NxTrigger(this, inspector->getObjectRootItem()); if(object) { object->setInitialId(id); setObjectGroupId(object, ""); object->dispatchProperty(COMMAND_ID, id); //qDebug("=> COMMAND_ID %d", id); setObjectActivity(object, ObjectsActivityInactive); object->dispatchProperty(COMMAND_POS, "0 0"); object->setParentObject(parentObject); if(parentObject) { NxPoint posOffset(0.5, -0.5, 0); object->setPosOffset(posOffset); } document->objects[id] = object; document->setCurrentObject(object); return object->getId(); } return 0; } else { // ---- GLOBAL COMMANDS ---- //String parameter if((commande == COMMAND_ROTATE) || (commande == COMMAND_CENTER)) { if(workingDocument == currentDocument) { if((argc == 4) || (argc == 7)) transport->dispatchProperty(qPrintable(commande), argvFullString(command, argv, 1)); else if((argc > 4) && (commande == COMMAND_ROTATE)) { NxGroup *group = document->getGroup(argv.at(1)); if(group) group->rotationDest = NxPoint(argv.at(2).toDouble(), argv.at(3).toDouble(), argv.at(4).toDouble()); } else if((argc > 4) && (commande == COMMAND_CENTER)) { NxGroup *group = document->getGroup(argv.at(1)); if(group) group->translationDest = NxPoint(argv.at(2).toDouble(), argv.at(3).toDouble(), argv.at(4).toDouble()); } if(needOutput) return transport->getProperty(qPrintable(commande)); } } //Single parameter else if((commande == COMMAND_ZOOM) || (commande == COMMAND_SPEED)) { if(workingDocument == currentDocument) { if(argc == 2) transport->dispatchProperty(qPrintable(commande), argvDouble(argv, 1)); else if((argc > 2) && (commande == COMMAND_ZOOM)) { NxGroup *group = document->getGroup(argv.at(1)); if(group) group->scaleDest = argv.at(2).toDouble(); } if(needOutput) return transport->getProperty(qPrintable(commande)); } } //Spécial else if(commande == "setlegend") { if(workingDocument == currentDocument) { if(argc >= 6) { render->legendColor = QColor(argvDouble(argv, 1), argvDouble(argv, 2), argvDouble(argv, 3), argvDouble(argv, 4)); render->legendSize = argvDouble(argv, 5); render->legend = argvFullString(command, argv, 6); } } } //Solo & mute else if((commande == COMMAND_SOLO) || (commande == COMMAND_MUTE)) { if(argc > 1) { QString key = argv.at(1); bool isObject = false; quint16 objectId = key.toUInt(&isObject); if(isObject) { NxObject *object = document->getObject(objectId); if(object) { if(argc > 2) { object->dispatchProperty(qPrintable(commande), argvDouble(argv, 2)); if(currentDocument == workingDocument) actionCC(object, 3); } else if(needOutput) return object->getProperty(qPrintable(commande)).toInt(); } } else { NxGroup *group = document->getGroup(key); if(group) { if(argc > 2) { group->dispatchPropertyToGroup(qPrintable(commande), argvDouble(argv, 2)); if(currentDocument == workingDocument) actionCC(group, 3); } else if(needOutput) return group->getPropertyFromGroup(qPrintable(commande)).toInt(); } } } } //Other type else if((commande == COMMAND_TEXTURE) && (argc > 1)) { if((argc > 6) && (currentDocument == workingDocument)) { QString filename = argvFullString(command, argv, 6); if((!QFile().exists(filename)) && (document->fileItem)) filename = scriptDir.absoluteFilePath(document->fileItem->filename.file.absolutePath() + "/" + filename); return render->loadTexture(new UiRenderTexture(argv.at(1).trimmed(), QFileInfo(filename), NxRect(NxPoint(argvDouble(argv, 2), argvDouble(argv, 3)), NxPoint(argvDouble(argv, 4), argvDouble(argv, 5))))); } else return render->removeTexture(argv.at(1).trimmed()); } else if((commande == COMMAND_GLOBAL_COLOR) && (argc > 5)) { if(currentDocument == workingDocument) Render::colors->insert(argv.at(1), QColor(argvDouble(argv, 2), argvDouble(argv, 3), argvDouble(argv, 4), argvDouble(argv, 5))); return Render::colors->update(); } else if((commande == COMMAND_GLOBAL_COLOR_HUE) && (argc > 5)) { QColor color; color.setHsv(argvDouble(argv, 2), argvDouble(argv, 3), argvDouble(argv, 4), argvDouble(argv, 5)); if(currentDocument == workingDocument) Render::colors->insert(argv.at(1), color); return Render::colors->update(); } //No undo or specific commands else if((commande == COMMAND_LOAD) || (commande == COMMAND_OPEN) || (commande == COMMAND_CLOSE)) { if(argc > 1) { QString filenameFinal = argvFullString(command, argv, 1); if(!((filenameFinal.toLower().endsWith(".iannix")) || (filenameFinal.toLower().endsWith(".nxscore")) || (filenameFinal.toLower().endsWith(".nxscript")))) filenameFinal.append(".iannix"); QString filename1 = filenameFinal; if(!QFileInfo(filename1).exists()) { QString filename2 = getCurrentDocument()->getScriptFile().absoluteDir().absolutePath() + "/" + filenameFinal; if(!QFileInfo(filename2).exists()) { QString filename3 = Application::pathDocuments.absoluteFilePath() + "/" + filenameFinal; if(!QFileInfo(filename3).exists()) { qDebug("Score not found %s, %s or %s", qPrintable(filename1), qPrintable(filename2), qPrintable(filename3)); return false; } else filenameFinal = filename3; } else filenameFinal = filename2; } else filenameFinal = filename1; if(commande == COMMAND_LOAD) { getCurrentDocument()->skipClose = true; loadProject(filenameFinal); } else if(commande == COMMAND_OPEN) { NxDocument *document = new NxDocument(this); document->setHiddenFilename(QFileInfo(filenameFinal)); documents.insert(filenameFinal, document); workingDocument = document; document->askFileOpen(false); workingDocument = currentDocument; UiRender *newRender = new UiRender(0, render); newRender->setDocument(document); newRender->startRenderTimer(); newRender->show(); } else if(commande == COMMAND_CLOSE) { if(documents.contains(filenameFinal)) { NxDocument *document = documents.value(filenameFinal); workingDocument = document; documents.remove(filenameFinal); if(document) { document->askFileClose(); delete document; } workingDocument = currentDocument; } } } return view->windowTitle(); } else if((commande == COMMAND_SNAPSHOT) && (argc > 1)) { if(argc > 2) return render->captureFrame(argvDouble(argv, 1), argvFullString(command, argv, 2)); else return render->captureFrame(argvDouble(argv, 1)); } else if(commande == COMMAND_VIEWPORT) { if(currentDocument == workingDocument) { if(argc > 2) view->actionResize(QSize(argvDouble(argv, 1), argvDouble(argv, 2))); if(needOutput) return QString("%1 %2").arg(render->size().width()).arg(render->size().height()); } } else if(commande == COMMAND_PLAY) { if(argc > 1) { qreal speed = argvDouble(argv, 1); if(speed != 0) { transport->setSpeed(speed); if(schedulerActivity != SchedulerOn) { setScheduler(SchedulerOn); MessageManager::networkSynchro(true); } } else { if(schedulerActivity != SchedulerOff) { setScheduler(SchedulerOff); MessageManager::networkSynchro(false); } } } else if(schedulerActivity != SchedulerOn) { setScheduler(SchedulerOn); MessageManager::networkSynchro(true); } } else if(commande == COMMAND_TITLE) { return view->windowTitle(); } else if(commande == COMMAND_FF) { forceGoto(0); } else if((commande == COMMAND_LOG) && (argc > 1)) { MessageManager::logReceive(MessageLog(tr("Script: ") + argvFullString(command, argv, 1))); } else if(commande == COMMAND_STOP) { if(schedulerActivity != SchedulerOff) { setScheduler(SchedulerOff); MessageManager::networkSynchro(false); } } else if(commande == COMMAND_GOTO) { if(argc > 1) { forceGoto(argvDouble(argv, 1)); timerTick(true); } return Transport::timeLocal; } else if((commande == COMMAND_SLEEP) && (argc > 1)) { QMutex mutex; QWaitCondition sleep; sleep.wait(&mutex, argvDouble(argv, 1)); } else if(commande == COMMAND_CLEAR) { document->pushSnapshot(); document->clear(); } else if(commande == COMMAND_MOUSE) { if(argc > 1) QCursor::setPos(argvDouble(argv, 1), argvDouble(argv, 2)); if(needOutput) return QString("%1 %2").arg(QCursor::pos().x()).arg(QCursor::pos().y()); } else if(commande == COMMAND_MESSAGE_SEND) { if(argc > 1) { QString mess = "1," + argvFullString(command, argv, 1); NxTrigger *obj = new NxTrigger(this, 0); obj->setMessagePatterns(mess); obj->trig(0); delete obj; return true; } } // ---- OBJECT ORIENTED COMMANDS ---- else if(argc > 1) { NxObjectDispatchProperty *object = getObject(argv.at(1)); if(object) { //String parameter if((commande == COMMAND_GROUP) || (commande == COMMAND_RESIZE) || (commande == COMMAND_POS) || (commande == COMMAND_POS_TRANSLATE) || (commande == COMMAND_LABEL) || (commande == COMMAND_CURSOR_BOUNDS_SOURCE) || (commande == COMMAND_CURSOR_BOUNDS_TARGET) || (commande == COMMAND_CURVE_EQUATION_PARAM) || (commande == COMMAND_CURVE_EQUATION_PARAM_LIST) || (commande == COMMAND_COLOR_ACTIVE) || (commande == COMMAND_COLOR_INACTIVE) || (commande == COMMAND_COLOR_ACTIVE_HUE) || (commande == COMMAND_COLOR_INACTIVE_HUE) || (commande == COMMAND_COLOR_MULTIPLY) || (commande == COMMAND_COLOR_MULTIPLY_HUE) || (commande == COMMAND_MESSAGE) || (commande == COMMAND_CURVE_ELL) || (commande == COMMAND_CURVE_POINT_SHIFT) || (commande == COMMAND_CURVE_POINT_TRANSLATE) || (commande == COMMAND_CURVE_POINT_TRANSLATE2) || (commande == COMMAND_CURVE_EQUATION) || (commande == COMMAND_TEXTURE_ACTIVE) || (commande == COMMAND_TEXTURE_INACTIVE) || (commande == COMMAND_LINE) || (commande == COMMAND_CURSOR_OFFSET) || (commande == COMMAND_CURSOR_START) || (commande == COMMAND_CURSOR_SPEED) || (commande == COMMAND_CURSOR_FIRE)) { if(argc > 2) object->dispatchProperty(qPrintable(commande), argvFullString(command, argv, 2)); if(needOutput) return object->getProperty(qPrintable(commande)); } //Val + string else if((commande == COMMAND_CURVE_PATH) || (commande == COMMAND_CURVE_LINES) || (commande == COMMAND_CURVE_TXT)) { if(argc > 3) { object->dispatchProperty(qPrintable(commande), argvFullString(command, argv, 3)); object->dispatchProperty(COMMAND_RESIZEF, argvDouble(argv, 2)); } if(needOutput) return object->getProperty(qPrintable(commande)); } //Single parameter else if((commande == COMMAND_RESIZEF) || (commande == COMMAND_CURSOR_WIDTH) || (commande == COMMAND_CURSOR_DEPTH) || (commande == COMMAND_SIZE) || (commande == COMMAND_CURSOR_SPEEDF) || (commande == COMMAND_CURSOR_BOUNDS_SOURCE_MODE) || (commande == COMMAND_CURSOR_TIME) || (commande == COMMAND_CURSOR_TIME_PERCENT) || (commande == COMMAND_CURVE_INERTIE) || (commande == COMMAND_CURVE_LENGTH) || (commande == COMMAND_POS_X) || (commande == COMMAND_POS_Y) || (commande == COMMAND_POS_Z) || (commande == COMMAND_ACTIVE) || (commande == COMMAND_MESSAGE_INTERVAL) || (commande == COMMAND_TRIGGER_OFF) || (commande == COMMAND_CURVE_EQUATION_POINTS) || (commande == COMMAND_CURVE_POINT_RMV) || (commande == COMMAND_ID)) { if(argc > 2) object->dispatchProperty(qPrintable(commande), argvDouble(argv, 2)); if(needOutput) return object->getProperty(qPrintable(commande)); } //Activation else if((commande == COMMAND_TRIG) || (commande == COMMAND_CURVE_EDITOR) || (commande == COMMAND_CURVE_RESAMPLE)) { if(commande == COMMAND_CURVE_RESAMPLE) pushSnapshot(); object->dispatchProperty(qPrintable(commande), true); } //Specific syntax else if((commande == COMMAND_REMOVE) && (argc > 1) && ((object->getType() == ObjectsTypeCursor) || (object->getType() == ObjectsTypeCurve) || (object->getType() == ObjectsTypeTrigger))) { NxObject *object = (NxObject*)getObject(argv.at(1), false); removeObject(object); return false; } else if((commande == COMMAND_CURVE_POINT) || (commande == COMMAND_CURVE_POINT_SMOOTH) || (commande == COMMAND_CURVE_POINT_X) || (commande == COMMAND_CURVE_POINT_Y) || (commande == COMMAND_CURVE_POINT_Z)) { QList points; for(quint16 i = 2 ; i < argc ; i++) points.append(argv.at(i).toDouble()); object->dispatchProperty(qPrintable(commande), QVariant::fromValue(points)); } //Dual actions else if(commande == COMMAND_COLOR_GLOBAL) { if(argc > 2) { object->dispatchProperty(COMMAND_COLOR_ACTIVE, argvFullString(command, argv, 2)); object->dispatchProperty(COMMAND_COLOR_INACTIVE, argvFullString(command, argv, 2)); } if(needOutput) return object->getProperty(COMMAND_COLOR_ACTIVE); } else if(commande == COMMAND_COLOR_GLOBAL_HUE) { if(argc > 2) { object->dispatchProperty(COMMAND_COLOR_ACTIVE_HUE, argvFullString(command, argv, 2)); object->dispatchProperty(COMMAND_COLOR_INACTIVE_HUE, argvFullString(command, argv, 2)); } if(needOutput) return object->getProperty(COMMAND_COLOR_ACTIVE_HUE); } else if(commande == COMMAND_TEXTURE_GLOBAL) { if(argc > 2) { object->dispatchProperty(COMMAND_TEXTURE_ACTIVE, argv.at(2)); object->dispatchProperty(COMMAND_TEXTURE_INACTIVE, argv.at(2)); } if(needOutput) return object->getProperty(COMMAND_TEXTURE_ACTIVE); } //No undo or specific commands if(object->getType() == ObjectsTypeCursor) { NxCursor *cursor = (NxCursor*)object; if(commande == COMMAND_CURSOR_CURVE) { if(argc > 2) { NxObject *object2 = (NxObject*)getObject(argv.at(2), false); if((object2) && (object2->getType() == ObjectsTypeCurve)) { NxCurve *curve = (NxCurve*)object2; cursor->setCurve(curve); cursor->calculate(); } } NxCurve *curve = cursor->getCurve(); if((curve) && (needOutput)) return curve->getId(); } } } } } } return false; } void IanniX::executeAsScript(const QString &script) { getCurrentDocument()->scriptEvaluate(script, false); } void IanniX::send(const Message &message, QStringList *sentMessage) { //Launch execute(message.getAsciiMessage(), ExecuteSourceNetwork); //Log in console MessageManager::logReceive(message, sentMessage); } QString IanniX::incomingMessage(const MessageIncomming &source, bool needOutput, bool needToScript) { if(needOutput) { QString retour; retour += execute(source, false, true).toString(); if(needToScript) { QString retourScript = getCurrentDocument()->incomingMessage(source, true); if(retourScript != "undefined") retour += retourScript; } return retour; } else { execute(source, ExecuteSourceNetwork); if(needToScript) getCurrentDocument()->incomingMessage(source); } return QString(); } void IanniX::openMessageEditor() { inspector->actionMessages(); } void IanniX::actionReloadScript() { setCurrentDocument(getCurrentDocument()); getCurrentDocument()->open(false); } void IanniX::actionUnmuteGroups() { foreach(NxGroup *group, getCurrentDocument()->groups) if(group->isMuted()) group->setMute(0); } void IanniX::actionUnmuteObjects() { //Browse documents foreach(NxGroup *group, getCurrentDocument()->groups) //Browse active/inactive objects for(quint16 activityIterator = 0 ; activityIterator < ObjectsActivityLenght ; activityIterator++) //Browse all types of objects for(quint16 typeIterator = 0 ; typeIterator < ObjectsTypeLength ; typeIterator++) //Browse objects foreach(NxObject *object, group->objects[activityIterator][typeIterator]) if(object->isMuted()) object->setMute(0); } void IanniX::actionUnsoloGroups() { foreach(NxGroup *group, getCurrentDocument()->groups) if(group->isSolo()) group->setSolo(0); } void IanniX::actionUnsoloObjects() { //Browse documents foreach(NxGroup *group, getCurrentDocument()->groups) //Browse active/inactive objects for(quint16 activityIterator = 0 ; activityIterator < ObjectsActivityLenght ; activityIterator++) //Browse all types of objects for(quint16 typeIterator = 0 ; typeIterator < ObjectsTypeLength ; typeIterator++) //Browse objects foreach(NxObject *object, group->objects[activityIterator][typeIterator]) if(object->isSolo()) object->setSolo(0); } void IanniX::actionCloseEvent(QCloseEvent *event) { quint16 nbFileNoSave = 0; /* if(currentDocument->getHasChanged()) nbFileNoSave++; */ if(nbFileNoSave > 0) { int rep = QMessageBox::question(0, tr("Score save"), tr("Score been changed without saving.\n\nDo you want to save modifications?"), QMessageBox::Save | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Cancel); if(rep == QMessageBox::Cancel) { event->ignore(); return; } else if(rep == QMessageBox::Save) actionSave(); } //Save settings if(iniSettings) { foreach(UiOption *option, UiOptions::options) iniSettings->setValue(option->settingName, option->variant()); iniSettings->setValue("appVersion", QApplication::applicationVersion()); } if(render) render->close(); if(transport) transport->close(); MessageManager::deleteNetworkInterface(); event->accept(); } void IanniX::actionUndo() { getCurrentDocument()->popSnapshot(); } void IanniX::actionRedo() { getCurrentDocument()->popSnapshot(true); } QString IanniX::waitForMessage() { waitingForMessageValue = true; QEventLoop loop; connect(this, SIGNAL(waitForMessageArrived()), &loop, SLOT(quit())); loop.exec(); return waitForMessageValue; } void IanniX::pushSnapshot() { getCurrentDocument()->pushSnapshot(); } void IanniX::actionPaste() { getCurrentDocument()->pushSnapshot(); QString paste = QApplication::clipboard()->text(); getCurrentDocument()->source = ExecuteSourceGui; getCurrentDocument()->scriptEvaluate(paste, true); } void IanniX::actionCopy() { QString copy = ""; NxObjectDispatchProperty::source = ExecuteSourceCopyPaste; foreach(NxObject *object, *render->getSelection()) if(object->getType() != ObjectsTypeCursor) copy += object->serialize(); QApplication::clipboard()->setText(copy); } IanniX-0.9.20/iannix.desktop000066400000000000000000000003771317340345000156600ustar00rootroot00000000000000[Desktop Entry] Name=IanniX Comment=Graphical sequencer for digital art Exec=IanniX Icon=/usr/share/pixmaps/IanniX.png Terminal=false Type=Application X-MultipleArgs=false Categories=Audio;AudioVideoEditing;AudioVideo;Video;Qt; Name[en_US]=IanniX.desktop IanniX-0.9.20/iannix.h000066400000000000000000000206341317340345000144340ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #ifndef IANNIX_H #define IANNIX_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "misc/application.h" #include "gui/uimessagebox.h" #include "gui/uiview.h" #include "gui/uiinspector.h" #include "gui/uihelp.h" #include "messages/messagemanager.h" #include "interfaces/interfacesyphon.h" #include "interfaces/interfacedirect.h" #include "interfaces/interfacehttp.h" #include "interfaces/interfacemidi.h" #include "interfaces/interfaceosc.h" #include "interfaces/interfaceserial.h" #include "interfaces/interfacetcp.h" #include "interfaces/interfaceudp.h" #ifdef WACOM_INSTALLED #include "interfaces/extwacommanager.h" #endif class IanniX : public ApplicationCurrent, public NxObjectDispatchProperty, public MessageDispatcher { Q_OBJECT private: QSettings *iniSettings, *globalSettings; public: explicit IanniX(const QString &_projectToLoad = "", QObject *parent = 0); void readyToStart(); inline void dispatchProperty(const QString &_property, const QVariant &value) { dispatchProperty(qPrintable(_property), value); } inline const QVariant getProperty(const QString &_property) const { return getProperty(qPrintable(_property)); } inline void dispatchProperty(const char *_property, const QVariant &value) { QHashIterator documentIterator(documents); while (documentIterator.hasNext()) { documentIterator.next(); documentIterator.value()->dispatchProperty(_property, value); } } inline const QVariant getProperty(const char *_property) const { NxDocument *document = getWorkingDocument(); return document->getProperty(_property); } inline quint8 getType() const { return ObjectsTypeScheduler; } inline const QString getTypeStr() const { return "scheduler"; } //OBJECT MANAGEMENT private: NxDocument *currentDocument, *workingDocument; QHash documents; inline NxDocument* getCurrentDocument() const { return currentDocument; } inline NxDocument* getWorkingDocument() const { return workingDocument; } void setCurrentDocument(NxDocument *_currentDocument); public: NxGroup* addGroup(const QString & groupId); void setObjectActivity(void *_object, quint8 activeOld); void setObjectGroupId(void *_object, const QString & groupIdOld); void setObjectId(void *_object, quint16 idOld); void removeObject(NxObject *object); quint16 getCount(qint8 objectType = -1); void* getObjectById(quint16 id) { return getWorkingDocument()->getObject(id); } public: inline NxObjectDispatchProperty* getObject(const QString & objectIdStr, bool saveObject = true) const { NxDocument *document = getWorkingDocument(); bool ok = false; quint16 objectId = objectIdStr.toUInt(&ok); if(ok) { NxObject *object = document->getObject(objectId); if(saveObject) document->setCurrentObject(object); return object; } else if(objectIdStr.toLower() == "all") return document; else if(objectIdStr.toLower() == "current") return document->getCurrentObject(); else if(objectIdStr.toLower() == "selection") return render->getSelection(); else if(objectIdStr.toLower() == "lastcurve") return document->getCurrentCurve(); else { if(document->groups.contains(objectIdStr)) return document->groups.value(objectIdStr); } return 0; } //FACTORY INTERFACE private: Message message; QHash messagesCache; QScriptEngine messageScriptEngine; public slots: const QVariant execute(const MessageIncomming & command, bool createNewObjectIfExists = false, bool needOutput = false); const QVariant execute(const QString & command, ExecuteSource source, bool createNewObjectIfExists = false, bool needOutput = false); void executeAsScript(const QString &script); inline QString argvFullString(const QString &command, const QStringList &argv, quint16 index) const { if(index >= 1) return command.mid(command.indexOf(argv.at(index), command.indexOf(argv.at(index-1))+argv.at(index-1).length())).trimmed(); else return command; } inline qreal argvDouble(const QStringList &argv, quint16 index) const { if(index < argv.count()) return argv.at(index).toDouble(); else return 0; } QString incomingMessage(const MessageIncomming &source, bool needOutput = false, bool needToScript = true); void openMessageEditor(); void send(const Message &message, QStringList *sentMessage = 0); QMainWindow* getMainWindow() { return view; } UiRenderPreview* getRenderPreview() { return view->getRenderPreview(); } bool getPerformancePreview() { return view->getPerformancePreview(); } //EXTERNAL INTERFACES private: #ifdef WACOM_INSTALLED ExtWacomManager *wacom; #endif public: InterfaceOsc *interfaceOsc; bool projectIsLoaded; QString projectToLoad; void loadProject(const QString & projectFile = ""); //TIME MANAGEMENT private: UiRender *render; QTimer *timer; int timerTime, timerPerf; private: SchedulerActivity schedulerActivity; public: void setScheduler(SchedulerActivity _schedulerActivity); protected: void timerEvent(QTimerEvent *); private slots: void timerTick(); void timerTick(bool force); void timerTick(qreal delta); void timerTrig(void *object, bool force = false); //USER INTERFACE private: Transport *transport; UiInspector *inspector; UiView *view; QString waitForMessageValue; bool waitingForMessageValue; QIcon iconAppPlay, iconAppPause; private: QString updateAnonymousId; QNetworkAccessManager *updateManager; private slots: void checkForUpdatesFinished(QNetworkReply*); public: bool forceUpdate, forbidUpdate; void checkForUpdates(); const QString serialize() const; public slots: void forceGoto(qreal, bool midiSync = true); void forceSchedulerTimer(qreal); void forceOpenGLTimer(qreal); void actionPlayPause(); void actionCC(QTreeWidgetItem*,int); void actionNew(); void actionOpen(); void actionSave(); void actionSaveAndReload(); void actionSave_as(); void actionRefresh(); void currentDocumentChanged(UiSyncItem*); void actionUndo(); void actionRedo(); void actionImportSVG(const QString &filename); void actionImportBackground(const QString &filename); void actionImportText(const QString &font, const QString &text); void actionReloadScript(); void actionCloseEvent(QCloseEvent *event); void actionUnmuteGroups(); void actionUnmuteObjects(); void actionUnsoloGroups(); void actionUnsoloObjects(); public slots: QString waitForMessage(); void pushSnapshot(); void actionPaste(); void actionCopy(); signals: void waitForMessageArrived(); //FAST IMPORT public: void actionImportSVG(const QDomElement &xmlElement, qreal scale); }; #endif // IANNIX_H IanniX-0.9.20/iannix.png000066400000000000000000004560301317340345000147740ustar00rootroot00000000000000PNG  IHDRx cHRMz&u0`:pQ<bKGDIDATx}w\Wys-ժZ%ےmݸc4!bIHBH`!$0ظb&Yz]mo;;{w4me7ڙ;}>/ÃloG>_b]]]袋,Z@QB!"2%IC,4S$B5sN*_h|Im۶~p8 Xmp 7K/@ uI  ezx;8R.yww7N>d266rLe;0MAQTU^Va&v؁~TUy"˲ȲL-"}J)aA$J!1b; ܲ,9g9ap׌|>_Q  pM7(4M~/ټy3T*Pvm,ko~ Qáajj v0o~>;<;"Vk_9p'EQm r9R*ղ,%(xqC$WfɄ 9HsY$9789纪:R)j (+R$D)((YaeY(&ڿ?֬Yx<)'A*1 T*ڵ zի9ka|ӟv; d``@ڶmV bر[NÃ/C0M,Z}{/'HR_5\APJ$IR bˆa3L0 J4j:(IReY}b1aYVB,*!D"ȔRB)!,5Vח$ $;D@79,8;۸2jc _˲`Y81 3l D$MZ5 wuuMD"iSeM<7(EA:,4MdȮ]W\$ '-:x!2>> K.,L$122J)cAJi4^@R^rR49e9DQ$I( (֌,ˠBcA#2@,9nCnGm8Fm9ymYV&bY,qjY#i9O,eygOOx<>9+Sh"r9D"T*M;H.ο;eC-e/C3x099L&CVZE4MC&A0$ׯG__{ntww[P((H:.YN/+JAYÔRRJEӪ(J-b>Icc`V>w~]л;:.G9w+@c0 b;e-3 JgܹD)D"#ccc{ξa4->n>*yҥKi>i.\.g3=x2-ҞeYxp9|>+ɒ%K%Kx"ccc{ȅ^J$\.$/:0ՕJe|(IdY!I$>w;F^$Ȼ=iz_{owg 2'+ݙWq14a-˲Lu]F;}>K/(.EQV*'|7bbb,K[o{^ o>pBbgS!0O9L^{-FFF뉢(-kײjc>[.NMM՚VKEIȲ$ R UU( TUR"2EᎁW=wǀ4~#C6}>>{}zG1ƝedlCϝi1Fl'ALӄ2`麮dYm j?L&ۉi/fJ)/JB3asDQTe>,;SJ( QFv:,szzN;=`;efihv_ވ@0g ꈄ;@eYN&7 ^s ,Uh(~kݻwJȲ MmHRW\ !uaa^ssΗ8}Ϟ=s 8eY=;\嚱ĕwI]tp9H3G6+ԗƿ~; 4i,d4Mb*cuapMJ$ > 7BvڳgqE0  ix+_ Mغu ,5FNx B{DQre!E feBb]O߻wBpgPJE9މE烢(\Q$Y.y} ޡHh4ZPtدeY4Mn;) A a@ZiE^hsdrI'T) t׮]/gRɃwpBs<`!"d2Iַ;!JIR2NOOP(\jY)>/dcUU%pOl_3NdG#~}D5zaFuZmO4MU2paT᧺ԞN:`bHprYQ.YЪ҃cḅeYx~FEahR) BТL&vjjbxeY+}>_բ|UU#>VSIB[+H#nJ FGk( 8إ^Vi0 ZꌱX,xwwO߿)RD2$Ν;ի݀Gps<W4 oWF"/}>W|>n Yӕ?H=-Ml EvYـZf@uòhŋX,6ӃJBO~ۋ\.D"}<scظq#s\zX|9|>/dzzk B!"2H6?q?en @u+.%ٞqF=x& D:3`giT*D4iT*SWU޻z{{P( R*MOOxxOOѾ<̂x8f`YH4%?89묳xZe=/_0 㬉WWsOUU (DUU~}bGω݃t s,Ɖv߽p;4̢~:qdBM @>kK8 C h4qNZ'iT*0 J%Lb Ş$iSSSD$h"C.]]]p,s<uLNN"SJ)}Yb1644L&CL&ʑkvK~ kQ$ wcƽG"2906ʜq@ƞapE@sp6/f3ޑ$m3Vy(_7R>Pp)uN4MjT*]a;/&-ZK,{{{I:~<@ r9 I~8{j[haQ`N4g"zff!c}swu9c(qsDźTyC j6~#q瀫LqJ :q@冹i p'JjJituuݵ`;,z+'Ic҆ pWpzxp9(,˂aB~aժUXd K&0M3J)=obb-TZIa~ \UUi~Ե[o(21ȬX[w[`ۚ 8LaX0MD3MpS $J Q R2J)TP P%Jl#Nx1޷8Dqbt‰,q܂Dnb[69Vql@& !ci||+W| wƃpDPTp⢋.ׯxGQk83FGG/}[RBUՄMC(E~iex[ .8ѪcO9fz͸3_3n?ga2^OgWƁaLš&4PMT5:P-Gղj",([Y pӞYX_Ssȶ)J OP>" I2*Kd! 2v(q9~mg$W; Ȗ rrLiUB3]]]/]P(U*gSOe$yI,PXR0Jҁ9 QQ()0̦ Q9( \0 gLpA )A'#WAOEP/,b;2n] %9.‘vלgRX.T*(ˤ\.C4ۚH$~hѢ_}}}fZ%###SNT/Z>{7i,T*b&o~Cj:ۺu+V\r||-{yS OvoV?~-OfR~,; mCoQre L@TEV3PLP*& 4P $0BN$\‚m9%39}6 M! >\X*=S!.&"wnA [}v̂-A  d #!!R D r $ Cy+[du%YGbVAR*P*h,}…?|/,Y,Jd˖-sl xx?pHQVq3ΠO?493@ldw^S0 }N6V~?\pRf,3. e PP09llYG!]ҐL4 9bEa LH0-KR`28`@&7ȝ[`+1a0Sr ܡzk{m$D/KA  ŃAL @Xq ~f" >1U9QIBD&΀"ҁDDiB%9w F@}F) 8BN9\.HvV`4ݾ`F-[fi~j*<xC9R,zmo{t]&&&D9JR: " uk Ϭ},rߡ =1rznG Y 钎tB 2Q084.(L** I2 Fe#Й-I fCm2@n' ''9 UNf¼sShvDd |P , -̀dNB0U.X >$">l>"ٙ*I(G]4NT+,r<+#H$XpO%Izvɒ%idddDZr%cH$ݴ=xr\.Go1;Y699yԻj? 9;F=;qXDM&Pvto1$ULgJh*jHVLd IALQap ,B3 a 8D1N>Mlka Sߠe-ϦNJg~J4" T*9{~`[c`h"Nኢuh|x1R)"IoO?-_v kob] p8 Cse~PG<1)e$ |c2FEL LM䘌 U`R4Bhs;7ZPW^XRo"yݺQ|2hq l CNP|̀&TYTgU $uE0C\&I\ Ժ S0#5ȝV@R!Bb }}}p{zz&u]Ԕzjf CT*!ˑ[nx\4OO?½{~X,#H:z}CQ}@8vM nU-`Zg/Yp BP t`J>TeQ،T3Z 3z7Q1 az}(8x6-2ި{Q [ٵ@c5vq@ a"~Ktլ"FLe, l 1U?T@ GPf!5`Ҁ)"*SEyxߊFbE0䤴zjVVu xh eaxx<#K,˖-lrJ2|}|h`pf}>|>Q1]LJ]˷ )DwJre7]pD (StB#>T%@#m`ܖʯ7ƭtpcYk[ɵmcJp47n#g* [k3*k-ŁF\8i@&|ĄX@jU3+e }>% %(A_ȇd ƜF m`((JP(\.BН˗/cgqU,'> |3sws!"<"}'HwwߏRԷ{?MR7ʲ|z0D$lAw+.o1QD_c@iaPt{E 4(?QQ!*4&Awv*S{RN~|s_nY/lot^{ Rӌ֪K1^>1V+$ aO C#&Kb!ŢTDeC d5V>^uN;#P/&hJ%|/lbX,J֭㺮{ms<4wӟ?===g[3. a=VwCv!u&U Hc*v؝,_?t&Q0U"9ѣ- BgR@k 4ZY߽h4cw1n?hvDVltM]c].I> 7+e |˺8 KUe. rE;a#G,h' T*,k{OOϷ/^|@X,_z^Ǻns<7I HlڴB!K4yr@(@ @زω fL>c5K< ,Ns: 4JmTL 618t787B;\'EՎ9hյhu^͌}+>sٓ,ѩ~b!AD`U2R,,prO0 e"p: ;rwcV䶤0T*\.#ϣX,2wŋ@a,%K0 <@uYb1rmX,Ƨ۶m>(+lS~_w4f1d>6c+`< :R&P*Tؙa[Ju2mަi4Lh[m7휓Egiv>α`.6#X J@PA Y*#ªIX ``7tE1P~ˆ"+P_p?X,bR&tIW(0>>.viT*񁁁F;<"QU߿ sr|4 @@D"܎_DBgv>-SE?aG;&ؕb̐B~T%%pPP'ztšZG2ds1`v靔)ڕZe%Z['oF 64A} LGH2d:UO/K68VtcI,R(ˀ…}ڡ^Us4n* r,P(@)}j_!sΩҏ}c[twy MP({r:ddtCvʿ6w(|}"➬H}2`4_ŖMdh"T%?JUP*Dtg 璪$m_]]ltsyͮ8  4wZ^B"?12+YU"bPaXKqRW=_E7la{f:N6EJ!b;+PD"?Yx}>ߋe!Kk׮`cxI&k׮$IT*rOye0D,C0PAwHq7-liɖe"-Vr@(KADT3 @u8ƴ]eBש*Bovv0WaRo"˲[ ) CĀ*#JL}XǠOAHVl38xGSVueew$X|*CCC0 +x89>(.+ctttM\/`܎y(wH~@UڰCQgDMhJ&0e{sElޟd c:E~hR%ُ WQdANmgP|'vN@ƹ}ھ9ϵ\Υ!E>a""*¨W#XV/™K4DUڎ&M_&?1Abt䅝N$hxT"|BA?Xlϲ{^8a4q9H$wikr_8vGlZr`@3 (αe2)6UT|TIeCRj݀];wQe=Niv.h~;ըlZNviNE0Ju4쭲!h/]~B*f~Q ]8ca?BJOAGIڀ!˲_t鿕 hT媪zNpx )򑏐OlٲeطoI{R`0(GQB!D" l 8>Ebe](mMa۳&4%BPcmUGfHkgGݶFh#|37wgnƷ3״}'P]Fkã882UDUG$Hfg.p@A@<08ju7 ϓRR4^|gFկ~%[߲?)psN0>|fntt)bz p~/'ꯍ!ؒvtm^72%A *1@]SpԞ[Ճ!y3\·?6؈vBkov^v׸pf׫Ѿ~Ch!JXXkaQ,*: l@mAfNr [8yh6UUdɒrOO J'|3G<B~N;njj?D"X,h4h4p8L#NcdoŎ :0S%<}?5EC^#C#HZh&ĝNEcsS# 5Bu]Dh=`ajٚghuyvr^of[$ kV}VbqaVD<2WP*4R`>?%)8 #tfgq$t~ώ`'n,˄sfWqCЋl6`0HS!psNLNNBUUǙ$I|v5]?D|xXƟ8eSɏ: Bd Q ܷm r r y_$$BZDDJTHvM7[q4">hnuNRݤIα͜vPH5n[Zl7&͎hN(CZ2S`H*/Saa4<"@(W<㎳O)%,,DeZ.?Z766ƿo˫Vh ñ8022B> .ٯ_k׮oB~DHB!Y,0LbD-a:0q<1}2I_24lpBIꠓ(moͶk\/MlHoNKV[NFIoU.vNA\fdO`F)A#*LYS$NL![,BUHT8ـ9xgU6%SSSWJ /4MS BDQ~|ǨVD4<t``2MS1qaF  h;ft 1שL<7 Y@@P5LvPU*:^7ro!h^smv:jҭjιӌK;^ o1:]]֦ghu  *!Fth1T,gX&8wq/.[!P@!!5ifAe* * J/J($NX,x .dP˖-xF88~AD088|J?ሓD"]wZ&_~% (@Jxp~<{ rrFR`r'0k"_O[h~+iخn.ӀtvsHHfYFvWkII/vhG`@}~4 SN"H*#5OǞ#r=\QB)ⅩTt?F`PF()xqI( D"V(⣣kmv ch4JcX-W9iNQCD_ɯl ޽eG&-#x>cB#'Ǒ"AN/~2V7VFV7VFU z֝[}VZo撲?F}:ͮ/ڬm8 >o+nCV_sD'@ŢJ>hT`Q=SKP~U*$پxsqewI pN)%iJ.,k" nGK.b9ñp|޽x7UUW5~DH$@Ǹ YNQ^Jq EB(Qh9S03z_F7wv4m4pUh$-jfhWVhyK8s9Vlݵmus)4>c#"YK(#dpReXl> ~[;@!Js*eR p22wZ44MwwwsTeF&ʕ+apsG}/gbiϗH$z=@$SϴG `Xgxz8McXQPȑʚ}ZS| gM^;:o켃. f7vu.ǯA 43>{'dFuiV81M63tK:ⴊQD@ˠ*bM_%67vh/Q', w^@P@>'||ʕ+?-eY7JS,a8%ɖ.͖urt۬n݊鹴O zzg_4ԯ3Qh|F[a)@ LQ4U$>-}ILSTP2(2trh p I"]LMMiڦj896ȯk ݻWnݺB[m_w~>N{p4 ([@$H3ܽi*c H#?eJ~ޮjZ1Ǜ?C<]4?s PJPaQP|d)TMXP*H~Kc?nr 8DJ)1 cY2|ic;}>WUNOO#{cp0(E"LLL\y|+}H("@`V?L=e&d|wk ܏{M`"FV#C(nf]ZEonou>͎g:hMq ' Q0dLVATJ&dLPa}^~8;!w۠ p˲LLKWWՔ,3 G?*YAM9&2==t]Ǯ]^s3씿ÉZs1΄> (@F^Lp}hSRY_7,4oZJov΃l:j\pI$pNeLx~*H0Sf|,A\F9 WE\.?s5wqd$ usMЩ)622ݻw_?55@ Hjƿ~Ois[͏ %i O#x)d| x%v]"XynJEe{aƀr` (Y ,IWT@!B6_@(DD #ORZs6~N쒁\(z .yGQ{cplg;w###oBzeFm~sa;]F쨟 Elk'aB׍ "Oμ2@4+TqW[~A8P>X `0\$$!@x%s hɁ rT* _tig}}}j186P3|?iPȟH$`;5{, E.|xf@ߍ$ !o;62xaJV8/z N78JK.Ȗ4LNU ftSuw25G\.N֭+޽yxG;>>7oެ+cBX,#zsm}0 3)h5oiB`3^7$ov5u- 0 .ˀχ1:9L.P$'wj3. BHR9kzzzNٳJ%Xp8|]SN!{ LNN~4OF"JN)l/}xx81DW*;pm~#cp!Sԁ) xl4~m@R<8G}O\='#vbS,T$P0:1Rh$0Dz@l>,k:]/_|좋.__뮻~h_yo9^lxxk۶m_2M?d}ES YHWlaQ#{=I ʁny:Lg9O,pC]aYV/.ٵky~⋽6lH$x<8D"p9\~&vr:d<3#FZcQ11׹ov<ñVjҌp0NePEEcljBZ `@z'1Ms$=zL&C\xG*x!?qxk^}]OOG>>66߾}E3cXi~ qOOcsCDAAvw{þHc|ڵz8  9'l߿_޵k?7hxw,;o}xl4i)+Cw4dfqv{a0 <S|,.c}z '7|JCC;^F&@QqJ"@8!4^qƯK/t'nk p9o$L[bxxe}8F4O\d}t`gQǽ/Sed]qLh$e6ٯ퇃GxDqn@s`HY>XHVF-(Vhb ea86NeZ c۶mZ0^]d _jZTU=W")9f;w_[/`PrzFDzq _4M2ټ:VB1at38qY, YKE(}).hN]N3᧔BQk9g6mT1M#Sg7MW'?IWգ}kxB@eI|j`0b~~s;qb1rk>l`2`3  pJ89 ,}*UD S: ,[0VrN˴DDziݬXy,էW!P!4(wds˲i* * B~[m{Jn>80MȲC^W~xW|>_3&w|fܹi/vi*~XiS$ۯ_Ɓ?Y\~ZgH yЙ(WRD`] 8'.2 1 omy,C8EG~[֗CkQOOw[F#A U+t?<_ +z?6D~9x><+DSnYXΎvWgǁ {o~Ѿ*"F$YNfY AX0! 4L ׮; *(7[-P$(c4M駟Nwyywk <J;bJl?!w!"6'F{>6(4:ƟPڽqzOOh+FD~*"C , o]`5uBn4Ѭت[. L+gӈWqP [w:dQ*k9 h&4MC\FXldYiMV.Zm6rJOe›@ e'2gc79bج~>E_6ld 2=ZpV9Ss<_MK\ *z*|{/ۦƀix8t8N.eᔼa@| w;:x8DhM/Gm3-T P j<{$ڢN9{CvkgH!i2 3<3_Zv xiRH$nh\9ˉDҟ(swZt;ցdžpaca=H!AE{kA )_.u %]OG})2pfw1 VQpЉG;.ez )\8ןC"H p7Ma@4J% r10_~83/^& e_UW]xWCPfh4J"B?9< _)jwmڇ},|I+%$ZG<4y1_יOUlKhSh x">.Έ Geqxx.':<fhNv3*T@@% $ITE,EP3eܜωeYsNt]?=ɠT*=x73MӨ,{t䪫"^{-N=T<裯عs>G'qb'\du4zi~dH!) 'O۹/w^{™Q[gXf-W ~(E7#)`UD8> \%[ 82 m7-neH(4j CpgNU/ Riĩ,|xxb}u;xA4Mgg[iӦ|wuuHB!|鯣|f_^ΗbWUE6؏4 #k*Sں=Ԏ:p݀*3#3^]"+YV]k`}Q 0@3M$!86`ȏNYjAA-й*ai, o~o|dYf/9=' @<#, aNoJ$NN=ڷS0{|q'-"CJI` g1Km1˺|co 0Z=3~xqLtVh!`(}r f;4d~,~mO6iBuJ%J%dYdY$IT*/~ǕW^wApo^@k @.wxBC$M>ZЙLp#dE[BFr&ް {A|5Aeq{^a 駟7L&C4??0ؿ}1hp6g.hԍ4¶Џ F}@kZ ;bXl!pRο: ^`e 3c6/U&2gS !Ko狧 Ɛ9;̑;ڇ[I7 ?Z8P00L $CY,C"XaY1 a8|҅ :m8"m[P~nJ=ܳ`rr6UU/rpM߁!)Zn?Stxb m#)iaBjO(6=~4*Fn>Ly4go'Ox[UЛiA-c iDc`a o>, UHD]ʀ4 R \tr9JjժyVPH+԰yfp :9S0٬؏Vs[Eܷ},B )Dٰ#ν6#8h~g9vH+u9 ;&A+{7|{q& 7,ƀwoM& !{w áŁOm G,謘>1Nm&,y bu<7:D`+^wj$"!N)! 0 㚦\.wS~2>>{ޗ }c=l۶ۊ?!HD"AbZ u*gQ/:~L1$-Xީh5CJDKMKkLo~5~p,2 PLk2a` pjD.g>|{$%NȄx#FNL(X eȏe3N@'=Nl$\,fJx6%R38sήku]:j_L&nN_;:eC91(O]wfS}Ula8?`-p[6;KBǁ읻R7=ODo8M'>)cG±ݘb=>|z(?j~J`!UOlK,[8/i_esP Hip0ںO4ˮ_u9d' j0dY>c۶mݺu+뮻yo8餓O=ԩ@ `0H0oX_ Ԟ1_o:)@tF3Znս-g,DK#qvڏP22Vi)r5_܂8̺Z?;R}־DGFF^_;.r-nbO?m۶o1 v_-j'?lExz"3\,AfkՅDglFy3(=#w\_IAu(VM E0 b#]xzn+zHߝo_sFNI 3 (by I lY/xZtTH3R`})\.#\.L&T*Ec_|VZ5FI>_#'b'`f.#W_u]6˟AH:G,.=gwYCۆ1(H#04b c\> uǣDyMx"E/[G7,wZhۮׯ_OVZ?Ἤ~pfpA(ՋNc0./xb_Y_7rrYp6C 2?zafNx gEO^w`zB~_Lk[[\$T4Mż(nзMt?r:pys+`;%Kks1CTn8.n^(ȩI Y'E.[=C!&:ISJ(`!@u:"u{xG_r%iؼ ۮSw^wfi䥗^_{t:GQsbW `[Gv4(H~hiᘡ`֧nk5Jիzh y)Ɲ%!q֞ }"E]Imcǀ?oDS' bJVͦuBЭ; xBC 2ͲQ78Y(d?SM16\n5*m]&=0HUU0 #@kR H)cccd'uo$rL •JG7b1tuu.b3] 21oTճ[X L:Vs'Dx1} v=a(kʰh߻~7ž(<}msz+yI\0 ۞=G͌x;{VVZ&G/`g]ƅAD€QlBeYuJe֬L&|>?|7]ve}kCN2hFtrE?񏓛o{M$?"Ȭ ށ`K@F5߼S^L)ݘ`!In>wy. ƒKA￘l[G疊D}`ѭ r%y\Ɓ%,i\!X7n8ڟG4vFG'sL "AA</?aPITN :+XU (r< ͒t: YT*nxާMLLЁG066֐_w{sE:- =iX8X;vʟo[3yq8RR)44'K5Sj^#<7UW :orQw =Wľ_/ NsS~3q&A+y=?9$fj'D=m&]"^g@g$w۬C3PqR~Ez=7_܂ ֡'uŕeّ &sMx0$tON:_'ȭ:/2  K,-ݍD"8L)% Sqs[Ԕtx4?umz7Ky࣢Kgk =ѥo[ 9TC~ n<ू9X)ߞޕe0pb`Jx@>d;fA!CRVq)p٪eݙLS (J5mt:M4,zxhh譗_~y+$>0">%]w`ɒ%'?wd~0 5_G?? ny_zp&q[38߶D ֩,FN Cu̶mU:g/WT|}$iriΟjߠ_(]'} oZ<~}(c% $ u€$:6C >C ߤ&w#A^=x< \43}>;gs֌V33DKu9 :n&Yގ(*ۥ"Ï _D(iz_Bй@#( TUE0jzꩻ?mK.=W5 !SF4z{{w۷݊=DDњ޿oڠTt`_/ٌǧt $MEDΔvD&e'V.dz-Qw0w/޹8-x)x677 蓿8/, => & "NbDZ!vt@LƾY"2W|l9p鳗y9viN:P4`\+84r%F5MCTB6E:\R)ȲN:P<"P(tXƉώ3<<|S(R~?wXaA )Z=c0YD)؏FPgZ_t/CmN t>7^? 9~jn=QY>\ӸS &9D绲W'{ƅA/[thrVp&Lci87. TEc}NdL^*ޑB8GO:8E_lNݢdcKDwwܢQA3ݑv&@fi"?R_Fܺ z,㶞ZAA`a0Q[i>v]OhBq瞿޿b]]]4׆8Εs;g@*)SϞڌ*>d"g1M (2Ҿ*}q@cݱo侹DC"De(ֹRѷ~vL85 0UgYWtZUe>*QˢcWN͊̋">xDiiX>zJ'W4~cG6m!LhV#JZ]ڴJ/0*ӈSsDD!6isSt5MC\id~e˖~S8"RtnT hlgY3|K_<'  P(ă ߿? w`W( erH4^'*ȼcH,Z̈)Q۷:R\ܸTٛͪWCm~_.Qg3HDe x:<L)!S\,tEnx|x <gx&sxNE8v_]}o[ =/t(|™e*331/ьhFCmTGP2TP"ݳ' ✥Ck@s^RV yR!dwolΝHRtN6W'?5M3귻EdY4st.Ҭy xdn{qKHz1bEDXՌ꿢 `ۿq@0 >U&uB#s=5 D)x.'~_D/>`uTkv{rD$f)~4YQ{, dBT?P۾=g ۮ p~큼R]_1==6կ~ -W=g?+^?D"xy# x g9gyқ::)UjwD$ziCRCirrt:D}tN-R\.ÞSIӼo7| z!rWPs}{_r)|7Ͽbó$;G$9~KxhJI =ǠCPDqaO ܨm0੬cZP~޲@V5D<8>㸱6&+z5iA{,- >sZD >hEtL|y?}Tx볝92~}pn!EKs/Dm   )U&uK!K p\.dz,2 R) /{?3/^ Pry{n=6luWWWO-|4 (c&1B0~3  @V1 QNwJHOP5 &j/H5Qqm3bBӢEpkQ8tsEPF`˯56|-﹜ (;%>߱w8pjD[x@SIq(:UӽĠNgF.=$qA,u_fnUiyd3ѭ$9,҈eGp`o|UP"~ W[`Re2' D"7_￟\uU'<7;_җ˗w>w"@ww7O$$m?`8P6=%?{b#h YCdrLe2GPqE}`iw0FIDAT >98c@_ ِ8~3/gI`QYD#/pE8M*|b)O,ElS8aЌ˄;)81 Qɢ44rΩk Yj|>_3l|?uk֬9ڗPD l7x#ࢋ.zߔH$`kԿY\t `85(AwF}u`+f9Ca`t<8v,7Ľ%`rώ8pQWsᚑ =`*>QJ8=Һ]osA<rҁJ8WU.r=@Lxu07o_Řp\Y6t:7C thM}4{2"?U/♝{q$"`ܖPi$ ZjJJ;vxۚ5knw䵯} 9075kzH.c]]]x$#kp[2eMPV /"gJ(HJ۷w^;H@!¨% x=qe6K+ tVDչBnN\FHBqIQ^ $"3E,8`0<qor|nH })d}#BӲ +%u\*CtwJa+.  ,i$cx%3w;PtVU dH2L{:}^{-뮻NyBdL$?0֬YH$jh4Zay x~~.Z0rbkkhadѥ}`awU~'m3: MD{/糢;\] Wo^ +co`!MxӠݏ7qtCIq?q|DKp?OONy>^+DI5@tRlFXnvk5rr>%bE8 )zGPUUXG *4M[cǎuYq]w|\yǽpBd6mDV^ʅBỆan]]]v,~`ad C2 h)'f/U~.8zɄ ‘lUKnix#_*HvyGd3D$f -(OБUxf87!:eҺ`?F& .5x<>Lo_|1{v|17~sہ޺ %x> =u lNmRC<h z pو:r85uJRLOO#!m ߰z=G*aÝwމoo޼GyױX,ݍ? v4sgXE0sܷ/׬]?9)9Zգ V0dΉD|*mþ,O9C<5s]1 !jWk3'dtIEOE7EyFQe `kA{84X4pDd^r <7hnֽ86УVKDH;4<L3">0Xc1 @\r3ᱴP<d>b"N Gkh͢r0H{_@o[p+r\|/5~1N~)A 'QA3UI5\n݅%݈T;8%bY*TU~@~dO7mիW_|9M6=ݍ.DQ8\D&8xpҵ$G"(t&U]U<i9s6j%jU&M?zE??!Rͮ#!/jΦ mKWD?BoiAZ|CMٲ]rfQ8߁yI܀^m]ϵ0Ps4B_#%S.xԛx[Gu28i$zbye̡~1-R0M!"t:T*E٬o~ׯ'gu1vs=Kٳ-؃3Ae(RkkK$4>,*8&,?g џf}@g?R!s^\翢[-awRL]\""FؾePzZтH HGK&!Re!C2$/=>a9%#Pakp^uWIdyU9-2w'&{%'pE 7ቌHq<\`xQbӲJ|\UU2'bE696NbBP GP 3~ܬ8퀍~ ?6zU7s"VoSel)wOgFƄk6EJ٬ A,EeOtdFq`5x>+,Y:v:ʖh{!i~W(Gq}MO?c,|}5EK#l._|v =i u˝{0$@D2SBQl™㓈/YPttdTUET,_s9?Ȼc=dE{1Nj$ D"&4Q HgnDŽڏ1# P@[WoZ=a8B~]\SâpMa=}">W«Dk`Q`i3%Od,s? B*[K4 owcp؜kFW ;%&>CsAD+BB߫2/ џj1f$&֋m)< :sIw-_m@p{HaD<;%'_nU!9n]R:e~ 200pRa͎?l߾gu_ljΝ;4EQ᪪٥9oC$Hr1iH(4 B{p:IF0+Bc܄ZDk!drQ[]/j[mvޓaoWVҖNZZ:頃6e Q6 +!!dx=kҕ,'&mo"#Qf #.J6Mr`ձԪ\c(3`1qj?%J=TOl9iOcx7f5y떡]O۷|zLT? ܶ5yv^J{f -?ejP/Be'4 $;ځ TD0h "Z-z=F`XFFxΘ1cu]'L81HvJ`Æ Buuގ{{{-++3?N`Z< } .h'ue6ՠ5U$4LqL&3?H3kl::qgי߆ Za}}ғtd'sQgOiUW{p! t3ll#mcT ty]! 'mK!2Rr#Zd)JHW'pЏ`] 1-q6 m[M PxQeŬo@qY`&J@: ] c.؃mXZoǥ'-EIG,u$O # !z^s\~O?}9ӣOGy$S \p8P^^.9Nv_H_Iړi® |+:.''O+op8Q8 ~]N+7бN,̦ZH4sLEDÑ4:EQę_^࣐@(EzEgNQ1{ EǾ%~{GnpX V TAb9f@3;xhzM bJ-VLS%ov=RrO2m['D+TLY+|W^N D"Mxq p\=t J!L""rv#9ϝ4)XŚn99v::S~i4[Yn@{D){ 0ǖQo}j$]=[F&6}bwNƘm-/1e}ISv\v&p+(9``> ."i-!}غWV*fu:F`2$< 1'x~a;j&vkI>,.3,K`r2 bɜE`G[)L[ KQj$'JA~57|trUb"ay_p-H7nj,JNCZ0 E$$X ㉕1fNCCą8 ]̈\2lJKYN |Iìq lцNjSq'XKKdo6ؽ6 "pi9꣛?WlgŌR -)׬Wg[ d?IM7qrXȁmKLNZ {Py3a Xt:7%0 A.vt,X n`0(bG`8]w%r)O;\S4?³58msaG\ǝϾ3=7g=C`'𣣵)l8,_6>Zg~P8PQF@h5T{p8uδlE("#!H. ^WpO0e˖y)Àك&v,^xG}tZYY`0$N'(@J"Es i#z$c{]Ś|>a 4i%l˛g[٣_(*%)6agm0x7hka=#$s%jgy`JFgQCt#*8o ZBkSx0^7O,gVF5t<&7p8l(<b*V}v 'Cm%6sL2@ `2  c[o 'x" hO=F@:ƦMZ---9Ol6C ˭4Оԇaw=zthJ9G)\?P !]O:Vvo)Pծ{Õl: ̲ʹ/SK F]aV{f=r62=j=aw+8&ϣdtE7'fTeZ1Dz ύ%morh4zM|* 6M?$Kw،d7.\v|3 Bt:)npܹs4s~(wq۹Q|>7(K&QhnV+L&SQ\&5]n R4vͥ^Rt& bN̶7 =ZX5TB`'͕R@sX{Xcl6,_ [Ih  %DQD"@$A(< ׋@ {Ο?ב>Eڨ$ftIzhhh}N' C W/!WJ!1Q@.ދ"7g_Xjg>_ KmX'}P:li{FWX򇒵U8ApĽs[ o 0${h-Q*E^lK(&l.$RVn6f.d׷QR~:A@ɘ_ f0hٶȅV4z:7XfoTK$&(Z5o7-fc t^1"-AȀ1R$Zxu*]uVaƌ9]F{ FIjiiA[[Y&)aJFQPV\ٷE;ƞ/B:+"¢H$,LL=JPpPwz),}8%Es\;Gx_tgVQjvZiapb;o8oL.S4PB+9 ԾZb$fHj4/Czb7gup}#<|HNKzkM,G[R9}pᚁvla3 !jϩț ݬ̪!(`Yco[&TC!aꋨXfdlֶ?zEnl;ؾ};#qhnnzg)L&ֿLan7)$-%S:T͌L|h@{AKHқecv_%D++WMG*NדIrؓ?pFY˒USizoEJ/>)OZi>G:c!I?)fBN1 > #m'|m@1ZpX0\,eZM HK <ۦ>N+ށvXdI]_^Q/t%6X>T!q|hIP2grwK#+":vuaI-5A J$(t"8t.믿e˖16뮻c2/ L!3?.$b:3"U" ]:Qqz$+3v \/LgNC;eFi #Є (ːjmQj-Tkl4&Y~^aGhLK?:po jn5A_m{D!Ӫ3N/(_<(w_N594P>J.㣅6VӔ{!ruR󓭜ָБ;w~R"’;azc=lF-DXAe4Z2LJ~kvg}饗pg3Fm`ӟT={6hOJ?L&e`?IbGًޤDI)Bq/0@5ZfpfFlT e<׬c1ʀl{·!-)c=f)!$]76B ^|.skOfSb I8)W̑4IT%}\VjTJKG:tr9&/ՙx-Md%R4|~<7)R"zs(.-x :5մR}D UI/!sSZM #|~lsJ_4+ߘ#s쏈9BȀ!/*y>U*#i+J#*KۅnEg}shZ-Rޝ8q"^x /TxT٨ DQk&L&[`r((~=-IHz1"*0'!@EEϬR Ju\m:P `JсDE8y|{~[P#*[_Qh=7GG4V)Mδd:$[b"G+sz ~KN|=%ICezZfۘL+0p3gTA0^=K1x޿R҇b4ez0ʴR%vJszs VyVzH9+速ON[5|ɨ|}8|~v?U a6װL+kaI q=?vclU9 Bq< &җ|EzW8b6*u~?/^,w^}U3EwwםN'ʤrtB $@$ߎA?>qUQ-Da E›+~!;N9Ìc4-ت `y{SKkǏo0oz 6YS3af=cg27HX5Bnyp.+\7);}*C; |IO فǩ#`$ 2N+$G[G+{- u Y;Bu똘dE#{D_'?au,0'Hb0$@>QH$@ y<\."hhh3رC:u(rlt2׿.Z۶m;b(P3KKB:,_2]19D3je{NЩ{'I@ \$YPheFsf|6!"J7I| D|,8ѬjiI>Ή.(9;B`jxK\rP3)|?Et*NEQJR#k'3zsx؟dtmF,-.W' \@'i7E",_)/doO"23ܣ^5SoM~2=wSl @N de FtV{}umPFeLNC:ggx֭lFSSӨ F "^z%!jJ555g]9iv:(//Gyy9JJJ`XF3 ,'$o ౕ-iQ ޤqA)}"9}vj̬)c0<.Ya}; a/p0)iw)Cf zVjpNN*'S(s{Wd$gXS ssgΥrwXP},MO`Bi(\@rmr?n3 Z?[n|sbiN ]uYqy0h#*xP~.Kx<΅^x7_^7orf@spwK+V<̟^^^H 6 Fo` %viE-i1O:|o 12=I';J9Ol$Lz&$Ѱ],q'U03$`qǬ+8l(ϱNgN/t5MHlc |FybAk3V:l@%?7:A0Qb|ISh2PTjzAXl}l~6^X#=(bNW~j)R)$ID"2C<d2]|W{9/m+vxgpWbk׮}f-w8j % 莉G3WiZ2 NǙ$]@(+}e+Ɉf:ˁedEf1FoZ=T_*igTq?jM27ΌCsElxͦίaoźd?F.HI;Ix; ܺ\j#R|s5| ǔ&^@Vp##uĬgY5+sG @(9pԑ#}{=EzWc4&{QD]܃+OYyc@][lT*h4`09.Yy}N={6-[[ }À'۷MMMRGG[n}tZtnl6  b `+VnĎt),hMU(؟@ȏ*dU ̰^Af|Bh(E''dN>¬rfC,T2m[j/kЭQ>զs>UˡLh q1v=p8ۓip~Q?V%emΏ|g2}]4-t0`l/#wLbF?8&wmn0? |a\`O&FɃMi9KUPxOrxL;3'9=a=m(^_^yټZYjZ)Ruh2E xkHD6*Oi@Z9{oDɟíYN(H$Paa* JvvruviL:bJ B)g5>e7SFcKt@I`I'+6%%1 IK숧)¤(G(MyG-gT~M4j(\TwS&|kmQO8TZ'Z.~g5k֑-ofwlȼ\Y b:K^C-KmWz[3 IYy2K3ˡS>_8€ƌ@hn̆zYApfCK򠠊p8<:xGkv0g(('n3Ud48@g$DwRDhFLcD8k˰bz u@>ۃ)_a-oBBQ;k--ゾؑ_i/%q!^!=P)|̄kM$mUxlMZք42oݒJ@Ez<1';br Ch)\LרagŵԹs3E|0J?I;Juϵn8w\?1?Mfjm{tpT,p 4~? f-iDk0ٹncT,ofqD=I;[;+WgϞ}sf_YYY`""^vD*i@։!2uBABmZ T7ɵ V:2yll]w:?Q[jz 3X\&Lq^6-3jEi&;Y\Y^FK!r=%$:Vϣ+1pHn8~|7qj%A:|>Ss3HKߑU-VwT? w-cvD-_oPA`̯ NjBdxn2?WLX'pAUol?h'jbn\,]+ʪT H>Oz}^w[dɨ =jNJ?>xyKK˂ҾHJP+%HZ?#U*3nے1)sZCgہhpM=AMƈp hŬ10HRaMV`RTAzg4Ǐ,X0*Q$IVQEx(Q>f Qo4V\ckB?#(O&ԛ0zEgOMb=@o-y՜p7˖η$j=:Zau~g^Fostݱ}hA_0{5 2mg/)k%3n^YNkF)9oi(5YeՊb7|FÒ7'67J`Ml31r#-N}=\^S)0x#L$p k2\`ť^*%X,?fn݊ovuup|@d^/F뎦xmF<|j#نSb I,bԇ[ԦWOeKzWqm?pGxE''̪%td/Dj]>V[DZS]|g;7jMXTa`gr 0窌Pb1~_[G_;Xwn \`),-Cj|qеR ʞTאCpIII .$&]g[6l^Fif>s^PKI(CsXŸxكX7BmSǔJH48L!"x_@^/z?f;c7tm4v¨~NO?PlN~i,v&gcF!mAfҾ& y!%e;#ąAѣgrA1izFxl` `x& SMp \Lec_6$ 0=o5-)ʶہjb4.R/+&*NCl{ ob gvq'$~M.эH.^4'" @2D4E nrvwwy644>ҧ$FE رCۅRww>Ns@ee%***F#2$ѩn7p-W@8 ZҐ]`T(c/S*6(2;9DgBk"G\@Yr+47!2Z@X N3N$KMyYj 9RĖ^^GgђyW>"ͪe*s6D_<0Ww|cX>MMtfjaK;& Z%eFFx7m8yl5.:X3+"$bB<$ >/6{-Zw-L&vmGze<À$~ xFQ:s>yv"T^^.lE4_۶/liE*J6i6 );|OFf")RnTGwrLHS3KQù}v,p\yjQb=f:(5UzIF̞|u 3G0T})+:I,c]-SS*ۀ7<]T i6y7J+O6 ;K3J31r= .VJ)8)4~4zQkR \~EYD"P(#nvg=ܷ?K[nf̘q'B!뮓{1!j Q`5Qf"~DG\kBzI_h>1 L='Tׂut'ǖ gg>W{SOi?g7./VZv_HsTG[8UeFMv~ %7 \ok7~ J^O,'O Sͯ=|s+x[:\Q=۟BBGztZ&Ss;N_EqfϞGfTt$ᣏ>kK.DWZ(++Cee%aaX4#*lىwTSZ% +@%$iE[Ju|Ԛ>5J$O,Xnk۷wrJ`ÿAV`˷_ r ocXl]ߦogmm7L>meqG߶ ͎zY7k(MBTedPSG" Q> pὤ bcJ":d;#?x'[NP?_qQshA[mU:>뷐9 KFr 9/fii ৻_L^˙Xd[L8ZKߖLѨaLʍP;>\yPwWxxp~.Kr\FEE|+۷ ӦM;b++@ 2k~FQ`$@_"`)L-U(7DȺ%a1ͺbDZ@Ky}`Ͳub9x;bus)JcʘH_b9yJFmA֐՘l%Ir|{?DiNh6|g =%e4νYsag2x&8[{,5 jPiGMqj9߯1/LC\TWz4$9+ 9-njzȞUKtƟ&م %qϟѷF 1Dj2'gyX1jL"mmQ^/R@ AހDZ$C2N;8)3YA)ak4 3gl[n ؽ{7x㕪C ;Hˑ涽xns :L;n l  ,iZ"2btղ}@lafp|pN `,г3D'RbZ.sl4.-|;|;\{KtV/9;]m$@Dz^o:85z pEӱXg Iì\b(C=pζ8pyF=(<'۩RrXmsFkin rH4ptc.&+Ff+/Tuǁdd2@Ф!у@+ftPkS2Dۋn! E/_~Ÿq^g?;wtH) {Ǝ+444 NlXVj %%%hh0 "dk`/ىfk> `[Z̾3$9YqhؒrY=pTId۫1T}Iݹg]JGȢ/dcOwLsS#$Ek3v pY$Mv^B4i:y5F&-aK$M3.B&a=WV,7T+(J3mZM|Pm2gY@B Pog0^[g1%:0 E ^%JD*r!l{^oNnMl$ؔvS\Z߿&D;lqP;_Lfn?-Q d&JB7XJ,0&UQ +0IHѨŐJX,IRk'Ly' G 9R%iѢEB4͛QVV`0JdD _"O)Q$-=:Z].Tf[1"@Q:pn<;dwWv#JԢ\%u*/q _bF%)lFA>mlzX.w?%u Vy9}!FGD/cYn4 nf=RM$+3#WDȨ!jk! >0q2|zHL`i"@#Vu_L\6yP+PSݪO5>f?=MtV/"[gϫ~?r͊) Hy"wLR'bn -xW%pSs''Z$AFQgD$?8KAASKZQ'~[g?K n{q}0R . O `_1Q(<8RE YxWWt\{L`Q'-)#PK?ì垌ep rίr ,6^oj]N̲y\G7j)c03NJr&ͅԛ46O_+#6z2}G}Ugdkesx~z;L*DNHزjy /)Vip2_G]i03<^֌Mf vVnݬ>0)PkEN`턠%l_Z?mH‘9v7{YGBϧ:p{"G& `dcM9\?a_~W+KkD ,-`hЕMz$%nNI*Lh4H Db`0HV#&{\d> KDZn=&k(M6MM$w΃-#_?jۢ,iж4pZi*ವ9Q@:Z,lk'~XpE-+s|v<$pHP6RG7g*5mはOT'FMA>J!DZvj,p0O`LN [KK@Tj"<y{9ⰘvQ׿WC=m۶k/VTTp8rTTTp&؂NJxg>sS3:uh7T5mCB80;{Vs^~rϳtt+̢>bb9Vn :f5`L[QƖ6hO.8: 3 XWUhY-ձfnp)$.yZ[7@&P;V$Iud9Zb&Y|JR~O2ܾrݿYCWvKt+26pF"jvv5lљ\x DjHƪyS-r/;팱xrEwKT[Tj㭜pRRw? 22UE",=W9peFJLslm نD.3NB]"St:r~M8qMލCid˗/{g_~UUUSV^`QUUrp(xc"^\6{S2-*Jx\uzp q73K:I.$0s"ŵ\8ugZX+ۿ;zNc0h_A@|[oK?!s%83`zNjHXޑ#JDxoi}爛C&`yW{зՙخɹHC$M~wP ? \:N_Ә$> 6Lp'abM  ^ %'xɓ曅SO=_~HG x<m3\Ȟc(X1z,V:zd΁(B/#ДE} .7oN? "O(*#fSQVVv_wwo͛Yf|6>@OOfΜ)s=ҪU]t]n/(--d^tp@2lc@m~Q@e&fgiqMKXVۢ,OYհFzu0)r̓---m,evtCbӛ`fZ3=aj1RJ29 s̚6WBXKWO:i3jkZ.7{?gp+ JdYX4W3rюD!Ԛ8f>ܻVshAZ)l 8gȴjGS蘋,OYֻg&ןL{zIt`Jckc3,k]\B\Ԭ%Jp+E@tAzє#؎epIKa׺JH$DGHR655]z)?caѢE#6YfaΜ9hooקR9#@JS 0j2PaP*MtFݛ *͊%E:ǵ>fm'Z1ߗֳԙ_.BkDžXξy *l'ٍVmlA>:X OG̜~SS#G&Q7ɝ7Xc7{FL l{c(ilga7z`}n,PE b2d@N`QaC7^[u3Vɮ3oR`v*I%E eNW/> |m М#mD>Ӕk`8iPTh2AZ" #NDIf:FQPmV+MtVV[ӦMCmm-0m#(I=N A*-K$IP&n By")WHZ@DE8GQs'ӟ𥀼+ oY bP̌:u>'_hǮYv<ۦ#@o7Yi6fI2y1Op\=&a?S}`(,`tpNyv2-d_@hʹHDlv:Ი)dS J38ps[.7>6g &.XCojb08YU' 系vGwM^orNwAğmvﻠ&w+7#i#]+`„ Ree)+Wf+q:DEEJJJ`ZQR"K{<:h]Ҁ."R .3AFBb_EFYnTx*ߞ[G> nqd+fP,VFN=l2]dd6Yկ#`^pXǕcI6فHv=onN7|JŚYˮ/ca0)-wțα nnRo&DBgᴬHNUϭ^OpX|t>l{ r-R&C?5I?\E X] 1a?of{7\l𗹹YBK$}~zP_^|dk5_ (T0|]m w2҃ g0DXld5@{/O^^!d2B8N-[vƍlF)UVVMnT :uhN~`@>5lSk p SM◚E\lNتoHqNΩέzcZN8Rn\.v . _kv&O<vDKpk֬ 7 xWד W{ 74oקcn:A¯i/QJYǔe5ߣ #xWoO(!2 i@$:e%Q"T;Sxm~}K<(Dyjj )_6_)B+*~mQVZI2$&ZJX{`1(Lz3W|uuw,]l `rDfqGO@wkM|>'l om'R[xzY hn>Oz+N;&h 3%lCo p'!`e6Ït)3\v2؊ ǕRoorݽqɒ%/]egM3b%^|ػw4qD~} $)/d őEJ0rm@mK-[HU["w `/V dWo@@"!h44:D b1fE>~ ITdii҈!1/^ F6lٲa˖-/WTT̶lX`Ib'3z8`AT0EI `0",ngVjmWy|Zcl|sL\ mPZb(ߠafj{t$ohΛ4RBW3RW ~[q5¯ cj{~sQ+Ŏ1t5FcyQs$?51)ܗ6]W>7wfnvJ}T3^b}_>p@Zk1׍bl]2ߞ;{ہWz8H]Y[dRU |mPTZ1{7֋Cl:`DcYIytC̝yD'#efֲTvE= RDTZ?3m8n>΁Rq%vre: :S/??~ }s 6A8L﹉`'ЮkIwpg'%& J[AK@RDy:5)15`D6X+ _#!L"J))D"m6_;ޝIDATvH$"fW* ^x!bt:t^/Uؑ&J@8D$! %WY2@2{4$c,R.s}PBd`kHN .H5:r?'foȥfSJ7^XJ SGY-6ؼ~3JtS@RF`tI_#)p 珧 ʴOۈ4@@.>Z/㤴B) t<+{Nve%:f6;j/rgid/5}hʓ 'F YtT?Mg6/8ì8AmK7& ,(0}1m2a}MZrc0|kddxҤ/c/$ sF y![QZi7hX$Q9FXZ)h4% P(ǟYjA[r54x6$@7n/_.n޼+Vt:Kʔv;f3 rn0_qzcnD 0 I XDRs* nJ q8E]vc}*sranQbprv~FsIp!nߦ>Xe3 M0Q:')B4@<>| 5j|e:9oL.ɀmGߓ i 7ŜRP ^LJv>эP'Ϙ3. $I <Ol6]&;OjnnƎ;rNyt:O>D$ &Lpu랰l!UTTRlX,K܎&Jv[{ҥ:~"ΙXA(6Q(q:(~r~1y#\ߨ1sP噘tߛLl&IYUKum'qhTtDe`h i`rSVcp:*A5 !QŶtP<:O:kD/sX'| ϸϲ V* 2Mi#-LTz<实l{~;cO}wr~*JDƚ0':V]\B g;%ZAL@^݀p#FY'Os[}bt("# )uuu}_2O _~_ ;eˤTWWh253@A@9是p˥rA)LiQB2-`vMhVɆ !1lɉI;@[ U{]\zEfQGm\k׿ߗޖLd~}zk>g0k9<:`@ټ;SOrA@I=(I^3Mu]V$EZ2ϪVogZ%"fzf6L#?:j6,U^^//vqz?#X>2<oA=tjCMQfSAV&XΡCU`#-.W;;N[99DDk"1oc9SչMq]R?%7׉VîIL̇BOw+zU|yz,0#zJ4D {)4ӗb<EtDP~<Xp8φky3r VXo`tڌ1}ξIAN@F'EځA ͫdd>;5k5@j!8tȶhc3ݹ$8OԦ*M>FLY8'[Р!\zj;.^PC4W,0؁iuJ1==DcLO#K ?0ASU' ӱj j+E,Y9zy :Rߛ|#Ap ,T_[Vz?F#einBj>qۀ[?7|{gk3 ~Y'n1: V`ڑgq`sx/? ";16Ս@; ._~fm(J XA0B\.W_xܧrӦM[ r' 0@$XVb1;w|%n ݱZ-k^TROPi6|(H9I< &_[ʶ >P&z2󵻬M_88Zsw$ڋc[uD7Hm{OfcN_.󮛈p[[Ʊ]OdJ7!5#(FDq^A`A0FE:mAŬprs3CQZ π8Ѐ۽gkMg3P좖)q 9' :X+=\;>7u<_(Nr'SyR V~XĀy©/4f1!݅p'*^\z;y, ~?tI']4mڴx c3ai,--Eii)*qj:F:o4b&ؙ|pEHZWekF""0RrU}Vfc[YypZ 3jo4MwNQ/)N'ԡsPg#x֭71f2h5Y)DHuwٖ :bÓ){_b-c'|r9˽YAؾk9!SM9psf8Z.rg|D{tK YZ@ga?Yf-Ϗ㢖m1?+yNpw!,ꞽ!2='sPJ}҅7'"} lg]\|k"==4jgkX?<^ܳ7WaHqJIVd!2Tkk|,N"{V,@F<(!|"i^?o]ZF$d&U2IDPrJOF0ZV{뒺\EKBŵ,ռŠV[t(2b')$Qb3՜PkDJ @H%V3},z'8N Z T cǎ= g0Fxg7͛NX%9CIŐBQOIoRAI$) *$ 26%Aj& xS{J:$N@50Rx.j ~'YNH̄Fl}3)DG;u2%@ŮUf3*!<<~8p'Z< ?' 30zL:}ҵ|gԷIK^͙Oh&vdb+밢_,շ=U:TnPj4 ĴQLCJ;ǩe'>O 6m¢EFL,:{0h4LuҒQi茊V$yGXCOhѕ$I#_C;gW!|&I}HuTάW-+Xw%*!D<"@qumda$w\ls~ 1e>΃Gл1̴K nPLXےuX_%JV9UfS5FkHÌx5T]c@z|9i 3j f(')tizV<ǵ ği_ݏgfm^s x13>F֙^VIsWylVa(Eûn:UJ `u``ԁ$_=z1T?my;Te,%/mJ&ߟ2pj[*>-ʤ`:pc5H"0TJjt>uX+}mZȡ>$d7Ok``JJ!QNf/?'DQ=r)# ,dۑN tW7 P)H'%')4X8 SfX"{Fw֗gۡvB:!%žwZ"|zv9aدod&t|V 0F'?8_B$`d23i莵p:}'OA.Ԍ^؜:e|.>:xPv[oD>I}itSJem:>Ƙ)J򲆽%>MP-9Z} E5?;Z% Hض K|':2ϫɿ4Տ|=;n 3fj_aju$w79·\Ob$yO:$93I%$tQ &)SF0xlшJBz! Ho3jY>f:~E6X~nY99άRw8v \&Xfnmۂ~Y~9o5{C?XKJxuͯmU{ QP;F]\Kv$jpr/ʹkXN~j|;UtJ@r r[ZKmﺙnh\!c'LEgd(sf[ s3+M3Df2x]]ZkV猏`w'/V?РrQeGZm`|)0`Fddwqpw%$rZ@s hM-1-AWpB،Ic @H$IA~-oQQpHOMΘPnE(-.ZcRkM:d.XRIbqw'9 ;('$B+Q!I"}C$ 7oƤIG_@4? NJ{B&c+*߾zֽiзͬϰ(G{TuI'8W mxH*/pfj6LE%\Xf* YEL$%l<;tpsS 5{|;"[C\f;U&Ң%ipj BR>6~65Lgqz%IO?MSa9X Ȇ`Ͷ@i,q1 rmR>0 B\sȵG|lv4>cN\c"ߊ>#/Fsj0Z׎A&^ifzQzp8-!<gG$ZL~^z#1fvq̰xl $3uR;#3ʬ>} fygNpB],h76r咶oߎ: z>-"2!e J >]A IY3T^ X fkd#;|mMgk'Eim=/wv& Ũ4$ԙqiۂ<8' )>M5$ZAUA zT|7o(5G V&g0uo)%ALdٛ'Z|k"g:Ї]_Y2GPʽa9 cAKmߺɡ(O텯N؋T{+fGefoc6;24W\}KDym 2Hbi}[ OmHbjc?ϚqVID'+lہ(?\5?uCJuԻyPpIǔDn]X uL$l+.@1 B~H"lUsW{ ZH~R?O~Q!#k5R(&gϞ=g/XPZZX,G} ,HLtV -Y)\@#JEhP2ΜScJsʘ)l$FoGzMA;@ՠ$P"o|a6sye0pF.Rk;^[QO`;֏ (MMd-ҳCaIV?2r Gw 1t{ J2q 9~m7 d2tMfnCue4O?#xΖ') p&>{|d2Ivl!V9XK[t9y$i9V?POIkg V  ]v-ǿI#ڴi&Nx(X9 lڂ jөTJ#MXN Ad_'Ӭt'؀)fY"OJ{x E"M0 w| knWcվ |~-й1gIy@H1Y]!aF)Y7f-*/P:c57XOφol~[N}̺ui)iy]5yg|08P&<1Qn= : YbkgVR o/B$lhgg<(zv;h[!0KB D@2(²X}N]lqxq;aVxװqt<O+\Aih @JhhTQe8ߡS=K9VDp^5sL̠Hrt;C׶d8+窓li%JN){dfu9Q"<= 9+g?ºeuǢerWl8d%O}_롌 ܶICUGѠCxP,%Qe(󽠆+Gzw\,uxٙP6 d]&}wx;ۻV%`@JHH#HH @ȏ $^B76nK,igF;+۲Irgm;du]rʪ0S*!!*ĐJ4uQzL*\RLץ֕Ǡbn"JIt_)( 93Sߟ"L(߯X4֝2h)gq-<,HvURm`.E3^}iRIg(l5#X6yX~=O=UK/A4 P s]A{8Kbֹ KɁ& Ȋl>@@f@/VRw Mxm21-Jò U0qWei#.-ӽLe|5'JEtFSYڼ$I< LD.䒌sO,JE9(T?\ ڴ@ 2c"xdv+ D`w/pY]F+^+o7@a % [G]zR}PH+b]OX{P)ZPh H%q%1LCO }]4 ]R@-Xݒwy_Xa$"*Z7a~ 0~?C{ՔPJsz= moL!K6RE62zKSPR NZGJ6DrdJ9_?M g[L)E&(Q¼?Do KR;j SaU#'>G1?BqphUnԷ\eY /P/^^eYn;!DP_PE [حX hgzuفjspfa $0<;n/=XǺIFxQF`C*h݁7ɏֲp'Yh_6R׷I=+b6۞2S4.@\HXPhXon!B1MQr[EJAAC ŪAaF!m"+oX Kaj1n"GҤl"56K+i^vĄub aS>-OI OldI_] LO@, $%#0g r9U.Zh 4)3Ao ߏh4ӧv9傌WY#WXVф ,L:Qs'gWxhOhm,Mz[alF \K4G#Dvg&FI\YI鞺,_R xmWzRHdvEXPH H:Tuo(PAe*pM ۔嬨*3 8r Ϊ7F86'mD5S R@#H(W,@J~%Li $ȰY-p0N6@DӶ)5{9 HK,sWKO82lv*˰6N S]fXVYg6o хeI81kllԏd{M!{'KdX,744㢢"A (**jfl|^XՎ~o :mhT"&r2_^LY*[gdF߯Mf(H]Ԕlh?7ߚ-uP ϦS Ԯ`NiR\HzYsRf 8n.^jieR2V3;qV%FL߭(dc(_}D1۵C| Kl);vQ}t Xq2遰@ǻ 4Sm4pvVC*XrX4>IWIjHVz1"2R@aFK$"ǬHAD{p4oZ)C2D4ؘ<00aa. }TSSs '0 ӭ˔bDQD @8xɦDVb1pn*X!AY䱟XFzk!!AMW5Ռ\<@8z%׿tHeA`v8M9>.m0`ɦ;ID;.&ET|/ʠcDs!nhpoaإ?eӮQGW$;ғ$ 39i!#8q , Q cۖ 7BXt eA^OFzԱ5u>h\x8K&%7 lIN; ?MAWJiH]_Ld@_XNI'Vt6HҥK'pVZ͟?<t:ò,$Y`@q2r8` lb]wIe[I xfXV,Xxm = 5C5F>'}ݛ)L=`l4yяP31ܵJIX %?EZr/=w@^J"^=F&ʯ^pvU襔3\pv,4#*,@ڒb>铔(b}0Bۯc/IJ/e|_r}~;%Е jș Q"zo+5zFĽ GM4G6@eÒ>iحߙ&aX f睥Y p2% v v @ So!"ƜNV'w&!S]0.$eY@i|fD.Qa8vXd `lE6j{P1oT0(0"4f 8$ڈvh^o8 &'dO*a&۵o#bm8s\5+ۢ4J\<|F8.R CۨiOFf$Eٌq5ӕ+E,l!vunj)u:ts>OP8wqsܸ,SJ@_k,Dz0u|IɀRN83Az7y.+VFt}FF麗;^(DG?&R۴DQ Owp;]%Q8p -T9&E9g|L#oA]O1Hd DEbxU AHbJARwr E&R"6N dbDQ($St^pH&pS#ScDYW3, nI+_%sI(0ڰrp`[z`#=pI-zw>GjMI_G!&93t/=.~U-5"kۖLTF&/^;Jdғ$߃<=$7Ը;CAs/C)"ha+Gaݤ1]/m),`-e ƕ%/__8cߜ+v,NfdTz9:F'ulpCi$[RK#O&==E^XM ]\ĕ_!ۃؒN^ S yV_z/ǐVK9kyC )#>IGEP}Awm+EP8'sCT'{->&4/ܼ8 +yiZp:@w;d8HYL^TD8PdIۢVcUoSvĩĬ#'.7!\,=?E6˝=Ti.:g5_v!x^|S0!N5 ) TYRL>A*5{U> h[eN,0{qE _o4+ub "*ةN-T# F r;{*өV p ZA2 HفV,`~c̥Zд~ߊ2TT\:z,EᔐHF$ 9 'Xe7u\T*֦lߗ] W4={_#DtY]݊%4۸ȆOI);D+DkFztTv)@%EvRjH$gB0BFOf3!Ӿʅ)0L|8Bύ\R+$r{: C`O+ pF(bdH1L/Ej\ *yڨ!Jg:49&;i(F IKw_xK gPrJ^N-u;Xf?+(T(SzmLU[cTV(%ǽ+}U<%)ZXG$%mΨ6&'"4?ρ`TOsDC(у*lQyhj,\ .kM ȰBEI1Ͱ~M[X,Oimj[[[ Q\\<*B_EG&Еt9X`H36ēڑ6&q*QYu+nA1 x#ЦQWrՙ^CV %6 `!9ĒHe$tDNDG`WvS$•jzvr֓2G7LGCk/jN0Wd,KV8R"DɠMfP5+/qCn񎪈ԹDUܴ )J`Sa`O}J^}W -NGTxP~.y)ic(=FHLtO6$0n?!-n a!e ZʘK %ct^JE+ˊdF'rf'ǯCFm!Sfps֝yH$k耥Ymݦ2M$Ihkkg}͜9S{ 6G.++Cyy9 x``q%pBS.Ż)ng!md4+Cq:yz" xo,s+|G&P#iUpq5zb2"M@|KÒ#ib{&|rj-pz|&Sos|g GprRVEjB.n.u5sB!LZ.|_7Qy cXH!o#KM`@JI$چ6*n5UxVw'Vg32Rl6S(S_Ng)~A.eK; CLǗ&k# B>J վ|^ښ9=  (%0+ދ^ x;clˈ XUT xPCCC(!rLKK|rn;=:Le}w䎎|$|˥(// <v;83Ll>Ơ** 82 B؟5gURH+a 尌<d<;XZIǮ!f>M1_n]E^@^ol>9sX*jOV?Q1S㪨BAVi_wm6/#95,f)+i#)[|62 [BTF鉏FfveېEb564,Io}]}45]}`"`Ɉ O"F؁#:y}H@E<4ڃk;[hʿKY HRb* 788h4 ~UUU&!Tl֫jJuvvbpeD"tr. nxxD|k3Fڀy*;` DQ+ ZJa<;K@(&LJ3LC8\FHauZ5Rؑi\hG"7,ȔXԄV\Vϧ!d0#T3eˀ֣7Z8 kq/#-y'IgΥ=%cW[B (s}H`ETO$l倠 8x03_%''.)9xT 8 gR/BM J-|)(IQ!EPGNPubaL<4QX X [dTSO$2V+lzEQ$Irhz\Q4u;rY$dNYzݢr|@+ဓ*o2ړ=c&V 1[@W^~gg+[ʘm 0@R/nLYsKOPG"$VV('N@9~!zrŽN+NKumrx W9qo, -WCeڴ$ނ:3v+QLdW{#Q;sϮȗf_7nۆ'd:A|Nw ]Q}0Ctbpw5a~@9GSjvS`<] 9Q"Jڕ"3E8zئ|Q`^C`$X$,pe3:ZQ9I`z\.7oƒ%KCWxG<U_*W hPewk"I"l6zHeЅ5Ct=L2?0H~>']&{zvv4pv+bh@+ 0_PS+ 篠cFpy->REn?I=|`8_ thܺBhitm,'&7b?9 WII5C.6S~?ٶPkb%m|ATҲ;?!AWQ`]q $ ! <;' j.뮓j݊zIʔ<]wyNӣ$kZ҄|bP%aie8OCrAYFHyҾzP"!<3L^{>LCe:Yzg?M;Lt36Pԥ5d'8lN w)!~h<+ʬpnpĥxnDI"hpq_uQy_w-8 ?]A"H.)_QK>M>n*OӤV|R(o j`[.2f/’bcO=, 3,?BV }^M 0IVFX71rX8<2:4@2E> =,:7)2)f+fJhC6P߉LIp; ǪO)xoḦO}n&tHr^t'. .t)z!W0;!7^DiB'rZ7CP~:F,;]fp'}QtABcU+--Z/4"@Z+v xa/ŒQb'/y2>uYC)J ,p幹٠@*0C]+"LBZ"aGd#io^3%KgR؜fp:@^uZ(_w?ƌ?)٫2pW?:`eVW~0*nDS۱/GZK3֥I~bu lR[Bt}1B\7L¹9Ƙg2rΗfv~[zZo1XC~^Mɂ"588*z<2^{QɉpHFĐ Hy JEp2bbN=LJ|&PH!9`eH̤V6$Kځ+?h>1N4T<:HA}G4]*.* !6 GVVWP [~h0Oޘ^.\&؏%lp\58Nk0 k6Pie͙.?AC~8IT +W@8՛Y&M,D~ ZDF _JF&R,M^by<0E٘8 <6zي\ʷTp6@<1?,gWMTy>Ψ RqE`?1 VtG'3[4D" 1 l|(W &p.Ay~NwgLVz{{իWl?ًe5 zI,rK~clS?{ّ)19Q e@ 7ꩮU{ 8UyHA9 kM d\KpJ5V>  1>,pLKÞMu8`Sqab``@"C$ON pSzб1qͲ,˛xIj)Z zPuᴈeuCn?mvy|!0ݲ'VZJwRX_}jd+WFVfD~3H/8*fk%RA "X​W8$,8ZD8E7-4Q} 2'Eݹ&=s|sSuOH9\;wןA~6sb8U A+>?wX)!2:Ѫ#NFE6R.W$E躵/(%Q0RE[(l 5`X_]W_⧆ )֋:OR _W4o;DH?nUr2xeTi-<1&cx,)I():@,~\8K/ᬳΚׯ|A<ؼys7,{$IUZB\b n{]aMbm.MӁ`O&Bji ܗ1zEܰf%ocVWexrpxr H)+ޅB׺ 5m!)!sRLP` * |:jpNʲFC}ñUdde,dݶ @ 24~2(W"DE eЖD۩QJOk1*\Hgbb̈#z7q;LPF}RQ*/ 2L`r8L? 6s qFΡP6K\a}ez# RgX83?OdQ]nWu|-;5FI? >Gߏ)!,!x+7б2'X$v(.*ijܔӲ,o$ַ5 7y!|AC$B^eY Z$-=v+=nظ14V^I@Xf(:k9hΫ.I{d\&2ub9pkSNLo!oS UZ ݪ]$Yl[Sj@+Gi%2jjݔQ;؉oOy^"c#N~3AOh/ !QP$S4/\/ndvn mȞ[>¨J$# P@*@3>뺀g1p[/zIXFZ' N)'@Ga"4IV9! p@M))^ : _m,'"xO>S]oӦM ( z~XO7KKKQVVƕ vp,!C92ΊkBc6:1f5-V1:ҕ"ó+"pZ`dLpi;pc7ƍRy(* (9A߷_@OxjvU[ 8# ҝFc}QmT?~C^D6P}¬\+IRkTFARj%"t1,IIu'&RZ"kb(ⴐQQ[wlxaJ7ǁ5 Ͼ#AL٨ʃ `pF=pZmvh냄n.{] QWs Zy@J߉|?+o&ZUhD+WW7@uMl!-SRFшr;q WJTnN L%N8לHKhДA0.4;qґ, iw 'IDQ꣎:ٳg ftwwsK. \PRR"r%%%p\p:yAD盶w>C js+m <\L7j!PV0ʈe|=1==۸^nr#K(̶T,yLК$F4 9^2;,2p2')%i|xl7~$T^[e,3<{ښ%?[䨹wN}"*/|\7Ժ;ِV6ƈ'<bP7R Jڵul"ȤR@wؒH8a:C?_\}H2\nܚ>MCm!5ҕh3Ɵ+.3@J_20+2ϣp@{/GO/k1?1pn a SGǼf/ԍ]kq‘iDh### X,pwg⋹oqG(bE0QVYyI<ϏL΀f(՟|>vX4"MRbf=D]Os'Ӳ.V;bKpLU;м_'|[ l`ع6$LJ p]@`=ԜLL 51o|< kd.nL\B t:yO T|?)Ӗ){0<dyƉ{xvՔxv)6xT*:W: I_㢿6VzE̿UY= :2ER'!'&IR:/E`B$p);B(Q)-,zOfO.ׯDi{G%P{O k,1ghspRМդ.ХXzg047/BpL) ͂.9%i%6NB m"o8hJ_-s$IBUUզ_~9ug⨣LM/X,6~aڊvjCCCiAŒ\Ng{=\ `wpJiXd>B⿬! t?wQt\4/n^ྙD*^G޻;`ҪW 4ٞ .7.2{1'o lqD@֤eZ| uWc_79I{z2XrB3j|0B\-ά~U hR l?cSށ)`B1Qs۩9~}0oU>"sU7LML7%)yy>_qD%\J}r4ڱިՏ/W_K`9":gl/@s؉kMM,%nOg Q,hvSt/}Z0 }D' )(-)gth+TV~ me?>_v\' ʣaZ;ȩJK .T'Î ;bpHi0=Uva%= z@ehe""[ۚ̇Yw[e3>Mʔ.fz!D(6qo=|GMHx30Ý͂urӽJɝNxDQ9&'z5xQ>&Rؚ-k<ʵri3)_5ITa]\6%@FԽ%IjVRD;fj/NöǺ,OZ_L oѬkDm鮟vfQ# PZ%5y/UCC&J'wS!FF4B '0M(R En^pH<,BN 奥L\PmZ'4Y---sαp; gꪫA'x"{1,^z(~T*:p4:ptrqv6 V< X,acvv/ QԄ""P+<6DhG.;pX ϙl^m,Hړ!xlHT!<ƀÔ ӎ $yUc(9{j.  @ʱ"NNO-.TJ5y0bff{UQ/(mpؿ,.+O 539d{6oIL y8nW5QYɸ0y=WR{ğgSe?L  3`(6 N$A= #՟^r=k"H8p\IaA x^az]Mɪ,QEUgQNܿFh$Bi+4CiBP4 ϟ;?dxHb\2D"c.\nWlRܥ{뭷d2\ <',H@ 4CHL)/bC ;*N +ٹ}t)3ZA|iM'5pLigm2?v PS?'l5'd.$8dTP?^EȻ:Ja<ڥN 2aj WRbyǷbgY|I>@ge WR>FT.nAyZ3wuU3pL q&!*AJO&3~ p 6)σy!3@,kO[Si+<eY-r>bfM G%@!}K< uQ4CBE@bNcuTOF.DXFH$d26n{-s ~ȔbŊXp!}'9N4i8dasg/#q+[\hrM(DOU; Wͭ/Baw7oCVT$[c'[](?(sd{,;lXS@+-n 2= }82H^$&ʙ41θV>=ӫxr1<e2橲g}ƍ&- x"ǒQY>хH  } 0]vvIDAT#sdRSO^xn]v)l#ّDQDSSƄ].WnN've-@5ruXwdGtx1ăAgQ_oꡇ+-M2(m/jWdjs .Ve? ;F?z@zI$("BKl+4F'8I5l#ET:7c_g] A~#+G zoǼfU25|2BI9ጉ?oI*A/k48>7?n.[ <խ>w`TߘKVA j:Q/黕JѫmeeryFk}ll .P0B<=2t-9!ǖP~U# eHhָp[2JgnNQ.HGQ)EPCۊ% J?AJ?(ǑL& n; vG5l6zx9q"|iNY9c6!iq`]ҎC.2`C;D5̇,g䙇vVn LpfWe!xgi}nJ1ݼđOHʑU^rhIWAR=_QI @[w} 2&J<^g#~M2WǁHO6V.5x&d#Oأ8lɋ6ŀ{+Q,.in^Hۨ͢=/#+;#L֊Pzr8XkRfѬatЬ&[ 3KKWƄb[)(TAi &jSl%44GVp"j!a8!4cyp4yR)b19qx\N&\"pKMMؒ%KP[Ɏ5 NseY|s7v;t:p88 njp@RѺc$R=I|}}(ٰA )qHgQ s=()}o ? wN9VFb2-3#S ܺC4k1 !`#|8qxxx| hG0^T9xġhjll BD/{~3n޼y8wH"S HYp _~̙3O?? |rqq1PRRx ya"rߺɷIm)ϬF)_Jhz[/z ƪO# IpOަ' ژ%/Ӂjؿ rTxv H+o7['e~>%D>J b]y?.zS ED4Yo`W'Mu r&+&ϥ`?3> ' vL ˵?aAUk3*CpY8MSDpXmQD"nttݙ3gs1D/_-^xG+_D"s=== BTB ɩ|vv;p9eׇp ͍Յ(DigΨoudլ.h# }3J(oß~Ѧ2ߋY_7&%b;4sӟF3LwQ!XAzO5xnD6֊2#ы`XU?| pJhs09H:ν4@tov9`RkO lxj'1D3_ ƳJ%{t* WnD*ZSf[>F׷#%7K:;GMץQdlI7E w$Mes rz6Vw/V8r뫝Yb0MͫD"^ K?oidI+:ܼ-6=deM]QfFӻh^!8ey*;ߺ&}ȿ[fn>d1J}Qi ]<;5U&2eX/a\`(#i@j7Q9IL&y^nܹ;:DbxhFK&.oذVx<|>8|p:y͞P V)Gi4\kyx+L(TڡfjO3r])f{̽#i`}Ǐ Ft!iXʶ.$6Dޯ^bRN{Ei88R~aڸ, ,mITddf(⥰ѕU0YIIIKّ;7az '@[dș{2Ƞl:p42Xqj *ҙu_JoH '؈3"m&} xn.Qz?7$:LDo6耪YqZ,Y.ԊC!{odb5"_<<p˖-Ê+rPZZ=fv8v?y(?٬V a`Ս 5 j Fכ)NPՑ>> bِ2[a<5? B_r T>ʯ&ʶwۍf[<\G2[RTˊ@sẎ i^2֬GäXPb^F[0Z8޻yWi_.o*1Q`$ǀWGD E A6J/ڏJY xE-FBDztFBN k"@_09Dwj>.n #:]hORDg(&:ZҊHdnTssFsyTșXG>c4# hM?h[!POPClMMJTvX U*1IQlnh*#@p( wvp/Z r ~pǯZ8UbZ9nY5V)V@Y u msaC†"۰)I$>"`uLGj ϟEӛwژ~&XCKc7/鐽3CzIeHvgF2A8^yfb Tu"avB# L #1(šA*̰̈T 2TUpㆂe `ĊgzKC"-OcT0b?(>C7/ǀ6&E `fCQq뮇r-j~ZM0D>R}Κ];}PU'@cuwn1k@d .,Aq 6& g(rK&/QrT 3!'"ҲAe2rJl Q1AU`+Qp[RyO _RϣzycS v{@(AB'׼d#e0pcq/Kx X\Νzb>FR O 'H@Y:[J!$aMQYV |c- V_YMCCC+Ix0>_~Yްa*++/ B7z^.ȥ8ߟ%y<;w `=,€F<Z&ґ&wU 5 Yĺ΋%;k_ XH X|IE+ha%2M}+{oFA鋡۽ ٙz [BRUU[Ԏo~VMVm(ћlI.iWXa\ѡ!~,`&3Bob?N @ E"/e;i"zc4sWS [-GМ4~~(;h,3 DO;66  K.=nH_xmݶ~6 n\mmms=QQQY:)J.N#JAp19,KH#&@B0riSsu8|U <>ۼhB@+d}ص p :~ב򾹉ͤWo!/KN-uԍ}X~<@Q|n>;4VLxF <_X4a Ӳe,ཅ*p`,5 >1DMc#"QMWfFywнYUP6eULs/6Q^Eʦ_tPTf{caș+ߚWp%%SI|0x%(bIIɇ7pC;I\&; 777Gu{oȲ6L$Im$iYEqޫ WOCk5GJ/`WQܬU (4\k%SHF!`aW p\/0GɡM$Im?*9R$ Nx/F`yr: q +?mC6#@ ( 4Ùckk=Lx ew??~9uCR9ǬVN(^|8syL:/dHM O;ZC81. ڿʷ>/m9у@8s(FUJ5Ra'~.59b5SC:'PnSKiX4j** :HSTJuT9QC埫{^ѲSpݨ.]p89I2VG6ϫ{o!?΁1=8g tJ[@=WA93sDhAt; Qxg H 4`tyl§hes ^&n$nRq1zV3k3۱Q(u6 V .!bR^~1puAn ѱ!;ە.LwRg0r d%^kztZN&r2((++[O?g}Co4Uꀾ ,_,555npppZZ`JP 7eibd,>R67FdGvWo Av_m)-)4l/`2pj^C}c5^Wq#*H˙)?wD0N逗[xWƉE80^9N31^GC+u{qB\㨏r;ԳF`OJ" ʑjɘoHa]}m͔.!XV'G5ޥY_Ajra&z,d\cQ-ICT)=T/ ޷@E4ϑrOeDEu{/nk|xۤD}_*B x◿KPSS;WFXbbv}RcɥiyYͱh̳7~-P= ATpn&Gg×F r7(lVy"Ii#Zrg'83?crfȒst4Ʀ$X2ADd)1u{W!swmJQ٥ԯAnļEy>VmPTypmp*J;jU42N%mc\TSG-)Vz? %_(>Aseß菕c/Zh>rb划cVg~--@Ss `cpK),i(.6W+(V" ooɵE0}tL6+--ҥK[DYV8trhVQrP.Ӊ~E=HZ[9pXhg p\iR@g?ߤ9RJb[z_1R `}z|ƌ(--5ߩ֢EEERii{ddXflv8)PNZ`ՊPZ⼪+ SX,>TXz]yI ?K]B*YnŠ=$a!#m\ɰQ9EQ y1zsO`uzc?ppDrn7[Fg &z~"Zů-% V*AV >:KW5R2cŮ7FL@Q.^}[F#ğsf$D]еP}!;8,>wev2B %992q A!GlEsDK&l566>WSSH$9 ؾӥ@^v|g cY7+8`a<̢mdxfzcpIQ]8a'%ƐP[E N @7ʟ5!R$45KN ^dbNc8?ִսF%. :wnj"a^(Īiab*}|6E ?HӀ(W5͢Lwǯ%4vס"j^GEb"݇'nRd!g)N4[>[g/_̾Xި$5טrH #XgL~]p'@աIq8q=ˣ`Nˢ0)xHo15sj И,Ks6$Ii$e[9Z~bHf#ٿR oZjzJ9]s;M/Ly1C.l!{#Dyg_sILVe q9ogl݌hv2 M%G ((o|e@}|2V !7> ?xxT+RGQ-/x_Y\\|ٳ;ղS̵t:###GvNx!r@UNc86v@9ѕ!cvoi!/@80Ok"?^* Yy2yӯSऱ9I< 9Ed>kuYL}=*կfJJƃ^O{ d ^:*]LI0'g7Z)oybjT m}n1d]KVˣ[v nN%Rn~[O:]4*wQS$^!SCUrߡ=bݧȫ3ev F&7";wXVꝔ&xa/s949|FbdAkJn2b1DQ. sDv3gFFQAΘXB>ЀpіH|@QsÖ#%1aY Gˠ 0'K|Nm1A2ng9{ӿ)wX9փpu'۳s2ӣU`~  d>~+pw3'O}NZ,)Shyƻ mo)-T*[hPVʯ7iê# (Qm/7Qγ*-tV(D+1zftFL&'=V*B+溆fU 8c;vp1pLQ6Jk}GOh ^`Oax4ע89T`BǨ<4?`0{!;vVi#3f̀jkka"]]]sffc< `2d{N s`ˋ^юpM'n\$Oղ.ؘJ@۲2mzIq9 4vvٜkW>ݫIua1{[xSeN E! `E dJ%¡3E Zgvcpwʨk9ˆ_ZCy_25*|/8rOd0~=e_D Js~#/RoY9$T*"t( &NyWG'*ۿC Xm=dL,MZjT6&iL{f Qg!׸F8DB5ܔ`vh8D^ܛH =CFQ̇aK1 {,VkL&J `.Lɞg,Y^zkiiN*N% 'g}vؤTd4R{H U/b? '/@9GT9B,dQ$2=#ԙ,:`ryfrfsߠHƽDj=sIoM 8Sw,G/gW (u9-=4 P@:ǼCED WG txF`WD.ۘ 5A#>&(. 58ɀQaiMΣ|&eQ$qeٝE&mz E+h30 lL/V.1c B3ۘ{^' *AПkNүr^\/ϏP*lJd#mNxiSM1TK XS d`w벩:FO&Droz򫯾ʝs95q!wLrԿgϞ/8N;MV8nRЗr*$<x_e qaf4l[>GGWxi*985 _<"ub+]Yȶ o}rΩ>dAm.#Bj oN"kkOֲYze)sWN)0Df7F5Pa*vյɠdƑ]0M6ӳ3. a VW(^S%@pRZ|#YImP~A-U-d%)ذmNoI*My aݤ\ #϶P^!:3`HaߌR/Fs_K60/v"J qx"7Xg MjہV+Xi>~xVD] !{Ƞxrl pN5uL@ݰJZW@E4T5bɰ@Z%o\st#XEzyr]5GM֓㿵'ص{3t8,Pe/?9$xU8@n_V7_o߅n&55 `Fk<ʺ+F?gf^0Gbp) X44(?_' .JjE@ssKz r品sN);N>xxpw`ۗ O:@Vz@8AUi3*ѽ)΅-L~R&!%~J3tf$drF)?~ޏ PxtO~)dMʷ*B5PzK }3VK}i GI 64gTUW*ia2\s5駟=R,`V޻C1-[p// p8JL&[8|倲L`@͂ X xn1[Ed"!m=^9 5 my)Y/NxjsVJFL7tR+an#MP-kǷ2NE5c5ZsݟF?"?m&@HQFs5rs CG]iJ&Aj*z؀W@/)pW7)9}M'ำp(LٚtY~^Pƀ(4ӉLcJα^c=i,J6"ODp@*ں*TW14j}?L?uuuڳE@UnttT~ꩧp"H Y)j`(WVQ‘䱟&4B\p@F5JX}뮻N70rx3#WR-YyUWisrWHxh~3#m^.K+%||,ïxUZe()!־%Ư<]@۷1IZ^eoˎfz R \̼?SȻkd8,g-7|=n>Pl2[`=eK8aV;G!=}: ٸQ!jZ6KӦM{f\}S&u1d'Ϙ1;ht4b @U0 pI1t/ˇnǰ@(rfm4Bkgn^.0wOJTϢ@2yM Px>^.ng9G}3{;#AۨN/D|V~&8#2ӧTHXsلO#pAioRA5~^ayfѾWrr >4:^.Ū? `4~)Lf餈O: XS1}2VeprFT=M7' R)NIn s^\>syJ KR'e-7ZO;p`eYbpM0_V+0i*<ax8\b (yK*Yrf0_<TY|u23cQzAym4;W^~[cHQ]F`<98$']UOb\Cg[EI1Wd1v@m="":M(s{ofU^V_R(p!xz=5v6YN ]rmS`&`t\ׯ2*,%k΋(pKqx X}.̛5[NUj@q>d2)WVV>{QG%EydJ|p8<1Zg>`466r{s$IZ+ e8lkiB g| >1@xQi22[˳k}7̷|u^^0wzM'ϊ442 lzpY_@(<6$ڮq<7tYYEs+F)gtCɜ?;\Ҿ/XXS3ZV@Џ VcO>W8_pjRa|b.!.TMy*_2D2D"Pk7655nWVV+ jp\ᅬ-[=YSSh*Ld2+/  MpqN+qvf<0-4\hv\M̭&h9ٕ̃9}mgc7u.k45Dvr;Լ9(Oǻ!#NuW)Y%$^@pkYl\:N_!!Y=BRfw#cLj\) 3~ `Md8|6 67j%]ur,E#LʪA k6^u/?@ 8pg};p]t˿NFPdpe@7m49#kkktPZ֜]CQ[ƒ FB{U*㴦 p:ϒBrױ^F,k]y,u;(7&茩e/Û>j?aE 8& ]arpt*SԊB逓(|gqu,6R:%R3' [ɠ VwzMrEX ܟnTB̒/22lYgF73~>$ETKqܜyZ& 50d2M `<^qJEVkkׯD /~hIIIu"njv;*=LNj~ hsy(qVuˇ޴wu4Xꆷ;1@Vu\;F@i`w?)l4ȰkEX`rQ-o(LsN)ghgNxv)ЎKzqq>Jm٧?S/7v):] \ V&t0og3Ci۬g4WjV($ka!B`/9֏ 1`2 o* {-A]D%c"+Կl?vaKMN#n*J#Xa~uA޾" TT,@*jj5E 1_;: Hvk0Sׇs0<ˍ`T(qB oz`0&fYǖ8]1b;$gnK^V6=pUk RNz.PF,_hUq(պGEILX)7>Mwyiyt SZ? O;_޳}V/,Cau0p+~zf||~3\ke46$T&B1xbn]Wfr(fBŕMMM/|M?)eڵN;4z8#ѓN+JqdxN.k(QBCE^͛O "[=( evd[vBз^H3 {2!=~̬81ʽvQQdM~wVdw> +Xk!A DlpuVҝ\(~j9yz#88Ҷ'M\I*  t}dJ'9I:D°,R?WGtf0= \gvـgCu2>ʮڊYeYJCmg|hfW#&%chL]HT5*}řy4w}`͚5ܹsgLl޼n vm7-ATnH$xT*[ X1sF|9Ӈ͍TC6Wf;|y,3d„p Q=$; `稗! O9Q ?[B E]a1 $dz,[ F mSP@{QV9iGC1!)RlzG+f O7 JO/$`K]ΆEx._uT*x<|X42^{;/YSSP<!#LuL8W:GE%lY2 6(o͛df ~{qx݀bՏKRr簰7~mej6$^"*r;Y!6.;t룝o{ds+;not|߹Ê:DH@}t% 6w:.Ac440&;$v-Zg} g@+s HUfSV%'/Vfh֍XËՍL0zW38#ٚ Ʉ4n&/*[/ bJ3y P@/l 0ⶖ!Bjyd x7*KlWB(1)J&q 7 X)jaҚ f}jj>2Hd>dd|b{5Y%߻ |-4hvYGPn(J0MO`X8:oN BkiEQ`S8ũs=N;;aX8IQ 2=|饗F^|{6lذfHD" A=nƾ1Y݈Nԥt{+OZ͕`"w j~$B~U <̬k$ {*a~t">5J%$zY Wl#eN^" % ,0"(S ֱ1dT]Ikf+niD4rM&1NȕȵUy"2QB}dR!w:#hnj榉C8/FN@}g5tI7!&7=W_}م %JL&x<ι\.8% u]Sn~lnTcL乄FuU̼ }q(CvVV5SF+oUh(s&B=lRb^DIڎ%$~$h>f {dpJbuVAuJ4T$( qx(Nv[ v{]iszWh:ϟ?^'|bBlaT- .n-ZZZd2ɫTc|;3n A{b >Cm"a3VOz\|dA::cdU-\1; bY*Ǖllf5ϮАCGhg04Yb~> g* .fL38WZJ^\\؞{.3Wk!_{*wy$Iʲ6AmĢ6#5X2Td~12~ Yz!r3^7+_HI X6Bܲ 1|RMqZ>Xا6!}iVvi;Xd~-R<oHm .6E-lO{^A׭M K#ԇ!h?Hhch=|sR>E301TdEi: ȏŻ.T] LZ2Vs̹<@N*-_vf3G?Qd2sJ+}KAm|A.tHhF6k9W:FFB 5>}'rE^>7?BA|3[@H&LKH,/J]b~bB̊W{Q]ﭪarhF3F( $Be0ğ^k{^kkl &LF03:UժiuTpsY矛.V͆J?7vD])~J&p(R{A+ZGPJ"9,Z.Eegr믿|G8N?q,++N֎.[8sR JB{B^0c>/vou< $7b*ù@{ $spsC bkfد!Z৛h@=` ÙȗW#`vtL]4S wwVn3ֿ\/,53/F"._'|'"%QYF<0DD Q/B$l(-?X,vʕ+7:f"A>XE[T@1XGB\1 D$*ff,ԩ-&^bNA\_(әCsa>ots~,MWnS8Wtm&/ v4Ȕ@|ظ%YOnہ?p&aMߕuSpVd|h;᳗`roP,*)#H!WҠBs[`~b?r_&Myp @h=B/ T,rGV!  W"@HO!РL *gxϷ])~19!k_ Mp:^I?Ͽݱ!ZL l?㼺>Qn7_i90ܯPS#xW\02l$D\@1-V_}s\-AZ 8jaMN {phn[CDrm !WYY|sΡ 5{; (ʣGTUT`}VQ8] QO#$Q'"imU@!^2r;ʩw-oŻjLY&x6ЎٯNZ9CiI[γ_\@~wq0G/gOL3pQU~rpp&{^hVT|s|&Y]f>ߌpMf7>A #զS[/fߧva~ ܔ|eBG <)A(gb_`y*Y@ҙn?v*+bKqHSDRM?pF,|']v8G x~^`9Pe~pk/F+*$fKcNJ9§x0b(:%sW_͆8Pݝ_%&mqY[-9mgxbS=+C'\'Dž?0@|i9vmN ߠ \fDg4b'}K|η> h5RkJ H'5,4@?{ I^yD/: pUWm%2VgP*w^k+V̟ BPI FSUhҥ--#\5[q{\9:!__T 4: Ky,Go5̲a-6 p˂ݟҒ +kMQ99v} CcfC!'?0;V^l˶Lw}Ya}3lޯF3:Np_E05BHM)"8nrpR[gCjM@_Ӵ7 w(zK/~yտ45jNP, /Zm5cKqhM|fߨ4JInSU*;qJCOcKXb`P6|'gWnĴ`H5ڞSC *?-YL8]%w[ zIsVf/p&K3+7}VwY5<q'r%~ q~sVCPHD,ICH!bUKOme9+O2꫕7ASd@p;rkkkoEQ̈́{`-R/6Q cͲ.D9 0DG0hFaNK,s+v3η~RB`s}K-sSlJnٚ6WneԳ }Y5;471f޳K{:Ͳz~jt=0CUf*!w^>[J wq#.s#/hH:QzA% ̝݌K 'oUUQSS3yxtBR' f?#4_6e83f$9Og&5 Ny{tPJ~q58"zA%"&P9 [Ld{N?[ GqzcIB>0 K.>Sk~`##"!!yG _+.Ac[>Rwbz֐N[;Y/M\elsͺ\$t` vz#Y4̘[8HbPT&!J 5mB@X1F3=EVt66a-o>i3S*x+mWr+r8̮.}9{$&VC2@z ĺVa _ҢVWYN111 #Hd__*|F̀? a###<,˟dQdYϾ?pV/__M#XmAcA͘{ˊm"ڟrb1ng? 3܎p֔O ;m5QyR7<7޻3Lu=py4€A!wo0sDLQuρz 'EfJBrk+BKؾly~Tz@MB Ʊ˖MRfpٰS ?)!|x衇:oX h|D"D"4 a~xlJI5fxmõ Tc@v*FQϝOL`Qx3˿?Tވ 9`.nm5KsQS#ǘNY3=qlX:@nj2}/3Q@1̮a:cG;9 |F`L(!^K唅\?CzvH*IChPJEmďwv_QL&H$T*AL&gϾ.Ɇ p5;fD_뮣\p{?dYE| ,__Z 'XQlGx=hG| ̕Kyv8!5S On]y A;qk?#I3:Я i }5 bi$+93d`nF5`TC9|@Ƥ<;%jnubyd}Y$qZQD4"J Xby 2oٛfaQQQӋ. 7|3t~+_9b_s=iʄi&O8qRG@ϋ`0e 2(0ȆAynީ:]`ȸcs>!l,Y+E YfG3ek7u )f-Ʒ^[Es>4sng] ovo||K|՝~3&Nۇ XE2J58fa'N:쳷D"d2I$Ɉe7S{{{V\yȾ#G}`.x~?2w[Eu(AH:ΪZea[XmAl ~UD@MQ-ўENgs0 (GXqY}E|aqM|Jm>vɨ\x`3}wL ;]x1ݩI4 RV)kzʌOiX~&o/Ah4380G_!8|G X]N֏R ;Ea x1n@HЬQLF>`($t'reS @g-dpLfoO6HK}NC9 aNBD>1Bir,Bmu a4H0ipr !5VqZEQaL @E(8/Ϙ3pf쪪+OMԊX΁*u ǩ'@c69@aQ13E X.tSb:&k}'pא υ1 SVk"o"~#n5CϻL?6׉z.\͝qȕ.̸;rl-1GB@XI+)X ;;͡J2Z3SB !@${{/tCðˀ7(s{jEp^}7J乡j/>}do˓&ȇQ9!rLg*>3DLdp6S@PjS/g)M蒋iB$|>',B٦B(уuz!5 ٳp)Û?Ry+:EV*#,K/#Aҙq2f"flRJ?Ok_4wXTc( dzNZ4DX@%MV fYx)+&[Wn O OyJ,&Sl|])Qs&;, t%70 >mUm|d n)nD\|RC<R,C@TO8af5S̕fg7Lg\ߎX;?ٳg(/D#T*I(5ˏpb!q4fqsĄ{0?B9ܰ?GgˁZ<΃NMB`>rj8K#*tʓ>> e~?be/x]})bLϯf~W烉B[}X*A@DO!$2I'sR`-_d_Ї>D3 xy K4QUU"2RlU8"Zp>Ma?(bJF0jzxqoy@ xȂr-t.m!RЀ}sK|&1?:&qo]7f #?:P/4=ˏ IU(0\ȸcۗ% #&48UĪ˰xwPog۵3[j9---^|/׾5`F W\q,nGX͂9JPJA3?ZvJT(bzjs!pH;,|Jq JԲBƾ[w>| 5[޲ڱcڿj*}qZHzdSwFK&a$>yp[~p0= ݿyU+&1W@M%j4@^!YlgLh:(L}w?O?sF~ ݡA0UUէ2%ER)jXV!ι8i5~a4:#Vo-+dbOy/'v\\]_ o8S?k؇ ,1{<pvNdD>8m-16yi#8@ܿ,JZ#,@z-58e͉z uXj^)&$LZ`wkko/''t`VBɱe˖;GGG'I,U` p1jJ% `x@0 ?aJoJilM cb o.P;/DM%=hI1DyZw*ﶈܯoe'IJH&b]~P(D:::HȀRJ?7|_D"ߴrH$QK(JA,!1:, kGђ4C47\g_Ь<j=q S.-*XA4b{xc+f(-o7VA@B/S]088H>lwoÌkT ˖-yGyN$1>jY !rq\Oc2Ju 4)bXs ÈV]`bu6NWl0"Sߎ//%wfO5ͶpOY3m 3bf=W˸K2&5TXȧ̦>s1L'ɉs. ȽN]XS,FЪ #j1)@Hc1KbEbe\yOӐeHB;/SO=U#N7W\q`ժU:ر j( h-'Z`R\XAB={Bep xTCpB֛`Pkiw}YxfNn;Sv* <7 lzpe)MgLU7lS4j6>?/sj$ .ˑ[~%iFH^sЍ4[!|B'zy&-sRXE@D@N&'t^;N_w*<0@)TJ-$I"KhS^x`Yzĵw:y %z*Ƿm6,8Bxb9֫@ 5`Yn@[n )z9X9c ;#iO,/4&4Q xh x.LXhuQ`e (kE8y&SZsߌڌo,J?;9n qu?XuR ,V9T 96 ,Mtڈ#%@b - 8I3ɏJ,"2(} 7w&ׯ;č֭[)?ah("h+ !fm+M_0 ŗ@E VaC_-25ݶ&7URQ>p)bfm{z_ZהNtMC|vc W1SƁ=)`4ÜO#&ǘƾTysZ1&1 h>8zpvyb}qf@*5K0]NCͷbǶeUѠ%)$FT眅z8]/ӵT Dxx& i"2RC W]yD8:_2Jq^@B!DQbw|>$'hxgq6JcfU)O97>0A9r0I~N~nĔ]_1Ń A4L>рf:%ѯL1z|_ %48؄d,=ځK'/O?r~G= ULǽwa<@TI"3OGǜ9}ۭ]O$@<FAi;/:6A?vwwzD"FbBzy>(fEn2-ǟ{zGkWb`oRrJIr98?Sav(:,3,D,Pj*w,~'81b C{O>$E\#^n<&va< uQ- .1uX55qLLL 3^骪k?fs=:KyVy'pgï|2!0 A `PJq%.#g 8!*Oa(, ˀ 4@ ˱6X}^h|p-PNeOLCE+jLy[ *9A$hj zڳ5C LtVxW4+ѡxb} \xb¬>'>r~c H,e1-'%1Tx,Y,sٿ]ɈQ+/p}|#/7%\B஻b2:Y>@$F"~?|>_V4=O'.@"bD+PwCΩS3S`| c't;Fpc~161x:0Ņ&Ҋ|Ӆ |y0q93Q !~ČbRR8aiQ;(rLDD @2ʬ p R<'h~. p qwWm Kh/RҒj P"# P#~T<\@kTWTaVٶFN5cIR4`~U =zyQLX ,4'C0@TMJ7[qIDAT&!] sead2$M&D$""(o,[_|(|>pVTTPX~f͚/J!HDQtR)$IX-~֖絷5' F Ĥ8*8:AL|~%"/_(J_LJϠ \$Q13 ט ί]L Bʟ~4X-~D*h >5 #>cúSNL?u=l]hKKN9唽/BEqHnݺt:}6H&ł8 ]^WS ϋnhÁa<.\1]`ygWcGu&4)f'zcæLZ7 |uIW(GnB)ObbPMH"&qt" dK[?D"A 2QEF|ػw/Ї>7P(6}w \{/UVV~AUUYQ(BAd2X'u, ;.^3O:FATJTcz(蕯`yϋ9S lz bh a̲#j+Wn>,StqнX /mgAPKAt}*q4T uk &?EѐedZ߱t;O$55du ҏ}cw2D*BcS:+,U+ Th TjLCkjY~ҍkQU(g&#!No>/1yfZhFjLX#!`;d;Ŝ|!{08ُyI84̵"1j;1g?eQUxw<c_@e 70E_>m۶ńzhOeptլzxd`@h > 0WL=1UcTsʰ)canv4Ua.x|f@G)Î|Ncq}MO`NS94TWF2V_DQ$/G?}?p#Ӏ}CqT*,P@4͔dEHSBzrj9MRKF@sR#fN.yb$SJ-/7Epf#;ŀG 2~<߽9;Q8h8Uu/)ȷci >TqDJ FjjpiPS]`Vw?A@2T@2Qԝ|9>9wpu>{!KrHD"I1 ~Q b^Q-D@NHcVM>4477:EϚqR)LLLd'Nt^{? oYjvS8HBHCCYbϟ?}d 0"l`Bu ;NYBf55ޞ@Sa0,U2}-؃&7|pX,~٩aul{lxlB%g* [֓%&;&3G5'wr1s ڇJDLI %@Shk٧绵1-_+ߟL&}A(DQ% }ꫯvE,Xn`z@vލ6 w߇{{{c@,fQɢ3/_{D a[:3'̓P&L%P6 [P(p0]|a6`Q`?ɏx9 |nn輻u:Sign'2l9 =1yp;+i$ bgϖ-[V]EzUMpiDWW? -[@嵔Rb5 a%Br `rʠ~}z< (B /! c T% \șjx>Ŝ)Kp\x!mxϑ–?l{mfA{M) { #BYN=%5'&v=ՏM"89g [~6OQy~xar:<6W 4dá7_ |ٌPBœ|R|Qr79% 'vEFH"0RXފ81LJo EQ}~_"2ƞX`/}V4a$ 0{l@+q aPJ)('jk IH _er!,wS#H$PƹtGͨ0ja- o:*ю8H2|3ϰ_\ru~wѻF${o^SS8pG~?( 61,1tAn-wg@BFF c; B'֓bDCMR:y* !՜i?:<vMO`AT;-f9)Ccf9K 3ubx0cS`8%{P!bRR`XM18 :Ӱ EvmD"A3~DeVGG{fXnyꩧ#u1pCIӟlX,v^FAD"  zxqfW9=<01(lþ j^lQQ`8,@ל_\e.,|>vݲ~$+` ʚ)kQE\^KO 8B1ݥ}Ʀ%QL J) /_5'޳_bƿe)t64/Aa[[ZZ^~F@.RPP$'o~/H֯_>lܸ455uRjoo2 CJ-EjQ[Ya$'FeRx" d N$P̿Qpq#Wo(]nD:P ڋt8"z A%8cS ;pϒt:m+IpmmG~ /8 hjj"6m"hiiKR߷o ,f|Z7rE,֦F4FAC!"&c²k("϶fNPL鱹pq8wGF[&⤱mH!$8*~;i NX 3i'Ly%L& $iUUUꪫ dk\0ۤ}aӳ@/0I_T@)'q ǜٳRCAxo_Q 9/Cg*D;' |c9p.7ڷޗq FIADO# q8ZpֺuX9,^5giiiTUnk/waFe---C -bYv!hFL!EYFBcY J  S/`E8B8 헊@s\H@aj:&NfHsީK'b)r(Ƥ.څrʥXYC"k2ǶM@DK!L4hrabSPY+m0~Ir EQH755]x޻QUUE̙c?cG馛?pI7Ikk+:::hOOsutt$R:lQ0ݦax]<Һj +E8!O%d4qqaVs]d˓W @le3z3=YhsbjmZwH:G>gMz{{7jժ<dͷQJ?P0i4-ձnhǔ*}pXyR44aƿcˮnMWS^CBXM!TM8(P:>'g|(L=7+8&~Ĵ|TBI袀H˗/Ү.Ogg[Z]4$)['ΪO,z477|3z)kvmnn&˖-#/9眳]$l Ad+rady@" 53F뻛oahb~ //4E(ql.>plN@>K\ t_> ,A:!o*"t,1h^;N8n:/zJgOTb2;::>iګh A8:e˖M638~@ p82N5M˶^@R<'^>+/CˬfxgNq ? _ZFLN_&†i}NRxnz`fXYj)>OIti"EIJ2%e#|NXp+٥}Ldj5o޼7o^+N:[g9pS+8֮]T*ۄ nyY p`99Y7< &*Zi{ux')'=\r* cw:Z~ߐ`Yb/ZӃ&ϧKdf> q܊~VߞE1+kEQ @ek/̚5۷O>$Cj|@?Oy_ϛ7o޽{oEq vB 4{RΎñXp7[C|bA$ 2z(2raNщrAiC]hOC0ExU DN2jceN~] @& [3L|,˻kjjR; `ll,]Ժ: /$_B%_$4%ZJ)8˖ CO3**b8ԓ҂ ݽ}, {U 15Y*l1G6gNry#ʠt05 S݇C ީӒB%v=αn4J#R ^Cߐ) ]ˎŋQYiggYY_ [~NKa&ܹs?K)}ubbd\ B׾F:+V|u]L @uqR#씣$64a֭xM 0x_B@Mj ݡZl7c<PÿJ%h9))2N{Gi)::E‚Df%xMB4t1 a9.Vs 2~MUU [A%~u/:::};N>)Nn pB!dݻ_JBLۅm,d-w 474m,<,c#  ShP*lpbFکP@KZoXhb(יpjPLy_umZOce|7؉bH# kUBkC֞t"_XŔ%kE- YEL3jE Ɋ/uvv~ipp0ycd9gt#R .݌8:@9#LQD{{%O>7kjj.5 ê W6%( TUE  0TWUⴓOvxo.R? / BJ`0`xgr'F8Kiez;PnŁȧ7]׬s W(a8 9.gj2UF8fbt-X`(hn>Y[~'rvom~J2w*++#=|gc֭hii9ҍ RpB /;\y͂ 0 CR4 UU`4 @>al|D45ƫo=F(28Z!tn)@/fJ&,tq&1Qӥ0+B%}hMBK+xMQҠHc6iU}goc/EJx֭(FFF̟?Ο?:nࡁe ŋpBK/x ü5Az<U!X!BUUz<\RZV4 bvK36oF@<)"dTP=6b[K Ju,%'߾+}1P*SJwH!t]b&ZM5`H"B/-] %:#cgTj־ʲ̨ Q*++>gΜ)=== -qX,84ps%+WYg| _08{;/JtPJI&@3 "2` :^o h,GPP~,>Oӟ466o`0xeX H(B0D Yd+:(5(Hݾ ݊x T=^ę #GP9p:J :QLܱ߬4Y/wts:-V. 6DG(bz ܇r SN9lذ}}}dƍtڵ~{){0UU EQPURC0I$Ak4-@2xJJ(TWUpŬٳdBti𷌿(<X +͗qT]>wmذz+[p$0s@#" .{8mdd{~~?#%D4MVPQlJyx^pg#`Jrj,7mێwdDNJShbQu`RR$AYpRv(3JURǚ.tE9N7PAetCBuj!C*TʀTрى֖Yoӛ ŷ=og4]בNVUU}[U߼Kj]]N:$rE!t /'!J>=No*բo&V߾*dS"T)!)7X`|[:TFT踧p'ߕ1;=bj>]V@4! ayX8 pai022eٿ(\SE8ͻidž ~O?4촟7U}hrf.[;7ވ]vA>(y>vyC0D0̖ |I d_!)Hދwn޾~$dT !QR|(z5FTHdg.ݩh]964IuPOǬ2:hN J#l < $PD#7gϟڲu3-ook\E1+( TU}=l2mll ^o<"~p7r\{q뭷 _mmm /௨_~\˰{<EYA+-`U XrEž~evD2 07TWbwlC;qJ4ɹ:>'ҹPu(دNѡEBcjQ%?TxtPE9UU7EeE_L>?φ(e(Ixs[ow%7p,Y{G$\ࡃ2<< <4Nc͚5eyݻ?JyޗS V Xj+Pn:GFe$]PiΏao*Ua~8͉-אs!7cݿѧhhA-ch"< 2UH p6- 崬wZF*$*JY%>?{쯪e˰qFtuu1zgѳ~;\ZSSxbr7vi͵ݻT8ϗ P$$)[)`4MɪZjeYաKӋv ?ïSBΏ1o}*0dxyp B,rY>|Љؑ85NTB㕺ň Ha4㈥'x*hJU8u5hooÜ٭Ί(>{=Bp5$w Q]]T*5188k_VZJp#.rA8lق_Xf 4 ^f||d^8pG9t,@6`9M" ZzJ4b޽ݍ!4A8/ x$΋$7~%}g9W+|;S../C89㶠i #hGP)%x5FYT,=Tt_.ަ7]2 P'I5 1 ( qٷB͛k׮%mmmXM7J)~C9F\FQwqd||655 6кa]O%`ЗI,D$dg,n (8u]]ۋx O8x~ua%e-~,F0>oLکsXt:.)`}RTUc9 E4(|@G0jqr!EPBO50 ` HЋnA[[j& _Bg_~>o[F_Qч$Ij˲F?٩K+ɭފ+W^\%CpQJ>O+x߾fɒ%gwwwZQ5<ϳ<%̈́ !2eȲ $G XQ5`m0@O>tc$ xY<>?a%y}~!z!ftBr:atNupʮwJC }V*=N Ufyu8"r>M*ࠃ:XM4 TU@tA47cvK jjji2>f=B>$fU'"ĸ2i7+UUߛ3gTn'p{1xb<#_u.&u\]|9@7|>fϞL<|``}>_!%b,iǓ% r7l:V5m*òBMUt-x<^t88y/o:F8ZRY/\c112a2609ZPpUPNYSC]ȗ?ARF NAVCDHN 4p  h2) ik1kVfjA]m ~?4RkoZ*fVgk?ZP8eUUOq466"N,[,Jpq\dI$!_dɏٺu Tc>0 bk.Y,Al٠8"?\rA_Ě5kvvvbbb-%L~0˲Vz(J^oP-Ou]g4M$I*q/766o:~&)HR䤓NBee%jkkp:.dppشi+W244tc*:3-cn9CO$A{ZJ x^0 >hwTwTPQQM184> `<(+P faat@xȬ # #x1 a8@ٌJai:V'_4ߠ5Jf4TQj a1&" +"| 0Y8  5=aPs=ļVi T*xMj2<J2 tTgh9k'`u 1:@UT C! "L 9N-[iYb_&?gRQ|J X_Q0g͚[ox̋/HW^=U̅pYobxxF"ܹu؍d djD@|>bEvgrрVXPJ(RB cO c"D<6e4a9²`AXA52,tN Fh0, dg1(t5vP B `)Pn%|y XP05cKjnP&^7@`j`!z8BADC!**P!"gBy-rffR>FՖޡ*Ld4.DQT=ϛ?onnc"ݼy3 nF駟wCpp QocxxalڴɿbŊSƮIgzñ|}Ţ@,E8B0̦{ \۟Y>I],~{k^{I}emiBSSӯ{O?;w뮻ɅBppzzz9sJe۶mJ|!eiaYʲ CEQ '`w/`Ed#֬`Ll{}AL9;&RRB|]?W"0MӨ@2Q"GZZZ|M?83INlݺW_}apq᪫aӟ4{I0HMMͪx<~gXBj'ffyu,gF4M0kDB`rd`ǠXW8!fмmk5MD[{~_UլѷV'>$QJ{O,>+ Ν;rM>1q`Y^z饨&==q# {勵o*++?N;kMWX1Kzzz.NR'<_E04q\×ehF3cPMӈ=j IR: =gΜX}w{UUarWYbHpqD!J!4'|Qi7o]f |IہSO=uv:RRxSH1$WC;_r!o ؝K @:-AH{ܜ~nh>ӷf?UdzY>2 3|>_o(zyxxxCOOO< /g?#{,9 ǿ`_/}p_j.# y#N;w!a_fv={^Yh҉3۷0~?qQU2^VȲ,og6ѝI?96l?(=7'AxyddJ{wp1'E]Dt]m݆믿\;rqu\Q(b)op``@׿!Xar7uu\(2c SЇ>!sN{nrgguأ>ƍ=HdY<?sk5M[B^!  ,R+ed }^G 7B!XF u[zs []o{"Xks'k?ZT/sX|dr$B&Ivg۟zF";wַs!6mBWWB/9!ㇸp1E#e<(qGС!,](;vН;w:8묳}ѧ_}g׬YSQYYh``={iRS0y!a(04cȩZ˲nZmgl۝\.Af_f(r\h7+w&o}η}]n5TUU!YxD4BqTYUUU[_E*++Gmۦ}w]躎W_},˒'ˁlLdz|N hZ6g@ccr'{K/K/ܩ5kVî]_eY5;6VE'Ȥ&9BCGrS\i\G^)e.G'kco̶Vy(Ծ :cw>TU5t]ORX[[[_}wn߾=|r}ܹ _&i("/"@̋HeY$IBm_Ń]pqp#.(4odcA:f8o 7@jjjyM<͛QU_(RCܵkbdz|lllt 1 e`b3*dYɁ 1˲Zfwry\Ptru߅}G7ϝgS{>>gAvoc0TUE鯨 ޮy]v{g;VݻFq=%KPȢE/Ǒ Ld" ]mwH8b>8կ~tMGbY' ^'|o\rItx*B8PJmVOm3zǠY-E@<˲$uvane /c- QJiƨ?5 df4G aRJ5Mc,~ֱ3Ҟ(bBӴuuu<7?1#)ęgs=;v`:,駟&?֭[SO=P ~7bt\# n Cp0 MǫJ6mڄc=}r 'gyE (;.袦α.]0+WBxBoU >)O`7,˒6 P(@KE29ZTux S8PaaB" B{+++7b7;::l߾aSX!2߃d2[lҼ}9,vڑH$Z4MkdY6xxJ)G!=\Ɋ+022LLLк:Gwh Es{~{+_Wزe g>^/}$He]&=cqJ鶆~?+x)O?i```VP(,IҬ۷<_PJ9808eiږ%adld˷E)dbVأd"LFX,kI1UUG#xMMM,*++wqAX,~kIP__O~  vNqӛo+WD2?cF@Yc::.4#IAee%݋|;@ "~g3闿e/a֭[i:Vczjիoա555|@D;󉪪eu]d՞ T͔齽АkǨ2D>H$ iT$|Y9䱱1q۷T Gcpphoo!ٸq#g>Cyڵk(o 'x"֭[>w cݺua*/.# #LZL1,iwܑM>dA?#t'6l;ȭJ+**6 ޽t,ðBee%^/fϞH$_~W\qnFK s=t: al2",nNq=G֭#u~;TU`YX vid,#"ӇzqLb=5\őpqDTÚC~>|,#1bѨ.\ .$W\q|;vRٷo:\veWٸq#y<ϓn gu]WFlڴ _+裏 _|>_6"a:9sd oGL*deY466VUU0 z1}>Q;K "(>/]~>.őpJ=s3Pl1An$Iޜ^{kuYI(";i'd0,;a#|>ZUU@ESIp=+_Jk\(A5.\+… .\@\.\p… .\@ .\p1:.\p p… 3… .\@ .\p1:.\p p… 3… .\@ .\p1:.\p p… 3… .\@ .\p1:.\p p… 3… .\@ .\p1:.\p p… 3… .\@ .\p1:.\p p… 3?KaU [IENDB`IanniX-0.9.20/iannix_cmd.h000066400000000000000000000143241317340345000152560ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #ifndef IANNIX_CMD_H #define IANNIX_CMD_H #define COMMAND_END_BYTE '\n' #define COMMAND_END QString(COMMAND_END_BYTE) // DOCUMENTED IN GUI #define COMMAND_ADD "add" #define COMMAND_REMOVE "remove" #define COMMAND_CLEAR "clear" #define COMMAND_ID "setid" #define COMMAND_GROUP "setgroup" #define COMMAND_TRIGGER_OFF "settriggeroff" #define COMMAND_ACTIVE "setactive" #define COMMAND_CURSOR_CURVE "setcurve" #define COMMAND_CURSOR_FIRE "setfire" #define COMMAND_CURSOR_START "setpattern" #define COMMAND_CURSOR_WIDTH "setwidth" #define COMMAND_CURSOR_DEPTH "setdepth" #define COMMAND_CURSOR_SPEED "setspeed" #define COMMAND_CURSOR_SPEEDF "setspeedf" #define COMMAND_CURSOR_BOUNDS_SOURCE "setboundssource" #define COMMAND_CURSOR_BOUNDS_SOURCE_MODE "setboundssourcemode" #define COMMAND_CURSOR_BOUNDS_TARGET "setboundstarget" #define COMMAND_CURSOR_OFFSET "setoffset" #define COMMAND_CURVE_EDITOR "displaycurveeditor" #define COMMAND_CURVE_RESAMPLE "displaycurveresample" #define COMMAND_CURVE_EQUATION "setequation" #define COMMAND_CURVE_EQUATION_POINTS "setequationnbpoints" #define COMMAND_CURVE_ELL "setpointsellipse" #define COMMAND_CURVE_POINT "setpointat" #define COMMAND_CURVE_POINT_SMOOTH "setsmoothpointat" #define COMMAND_CURVE_POINT_RMV "removepointat" #define COMMAND_SIZE "setsize" #define COMMAND_POS "setpos" #define COMMAND_POS_TRANSLATE "settranslate" #define COMMAND_POS_X "setposx" #define COMMAND_POS_Y "setposy" #define COMMAND_POS_Z "setposz" #define COMMAND_MESSAGE "setmessage" #define COMMAND_MESSAGE_INTERVAL "setmessageinterval" #define COMMAND_LABEL "setlabel" #define COMMAND_ZOOM "zoom" #define COMMAND_GOTO "goto" #define COMMAND_PLAY "play" #define COMMAND_STOP "stop" #define COMMAND_FF "fastrewind" #define COMMAND_SPEED "speed" #define COMMAND_CENTER "center" #define COMMAND_ROTATE "rotate" #define COMMAND_TRIG "trig" #define COMMAND_GLOBAL_COLOR "registercolor" #define COMMAND_COLOR_ACTIVE "setcoloractive" #define COMMAND_COLOR_INACTIVE "setcolorinactive" #define COMMAND_COLOR_MULTIPLY "setcolormultiply" #define COMMAND_TEXTURE "registertexture" #define COMMAND_TEXTURE_ACTIVE "settextureactive" #define COMMAND_TEXTURE_INACTIVE "settextureinactive" #define COMMAND_SOLO "setsolo" #define COMMAND_MUTE "setmute" #define COMMAND_CURVE_TXT "setpointstxt" #define COMMAND_CURVE_PATH "setpointspath" #define COMMAND_RESIZE "setresize" #define COMMAND_CURSOR_TIME_PERCENT "settimepercent" // CLOSE TO OTHER FUNCTIONS #define COMMAND_TEXTURE_GLOBAL "settexture" #define COMMAND_GLOBAL_COLOR_HUE "registercolorhue" #define COMMAND_COLOR_GLOBAL "setcolor" #define COMMAND_COLOR_GLOBAL_HUE "setcolorhue" #define COMMAND_COLOR_ACTIVE_HUE "setcoloractivehue" #define COMMAND_COLOR_INACTIVE_HUE "setcolorinactivehue" #define COMMAND_COLOR_MULTIPLY_HUE "setcolormultiplyhue" #define COMMAND_CURSOR_TIME "settime" // DOCUMENTED IN SCRIPT TEMPLATE #define COMMAND_LOG "log" #define COMMAND_TITLE "title" // SCRIPT SPECIFC #define COMMAND_CURVE_EQUATION_PARAM "setequationparam" #define COMMAND_CURVE_EQUATION_PARAM_LIST "setequationparamlist" #define COMMAND_CURVE_LINES "setpointslines" #define COMMAND_LOAD "load" #define COMMAND_OPEN "open" #define COMMAND_CLOSE "close" #define COMMAND_CURVE_LENGTH "setlength" #define COMMAND_MESSAGE_SEND "sendmessage" #define COMMAND_MOUSE "mouse" #define COMMAND_CURVE_POINT_SHIFT "shiftpoints" #define COMMAND_CURVE_POINT_TRANSLATE "translatepoints" #define COMMAND_CURVE_POINT_TRANSLATE2 "translatepoint" #define COMMAND_CURVE_POINT_X "setpointxat" #define COMMAND_CURVE_POINT_Y "setpointyat" #define COMMAND_CURVE_POINT_Z "setpointzat" #define COMMAND_RESIZEF "setresizef" // BETA FUNCTIONS #define COMMAND_CURVE_INERTIE "setelasticity" #define COMMAND_LINE "setline" // INTERNAL FUNCTIONS #define COMMAND_SLEEP "sleep" #define COMMAND_VIEWPORT "viewport" #define COMMAND_SNAPSHOT "snapshot" #endif // IANNIX_CMD_H IanniX-0.9.20/iannix_spec.cpp000066400000000000000000000026261317340345000160020ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #include "iannix_spec.h" ExecuteSource NxObjectDispatchProperty::source = ExecuteSourceGui; void NxObjectDispatchProperty::propertyChanged(const char *_property) { QString property = _property; if(!propertiesToSerialize[source].contains(property)) propertiesToSerialize[source].append(property); if(!propertiesToSerialize[ExecuteSourceCopyPaste].contains(property)) propertiesToSerialize[ExecuteSourceCopyPaste].append(property); } IanniX-0.9.20/iannix_spec.h000066400000000000000000000035451317340345000154500ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #ifndef IANNIX_SPEC_H #define IANNIX_SPEC_H #include #include #include #include "geometry/nxpoint.h" #include "geometry/nxrect.h" #include "geometry/nxline.h" #include "geometry/nxpolygon.h" enum ExecuteSource { ExecuteSourceSystem, ExecuteSourceGui, ExecuteSourceScript, ExecuteSourceNetwork, ExecuteSourceInformative, ExecuteSourceCopyPaste }; class NxObjectDispatchProperty { protected: QMap propertiesToSerialize; public: static ExecuteSource source; public: void propertyChanged(const char *_property); public: virtual quint8 getType() const { return 0; } virtual const QString getTypeStr() const { return QString(); } virtual void dispatchProperty(const char *_property, const QVariant & value) = 0; virtual const QVariant getProperty(const char *_property) const = 0; }; #endif // IANNIX_SPEC_H IanniX-0.9.20/iannixapp.cpp000066400000000000000000001127171317340345000154740ustar00rootroot00000000000000/* This file is part of IanniX, a graphical real-time open-source sequencer for digital art Copyright (C) 2010-2015 — IanniX Association Project Manager: Thierry Coduys (http://www.le-hub.org) Development: Guillaume Jacquemin (https://www.buzzinglight.com) This file was written by Guillaume Jacquemin. IanniX is a 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 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 . */ #include #include #include "iannixapp.h" #include "misc/help.h" #include "misc/options.h" #include "gui/uisplashscreen.h" int main(int argc, char *argv[]) { #ifdef QT4 QTextCodec::setCodecForTr (QTextCodec::codecForName("UTF-8")); QTextCodec::setCodecForLocale (QTextCodec::codecForName("UTF-8")); QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); #endif IanniXApp iannixApp(argc, argv); //QString locale = QLocale::system().name(); //QTranslator translator; //translator.load("Translation_" + locale, "Tools"); //iannixApp.installTranslator(&translator); QString appName = "IanniX "; QString appVersion = "0.9.20"; #ifdef Q_OS_MAC appName += "Mac"; qDebug("Command line syntax : ./IanniX.app/Contents/MacOS/IanniX "); #endif #ifdef Q_OS_WIN appName += "Windows"; qDebug("Command line syntax : IanniX.exe "); #endif #ifdef Q_OS_LINUX appName += "Linux"; qDebug("Command line syntax : ./IanniX "); #endif QCoreApplication::setApplicationName (appName.trimmed()); QCoreApplication::setApplicationVersion(appVersion.trimmed()); QCoreApplication::setOrganizationName ("IanniX"); QCoreApplication::setOrganizationDomain("iannix"); iannixApp.launch(argc, argv); return iannixApp.exec(); } IanniXApp::IanniXApp(int &argc, char **argv) : QApplication(argc, argv) { iannix = 0; } void IanniXApp::launch(int &argc, char **argv) { //Display splash Application::splash = new UiSplashScreen(QPixmap(":/general/res_splash.png")); //Start setHelp(); QDir pathApplicationDir = QDir(QCoreApplication::applicationDirPath()).absolutePath(); #ifdef Q_OS_MAC pathApplicationDir.cdUp(); pathApplicationDir.cdUp(); pathApplicationDir.cdUp(); #endif #ifdef QT4 Application::pathDocuments = QFileInfo(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation) + "/IanniX"); #else Application::pathDocuments = QFileInfo(QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first() + "/IanniX"); #endif Application::pathApplication = QFileInfo(pathApplicationDir.absolutePath()); Application::pathCurrent = QFileInfo(QDir::currentPath()); if((Application::pathApplication.absoluteFilePath().endsWith("/IanniX-build-64")) || (Application::pathApplication.absoluteFilePath().endsWith("/IanniX-build-32"))) Application::pathApplication = QFileInfo(Application::pathApplication.absoluteFilePath().remove("-build-64").remove("-build-32")); if(Application::pathApplication.absoluteFilePath().endsWith("/IanniX-build/release")) Application::pathApplication = QFileInfo(Application::pathApplication.absoluteFilePath().remove("-build/release")); if(Application::pathApplication.absoluteFilePath().endsWith("/IanniX-build")) Application::pathApplication = QFileInfo(Application::pathApplication.absoluteFilePath().remove("-build")); qDebug("Paths"); qDebug("\tDocuments : %s", qPrintable(Application::pathDocuments .absoluteFilePath())); qDebug("\tApplication: %s", qPrintable(Application::pathApplication.absoluteFilePath())); qDebug("\tCurrent : %s", qPrintable(Application::pathCurrent .absoluteFilePath())); qDebug("Arguments"); for(quint16 i = 0 ; i < argc ; i++) qDebug("\t%2d=\t%s", i, argv[i]); /* if(Application::pathCurrent.absoluteFilePath().startsWith("/Users/Guillaume/Documents/buzzinglight/Projets/Coduys/IanniX/IanniX")) generateHelp(); */ QFileInfo file; for(quint16 i = 0 ; i < argc ; i++) { file = QFileInfo(argv[i]); if((file.exists()) && (file.suffix().toLower().contains("iannix"))) { project = file; break; } file = QFileInfo(Application::pathCurrent.absoluteFilePath() + "/" + argv[i]); if((file.exists()) && (file.suffix().toLower().contains("iannix"))) { project = file; break; } file = QFileInfo(Application::pathDocuments.absoluteFilePath() + "/" + argv[i]); if((file.exists()) && (file.suffix().toLower().contains("iannix"))) { project = file; break; } } //Add font if(QFontDatabase::addApplicationFont(Application::pathApplication.absoluteFilePath() + "/Tools/Museo.ttf")) qDebug("Loading IanniX font failed : %s", qPrintable(Application::pathApplication.absoluteFilePath() + "/Tools/Museo.ttf")); //List of fonts if(false) { qDebug("[FONTS]"); QFontDatabase fontDb; QStringList fontList = fontDb.families(); foreach(const QString &font, fontList) { qDebug("\tFamille : %s", qPrintable(font)); if(true) { qDebug("\t\tFont : %s", qPrintable(font)); QStringList styleList = fontDb.styles(font); foreach(const QString &style, styleList) { int weight = fontDb.weight(font, style); qDebug("\t\t\t > Style / Graisse %s %d", qPrintable(style), weight); } } } } if(project.exists()) { qDebug("Loading project %s", qPrintable(project.absoluteFilePath())); iannix = new IanniX(project.absoluteFilePath()); } else iannix = new IanniX(); } bool IanniXApp::event(QEvent *event) { switch (event->type()) { case QEvent::FileOpen: project = QFileInfo(static_cast(event)->file()); if(iannix) { if(iannix->projectIsLoaded) iannix->loadProject(project.absoluteFilePath()); else iannix->projectToLoad = project.absoluteFilePath(); } return true; default: return QApplication::event(event); } } void IanniXApp::setHelp() { Help::categories["protocols"].category = tr("Messages protocols"); Help::categories["protocols"].infos << HelpInfo(QString("osc"), tr("OpenSoundControl message")); Help::categories["protocols"].infos << HelpInfo(QString("direct"), tr("Recursive/loopback message (sent directly to IanniX)")); Help::categories["protocols"].infos << HelpInfo(QString("midi"), tr("MIDI message (control change, note on/off or program change)")); Help::categories["protocols"].infos << HelpInfo(QString("serial"), tr("Serial message (UART/RS232)")); Help::categories["protocols"].infos << HelpInfo(QString("http"), tr("HTTP request to a webpage/webservice (GET)")); Help::categories["protocols"].infos << HelpInfo(QString("udp"), tr("Raw UDP message (compatible with PureData)")); Help::categories["protocols"].infos << HelpInfo(QString("tcp"), tr("XML over TCP message (compatible with Flash/Director)")); Help::categories["hostIp"].category = tr("Messages IP"); Help::categories["hostIp"].infos << HelpInfo(QString("ip_out"), tr("Destination is the default IP set in \"Network\" tab")); Help::categories["hostIp"].infos << HelpInfo(QString("127.0.0.1"), tr("Destination is your own computer")); Help::categories["hostMidi"].category = tr("Messages MIDI devices"); Help::categories["hostMidi"].infos << HelpInfo(QString("midi_out"), tr("Destination is the default MIDI device set in \"Network\" tab")); Help::categories["hostMidi"].infos << HelpInfo(QString("from_IanniX"), tr("MIDI device created by IanniX (Mac & Linux only)")); Help::categories["port"].category = tr("Messages IP ports"); Help::categories["port"].infos << HelpInfo(QString("port_out"), tr("Default port set in \"Network\" tab")); Help::categories["port"].infos << HelpInfo(QString("57120"), tr("Basic output port used by IanniX")); Help::categories["port"].infos << HelpInfo(QString("1234"), tr("IanniX OSC default input")); Help::categories["addressOsc"].category = tr("Messages OSC addresses"); Help::categories["addressOsc"].infos << HelpInfo(QString("/trigger"), tr("Default address used for triggers")); Help::categories["addressOsc"].infos << HelpInfo(QString("/cursor"), tr("Default address used for cursors")); Help::categories["addressOsc"].infos << HelpInfo(QString("/transport"), tr("Default address used for transport messages")); Help::categories["addressOsc"].infos << HelpInfo(QString("/iannix"), tr("Default address used to reach IanniX")); Help::categories["addressMidi"].category = tr("Messages MIDI controls"); Help::categories["addressMidi"].infos << HelpInfo(QString("/cc"), tr("Send a control change")); Help::categories["addressMidi"].infos << HelpInfo(QString("/ccf"), tr("Send a control change (value as a float value between 0. and 1.)")); Help::categories["addressMidi"].infos << HelpInfo(QString("/note"), tr("Send a note")); Help::categories["addressMidi"].infos << HelpInfo(QString("/notef"), tr("Send a note (note and velocity as a float values between 0. and 1.)")); Help::categories["addressMidi"].infos << HelpInfo(QString("/bend"), tr("Send a bend")); Help::categories["addressMidi"].infos << HelpInfo(QString("/bendf"), tr("Send a bend (value as a float value between 0. and 1.)")); Help::categories["addressMidi"].infos << HelpInfo(QString("/pgm"), tr("Send a program change")); Help::categories["addressMidi"].infos << HelpInfo(QString("/pgmf"), tr("Send a program change (program as a float value between 0. and 1.)")); Help::categories["values"].category = tr("Messages values"); Help::categories["values"].infos << HelpInfo(QString("trigger_id"), tr("ID of the triggered trigger")); Help::categories["values"].infos << HelpInfo(QString("trigger_group_id"), tr("Group name of the triggered trigger")); Help::categories["values"].infos << HelpInfo(QString("trigger_label"), tr("Label of the triggered trigger")); Help::categories["values"].infos << HelpInfo(QString("trigger_xPos"), tr("x coordinate of the triggered trigger")); Help::categories["values"].infos << HelpInfo(QString("trigger_yPos"), tr("y coordinate of the triggered trigger")); Help::categories["values"].infos << HelpInfo(QString("trigger_zPos"), tr("z coordinate of the triggered trigger")); Help::categories["values"].infos << HelpInfo(QString("trigger_value_x"), tr("x mapped coordinate of the triggered trigger")); Help::categories["values"].infos << HelpInfo(QString("trigger_value_y"), tr("y mapped coordinate of the triggered trigger")); Help::categories["values"].infos << HelpInfo(QString("trigger_value_z"), tr("z mapped coordinate of the triggered trigger")); Help::categories["values"].infos << HelpInfo(QString("trigger_value"), tr("When trigger duration is not null, returns 127 when the trigger is trigged and 0 when the trigger is released")); Help::categories["values"].infos << HelpInfo(QString("trigger_duration"), tr("Trigger duration")); Help::categories["values"].infos << HelpInfo(QString("trigger_distance"), tr("Distance between the triggered trigger and the cursor that triggers the trigger")); Help::categories["values"].infos << HelpInfo(QString("trigger_side"), tr("0 if trigger is triggered from left to right and 1 for the other side")); Help::categories["values"].infos << HelpInfo(QString("trigger_message_id"), tr("ID of the message (each message generates an ascending ID)")); Help::categories["values"].infos << HelpInfo(QString("cursor_id"), tr("ID of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_group_id"), tr("Group name of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_label"), tr("Label of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_xPos"), tr("x coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_yPos"), tr("y coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_zPos"), tr("z coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_value_x"), tr("x mapped coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_value_y"), tr("y mapped coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_value_z"), tr("z mapped coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_xPos_delta"), tr("Variation of x coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_yPos_delta"), tr("Variation of y coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_zPos_delta"), tr("Variation of z coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_value_x_delta"), tr("Variation of x mapped coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_value_y_delta"), tr("Variation of y mapped coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_value_z_delta"), tr("Variation of z mapped coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_aPos"), tr("a coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_ePos"), tr("e coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_dPos"), tr("d coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_value_a"), tr("a mapped coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_value_e"), tr("e mapped coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_value_d"), tr("d mapped coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_aPos_delta"), tr("Variation of a coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_ePos_delta"), tr("Variation of e coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_dPos_delta"), tr("Variation of d coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_value_a_delta"), tr("Variation of a mapped coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_value_e_delta"), tr("Variation of d mapped coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_value_d_delta"), tr("Variation of d mapped coordinate of the running cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_time"), tr("Current progression of the cursor on the curve (in seconds)")); Help::categories["values"].infos << HelpInfo(QString("cursor_time_percent"), tr("Current progression of the cursor on the curve (in percentages, from 0.0 to 1.0)")); Help::categories["values"].infos << HelpInfo(QString("cursor_angle"), tr("Angle of the cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_time_delta"), tr("Variation of current progression of the cursor on the curve (in seconds)")); Help::categories["values"].infos << HelpInfo(QString("cursor_time_percent_delta"), tr("Variation of current progression of the cursor on the curve (in percentages, from 0.0 to 1.0)")); Help::categories["values"].infos << HelpInfo(QString("cursor_angle_delta"), tr("Variation of angle of the cursor")); Help::categories["values"].infos << HelpInfo(QString("cursor_nb_loop"), tr("Number of loops done by the cursor on the curve")); Help::categories["values"].infos << HelpInfo(QString("cursor_message_id"), tr("ID of the message (each message generates an ascending ID)")); Help::categories["values"].infos << HelpInfo(QString("curve_id"), tr("ID of curve where the cursor runs on")); Help::categories["values"].infos << HelpInfo(QString("curve_group_id"), tr("Group name of curve where the cursor runs on")); Help::categories["values"].infos << HelpInfo(QString("curve_label"), tr("Label of curve where the cursor runs on")); Help::categories["values"].infos << HelpInfo(QString("curve_xPos"), tr("x coordinate of curve where the cursor runs on")); Help::categories["values"].infos << HelpInfo(QString("curve_yPos"), tr("y coordinate of curve where the cursor runs on")); Help::categories["values"].infos << HelpInfo(QString("curve_zPos"), tr("z coordinate of curve where the cursor runs on")); Help::categories["values"].infos << HelpInfo(QString("collision_curve_id"), tr("ID of the collided curve")); Help::categories["values"].infos << HelpInfo(QString("collision_curve_group_id"), tr("Group name of the collided curve")); Help::categories["values"].infos << HelpInfo(QString("collision_curve_label"), tr("Label of the collided curve")); Help::categories["values"].infos << HelpInfo(QString("collision_curve_xPos"), tr("x coordinate of the collided curve")); Help::categories["values"].infos << HelpInfo(QString("collision_curve_yPos"), tr("y coordinate of the collided curve")); Help::categories["values"].infos << HelpInfo(QString("collision_curve_zPos"), tr("z coordinate of the collided curve")); Help::categories["values"].infos << HelpInfo(QString("collision_xPos"), tr("x coordinate of the collision between the cursor and the curve")); Help::categories["values"].infos << HelpInfo(QString("collision_yPos"), tr("y coordinate of the collision between the cursor and the curve")); Help::categories["values"].infos << HelpInfo(QString("collision_value_x"), tr("x mapped coordinate of the collision between the cursor and the curve")); Help::categories["values"].infos << HelpInfo(QString("collision_value_y"), tr("y mapped coordinate of the collision between the cursor and the curve")); Help::categories["values"].infos << HelpInfo(QString("collision_distance"), tr("Distance between the collision and the cursor")); Help::categories["values"].infos << HelpInfo(QString("timetag"), tr("Set an OSC Timetag (compliant with Internet NTP timestamps) to message")); Help::categories["values"].infos << HelpInfo(QString("status"), tr("Playback status of score (\"play\"), \"stop\" or \"fastrewind\")")); Help::categories["values"].infos << HelpInfo(QString("nb_triggers"), tr("Number of triggers in the current score")); Help::categories["values"].infos << HelpInfo(QString("nb_cursors"), tr("Number of cursors in the current score")); Help::categories["values"].infos << HelpInfo(QString("nb_curves"), tr("Number of curves in the current score")); Help::categories["values"].infos << HelpInfo(QString("global_time"), tr("Elapsed time in seconds")); Help::categories["values"].infos << HelpInfo(QString("global_time_verbose"), tr("Elapsed time as displayed in Transport bar")); Help::categories["javascript"].category = tr("JavaScript useful functions"); Help::categories["javascript"].infos << HelpInfo(QString("abs(x)"), tr("Absolute value of x")); Help::categories["javascript"].infos << HelpInfo(QString("acos(x)"), tr("Arccosine of x")); Help::categories["javascript"].infos << HelpInfo(QString("asin(x)"), tr("Arcsine of x")); Help::categories["javascript"].infos << HelpInfo(QString("atan(x)"), tr("Arctangent of x")); Help::categories["javascript"].infos << HelpInfo(QString("atan2(x,y)"), tr("Arctangent of x divided by y")); Help::categories["javascript"].infos << HelpInfo(QString("ceil(x)"), tr("Next higher integer above x")); Help::categories["javascript"].infos << HelpInfo(QString("cos(x)"), tr("Cosine of x")); Help::categories["javascript"].infos << HelpInfo(QString("exp(x)"), tr("e to the power x")); Help::categories["javascript"].infos << HelpInfo(QString("floor(x)"), tr("Next lower integer below x")); Help::categories["javascript"].infos << HelpInfo(QString("log(x)"), tr("Logarithm to the base 2 of x")); Help::categories["javascript"].infos << HelpInfo(QString("min(x,y)"), tr("Minimum of x and y")); Help::categories["javascript"].infos << HelpInfo(QString("max(x,y)"), tr("Maximum of x and y")); Help::categories["javascript"].infos << HelpInfo(QString("pow(x,y)"), tr("x raised to the power y")); Help::categories["javascript"].infos << HelpInfo(QString("round(x)"), tr("x rounded nearest integer, higher or lower")); Help::categories["javascript"].infos << HelpInfo(QString("sin(x)"), tr("Sine of x")); Help::categories["javascript"].infos << HelpInfo(QString("sqrt(x)"), tr("Square root of x")); Help::categories["javascript"].infos << HelpInfo(QString("sq(x)"), tr("x squared")); Help::categories["javascript"].infos << HelpInfo(QString("tan(x)"), tr("Tangent of x")); Help::categories["javascript"].infos << HelpInfo(QString("degrees(x)"), tr("Radian angle x converted into degrees")); Help::categories["javascript"].infos << HelpInfo(QString("radians(x)"), tr("Degree angle x converted into radians")); Help::categories["javascript"].infos << HelpInfo(QString("random(low, high)"), tr("Random number between low and high")); Help::categories["javascript"].infos << HelpInfo(QString("constrain(x, min, max)"), tr("Values of x below min and above max are discarded")); Help::categories["javascript"].infos << HelpInfo(QString("dist(x1, y1, z1, x2, y2, z2)"), tr("Distance between the points (x1, y1, z1) and (x2, y2, z2)")); Help::categories["javascript"].infos << HelpInfo(QString("angle(x1, y1, x2, y2)"), tr("Angle between the points (x1, y1) and (x2, y2)")); Help::categories["javascript"].infos << HelpInfo(QString("norm(x, low, high)"), tr("Scale x to cover the range from low to high, assuming x ranges between 0.0 and 1.0:")); Help::categories["javascript"].infos << HelpInfo(QString("rangeMid(x, low, mid, high)"), tr("Scale x to cover the range from low to high, assuming x ranges between 0.0 and 1.0, with mid being returned as the value for x=0.5")); Help::categories["javascript"].infos << HelpInfo(QString("map(x, low1, high1, low2, high2)"),tr("Scale x to cover the range from low2 to high2, assuming x ranges between low1 and high1")); Help::categories["javascript"].infos << HelpInfo(QString("LN2"), tr("Natural logarithm of 2")); Help::categories["javascript"].infos << HelpInfo(QString("LN10"), tr("Natural logarithm of 10")); Help::categories["javascript"].infos << HelpInfo(QString("LOG2E"), tr("Base 2 logarithm of e")); Help::categories["javascript"].infos << HelpInfo(QString("LOG10E"), tr("Logarithm to the base 10 of e")); Help::categories["javascript"].infos << HelpInfo(QString("PI"), tr("Constant PI")); Help::categories["javascript"].infos << HelpInfo(QString("TWO_PI"), tr("Two times PI")); Help::categories["javascript"].infos << HelpInfo(QString("THIRD_PI"), tr("PI over 3")); Help::categories["javascript"].infos << HelpInfo(QString("QUARTER_PI"), tr("PI over 4")); Help::categories["javascript"].infos << HelpInfo(QString("HALF_PI"), tr("PI over 2")); Help::categories["javascript"].infos << HelpInfo(QString("SQRT1_2"), tr("One over the square root of two")); Help::categories["javascript"].infos << HelpInfo(QString("SQRT2"), tr("Square root of two")); Help::categories["commands"].category = tr("IanniX Commands"); Help::categories["commands"].infos << HelpInfo(COMMAND_ADD , tr("Objects instances"), tr("Adds an object to score"), tr(" \nadd auto")); Help::categories["commands"].infos << HelpInfo(COMMAND_REMOVE , tr("Objects instances"), tr("Removes an object from score"), tr("")); Help::categories["commands"].infos << HelpInfo(COMMAND_CLEAR , tr("Objects instances"), tr("Clears the score (remove all objects)"), tr("")); Help::categories["commands"].infos << HelpInfo(COMMAND_ID , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_GROUP , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_TRIGGER_OFF , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_ACTIVE , tr(""), tr(""), tr(" <0|1>")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURSOR_CURVE , tr("Objects identification"), tr("Associates a cursor to a curve"), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURSOR_START , tr(""), tr(""), tr(" <0> ")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURSOR_FIRE , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURSOR_WIDTH , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURSOR_DEPTH , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURSOR_SPEED , tr(""), tr(""), tr(" \n auto \n lock autolock ")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURSOR_SPEEDF , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURSOR_BOUNDS_SOURCE , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURSOR_BOUNDS_SOURCE_MODE, tr(""), tr(""), tr(" <0|1|2|3>")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURSOR_BOUNDS_TARGET , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURSOR_OFFSET , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURVE_EDITOR , tr("Objects and 3D space"), tr("Displays curve points editor"), tr("")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURVE_EQUATION , tr(""), tr(""), tr(" cartesian \n polar ")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURVE_EQUATION_POINTS , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURVE_ELL , tr("Objects and 3D space"), tr("Defines a curve as an ellipse"), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURVE_POINT , tr("Objects and 3D space"), tr("Defines point position of a curve"), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURVE_POINT_SMOOTH , tr("Objects and 3D space"), tr("Defines smoothed point position of a curve"), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURVE_POINT_RMV , tr("Objects and 3D space"), tr("Removes point from a curve"), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_CURVE_INERTIE , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_SIZE , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_POS , tr("Objects and 3D space"), tr("Changes the absolute position of object"), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_POS_TRANSLATE , tr("Objects and 3D space"), tr("Translate position of object"), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_POS_X , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_POS_Y , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_POS_Z , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_MESSAGE , tr(""), tr(""), tr(" , , , …")); Help::categories["commands"].infos << HelpInfo(COMMAND_MESSAGE_INTERVAL , tr(""), tr(""), tr(" ")); Help::categories["commands"].infos << HelpInfo(COMMAND_LABEL , tr(""), tr(""), tr("
  • software interfaces controlling IanniX via Open Sound Control for example, through IanniX commands;