pax_global_header00006660000000000000000000000064121530073130014505gustar00rootroot0000000000000052 comment=a850f86e25843122c6c0303acbd56ec9fc6945ba mlt-0.9.0/000077500000000000000000000000001215300731300123075ustar00rootroot00000000000000mlt-0.9.0/.gitignore000066400000000000000000000003501215300731300142750ustar00rootroot00000000000000*.o *.so *.so.* config.mak config.h .depend *~ *.cxx docs/html/* releases/* patches/* src/modules/lumas/NTSC/*.pgm src/modules/lumas/PAL/*.pgm src/swig/csharp/src_swig/* src/swig/perl/blib/* *.dylib src/swig/java/src_swig disable-* mlt-0.9.0/AUTHORS000066400000000000000000000007211215300731300133570ustar00rootroot00000000000000MLT framework was developed by: Charles Yates MLT framework is maintained by: Dan Dennedy MLT module authors and maintainers: Charles Yates Dan Dennedy Stephane Fillod (effectv) Marco Gittler (frei0r, oldfilm, qimage/kdenlivetitle) Jean-Baptiste Mardelle (kdenlive, qimage) Zachary Drew (motion_est) Maksym Veremeyenko mlt-0.9.0/COPYING000066400000000000000000000634741215300731300133600ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library 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 of the License, or (at your option) any later version. This library 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 this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! mlt-0.9.0/ChangeLog000066400000000000000000015352561215300731300141020ustar00rootroot000000000000002013-06-02 Dan Dennedy * Doxyfile, configure, docs/melt.1, src/framework/mlt_version.h: Set version to 0.9.0. * src/modules/opengl/filter_glsl_manager.cpp, src/modules/opengl/glsl_manager.h: Fix tiny memory leak in GlslManager (coverity-1026795). * src/framework/mlt.h, src/framework/mlt_animation.c, src/framework/mlt_animation.h, src/framework/mlt_geometry.c, src/framework/mlt_geometry.h: Indicate mlt_geometry is deprecated in API docs. 2013-06-01 Dan Dennedy * src/modules/opengl/filter_movit_rect.cpp, src/modules/opengl/filter_movit_rect.yml, src/modules/opengl/filter_movit_resize.cpp: Convert movit.rect to mlt_rect. 2013-05-31 Dan Dennedy * .../opengl/filter_deconvolution_sharpen.cpp, .../opengl/filter_deconvolution_sharpen.yml, src/modules/opengl/filter_lift_gamma_gain.cpp, src/modules/opengl/filter_lift_gamma_gain.yml, src/modules/opengl/filter_movit_diffusion.cpp, src/modules/opengl/filter_movit_diffusion.yml, src/modules/opengl/filter_movit_glow.cpp, src/modules/opengl/filter_movit_glow.yml, src/modules/opengl/filter_movit_opacity.cpp, src/modules/opengl/filter_movit_opacity.yml, src/modules/opengl/filter_movit_saturation.cpp, src/modules/opengl/filter_movit_saturation.yml, src/modules/opengl/filter_movit_vignette.cpp, src/modules/opengl/filter_movit_vignette.yml, src/modules/opengl/filter_white_balance.cpp, src/modules/opengl/filter_white_balance.yml, src/modules/opengl/transition_movit_mix.cpp, src/modules/opengl/transition_movit_mix.yml: Add property animation to the other movit services. * presets/filter/movit.blur/blur_in, presets/filter/movit.blur/blur_in_out, presets/filter/movit.blur/blur_out: Add animated movit.blur presets. * src/modules/opengl/filter_movit_blur.cpp, src/modules/opengl/filter_movit_blur.yml: Add property animation to movit.blur filter. * src/framework/mlt_properties.c, src/framework/mlt_property.c: Compile fixes for Windows after merging animation branch. * src/framework/mlt_properties.c, src/mlt++/mlt++.vers: Compile fixes for Linux after merging animation branch. 2013-05-30 Dan Dennedy * src/framework/mlt_animation.c, src/framework/mlt_animation.h, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/framework/mlt_types.h: Various documentation and copyright fixes and updates. * src/framework/mlt_animation.c, src/framework/mlt_animation.h: Document the new mlt_animation API. * src/framework/mlt_properties.c, src/framework/mlt_property.c, src/framework/mlt_types.h: Document the property animation, rect, and color additions. * src/framework/mlt_animation.h, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/framework/mlt_types.h: Add mlt_properties_get_animation(); it might come in handy. * src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h, src/mlt++/mlt++.vers, src/tests/test_properties/test_properties.cpp: Add mlt_properties_set_color(). 2013-05-29 Dan Dennedy * src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/mlt++/MltProperties.cpp, src/tests/test_properties/test_properties.cpp: Reorder some property anim parameters for consistency. * src/framework/Makefile, src/framework/mlt_animation.c, src/framework/mlt_profile.c, src/framework/mlt_property.c, src/mlt++/MltProperties.h, src/tests/test_properties/test_properties.cpp: Make animation length optional. It is only really needed when using negative time values. With some fixes for parsing negatives in time code/clock values. 2013-05-27 Dan Dennedy * src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_types.h, src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h, src/tests/test_properties/test_properties.cpp: Add mlt_color and mlt_properties_get_color(). * src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h, src/tests/test_properties/test_properties.cpp: Add mlt_properties_anim_set/get() for string. * src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h, src/tests/test_properties/test_properties.cpp: Add mlt_properties_anim_set/get_double(). * src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h, src/tests/test_properties/test_properties.cpp: Rename functions with _pos to anim_. * src/framework/mlt_animation.c, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h, src/tests/test_properties/test_properties.cpp: Add mlt_properties_set/get_rect_pos for rect animation. 2013-05-26 Dan Dennedy * src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/framework/mlt_types.h, src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h, src/tests/test_properties/test_properties.cpp: Add mlt_rect and mlt_properties_set/get_rect. 2013-05-22 Dan Dennedy * src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h, src/tests/test_properties/test_properties.cpp: Add mlt_properties_set/get_int_pos and Properties::set/get_int. 2013-05-19 Dan Dennedy * src/framework/mlt_property.c, src/tests/test_properties/test_properties.cpp: Interpret % after numeric string. * src/framework/mlt_property.c, src/framework/mlt_property.h, src/framework/mlt_types.h, src/tests/test_properties/test_properties.cpp: Add mlt_property_set_double_pos() and mlt_property_set_int_pos(). 2013-05-18 Dan Dennedy * src/framework/mlt_animation.c, src/framework/mlt_animation.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/framework/mlt_types.h, src/tests/test_properties/test_properties.cpp: Add Catmull-Rom spline smooth animation interpolation. 2013-05-17 Dan Dennedy * src/framework/mlt_property.c, src/framework/mlt_property.h, src/tests/test_properties/test_properties.cpp: Add mlt_property_get_double_pos() and mlt_property_get_int_pos(). 2013-05-16 Dan Dennedy * src/framework/mlt_animation.c, src/framework/mlt_animation.h, src/framework/mlt_property.c, src/tests/test_properties/test_properties.cpp: Add support for discrete animation including strings. * src/framework/Makefile, src/framework/mlt_animation.c, src/framework/mlt_animation.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/tests/test_properties/test_properties.cpp: Add mlt_animation and mlt_property_interpolate(). mlt_property_interpolate() only works on a scalar double property at this time. 2013-05-14 Maksym Veremeyenko * src/framework/mlt_consumer.c, src/framework/mlt_frame.c, src/framework/mlt_types.h, src/modules/avformat/producer_avformat.c, src/modules/avsync/consumer_blipflash.c, src/modules/core/filter_luma.c, src/modules/dgraft/filter_telecide.c, src/modules/gtk2/producer_count.c, src/modules/kdenlive/producer_framebuffer.c, src/modules/xine/filter_deinterlace.c: make mlt_position type double 2013-05-22 Dan Dennedy * src/modules/avformat/producer_avformat.c, src/modules/avformat/producer_avformat.yml: Add exit_on_disconnect property to avformat producer. 2013-05-21 Dan Dennedy * src/modules/frei0r/Makefile, src/modules/frei0r/factory.c, src/modules/frei0r/param_name_map.yaml, src/modules/frei0r/param_name_map.yml: Rename frei0r param_name_map filename and install it. * src/modules/avformat/producer_avformat.c, src/modules/avformat/producer_avformat.yml: Add reconnect property to avformat producer. 2013-05-07 Dan Dennedy * src/modules/core/producer_melt.c, src/modules/rtaudio/RtAudio.cpp, src/modules/xine/deinterlace.c, src/modules/xml/producer_xml.c: Fix some compile warnings raised by clang. * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h: Make a bunch of fields of mlt_consumer_s truly private. 2013-05-03 Dan Dennedy * src/framework/mlt_properties.c, src/tests/test_properties/test_properties.cpp: Add more properties unit tests. 2013-05-02 Dan Dennedy * src/tests/test_properties/test_properties.cpp, src/tests/test_properties/test_properties.pro: Add more unit tests for mlt_property. 2013-04-30 Dan Dennedy * src/tests/common.pri, src/tests/test_properties/test_properties.cpp, src/tests/test_properties/test_properties.pro, src/tests/test_repository/test_repository.cpp, src/tests/test_repository/test_repository.pro, src/tests/tests.pro: Add the start of a unit test suite using QtTest. * src/tests/Makefile, src/tests/README, src/tests/charlie.c, src/tests/dan.c, src/tests/dissolve.c, src/tests/hello.c, src/tests/io.c, src/tests/io.h, src/tests/luma.c, src/tests/pango.c, src/tests/pixbuf.c, src/tests/test.png: Remove old files in src/tests to make way for new ones. 2013-04-27 Dan Dennedy * src/framework/mlt_consumer.c, src/modules/sdl/consumer_sdl_preview.c: Fix race condition in mlt_consumer_stop(). 2013-04-25 Dan Dennedy * configure, src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_audio.c, src/modules/sdl/consumer_sdl_preview.c: Make mlt_consumer_purge() more thorough. (SF-187) This is applied to SDL consumers only at the moment since that is what most applications are using. Needs to be extended to other consumers. 2013-04-12 Dan Dennedy * configure, src/framework/mlt_version.h: Set interim version 0.8.9. 2013-04-07 Brian Matherly * src/modules/gtk2/producer_count.yml, src/modules/oldfilm/filter_dust.yml, src/modules/oldfilm/filter_grain.yml, src/modules/oldfilm/filter_oldfilm.yml: Misc YAML fixes 2013-04-06 Dan Dennedy * src/framework/mlt.vers, src/framework/mlt_service.c, src/framework/mlt_service.h, src/mlt++/MltService.cpp, src/mlt++/MltService.h, src/mlt++/mlt++.vers: Add mlt_service_move_filter() and Mlt::Service::move_filter(). 2013-04-04 Brian Matherly * src/modules/gtk2/Makefile, src/modules/gtk2/factory.c, src/modules/gtk2/producer_count.c, src/modules/gtk2/producer_count.yml: Add new count producer 2013-03-21 Dan Dennedy * src/modules/avformat/factory.c, src/modules/avformat/filter_avresample.c: Restore avresample filter when build against FFmpeg. This provides a LGPL audio resampler, but it is using deprecated APIs. Support for swresample or libav avresampler is another project. 2013-03-20 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: Add support for libavformat and libavcodec major version 55. 2013-03-18 Dan Dennedy * src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/avformat/consumer_avformat.c, src/modules/avformat/factory.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_avdeinterlace.c, src/modules/avformat/filter_avresample.c, src/modules/avformat/filter_swscale.c, src/modules/avformat/producer_avformat.c: Drop support for FFmpeg v0.5 and v0.6 and require swscale. This is cleanup work to make way for more version handling to handle current git master of libav that removes deprecated APIs. 2013-03-23 Dan Dennedy * src/modules/avformat/filter_avcolour_space.c, src/modules/core/consumer_multi.c, src/modules/core/producer_loader.c, src/modules/opengl/filter_movit_convert.cpp: Make the arg to avcolor_space filter a pointer. Instead of passing an int cast as pointer. 2013-03-21 Dan Dennedy * src/modules/frei0r/factory.c, src/modules/frei0r/frei0r_helper.c, src/modules/frei0r/param_name_map.yml: Add a frei0r param name mapping system. For apps that set frei0r parameters by their name, this provides backwards compatibility when a frei0r parameter name changes. 2013-03-17 Dan Dennedy * src/modules/frei0r/factory.c, src/modules/frei0r/frei0r_helper.c: Switch to indexed propery names for frei0r params. Properties supplied by frei0r param name are supported for backwards compatibility. 2013-03-13 Dan Dennedy * src/modules/core/loader.dict, src/modules/core/producer_loader.c: Tell loader how to use WebVfx. With my latest (merged) patches to WebVfx, one can load plain old HTML and QML files. They do not need webvfx script to initialize rendering - with some caveats about the meaning of document-loaded. However, without this loader change, plain resources need to prefaced with "plain:". The loader producer can now do that and instead "webvfx:" is needed to tell webvfx to wait for script in the content to call WebVfx.renderReady(true) (unless you use "webvfx:plain:..."). Also, WebVfx can also now load HTML over HTTP. This is especially handy if your content is updating itself with data from a web service. Otherwise, you will run into cross-site-scripting errors. 2013-03-07 Dan Dennedy * src/modules/opengl/filter_movit_crop.cpp, src/modules/opengl/filter_movit_opacity.cpp, src/modules/opengl/filter_movit_resample.cpp, src/modules/opengl/filter_movit_resize.cpp, src/modules/opengl/transition_movit_mix.cpp, src/modules/opengl/transition_movit_overlay.cpp: Add locking to opengl services for thread protection. * src/modules/opengl/filter_glsl_manager.cpp, src/modules/opengl/glsl_manager.h: Make opengl filters support attach, detach, and disable. 2013-03-03 Dan Dennedy * src/framework/mlt.vers, src/framework/mlt_service.c, src/framework/mlt_service.h, src/mlt++/MltService.cpp, src/mlt++/MltService.h, src/mlt++/mlt++.vers: Add mlt_service_filter_count and Mlt::Service::filter_count. 2013-02-25 Brian Matherly * src/modules/avsync/Makefile, src/modules/avsync/consumer_blipflash.c, src/modules/avsync/consumer_blipflash.yml, src/modules/avsync/factory.c, src/modules/avsync/producer_blipflash.c, src/modules/avsync/producer_blipflash.yml: Add new avsync module 2013-02-24 Dan Dennedy * src/framework/mlt_frame.c, src/modules/core/consumer_multi.c: Let qglsl multi consumer work with more consumers. Works with sdl and decklink consumers. * src/framework/mlt_consumer.c, src/modules/core/producer_loader.c: Fix crash on missing NULL at end of mlt_events_fire(). 2013-02-23 Dan Dennedy * src/melt/melt.c, src/modules/opengl/mlt_movit_input.cpp, src/modules/qimage/consumer_qglsl.cpp: Fix OpenGL context cleanup on Windows. Would crash at end of melt with qglsl. * src/modules/opengl/filter_glsl_manager.cpp, src/modules/qimage/consumer_qglsl.cpp: Some minor logging cleanup. 2013-02-20 Dan Dennedy * src/modules/opengl/consumer_xgl.c, src/modules/opengl/filter_glsl_manager.cpp, src/modules/opengl/filter_movit_convert.cpp: Cleanup some logging from work in opengl branch. * src/melt/melt.c, src/modules/xml/producer_xml.c: Let melt and xml producer use qglsl consumer (opengl branch). * src/modules/qimage/Makefile, src/modules/qimage/configure, src/modules/qimage/consumer_qglsl.cpp, src/modules/qimage/factory.c: Add qglsl multi consumer (opengl branch). * src/framework/mlt_profile.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_swscale.c, src/modules/avformat/producer_avformat.c, src/modules/core/consumer_multi.c, src/modules/core/filter_crop.c, src/modules/core/filter_fieldorder.c, src/modules/core/filter_imageconvert.c, src/modules/core/loader.ini, src/modules/core/producer_loader.c: Let loader producer use new GLSL normalizing filters (opengl branch). * src/modules/opengl/Makefile, src/modules/opengl/configure, src/modules/opengl/consumer_xgl.c, src/modules/opengl/factory.c, src/modules/opengl/fbo_input.cpp, src/modules/opengl/fbo_input.h, .../opengl/filter_deconvolution_sharpen.cpp, .../opengl/filter_deconvolution_sharpen.yml, src/modules/opengl/filter_glsl_manager.cpp, src/modules/opengl/filter_lift_gamma_gain.cpp, src/modules/opengl/filter_lift_gamma_gain.yml, src/modules/opengl/filter_movit_blur.cpp, src/modules/opengl/filter_movit_blur.yml, src/modules/opengl/filter_movit_convert.cpp, src/modules/opengl/filter_movit_crop.cpp, src/modules/opengl/filter_movit_diffusion.cpp, src/modules/opengl/filter_movit_diffusion.yml, src/modules/opengl/filter_movit_glow.cpp, src/modules/opengl/filter_movit_glow.yml, src/modules/opengl/filter_movit_mirror.cpp, src/modules/opengl/filter_movit_mirror.yml, src/modules/opengl/filter_movit_opacity.cpp, src/modules/opengl/filter_movit_opacity.yml, src/modules/opengl/filter_movit_rect.cpp, src/modules/opengl/filter_movit_rect.yml, src/modules/opengl/filter_movit_resample.cpp, src/modules/opengl/filter_movit_resize.cpp, src/modules/opengl/filter_movit_saturation.cpp, src/modules/opengl/filter_movit_saturation.yml, src/modules/opengl/filter_movit_vignette.cpp, src/modules/opengl/filter_movit_vignette.yml, src/modules/opengl/filter_white_balance.cpp, src/modules/opengl/filter_white_balance.yml, src/modules/opengl/glsl_manager.h, src/modules/opengl/mlt_flip_effect.h, src/modules/opengl/mlt_movit_input.cpp, src/modules/opengl/mlt_movit_input.h, src/modules/opengl/transition_movit_mix.cpp, src/modules/opengl/transition_movit_mix.yml, src/modules/opengl/transition_movit_overlay.cpp, src/modules/opengl/transition_movit_overlay.yml: Add the new opengl module (opengl branch). * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h: Add consumer-thread-started and -stopped events (opengl branch). * src/framework/mlt_frame.c, src/framework/mlt_types.h: Add mlt_image_glsl and _glsl_texture (opengl branch). * src/mlt++/MltDeque.cpp, src/mlt++/MltDeque.h, src/mlt++/mlt++.vers: Add Mlt::Deque::peek() (opengl branch). 2013-02-15 Brian Matherly * src/modules/jackrack/Makefile, src/modules/jackrack/factory.c, src/modules/jackrack/plugin_desc.c, src/modules/jackrack/plugin_desc.h, src/modules/jackrack/plugin_mgr.c, src/modules/jackrack/process.c, src/modules/jackrack/producer_ladspa.c, src/modules/jackrack/producer_ladspa.yml: Add ladspa producer 2013-02-13 Cristian Morales Vega * src/framework/Makefile, src/mlt++/Makefile: Fix OSX buld which broke when adding Linux symbols versioning 2013-02-10 Dan Dennedy * src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_still.c: Remove local references to SDL_Surface. (SF-186) Why bother when SDL_GetVideoSurface() is available? 2013-02-07 Cristian Morales Vega * src/framework/Makefile, src/framework/mlt.vers, src/mlt++/Makefile, src/mlt++/config.h, src/mlt++/mlt++.vers: Use symbol versioning 2013-02-08 Cristian Morales Vega * Makefile, configure, src/melt/Makefile: Make the versioning opt-in 2013-02-07 Cristian Morales Vega * Makefile, configure, profiles/Makefile, src/framework/Makefile, src/framework/mlt_factory.c, src/melt/Makefile, src/melt/configure, src/modules/Makefile, src/modules/avformat/Makefile, src/modules/core/Makefile, src/modules/decklink/Makefile, src/modules/dgraft/Makefile, src/modules/dv/Makefile, src/modules/effectv/Makefile, src/modules/feeds/Makefile, src/modules/frei0r/Makefile, src/modules/gtk2/Makefile, src/modules/jackrack/Makefile, src/modules/kdenlive/Makefile, src/modules/kino/Makefile, src/modules/linsys/Makefile, src/modules/lumas/Makefile, src/modules/motion_est/Makefile, src/modules/normalize/Makefile, src/modules/oldfilm/Makefile, src/modules/plus/Makefile, src/modules/qimage/Makefile, src/modules/resample/Makefile, src/modules/rotoscoping/Makefile, src/modules/rtaudio/Makefile, src/modules/sdl/Makefile, src/modules/sox/Makefile, src/modules/swfdec/Makefile, src/modules/videostab/Makefile, src/modules/vmfx/Makefile, src/modules/vorbis/Makefile, src/modules/xine/Makefile, src/modules/xml/Makefile: Version modules and data directories, and melt Allow the "extras" of binary incompatible versions of MLT to be installed simultaneously. I don't like the idea of versioning the melt binary. But kdenlive is the main user of MLT and it expects the same formats support from both the libmltX it is linked to, and the melt binary it uses to do the actual work. 2013-01-20 Dan Dennedy * Doxyfile, configure, docs/melt.1, src/framework/mlt_version.h, src/melt/melt.c: Set version to 0.8.8. 2012-12-31 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: Fix build against FFmepg 0.5 and 0.6. 2012-12-26 Niv Sardi * src/modules/gtk2/producer_pixbuf.c, src/modules/gtk2/producer_pixbuf.yml: pixbuf producer: loop option to loop sequence selectively 2012-12-22 Dan Dennedy * src/framework/mlt_consumer.c, src/framework/mlt_frame.c, src/framework/mlt_types.h, src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c, src/modules/core/filter_audiochannels.c, src/modules/core/filter_audioconvert.c, src/modules/core/filter_channelcopy.c, src/modules/core/filter_mono.c: Add mlt_audio_u8 (sourceforce-182). It should support planar libavutil AV_SAMPLE_FMT_U8P, but it is untested due to lacking a sample. 2012-12-12 Dan Dennedy * src/modules/avformat/producer_avformat.c, src/modules/resample/filter_resample.c: Fix possible divide by zero exceptions. 2012-11-27 Dan Dennedy * src/modules/avformat/factory.c, src/modules/avformat/filter_avresample.c, src/modules/avformat/producer_avformat.c: Fix decoding audio with planar formats. * src/modules/decklink/consumer_decklink.cpp, src/modules/decklink/producer_decklink.cpp: Fix mlt_profile to DeckLink DisplayMode matching. 2012-11-17 Dan Dennedy * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/producer_qimage.c: Fix crash on invalid image sequence. * configure, src/framework/mlt_version.h: set to interim version 0.8.7 * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/videostab/stab/klt/error.c: Remove exit()s that cause unexpected app failures. An app can register a mlt_log callback, trap errors, and do something more graceful than abort as perhaps some of these are not really as fatal as they claim to be (a different patch can change the levels as needed). 2012-11-14 Dan Dennedy * Doxyfile, NEWS, configure, docs/melt.1, src/framework/mlt_version.h: Set version to 0.8.6 2012-11-13 Dan Dennedy * Doxyfile, configure, docs/melt.1, src/framework/mlt_version.h, src/modules/avformat/configure: Set version to 0.8.4 2012-11-11 Dan Dennedy * src/modules/core/factory.c, src/modules/normalize/Makefile, src/modules/normalize/factory.c, src/modules/normalize/filter_audiolevel.c, src/modules/normalize/filter_audiolevel.yml: Add audiolevel filter. * src/modules/avformat/producer_avformat.c, src/modules/avformat/producer_avformat.yml, src/modules/core/filter_resize.c: More fixes for force_full_luma (kdenlive-2799). This change lets the image converter downstream of the avformat producer perform utilize the range as-needed. Then, when the rescale filter sees that the force_full_range is set on the frame but has not yet been applied, forces a conversion to RGB to enforce it. In addition, the recently added force_full_luma property on the avformat producer is removed because it is redundant with AVOption color_range=2. * presets/consumer/avformat/Sony-PSP, presets/consumer/avformat/atsc_1080i_50/DNxHD, presets/consumer/avformat/atsc_1080i_5994/DNxHD, presets/consumer/avformat/atsc_1080p_2398/DNxHD, presets/consumer/avformat/atsc_1080p_24/DNxHD, presets/consumer/avformat/atsc_1080p_25/DNxHD, presets/consumer/avformat/atsc_1080p_2997/DNxHD, presets/consumer/avformat/atsc_1080p_30/DNxHD, presets/consumer/avformat/atsc_1080p_50/DNxHD, presets/consumer/avformat/atsc_1080p_5994/DNxHD, presets/consumer/avformat/atsc_1080p_60/DNxHD, presets/consumer/avformat/atsc_720p_2398/DNxHD, presets/consumer/avformat/atsc_720p_50/DNxHD, presets/consumer/avformat/atsc_720p_5994/DNxHD, presets/consumer/avformat/atsc_720p_60/DNxHD, presets/consumer/avformat/dv_ntsc/D10, presets/consumer/avformat/dv_ntsc/DV, presets/consumer/avformat/dv_ntsc/DVCPRO50, presets/consumer/avformat/dv_ntsc_wide/D10, presets/consumer/avformat/dv_ntsc_wide/DV, presets/consumer/avformat/dv_ntsc_wide/DVCPRO50, presets/consumer/avformat/dv_pal/D10, presets/consumer/avformat/dv_pal/DV, presets/consumer/avformat/dv_pal/DVCPRO50, presets/consumer/avformat/dv_pal_wide/D10, presets/consumer/avformat/dv_pal_wide/DV, presets/consumer/avformat/dv_pal_wide/DVCPRO50, presets/consumer/avformat/hdv_1080_25p/HDV, presets/consumer/avformat/hdv_1080_30p/HDV, presets/consumer/avformat/hdv_1080_50i/HDV, presets/consumer/avformat/hdv_1080_60i/HDV, presets/consumer/avformat/hdv_720_25p/HDV, presets/consumer/avformat/hdv_720_30p/HDV, presets/consumer/avformat/hdv_720_50p/HDV, presets/consumer/avformat/hdv_720_60p/HDV, presets/consumer/avformat/lossless/FFV1, presets/consumer/avformat/lossless/H.264, presets/consumer/avformat/lossless/MPEG-4: Add more descriptions to encoding presets. 2012-11-05 Dan Dennedy * src/modules/qimage/producer_qimage.c, src/modules/qimage/producer_qimage.yml: qimage: let begin property be passed as a query string parameter * src/modules/gtk2/producer_pixbuf.c, src/modules/gtk2/producer_pixbuf.yml: pixbuf: support alt. query syntax begin:value for melt 2012-11-04 Dan Dennedy * src/modules/gtk2/producer_pixbuf.c, src/modules/gtk2/producer_pixbuf.yml: pixbuf: let begin property be passed as a query string parameter 2012-10-23 Dan Dennedy * src/modules/avformat/producer_avformat.c, src/modules/avformat/producer_avformat.yml: Fix force_full_luma (kdenlive-2799). 2012-10-19 Dan Dennedy * src/framework/mlt_geometry.c, src/modules/videostab/filter_videostab.c, src/modules/videostab/filter_videostab2.c: Let vector property of videostab(2) be read directly as mlt_geometry. 2012-10-19 Jean-Baptiste Mardelle * src/modules/qimage/Makefile, src/modules/qimage/configure, src/modules/qimage/producer_qimage.c, src/modules/qimage/qimage_wrapper.cpp, src/modules/qimage/qimage_wrapper.h: Fix loading of extra image formats using Kdelibs (xcf, ...) 2012-10-09 Dan Dennedy * src/swig/Makefile, src/swig/csharp/build, src/swig/java/build, src/swig/lua/build, src/swig/perl/Makefile.PL, src/swig/perl/build, src/swig/php/build, src/swig/python/build, src/swig/ruby/build, src/swig/tcl/build: Build the SWIG bindings with the CXXFLAGS (3554425) Based on patch by Cristian Morales Vega * src/modules/core/producer_colour.c, src/modules/core/producer_noise.c, src/modules/frei0r/producer_frei0r.c: fix aspect ratio of generators when set via consumer property 2012-09-23 Dan Dennedy * presets/consumer/avformat/MJPEG, presets/consumer/avformat/lossless/FFV1, presets/consumer/avformat/lossless/MJPEG: indicate in some presets codecs which do not support multithread 2012-09-16 Dan Dennedy * src/framework/Makefile, src/framework/configure, src/framework/mlt_property.h: cleanup sys/param.h include on FreeBSD Assisted by Albert Villa who says it is safe to assume sys/param.h is available, which is needed for FreeBSD version check on whether to include xlocale.h in mlt_property.h. 2012-09-13 Dan Dennedy * src/modules/sdl/consumer_sdl_audio.c, src/modules/sdl/consumer_sdl_preview.c: sdl_audio and sdl_preview also do not care about field order Also, have sdl_preview pass top_field_first to its children. * src/framework/mlt_consumer.h, src/modules/core/filter_fieldorder.c, src/modules/sdl/consumer_sdl.c: add ability to ignore field order as used by sdl consumer 2012-09-09 Dan Dennedy * src/mlt++/MltProfile.cpp, src/mlt++/MltProfile.h: add Mlt::Profile::colorspace() 2012-09-08 Dan Dennedy * configure, src/framework/configure, src/modules/avformat/configure, src/modules/frei0r/configure: allow env CC to override hard-coded gcc in configure scripts patch by Alberto Villa * src/modules/avformat/producer_avformat.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/producer_qimage.c, src/modules/qimage/qimage_wrapper.cpp, src/modules/swfdec/producer_swfdec.c, src/modules/vorbis/producer_vorbis.c: change producers to use mlt_frame_original_position() * src/framework/mlt_frame.c, src/framework/mlt_frame.h: add mlt_frame_original_position() 2012-09-03 Dan Dennedy * src/mlt++/MltService.cpp, src/mlt++/MltService.h: add Mlt::Service::set_profile() * src/framework/mlt_service.c, src/framework/mlt_service.h: add mlt_service_set_profile() * src/mlt++/MltProfile.cpp, src/mlt++/MltProfile.h: add Mlt::Profile::is_explicit() 2012-08-31 Dan Dennedy * src/swig/mlt.i, src/swig/ruby/playlist.rb: extend Ruby API with PlaylistNextListner and show how to use it * src/framework/mlt_playlist.c, src/framework/mlt_playlist.h: add playlist-next event to mlt_playlist 2012-08-30 Dan Dennedy * configure, src/framework/mlt_version.h: set interim version to 0.8.3 2012-08-28 Dan Dennedy * ChangeLog, presets/consumer/avformat/MPEG-4 ASP, presets/consumer/avformat/MPEG-4-ASP, presets/consumer/avformat/webm: add acodec to webm preset and rename MPEG-4 ASP preset * Doxyfile, configure, docs/melt.1, src/framework/mlt_version.h: set version to 0.8.2 2012-08-26 Dan Dennedy * presets/consumer/avformat/stills/BMP, presets/consumer/avformat/stills/DPX, presets/consumer/avformat/stills/JPEG, presets/consumer/avformat/stills/PNG, presets/consumer/avformat/stills/PPM, presets/consumer/avformat/stills/TGA, presets/consumer/avformat/stills/TIFF: add meta.preset.extension to image sequence presets * presets/consumer/avformat/AAC, presets/consumer/avformat/Flash, presets/consumer/avformat/MJPEG, presets/consumer/avformat/MP3, presets/consumer/avformat/MPEG-2, presets/consumer/avformat/MPEG-4, presets/consumer/avformat/MPEG-4 ASP, presets/consumer/avformat/Sony-PSP, presets/consumer/avformat/Vorbis, presets/consumer/avformat/WAV, presets/consumer/avformat/XDCAM-HD422, presets/consumer/avformat/atsc_1080i_50/DNxHD, presets/consumer/avformat/atsc_1080i_5994/DNxHD, presets/consumer/avformat/atsc_1080p_2398/DNxHD, presets/consumer/avformat/atsc_1080p_24/DNxHD, presets/consumer/avformat/atsc_1080p_25/DNxHD, presets/consumer/avformat/atsc_1080p_2997/DNxHD, presets/consumer/avformat/atsc_1080p_30/DNxHD, presets/consumer/avformat/atsc_1080p_50/DNxHD, presets/consumer/avformat/atsc_1080p_5994/DNxHD, presets/consumer/avformat/atsc_1080p_60/DNxHD, presets/consumer/avformat/atsc_720p_2398/DNxHD, presets/consumer/avformat/atsc_720p_50/DNxHD, presets/consumer/avformat/atsc_720p_5994/DNxHD, presets/consumer/avformat/atsc_720p_60/DNxHD, presets/consumer/avformat/dv_ntsc/D10, presets/consumer/avformat/dv_ntsc/DVD, presets/consumer/avformat/dv_ntsc_wide/D10, presets/consumer/avformat/dv_ntsc_wide/DVD, presets/consumer/avformat/dv_pal/D10, presets/consumer/avformat/dv_pal/DVD, presets/consumer/avformat/dv_pal_wide/D10, presets/consumer/avformat/dv_pal_wide/DVD, presets/consumer/avformat/hdv_1080_25p/HDV, presets/consumer/avformat/hdv_1080_30p/HDV, presets/consumer/avformat/hdv_1080_50i/HDV, presets/consumer/avformat/hdv_1080_60i/HDV, presets/consumer/avformat/hdv_720_25p/HDV, presets/consumer/avformat/hdv_720_30p/HDV, presets/consumer/avformat/hdv_720_50p/HDV, presets/consumer/avformat/hdv_720_60p/HDV, presets/consumer/avformat/lossless/FFV1, presets/consumer/avformat/lossless/H.264, presets/consumer/avformat/lossless/HuffYUV, presets/consumer/avformat/lossless/MJPEG, presets/consumer/avformat/lossless/MPEG-2, presets/consumer/avformat/lossless/MPEG-4, presets/consumer/avformat/lossless/ProRes, presets/consumer/avformat/webm, presets/consumer/avformat/x264-medium, presets/consumer/avformat/x264-medium-baseline, presets/consumer/avformat/x264-medium-main, presets/consumer/avformat/x264-medium-pass1: add preset metadata such as alternate name, filename extension, note. * presets/consumer/avformat/Sony-PSP, presets/consumer/avformat/webm, presets/consumer/avformat/x264-medium-baseline, presets/consumer/avformat/x264-medium-main: change profile to vprofile in presets * presets/consumer/avformat/Vorbis, presets/consumer/avformat/lossless/ProRes: add vorbis and prores encode presets 2012-08-25 Dan Dennedy * presets/consumer/avformat/AAC, presets/consumer/avformat/Flash, presets/consumer/avformat/MJPEG, presets/consumer/avformat/MP3, presets/consumer/avformat/MPEG-2, presets/consumer/avformat/MPEG-4, presets/consumer/avformat/MPEG-4 ASP, presets/consumer/avformat/WAV, presets/consumer/avformat/hdv_1080_25p/HDV, presets/consumer/avformat/hdv_1080_30p/HDV, presets/consumer/avformat/hdv_1080_50i/HDV, presets/consumer/avformat/hdv_1080_60i/HDV, presets/consumer/avformat/hdv_720_25p/HDV, presets/consumer/avformat/hdv_720_30p/HDV, presets/consumer/avformat/hdv_720_50p/HDV, presets/consumer/avformat/hdv_720_60p/HDV, presets/consumer/avformat/lossless/FFV1, presets/consumer/avformat/lossless/H.264, presets/consumer/avformat/lossless/HuffYUV, presets/consumer/avformat/lossless/MJPEG, presets/consumer/avformat/lossless/MPEG-2, presets/consumer/avformat/lossless/MPEG-4, presets/consumer/avformat/stills/BMP, presets/consumer/avformat/stills/DPX, presets/consumer/avformat/stills/JPEG, presets/consumer/avformat/stills/PNG, presets/consumer/avformat/stills/PPM, presets/consumer/avformat/stills/TGA, presets/consumer/avformat/stills/TIFF, presets/consumer/avformat/x264-medium-pass1: add a bunch of new encoding presets 2012-08-24 Dan Dennedy * src/modules/avformat/producer_avformat.c, src/modules/avformat/producer_avformat.yml: the recent A/V sync overhaul needed some additional work 2012-08-11 Dan Dennedy * src/melt/io.c, src/melt/melt.c: fix melt progress display on Windows 2012-08-01 Mikko Rapeli * src/modules/videostab/filter_videostab.c, src/modules/videostab/filter_videostab2.c: videostab/filter_videostab*.c: check return value from mlt_filter_new() Fixes Coverity CID 709365 and 709366: Dereference null return value (NULL_RETURNS) Function "mlt_filter_new" returns null (checked 50 out of 52 times). [show details] Assigning: "parent" = null return value from "mlt_filter_new". 201 mlt_filter parent = mlt_filter_new(); Dereferencing a null pointer "parent". 202 parent->child = self; * src/modules/videostab/filter_videostab.c, src/modules/videostab/filter_videostab2.c: videostab/filter_videostab*.c: check for null Fixes Coverity CID 709404: Dereference before null check (REVERSE_INULL) Dereferencing pointer "g". [show details] 85 if ( !mlt_geometry_parse( g, vectors, length, -1, -1 ) ) ... Dereferencing "g" before a null check. 104 if ( g ) mlt_geometry_close( g ); 2012-08-04 Dan Dennedy * src/modules/avformat/producer_avformat.c, src/modules/avformat/producer_avformat.yml: add image cache size property to avformat producer 2012-08-03 Marco Gittler * src/modules/oldfilm/filter_lines.c, src/modules/oldfilm/filter_lines.yml: fix width output of filter in xml 2012-07-25 Mikko Rapeli * src/framework/mlt_field.c, src/framework/mlt_frame.c, src/framework/mlt_multitrack.c, src/framework/mlt_playlist.c, src/framework/mlt_properties.c, src/framework/mlt_repository.c, src/framework/mlt_service.c, src/framework/mlt_tractor.c, src/modules/core/filter_audioconvert.c, src/modules/core/filter_crop.c, src/modules/core/filter_imageconvert.c, src/modules/core/filter_panner.c, src/modules/core/filter_resize.c, src/modules/core/producer_ppm.c, src/modules/core/transition_composite.c, src/modules/core/transition_mix.c, src/modules/dv/producer_libdv.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/kino/producer_kino.c, src/modules/linsys/consumer_SDIstream.c, src/modules/normalize/filter_volume.c, src/modules/qimage/producer_kdenlivetitle.c, src/modules/qimage/producer_qimage.c, src/modules/rtaudio/RtAudio.cpp, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_audio.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c, src/modules/xml/consumer_xml.c, src/modules/xml/producer_xml.c: Fix calloc() parameter ordering First parameter to calloc() is the count and second the amount of bytes for each item. Likely this has no run time effect since the resulting buffer size is the same. 2012-07-23 Dan Dennedy * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/qimage_wrapper.cpp: fix crash when switching image formats with alpha This happens when switching from image format with distinct alpha channel (yuv422) to one with embedded alpha channel (rgb24a). Reported-by: j-b-m 2012-07-22 Dan Dennedy * src/modules/videostab/stabilize.c, src/modules/videostab/stabilize.h: remove unused function (coverity-709390) * src/mlt++/MltService.cpp, src/mlt++/MltService.h: add Service::get_profile() returns mlt_profile * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h: fix memory leak (coverity-709375) 2012-07-20 Dan Dennedy * AUTHORS, src/modules/core/Makefile, src/modules/core/composite_line_yuv_sse2_simple.c, src/modules/core/transition_composite.c: improve compatibility to compile composite sse2 (macports-35243) 2012-07-12 Dan Dennedy * src/modules/core/producer_loader.c, src/modules/xml/producer_xml.c: accept file:// prefix on MLT XML file 2012-06-23 Dan Dennedy * src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/mlt++/MltPlaylist.cpp, src/mlt++/MltPlaylist.h, src/modules/core/producer_melt.c, src/modules/xml/producer_xml.c: add support for time string to playlist blanks * src/modules/jackrack/consumer_jack.c, src/modules/jackrack/consumer_jack.yml, src/modules/rtaudio/consumer_rtaudio.cpp, src/modules/rtaudio/consumer_rtaudio.yml, src/modules/sdl/consumer_sdl_audio.c, src/modules/sdl/consumer_sdl_audio.yml: add support for audio scrubbing to audio-only consumers 2012-06-19 Dan Dennedy * src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/mlt++/MltProducer.cpp, src/mlt++/MltProducer.h: add mlt_producer_seek_time and mlt_producer_frame_time * src/mlt++/MltFilteredConsumer.cpp, src/mlt++/MltFilteredConsumer.h, src/mlt++/MltFilteredProducer.cpp, src/mlt++/MltFilteredProducer.h, src/mlt++/MltPushConsumer.cpp, src/mlt++/MltPushConsumer.h: add const-ness to some strings in specialized service classes 2012-06-18 Dan Dennedy * src/modules/rotoscoping/filter_rotoscoping.c, src/modules/vmfx/filter_shape.c, src/modules/xine/vf_yadif_template.h, src/modules/xine/yadif.c: fix clang errors 2012-06-16 Dan Dennedy * src/modules/avformat/producer_avformat.c, src/modules/avformat/producer_avformat.yml: overhaul a/v sync and seeking in avformat producer The new_seek property changed to use_pts. This consolidates old seek and new seek code, improves a/v sync for more files, and improves seek performance for AVCHD in general (including libav). 2012-06-04 Dan Dennedy * NEWS, configure, src/framework/mlt_version.h: set interim version to 0.8.1 2012-06-01 Dan Dennedy * Doxyfile, configure, docs/melt.1, src/framework/mlt_version.h, src/modules/avformat/configure: set version to 0.8.0 2012-05-29 Dan Dennedy * src/framework/mlt_cache.c, src/framework/mlt_cache.h: add mlt_cache_put_frame and mlt_cache_get_frame * src/modules/gtk2/Makefile, src/modules/gtk2/configure, src/modules/gtk2/scale_line_22_yuv_mmx.S, src/modules/jackrack/Makefile, src/modules/jackrack/configure: fix cross-compiling gtk2 and jackrack modules for windows 2012-05-26 Dan Dennedy * configure, src/mlt++/configure, src/modules/qimage/configure, src/modules/swfdec/Makefile, src/modules/videostab/stab/estimate.c: add configure options and fixes for cross-compiling 2012-05-19 Dan Dennedy * src/modules/decklink/DeckLinkAPI.h, src/modules/decklink/DeckLinkAPIDispatch.cpp, src/modules/decklink/DeckLinkAPI_h.h, src/modules/decklink/DeckLinkAPI_i.cpp, src/modules/decklink/LinuxCOM.h, src/modules/decklink/Makefile, src/modules/decklink/common.cpp, src/modules/decklink/common.h, src/modules/decklink/consumer_decklink.cpp, src/modules/decklink/darwin/DeckLinkAPI.h, .../decklink/darwin/DeckLinkAPIDispatch.cpp, src/modules/decklink/linux/DeckLinkAPI.h, src/modules/decklink/linux/DeckLinkAPIDispatch.cpp, src/modules/decklink/linux/LinuxCOM.h, src/modules/decklink/producer_decklink.cpp, src/modules/decklink/win/DeckLinkAPI_h.h, src/modules/decklink/win/DeckLinkAPI_i.cpp: fix decklink build for OS X 2012-04-18 Dan Dennedy * src/modules/decklink/consumer_decklink.cpp, src/modules/decklink/producer_decklink.cpp: fix decklink build on Windows 2012-04-11 Dan Dennedy * src/modules/plus/filter_affine.c, src/modules/plus/interp.h, src/modules/plus/transition_affine.c: fix distortion handling alpha channel in affine transition Reported-by: j-b-m 2012-04-10 Dan Dennedy * demo/mlt_ticker, src/modules/plus/filter_affine.c: fix background alpha channel of affine filter broke when black producer was changed to opaque like other colors 2012-04-07 Dan Dennedy * src/modules/plus/transition_affine.c, src/modules/qimage/qimage_wrapper.cpp: fix regressions during refactorization 2012-03-31 Dan Dennedy * src/modules/xml/consumer_xml.c, src/modules/xml/consumer_xml.yml: add time_format property to xml consumer Now you can save the in, out, and length properties as timecode or clock values. Default unit it still in frame count. * src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/mlt++/MltProducer.cpp, src/mlt++/MltProducer.h: add mlt_producer_get_length_time() More functions that return time strings will be added later. * configure, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/framework/mlt_types.h, src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h: add support for timecode and clock time strings to the framework 2012-03-27 Dan Dennedy * GPLv3, configure, src/modules/qimage/Makefile, src/modules/qimage/configure, src/modules/qimage/factory.c: require configure --enable-gpl3 for GPLv3 services (currently only vqm) 2012-03-25 Dan Dennedy * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/producer_qimage.c: fix resource leak regression in image producers 2012-03-19 Dan Dennedy * src/modules/decklink/consumer_decklink.cpp, src/modules/decklink/producer_decklink.cpp: enumerate DeckLink devices when list_devices property is set 2012-03-19 Maksym Veremeyenko * src/modules/decklink/consumer_decklink.cpp, src/modules/decklink/producer_decklink.cpp: Initialize all decklink interface pointers and reset them upon release. Also, add a couple of missing releases. 2012-03-18 Brian Matherly * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: Fix incorrect precompiler conditionals for libav/ffmpeg versions. Needed to support ffmpeg 0.9 and 0.10 releases. 2012-03-14 Dan Dennedy * src/modules/decklink/consumer_decklink.cpp, src/modules/decklink/consumer_decklink.yml, src/modules/decklink/producer_decklink.cpp, src/modules/decklink/producer_decklink.yml: enumerate available devices in decklink module 2012-03-11 Brian Matherly * src/modules/gtk2/producer_pixbuf.yml, src/modules/qimage/producer_qimage.yml: Fix broken pixbuf and qimage producer metadata. 2012-03-07 Dan Dennedy * src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/producer_qimage.c: indicate image producers seekable 2012-03-06 Dan Dennedy * src/modules/gtk2/producer_pixbuf.yml, src/modules/qimage/producer_qimage.yml: update service metadata for pixbuf and qimage 2012-03-05 Dan Dennedy * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/producer_qimage.c: allow %u in image sequence pattern containing begin value * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/producer_qimage.c: add image sequences where scanf format contains begin value For example, if an image sequence begins with the file foo1234.png, you can use the resource string "foo%1234d.png" to load it. 2012-03-04 Dan Dennedy * src/modules/decklink/producer_decklink.cpp, src/modules/qimage/qimage_wrapper.cpp: remove a couple more remnants of legacy real_width and _height * src/modules/avformat/producer_avformat.c, src/modules/dv/producer_libdv.c: remove deprecated source_fps property * src/framework/mlt_tractor.c, src/modules/avformat/producer_avformat.c, src/modules/core/consumer_multi.c, src/modules/core/filter_crop.c, src/modules/core/filter_rescale.c, src/modules/core/filter_resize.c, src/modules/core/producer_colour.c, src/modules/core/producer_consumer.c, src/modules/core/producer_loader.c, src/modules/core/transition_composite.c, src/modules/dv/producer_libdv.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/kdenlive/producer_framebuffer.c, src/modules/plus/transition_affine.c, src/modules/sdl/producer_sdl_image.c, src/modules/swfdec/producer_swfdec.c, src/modules/videostab/filter_videostab2.c, src/modules/vmfx/producer_pgm.c: replace legacy real_width and _height with meta.media.width and .height This takes advantage of mlt_producer copying all meta properties from producer to frame so we do not have to remember to do it everywhere it is needed. 2012-02-29 Dan Dennedy * src/framework/mlt_consumer.c, src/framework/mlt_frame.c, src/framework/mlt_profile.c, src/framework/mlt_tractor.c, src/framework/mlt_transition.c, src/modules/core/filter_crop.c, src/modules/core/filter_watermark.c, src/modules/kdenlive/filter_freeze.c, src/modules/kdenlive/producer_framebuffer.c, src/modules/oldfilm/filter_dust.c, src/modules/plus/filter_affine.c, src/modules/plus/transition_affine.c: remove consumer_aspect_ratio property - use profile instead * src/framework/mlt_tractor.c, src/modules/core/filter_watermark.c, src/modules/core/transition_composite.c, src/modules/kdenlive/filter_freeze.c: remove output_ratio property - use profile instead * src/modules/core/filter_crop.c, src/modules/core/filter_obscure.c, src/modules/core/filter_rescale.c, src/modules/core/filter_resize.c, src/modules/core/filter_watermark.c, src/modules/core/transition_composite.c, src/modules/plus/filter_affine.c, src/modules/plus/transition_affine.c: remove usage of normalised_width and _height properties from services * src/framework/mlt_frame.c, src/framework/mlt_tractor.c: remove normalised_width and _height properties from framework 2012-03-04 Dan Dennedy * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/qimage_wrapper.cpp: fix regression with adding image conversion to image producers 2012-03-02 Dan Dennedy * src/modules/qimage/producer_qimage.c, src/modules/qimage/qimage_wrapper.cpp, src/modules/qimage/qimage_wrapper.h: convert to and cache requested format in qimage 2012-03-01 Dan Dennedy * src/modules/qimage/producer_qimage.c, src/modules/qimage/qimage_wrapper.cpp, src/modules/qimage/qimage_wrapper.h: split refresh_qimage() into refresh_qiamge() and refresh_image() 2012-02-27 Dan Dennedy * src/modules/core/transition_composite.yml, src/modules/gtk2/producer_pixbuf.yml: couple of small service metadata fixes 2012-02-22 Dan Dennedy * src/modules/decklink/producer_decklink.cpp, src/modules/decklink/producer_decklink.yml: fix regression when using producer 'consumer' with decklink This feature now requires one to set the preview property on this producer to support special preview mode when the speed is 0. 2012-02-20 Dan Dennedy * src/framework/mlt_frame.c, src/modules/avformat/filter_avcolour_space.c, src/modules/core/filter_crop.c, src/modules/core/filter_resize.c, src/modules/core/transition_region.c: let mlt_frame_set_alpha clear the get_alpha_mask function pointer 2012-02-19 Dan Dennedy * configure, src/framework/mlt_version.h: set interim version 0.7.9 2012-02-16 Dan Dennedy * src/modules/core/transition_composite.c, src/modules/core/transition_composite.h: make composite_line_yuv() available to other services 2012-02-16 Maksym Veremeyenko * src/modules/core/composite_line_yuv_sse2_simple.c, src/modules/core/transition_composite.c: use sse2 instruction for line compositing 2012-02-13 Dan Dennedy * Doxyfile, configure, docs/melt.1, src/framework/mlt_version.h, src/melt/melt.c: set version to 0.7.8 2012-02-12 Dan Dennedy * Makefile, src/modules/core/loader.dict, src/modules/sdl/producer_sdl_image.yml: deprecate sdl_image * src/mlt++/MltFrame.cpp, src/mlt++/MltFrame.h: make Frame::get_position() retrun type consistent 2012-02-12 Simon A. Eugster * src/mlt++/MltFrame.cpp, src/mlt++/MltFrame.h: Add get_position to Mlt::Frame 2012-02-08 Dan Dennedy * src/modules/qimage/factory.c, src/modules/qimage/transition_vqm.cpp, src/modules/qimage/transition_vqm.yml: add rendering to vqm and yaml service metadata 2012-02-06 Dan Dennedy * src/modules/qimage/Makefile, src/modules/qimage/factory.c, src/modules/qimage/transition_vqm.cpp: add vqm transition 2012-02-05 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/producer_avformat.c: fix color problem with libav (3483629) 2012-02-04 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: fix AVOption processing on ffmpeg 0.8 2012-01-30 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: fix AVOption processing on libav 0.7.3 Patch for consumer by j-b-m and extended to producer by me. 2012-01-28 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/filter_avresample.c, src/modules/avformat/producer_avformat.c: fix SAMPLE_FMT support for v0.6 and less of libav/ffmpeg * src/modules/avformat/filter_avresample.c, src/modules/avformat/producer_avformat.c: convert all SAMPLE_FMT_16 to AV_SAMPLE_FMT_16 2012-01-25 Dan Dennedy * src/modules/core/filter_audiochannels.c, src/modules/core/filter_channelcopy.c, src/modules/core/filter_mono.c: add s32le and f32le format to core audio filters * src/framework/mlt_types.h, src/modules/core/filter_audioconvert.c: add support for converting between all audio sample formats 2012-01-21 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/factory.c, src/modules/avformat/producer_avformat.c: remove global avformat mutex and add a local one to the producer for open/close coherency * src/framework/mlt_producer.h, src/framework/mlt_service.h: update doc on service-change and producer-changed events 2012-01-17 Dan Dennedy * src/modules/gtk2/producer_pango.yml, src/modules/gtk2/producer_pixbuf.yml: document force_aspect_ratio on pango and pixbuf producers 2012-01-15 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: enable codec- and format-specific options for v0.7 releases of ffmpeg (but not libav, which uses v53 of libavformat and libavcodec in its 0.7 releases) 2012-01-14 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/factory.c, src/modules/avformat/producer_avformat.c: drop deprecated APIs of libavformat/codec v53 2012-01-02 gmarco * src/modules/videostab/filter_videostab.c, src/modules/videostab/stab/resample.c, src/modules/videostab/stab/resample.h, src/modules/videostab/stab/utils.c, src/modules/videostab/stab/utils.h: do not use lanc_kernels as global var. moved to filter struct 2011-12-16 gmarco * src/modules/videostab/filter_videostab2.c, src/modules/videostab/stabilize.c, src/modules/videostab/stabilize.h, src/modules/videostab/transform_image.c, src/modules/videostab/transform_image.h: use calloc insteadt of malloc/memset use struct for instance data small cleanup use PIX(n) dont use instable yuv420 use stabilize on grayimage (converted from yuv422) 2011-11-21 Marco Gittler * src/modules/videostab/stabilize.c, src/modules/videostab/transform_image.c: sse2 updates 2011-12-21 Dan Dennedy * configure, src/mlt++/configure: add configure support for GNU Hurd Patches provided by Patrick Matthäi. * src/modules/rtaudio/RtAudio.cpp, src/modules/rtaudio/configure: only build rtaudio for Linux, Windows, or OS X * src/framework/Makefile, src/framework/configure, src/framework/mlt_property.h: add support for xlocale.h on FreeBSD with assistance from Gleb Smirnoff 2011-12-16 gmarco * src/modules/videostab/filter_videostab2.c, src/modules/videostab/stabilize.c, src/modules/videostab/stabilize.h, src/modules/videostab/transform_image.c, src/modules/videostab/transform_image.h: use calloc insteadt of malloc/memset use struct for instance data small cleanup use PIX(n) dont use instable yuv420 use stabilize on grayimage (converted from yuv422) 2011-11-21 Marco Gittler * src/modules/videostab/stabilize.c, src/modules/videostab/transform_image.c: sse2 updates 2011-12-10 Dan Dennedy * src/modules/core/producer_colour.c, src/modules/core/producer_noise.c, src/modules/dv/producer_libdv.c, src/modules/frei0r/producer_frei0r.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/producer_qimage.c, src/modules/sdl/producer_sdl_image.c: add mlt_image_none support to producers * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h: add consumer properties mlt_image_format and mlt_audio_format 2011-12-09 Dan Dennedy * src/modules/core/filter_fieldorder.c, src/modules/core/filter_fieldorder.yml: add meta.swap_fields to the fieldorder filter 2011-12-08 Dan Dennedy * src/modules/core/Makefile, src/modules/core/factory.c, src/modules/core/filter_fieldorder.c, src/modules/core/filter_fieldorder.yml, src/modules/core/filter_resize.c, src/modules/core/filter_resize.yml, src/modules/core/loader.ini: refactor field order correction into new filter 2011-12-05 Dan Dennedy * src/modules/rtaudio/RtAudio.cpp, src/modules/rtaudio/RtAudio.h, src/modules/rtaudio/consumer_rtaudio.cpp: improve selecting rtaudio device by name 2011-11-28 Dan Dennedy * src/modules/rtaudio/Makefile, src/modules/rtaudio/RtAudio.cpp, src/modules/rtaudio/RtAudio.h, src/modules/rtaudio/RtError.h, src/modules/rtaudio/consumer_rtaudio.cpp: add rtaudio consumer 2011-11-27 Dan Dennedy * src/modules/avformat/producer_avformat.c, src/modules/avformat/vdpau.c: fix VDPAU state issues Patch by Christophe Thommeret 2011-11-04 Dan Dennedy * src/framework/mlt_factory.c, src/modules/frei0r/factory.c, src/modules/jackrack/plugin_mgr.c: fix frei0r and ladspa loading for relocatable builds 2011-11-19 Dan Dennedy * src/melt/melt.c, src/modules/core/consumer_multi.c: change property 'consumer' to 'mlt_service' consistent with xml * src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/modules/core/consumer_multi.c: enhance mlt_frame_clone with a deep/shallow parameter 2011-11-10 Dan Dennedy * src/framework/mlt_frame.c, src/framework/mlt_frame.h: add mlt_frame_clone() 2011-11-05 Dan Dennedy * src/modules/core/Makefile, src/modules/core/consumer_multi.c, src/modules/core/consumer_multi.yml, src/modules/core/factory.c: add multi consumer (non-functional) 2011-11-12 Dan Dennedy * profiles/sdi_486i_5994, profiles/sdi_486p_2398, src/modules/linsys/consumer_SDIstream.c, src/modules/linsys/sdi_generator.c, src/modules/linsys/sdi_generator.h: improve support for 486 line NTSC in linsys sdi consumer 2011-11-03 Dan Dennedy * configure, src/framework/mlt_version.h: set interim version 0.7.7 * src/modules/avformat/vdpau.c, src/modules/videostab/stab/estimate.c: build fixes for FreeBSD patches by Alberto Villa 2011-10-31 Dan Dennedy * Doxyfile, configure, docs/melt.1, src/framework/mlt_version.h: set version to 0.7.6 2011-10-30 Dan Dennedy * src/modules/videostab/filter_videostab.c, src/modules/videostab/filter_videostab2.c: Request progressive scan images when stabilizing video. * presets/filter/brightness/from_black, presets/filter/brightness/to_black, presets/filter/volume/fade_in, presets/filter/volume/fade_out: add fade in/out presets When using to_black and fade_out, currently you need to adjust in and out properties as needed because we cannot yet use negative values to mean "from end." 2011-09-20 Marco Gittler * src/modules/videostab/filter_videostab2.c, src/modules/videostab/transform_image.c, src/modules/videostab/transform_image.h: set transform properties from mlt 2011-09-19 Marco Gittler * src/modules/videostab/filter_videostab2.c, src/modules/videostab/transform_image.c: use interpolation settings 2011-09-11 Marco Gittler * src/modules/videostab/stabilize.c, src/modules/videostab/transform_image.c: move printf -> mlt_log* * src/modules/videostab/filter_videostab2.c, src/modules/videostab/stabilize.c: set all paramters * src/modules/videostab/filter_videostab2.c, src/modules/videostab/stabilize.c, src/modules/videostab/stabilize.h, src/modules/videostab/transform_image.c, src/modules/videostab/transform_image.h: avoid unreadable code like (*format==mlt_image_rgb24?0:1) use mlt_types and names for it 2011-08-19 Marco Gittler * src/modules/videostab/Makefile, src/modules/videostab/factory.c, src/modules/videostab/filter_videostab2.c, src/modules/videostab/stabilize.c, src/modules/videostab/stabilize.h, src/modules/videostab/tlist.c, src/modules/videostab/tlist.h, src/modules/videostab/transform.c, src/modules/videostab/transform.h, src/modules/videostab/transform_image.c, src/modules/videostab/transform_image.h: added vstab from http://public.hronopik.de/vid.stab/features.php?lang=en handles yuv, has zoom (to avoid the interpolated borders), and seems to be stabilize a bit better 2011-10-30 Dan Dennedy * src/modules/core/producer_consumer.c, src/modules/core/producer_consumer.yml: add autoprofile property to consumer producer 2011-10-16 Brian Matherly * demo/mlt_voiceover, demo/pango.mlt, src/modules/core/data_fx.properties, src/modules/feeds/NTSC/data_fx.properties, src/modules/feeds/NTSC/etv.properties, src/modules/feeds/PAL/data_fx.properties, src/modules/feeds/PAL/etv.properties, src/modules/gtk2/filter_dynamictext.c, src/modules/gtk2/filter_dynamictext.yml, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pango.yml, src/tests/pango.c: Add "family" and "style" properties to pango producer. Deprecate "font" property. 2011-10-11 Brian Matherly * src/modules/decklink/producer_decklink.yml, src/modules/sox/filter_sox.yml: yml validation fixes * src/modules/gtk2/filter_dynamictext.c, src/modules/gtk2/filter_dynamictext.yml, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pango.yml: Add outline to pango and dynamic text services. Add pad and align to dynamic text. 2011-10-02 Brian Matherly * README, docs/TODO, docs/policies.txt, docs/services.txt: Remove docs/TODO, docs/policies.txt, docs/services/txt. All that information is now available on the web site. 2011-10-01 Dan Dennedy * src/melt/melt.c, src/modules/core/producer_melt.c, src/modules/xml/mlt-xml.dtd, src/modules/xml/producer_xml.c: Add consumer element to xml producer. 2011-09-25 Brian Matherly * src/modules/gtk2/filter_dynamictext.yml, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pango.yml: Add support for HTML style color parameter to producer_pango. producer_color and producer_pango now work exactly the same WRT color parameters. 2011-09-25 Dan Dennedy * src/modules/frei0r/factory.c, src/modules/jackrack/plugin_mgr.c: Load frei0r and ladspa plugins relative to exe on win32 * src/framework/Makefile, src/framework/mlt_factory.c, src/framework/mlt_profile.c: Fix build on win32 * src/framework/mlt_profile.c, src/framework/mlt_properties.c, src/framework/mlt_repository.c: Fix and cleanup profile and preset dirs. * src/framework/Makefile, src/framework/mlt_factory.c, src/framework/mlt_profile.c: Fix loading profile from datadir. * src/modules/frei0r/factory.c, src/modules/jackrack/plugin_mgr.c: Add relative frei0r and LADSPA dirs for relocatable. 2011-09-23 Dan Dennedy * src/framework/mlt_profile.c, src/framework/mlt_repository.c: Make profiles relative to MLT_DATA instead of $prefix/share/mlt 2011-09-25 Dan Dennedy * src/modules/decklink/consumer_decklink.cpp, src/modules/decklink/producer_decklink.cpp: Fix building decklink on win32 2011-09-20 Dan Dennedy * presets/consumer/avformat/XDCAM-HD422, presets/consumer/avformat/atsc_1080i_50/DNxHD, presets/consumer/avformat/atsc_1080i_5994/DNxHD, presets/consumer/avformat/atsc_1080p_2398/DNxHD, presets/consumer/avformat/atsc_1080p_24/DNxHD, presets/consumer/avformat/atsc_1080p_25/DNxHD, presets/consumer/avformat/atsc_1080p_2997/DNxHD, presets/consumer/avformat/atsc_1080p_30/DNxHD, presets/consumer/avformat/atsc_1080p_50/DNxHD, presets/consumer/avformat/atsc_1080p_5994/DNxHD, presets/consumer/avformat/atsc_1080p_60/DNxHD, presets/consumer/avformat/atsc_720p_2398/DNxHD, presets/consumer/avformat/atsc_720p_50/DNxHD, presets/consumer/avformat/atsc_720p_5994/DNxHD, presets/consumer/avformat/atsc_720p_60/DNxHD, presets/consumer/avformat/dv_ntsc/D10, presets/consumer/avformat/dv_ntsc/DVD, presets/consumer/avformat/dv_ntsc_wide/D10, presets/consumer/avformat/dv_ntsc_wide/DVD, presets/consumer/avformat/dv_pal/D10, presets/consumer/avformat/dv_pal/DVD, presets/consumer/avformat/dv_pal_wide/D10, presets/consumer/avformat/dv_pal_wide/DVD, presets/consumer/avformat/webm: Fix video bitrate option in presets. * src/modules/avformat/consumer_avformat.c, src/modules/avformat/consumer_avformat.yml: Support streamtype-specific AVOptions (-vb) 2011-08-28 Brian Matherly * src/modules/gtk2/Makefile, src/modules/gtk2/factory.c, src/modules/gtk2/filter_dynamictext.c, src/modules/gtk2/filter_dynamictext.yml: Add filter_dynamictext. 2011-09-11 Dan Dennedy * src/modules/sox/Makefile, src/modules/sox/factory.c, src/modules/sox/filter_sox.yml, src/modules/sox/filter_sox_effect.yml: Document normalise and analysis for sox. This change separates the general sox metadata from effect instance metadata. 2011-09-09 Dan Dennedy * src/modules/core/Makefile, src/modules/core/factory.c, src/modules/core/producer_melt.c, src/modules/core/producer_melt.yml, src/modules/core/producer_melt_file.yml, src/modules/melt/Makefile, src/modules/melt/factory.c, src/modules/melt/producer_melt.c, src/modules/melt/producer_melt.yml, src/modules/melt/producer_melt_file.yml: Move melt producer to core module. * presets/consumer/avformat/atsc_1080i_50/DNxHD, presets/consumer/avformat/atsc_1080i_5994/DNxHD, presets/consumer/avformat/atsc_1080p_2398/DNxHD, presets/consumer/avformat/atsc_1080p_24/DNxHD, presets/consumer/avformat/atsc_1080p_25/DNxHD, presets/consumer/avformat/atsc_1080p_2997/DNxHD, presets/consumer/avformat/atsc_1080p_30/DNxHD, presets/consumer/avformat/atsc_1080p_50/DNxHD, presets/consumer/avformat/atsc_1080p_5994/DNxHD, presets/consumer/avformat/atsc_1080p_60/DNxHD, presets/consumer/avformat/atsc_720p_2398/DNxHD, presets/consumer/avformat/atsc_720p_50/DNxHD, presets/consumer/avformat/atsc_720p_5994/DNxHD, presets/consumer/avformat/atsc_720p_60/DNxHD: Add a bunch of DNxHD encode presets. 2011-09-04 Dan Dennedy * src/modules/melt/producer_melt.c, src/modules/xml/producer_xml.c: Change previous mods to use mlt_multitrack_count() * src/modules/melt/producer_melt.c, src/modules/xml/producer_xml.c: Fix XML and melt producers producer_avformat cache size. Use track-count + 2 in case a track is using a mixer between playlist items. * src/framework/mlt_service.c, src/framework/mlt_service.h: Add mlt_service_cache_get_size() * src/framework/mlt_cache.c, src/framework/mlt_cache.h: Add mlt_cache_get_size() 2011-09-03 Dan Dennedy * src/modules/decklink/producer_decklink.cpp, src/modules/decklink/producer_decklink.yml: Add vanc property to decklink producer. This captures vertical ancillary data during the vertical blanking, which often contains metadata with timecode. This can be used to produce D10/IMX50 captures with VBI. 2011-09-03 j-b-m * src/modules/core/transition_region.c, src/modules/core/transition_region.yml: Add filter_only to region transition. YAML patch by Dan Dennedy 2011-09-01 Dan Dennedy * presets/consumer/avformat/dv_ntsc/D10, presets/consumer/avformat/dv_ntsc_wide/D10, presets/consumer/avformat/dv_pal/D10, presets/consumer/avformat/dv_pal_wide/D10: Add SMPTE 356M (aka D-10 and IMX50) encoode presets. * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_tractor.c, src/framework/mlt_transition.c, src/modules/core/filter_resize.c: Add consumer property top_field_first. 2011-08-31 Dan Dennedy * src/modules/sox/factory.c, src/modules/sox/filter_sox.c: Use the sox version in metadata and serialization. * src/modules/xml/consumer_xml.c, src/modules/xml/mlt-xml.dtd: Add MLT version to serialized XML. * src/modules/frei0r/factory.c, .../motion_est/filter_autotrack_rectangle.c: Convert some printfs to fprintf(stderr) or mlt_log. 2011-08-16 Dan Dennedy * src/modules/xml/consumer_xml.c, src/modules/xml/consumer_xml.yml: Add no_meta property to xml consumer. Applications that use the consumer for its project file might want to reduce xml bloat by setting this. * src/modules/jackrack/consumer_jack.c, src/modules/jackrack/filter_jackrack.c, src/modules/jackrack/process.c: Fix segfault on concurrent calls to jack_activate(). 2011-08-15 Dan Dennedy * src/modules/videostab/filter_videostab.c, src/modules/videostab/filter_videostab.yml: Add vectors property to videostab. Change videostab to save to and load from a property instead of file. It uses mlt_geometry for the (de)serialization of the vectors, Also, remove seeking on the producer and require a two pass mode of operation. Finally, make it parallel-safe. * src/framework/mlt_geometry.c, src/framework/mlt_geometry.h, src/mlt++/MltGeometry.cpp, src/mlt++/MltGeometry.h, src/modules/core/transition_composite.c, src/modules/gtk2/producer_pango.c, .../motion_est/filter_autotrack_rectangle.c: Add mlt_geometry_interpolate. This removes re-interpolation on each call to mlt_geometry_insert() to make bulk invocations of that call faster. This also makes mlt_geometry_parse() faster. Also, this includes a fix to mlt_geometry_serialise() for a buffer overflow memory corruption. * src/modules/xml/Makefile, src/modules/xml/consumer_xml.c, src/modules/xml/consumer_xml.yml: Add 'all' property to xml consumer. Makes the consumer process all frames before serializing to XML. 2011-08-13 Dan Dennedy * src/framework/mlt_filter.c, src/framework/mlt_filter.h, src/mlt++/MltFilter.cpp, src/mlt++/MltFilter.h: Add mlt_filter_get_length2. 2011-08-12 Marco Gittler * src/modules/videostab/factory.c, src/modules/videostab/filter_videostab.yml: added yml metadata 2011-08-11 Marco Gittler * src/modules/videostab/factory.c, src/modules/videostab/filter_videostab.c: compile fix * src/modules/videostab/Makefile, src/modules/videostab/factory.c, src/modules/videostab/filter_videostab.c, src/modules/videostab/stab/estimate.c, src/modules/videostab/stab/estimate.h, src/modules/videostab/stab/klt/base.h, src/modules/videostab/stab/klt/convolve.c, src/modules/videostab/stab/klt/convolve.h, src/modules/videostab/stab/klt/error.c, src/modules/videostab/stab/klt/error.h, src/modules/videostab/stab/klt/klt.c, src/modules/videostab/stab/klt/klt.h, src/modules/videostab/stab/klt/klt_util.c, src/modules/videostab/stab/klt/klt_util.h, src/modules/videostab/stab/klt/pyramid.c, src/modules/videostab/stab/klt/pyramid.h, .../videostab/stab/klt/selectGoodFeatures.c, src/modules/videostab/stab/klt/trackFeatures.c, src/modules/videostab/stab/main.c, src/modules/videostab/stab/resample.c, src/modules/videostab/stab/resample.h, src/modules/videostab/stab/utils.c, src/modules/videostab/stab/utils.h, src/modules/videostab/stab/vector.c, src/modules/videostab/stab/vector.h: first version of video stabilization from http://vstab.sourceforge.net/ 2011-08-03 Dan Dennedy * src/modules/jackrack/Makefile, src/modules/jackrack/configure, src/modules/jackrack/consumer_jack.c, src/modules/jackrack/factory.c: Make jack consumer LGPLv2.1 license. This change allows the module to be built in either GPL or LGPL mode where GPL mode also adds the jackrack and ladspa filters. * src/modules/jackrack/Makefile, src/modules/jackrack/consumer_jack.yml: Add service metadata for jack consumer. * src/modules/jackrack/Makefile, src/modules/jackrack/consumer_jack.c, src/modules/jackrack/factory.c: Add audio-only JACK consumer. Fires consumer-frame-show for video frames. 2011-07-24 Brian Matherly * Makefile, src/modules/avformat/consumer_avformat.yml, src/modules/avformat/producer_avformat.yml, src/modules/core/factory.c, src/modules/core/filter_channelcopy.yml, src/modules/core/filter_gamma.yml, src/modules/core/filter_luma.yml, src/modules/core/filter_region.yml, src/modules/core/filter_rescale.yml, src/modules/core/filter_resize.yml, src/modules/core/producer_loader.yml, src/modules/core/transition_composite.yml, src/modules/core/transition_luma.yml, src/modules/dv/producer_libdv.yml, src/modules/gtk2/factory.c, src/modules/gtk2/filter_rescale.yml, src/modules/gtk2/producer_pango.yml, src/modules/kdenlive/filter_boxblur.yml, src/modules/resample/Makefile, src/modules/resample/factory.c, src/modules/resample/filter_resample.yml: Add service metadata for composite transition, all normalizing filters (resample, resize, rescale), and the loader producer. Add yml validation rule to Makefile. All yml files pass validation against metaschema.yaml. 2011-07-22 Dan Dennedy * src/modules/core/filter_mirror.yml, src/modules/core/filter_mono.yml, src/modules/core/filter_obscure.yml, src/modules/core/filter_region.yml, src/modules/core/transition_luma.yml, src/modules/core/transition_mix.yml, src/modules/core/transition_region.yml, src/modules/dv/consumer_libdv.yml, src/modules/normalize/filter_volume.yml, src/modules/sdl/consumer_sdl.yml, src/modules/xml/consumer_xml.yml: Cleanup Brian's service metadata contribution. * src/modules/avformat/consumer_avformat.c, src/modules/avformat/factory.c, src/modules/avformat/producer_avformat.c: Make ffmpeg v53-specific code more readable and searchable. * configure, src/framework/mlt_version.h: set interim version 0.7.5 * src/framework/mlt_property.c, src/framework/mlt_property.h: Fix build on Debian kfreebsd. * src/modules/avformat/consumer_avformat.c, src/modules/avformat/factory.c, src/modules/avformat/producer_avformat.c: Make ffmpeg v53-specific code more readable and searchable. * configure, src/framework/mlt_version.h: set interim version 0.7.5 * src/framework/mlt_property.c, src/framework/mlt_property.h: Fix build on Debian kfreebsd. 2011-07-19 Brian Matherly * src/modules/core/filter_mirror.yml, src/modules/core/filter_mono.yml, src/modules/core/filter_obscure.yml, src/modules/core/filter_region.yml, src/modules/core/transition_luma.yml, src/modules/core/transition_mix.yml, src/modules/core/transition_region.yml, src/modules/dv/consumer_libdv.yml, src/modules/jackrack/filter_ladspa.yml, src/modules/normalize/filter_volume.yml, src/modules/sdl/consumer_sdl.yml, src/modules/xml/consumer_xml.yml: Transcribe service metadata from services.txt to corresponding yml files. 2011-07-17 Brian Matherly * src/modules/avformat/consumer_avformat.yml, src/modules/avformat/producer_avformat.yml, src/modules/core/filter_data_show.yml, src/modules/core/filter_watermark.yml, src/modules/core/producer_noise.yml, src/modules/decklink/producer_decklink.yml, src/modules/dv/producer_libdv.yml, src/modules/gtk2/producer_pango.yml, src/modules/gtk2/producer_pixbuf.yml, src/modules/vorbis/producer_vorbis.yml, src/modules/xml/producer_xml.yml: Remove from all existing yml: in, out, length, resource, and aspect_ratio. 2011-07-16 Dan Dennedy * Doxyfile, configure, docs/melt.1, docs/melt.txt, src/framework/mlt_version.h: Set version to 0.7.4 * src/modules/jackrack/factory.c, src/modules/jackrack/plugin_desc.c, src/modules/jackrack/plugin_desc.h: Properly represent LADSPA plugin author. 2011-07-11 Dan Dennedy * src/framework/mlt_properties.c, src/framework/mlt_property.c, src/framework/mlt_property.h: Fix build on new locale stuff when not Linux or OS X. 2011-07-10 Dan Dennedy * src/framework/mlt_properties.c, src/framework/mlt_property.c: Fix build for querylocale() on OS X. * presets/consumer/avformat/webm, presets/consumer/avformat/webm-pass1, presets/consumer/avformat/webm-pass2: Fix webm preset. * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/modules/sdl/consumer_sdl_preview.c: Make maximum consecutive-dropped frames configurable. Defaults to old value of 5 that seems more preferable for video editing. 2011-07-09 Dan Dennedy * src/modules/feeds/NTSC/data_fx.properties, src/modules/feeds/NTSC/etv.properties, src/modules/feeds/NTSC/obscure.properties, src/modules/feeds/PAL/border.properties, src/modules/feeds/PAL/data_fx.properties, src/modules/feeds/PAL/etv.properties: Convert , to / delimiter in data_show templates. * src/framework/metaschema.yaml, src/framework/mlt_properties.c: Add LC_NUMERIC handling to YAML Tiny parser. * src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h: Add mlt_properties_get_lcnumeric and Properties::get_lcnumeric * src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h: Add Properties::set_lcnumeric(). * src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_property.h: Add mlt_properties_set_lcnumeric, mlt_property_get_double_l, and mlt_property_get_string_l. Locale-specific variants of key properties functions. 2011-07-07 Dan Dennedy * src/modules/core/filter_data_show.yml, src/modules/core/filter_gamma.yml, src/modules/core/filter_greyscale.yml, src/modules/core/filter_luma.yml, src/modules/core/filter_watermark.yml, src/modules/core/producer_colour.yml, src/modules/core/producer_noise.yml, src/modules/dv/producer_libdv.yml, src/modules/gtk2/producer_pango.yml, src/modules/gtk2/producer_pixbuf.yml, src/modules/vorbis/producer_vorbis.yml, src/modules/xml/producer_xml.yml: Convert services.txt to metadata YAML (WIP). Patch by Brian Matherly. 2011-07-06 Dan Dennedy * src/modules/xml/consumer_xml.c, src/modules/xml/mlt-xml.dtd, src/modules/xml/producer_xml.c: Add LC_NUMERIC to MLT XML. This does not permit one to mix locales within a MLT process! In other words, you can not load a document in a locale using one decimal separator and then filter with a double property using a different separator. * src/modules/oldfilm/filter_vignette.c, src/modules/plus/filter_charcoal.c: Fix some default numeric property values in some locales. Strings with a period for decimal separator do not convert correctly in locales that use comma for the decimal separator. * demo/README, demo/demo, demo/mlt_bouncy, demo/mlt_bouncy_ball, demo/mlt_composite_transition, demo/mlt_my_name_is, demo/mlt_news, demo/mlt_obscure, demo/mlt_push, demo/mlt_slideshow2, demo/mlt_slideshow_black, demo/mlt_squeeze, demo/mlt_squeeze_box, demo/mlt_swf_variables, demo/mlt_ticker, demo/mlt_title_over_gfx, demo/mlt_titleshadow_watermark, demo/mlt_voiceover, demo/mlt_watermark, demo/pango.mlt, docs/framework.txt, docs/services.txt, src/framework/mlt_geometry.c, src/modules/core/filter_obscure.c, src/modules/core/transition_composite.c, src/modules/core/transition_region.c, src/modules/motion_est/Makefile, .../motion_est/filter_autotrack_rectangle.c, src/modules/plus/transition_affine.c, src/tests/hello.c: Use '/' for coordinate delimiter instead of period. Period is a decimal separator in some locales. * demo/consumers.ini, demo/demo.ini: Fix usage of cut in demo script for some platforms (OSX). 2011-07-05 Dan Dennedy * presets/consumer/avformat/webm, presets/consumer/avformat/webm-pass1, presets/consumer/avformat/webm-pass2: Add some WebM presets. 2011-07-04 Dan Dennedy * presets/consumer/avformat/x264-medium-baseline, presets/consumer/avformat/x264-medium-main: Fix profile-based x264 presets for FFmpeg v0.8+. * presets/consumer/avformat/x264-medium, presets/consumer/avformat/x264-medium-baseline, presets/consumer/avformat/x264-medium-main, presets/consumer/avformat/x264-medium-pass1: Add some x264-medium presets. * src/modules/avformat/Makefile, src/modules/avformat/configure: Dropping support for --avformat-svn. Subversion is no longer used, FFmpeg and libav have forked, and now there are the build scripts. * src/modules/avformat/producer_avformat.c, src/modules/avformat/producer_avformat.yml, src/modules/melt/producer_melt.c: Support standard query syntax on avformat URL. 2011-07-02 Dan Dennedy * src/modules/decklink/DeckLinkAPI_h.h, src/modules/decklink/DeckLinkAPI_i.cpp, src/modules/decklink/Makefile, src/modules/decklink/configure, src/modules/decklink/consumer_decklink.cpp, src/modules/decklink/producer_decklink.cpp: Add Windows support for DeckLink. 2011-06-22 Dan Dennedy * presets/consumer/avformat/dv_ntsc/DV, presets/consumer/avformat/dv_ntsc/DVCPRO50, presets/consumer/avformat/dv_ntsc_wide/DV, presets/consumer/avformat/dv_ntsc_wide/DVCPRO50, presets/consumer/avformat/dv_pal/DV, presets/consumer/avformat/dv_pal/DVCPRO50, presets/consumer/avformat/dv_pal_wide/DV, presets/consumer/avformat/dv_pal_wide/DVCPRO50: Add DV and DVCPRO50 encode presets. 2011-06-17 Dan Dennedy * src/framework/Makefile, src/framework/mlt_types.h, src/melt/Makefile, src/modules/avformat/Makefile, src/modules/gtk2/Makefile, src/modules/sdl/Makefile, src/win32/fnmatch.c: Cleanup Win32 build. 2011-06-15 Dan Dennedy * src/framework/mlt_transition.c, src/modules/core/transition_composite.c: Fix regression in field rendering luma transition. Due to refactoring composite and luma into mlt_transition_get_progress_delta(). 2011-06-13 Dan Dennedy * src/modules/avformat/producer_avformat.c, src/modules/avformat/producer_avformat.yml: Add video_delay to avformat producer. 2011-06-11 Dan Dennedy * src/modules/decklink/producer_decklink.cpp, src/modules/decklink/producer_decklink.yml: Add prefill property to decklink producer. 2011-06-06 Dan Dennedy * src/framework/mlt_consumer.c, src/modules/avformat/consumer_avformat.yml: Change consumer 'profile' property to 'mlt_profile' libavcodec uses the profile property for aac and libx264. 2011-06-05 Dan Dennedy * src/modules/avformat/consumer_avformat.yml, src/modules/avformat/producer_avformat.yml: Change URI to URL in avformat yaml. * src/melt/melt.c, src/modules/avformat/consumer_avformat.c: Send melt -query and -help to stdout. Nice for use with pager or grep, awk, etc. 2011-06-03 Dan Dennedy * src/modules/decklink/consumer_decklink.cpp, src/modules/decklink/consumer_decklink.yml: Enable external keyer on decklink consumer. Patch supplied by Maksym Veremeyenko. 2011-05-30 Dan Dennedy * src/modules/linsys/Makefile, src/modules/linsys/consumer_sdi.yml, src/modules/linsys/factory.c: Add service metadata to linsys module (WIP). * src/modules/xml/Makefile, src/modules/xml/consumer_xml.yml, src/modules/xml/factory.c, src/modules/xml/producer_xml-string.yml, src/modules/xml/producer_xml.yml: Add service metadata to xml module (WIP). * src/modules/vorbis/Makefile, src/modules/vorbis/factory.c, src/modules/vorbis/producer_vorbis.yml: Add service metadata to vorbis module (WIP). * src/modules/core/filter_mono.yml, src/modules/vmfx/Makefile, src/modules/vmfx/factory.c, src/modules/vmfx/filter_chroma.yml, src/modules/vmfx/filter_chroma_hold.yml, src/modules/vmfx/filter_mono.yml, src/modules/vmfx/filter_shape.yml, src/modules/vmfx/producer_pgm.yml: Add service metadata to vmfx module (WIP). * src/modules/jackrack/plugin.c, src/modules/jackrack/plugin_mgr.c, src/modules/jackrack/plugin_settings.c: Remove aborts in jackrack module. 2011-05-29 Dan Dennedy * src/modules/swfdec/Makefile, src/modules/swfdec/producer_swfdec.c, src/modules/swfdec/producer_swfdec.yml: Add service metadata to swfdec module (WIP). * src/modules/qimage/producer_qimage.yml, src/modules/sdl/Makefile, src/modules/sdl/consumer_sdl.yml, src/modules/sdl/consumer_sdl_audio.yml, src/modules/sdl/consumer_sdl_preview.yml, src/modules/sdl/consumer_sdl_still.yml, src/modules/sdl/factory.c, src/modules/sdl/producer_sdl_image.yml: Add service metadata for SDL module (WIP). * src/modules/plus/transition_affine.yml, src/modules/qimage/Makefile, src/modules/qimage/factory.c, src/modules/qimage/producer_kdenlivetitle.yml, src/modules/qimage/producer_qimage.yml: Add service metadata for qimage module (WIP). * src/modules/plus/Makefile, src/modules/plus/factory.c, src/modules/plus/filter_affine.yml, src/modules/plus/filter_charcoal.yml, src/modules/plus/filter_invert.yml, src/modules/plus/filter_sepia.yml, src/modules/plus/transition_affine.yml: Add service metadata to plus module (WIP). * src/modules/normalize/Makefile, src/modules/normalize/factory.c, src/modules/normalize/filter_volume.yml: Add service metadata to normalize module (WIP). * src/modules/motion_est/Makefile, src/modules/motion_est/factory.c, .../motion_est/filter_autotrack_rectangle.yml, src/modules/motion_est/filter_motion_est.yml, src/modules/motion_est/filter_vismv.yml, src/modules/motion_est/producer_slowmotion.yml: Add service metadata to motion_est module (WIP). * src/modules/melt/Makefile, src/modules/melt/factory.c, src/modules/melt/producer_melt.yml, src/modules/melt/producer_melt_file.yml: Add service metadata for melt module (WIP). * src/modules/kdenlive/Makefile, src/modules/kdenlive/factory.c, src/modules/kdenlive/filter_boxblur.yml, src/modules/kdenlive/filter_freeze.yml, src/modules/kdenlive/filter_wave.yml, src/modules/kdenlive/producer_framebuffer.yml: Add service metadata for kdenlive module (WIP). * src/modules/gtk2/Makefile, src/modules/gtk2/consumer_gtk2_preview.yml, src/modules/gtk2/factory.c, src/modules/gtk2/producer_pango.yml, src/modules/gtk2/producer_pixbuf.yml: Add service metadata for gtk2 module (WIP). * src/modules/effectv/Makefile, src/modules/effectv/factory.c, src/modules/effectv/filter_burningtv.yml: Add service metadata for effectv module (WIP). * src/modules/dv/Makefile, src/modules/dv/consumer_libdv.yml, src/modules/dv/factory.c, src/modules/dv/producer_libdv.yml: Add service metdata for dv module (WIP). * src/modules/core/Makefile, src/modules/core/factory.c, src/modules/core/filter_audiowave.yml, src/modules/core/filter_brightness.yml, src/modules/core/filter_channelcopy.yml, src/modules/core/filter_crop.yml, src/modules/core/filter_data_show.yml, src/modules/core/filter_gamma.yml, src/modules/core/filter_greyscale.yml, src/modules/core/filter_luma.yml, src/modules/core/filter_mirror.yml, src/modules/core/filter_mono.yml, src/modules/core/filter_obscure.yml, src/modules/core/filter_region.yml, src/modules/core/filter_transition.yml, src/modules/core/filter_watermark.yml, src/modules/core/producer_colour.yml, src/modules/core/producer_consumer.yml, src/modules/core/producer_hold.yml, src/modules/core/producer_noise.yml, src/modules/core/transition_composite.yml, src/modules/core/transition_luma.yml, src/modules/core/transition_mix.yml, src/modules/core/transition_region.yml: Add service metadata for core module (WIP). 2011-05-28 Dan Dennedy * src/swig/python/getimage.py, src/swig/python/waveforms.py: Convert Python examples to new frame method. * src/framework/mlt_profile.c, src/framework/mlt_profile.h, src/mlt++/MltProfile.cpp, src/mlt++/MltProfile.h: Add mlt_profile_from_producer(). This new function contains the auto-profile feature. Plus setters for Mlt::Profile. 2011-05-22 Dan Dennedy * src/modules/jackrack/Makefile, src/modules/jackrack/blacklist.txt, src/modules/jackrack/plugin_mgr.c, src/modules/jackrack/plugin_mgr.h: Add blacklist for ladspa filters. Initially includes dssi-vst since that is unstable on AV Linux 5. 2011-05-17 Dan Dennedy * src/modules/jackrack/factory.c, src/modules/jackrack/jack_rack.c: Let all instances of ladspa share single plugin_mgr. 2011-05-15 Dan Dennedy * docs/melt.1, src/melt/melt.c: Document -jack option. * src/melt/melt.c, src/modules/jackrack/filter_jackrack.c, src/modules/jackrack/process.c: Add first draft of JACK transport sync. 2011-05-14 Dan Dennedy * configure, src/mlt++/configure: Fix build on Debian GNU/kFreeBSD. 2011-05-12 Dan Dennedy * Makefile, presets/consumer/avformat/dv_ntsc/DVD, presets/consumer/avformat/dv_ntsc_wide/DVD, presets/consumer/avformat/dv_pal/DVD, presets/consumer/avformat/dv_pal_wide/DVD, setenv, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_repository.c, src/framework/mlt_repository.h, src/melt/melt.c, src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h, src/mlt++/MltRepository.cpp, src/mlt++/MltRepository.h, src/swig/mlt.i: Presets! Put property setters in a file and apply them to a service using properties=filename. Alternatively, apply a supplied preset using properties=preset. For example, melt ... -consumer avformat:my.vob properties=DVD. * src/modules/jackrack/jack_rack.c, src/modules/jackrack/plugin.c, src/modules/jackrack/plugin_mgr.c, src/modules/jackrack/process.c: Convert jackrack printfs to mlt_log (3301094). 2011-05-10 Dan Dennedy * src/modules/jackrack/Makefile, src/modules/jackrack/factory.c, src/modules/jackrack/filter_jackrack.yml, src/modules/jackrack/filter_ladspa.yml: Add service metadata for jackrack, ladspa, and ladspa.id. * src/modules/jackrack/filter_ladspa.c, src/modules/jackrack/plugin_mgr.c: Add support for ladspa.id variants. This is much more convenient to use without having to compose the JACK Rack XML. Also, we will be able to add future support for property animation (automation), which JACK Rack lacks. However, it does still support loading and processing JACK Rack files. 2011-05-08 Dan Dennedy * src/modules/sox/Makefile, src/modules/sox/factory.c, src/modules/sox/filter_sox.c, src/modules/sox/filter_sox.yml: Add support for sox.effect variants. The legacy forms of 'sox:"effect options"' and 'sox effect="name options"' still work. The new forms allows them all to be enumerated by Mlt apps, e.g.: melt -query filter. Also, this registers metadata for both the generic 'sox' filter and all of the new 'sox.effect' ones including their usage help! * src/modules/avformat/filter_avresample.c, src/modules/core/loader.ini: Fix inadvertent reording of resample filters. And add debug log to avresample. 2011-05-06 Dan Dennedy * src/framework/mlt_tractor.c, src/modules/avformat/producer_avformat.c, src/modules/dv/producer_libdv.c, src/modules/vorbis/producer_vorbis.c: Make the frame audio properties consistent. * src/framework/mlt_frame.c, src/framework/mlt_types.h: Add mlt_audio_s32le and mlt_audio_f32le audio formats. * src/modules/avformat/filter_avresample.c, src/modules/core/Makefile, src/modules/core/factory.c, src/modules/core/filter_audiochannels.c, src/modules/core/loader.ini, src/modules/resample/filter_resample.c: Add audiochannels normalization filter. Refactors code from the resamplers into a new filter to be more manageable. Eventually, we can add options on what to do when adding/removing channels. 2011-05-03 Dan Dennedy * configure, src/framework/mlt_transition.c: Ensure transition B frames get some consumer properties. Also, ensure both A and B frames have sane scaling and aspect ratio values. This addresses an issue where composite and region were not getting the correct deinterlace method impacting performance. In addition, it factors out some common code (best practice) from various transitions moving it into the framework. 2011-05-01 Dan Dennedy * Doxyfile, configure, docs/melt.1, src/framework/mlt_version.h: Set version to 0.7.2 * src/modules/avformat/filter_avresample.c, src/modules/resample/filter_resample.c: Finish work to normalize channel count. Also, refactor the audio resamplers to use mlt_audio_format_size() and mlt_frame_set_audio(). Currently, there are no controls over which channels to drop or duplicate. * src/framework/mlt_tractor.c, src/modules/core/producer_consumer.c, src/modules/core/producer_noise.c, src/modules/core/producer_ppm.c: Refactor to mlt_frame_set_audio(). * src/modules/feeds/NTSC/data_fx.properties, src/modules/feeds/PAL/data_fx.properties: Fix alpha on color of some data-feed properties. * src/modules/avformat/consumer_avformat.c, src/modules/avformat/factory.c, src/modules/avformat/producer_avformat.c: Add support for new codec- and muxer-specific AVOptions. 2011-04-22 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: Use new avio functions in avformat module. 2011-04-21 Dan Dennedy * src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/producer_avformat.c: Fix regression initializing coefficients. * src/modules/avformat/consumer_avformat.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_swscale.c, src/modules/avformat/producer_avformat.c: Fix avformat compile warns on const and 64-bit string formatting. * src/modules/core/producer_hold.c, src/modules/jackrack/filter_jackrack.c: Fix couple compile warns. * src/framework/mlt_property.c, src/framework/mlt_types.h, src/modules/linsys/sdi_generator.c: Fix some compile warnings about string-formatting 64bit. * src/modules/avformat/audioconvert.h, src/modules/avformat/producer_avformat.c: Drop private audioconvert.h for public samplefmt.h. 2011-04-20 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/factory.c, src/modules/avformat/producer_avformat.c: More libavcodec v53 changes required. * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: Fix avformat build with libavcodec v53. 2011-04-09 Dan Dennedy * src/framework/mlt_profile.c, src/mlt++/MltProfile.cpp, src/mlt++/MltProfile.h, src/swig/mlt.i: Add Mlt::Profile.list(). 2011-04-07 Dan Dennedy * src/modules/avformat/consumer_avformat.yml, src/modules/avformat/factory.c, src/modules/avformat/producer_avformat.yml: Add avformat consumer metadata. Improve avformat producer metadata. Significantly extend each with AVOptions. 2011-04-04 Dan Dennedy * demo/README, demo/demo.ini, demo/mlt_pango_keyframes, demo/pango_keyframes.mpl: Add mlt_pango_keyframes demo. 2011-04-03 Dan Dennedy * docs/melt.1, docs/melt.txt, src/melt/melt.c: Add -query formats and codecs to melt. * docs/melt.1, docs/melt.txt, src/melt/melt.c: Add -query profile to melt. * src/framework/mlt_profile.c, src/framework/mlt_profile.h: Add mlt_profile_list(). 2011-03-31 Dan Dennedy * src/modules/decklink/consumer_decklink.yml, src/modules/decklink/producer_decklink.yml: Add metadata for decklink consumer. * src/modules/decklink/Makefile, src/modules/decklink/producer_decklink.cpp, src/modules/decklink/producer_decklink.yml: Add decklink producer. 2011-03-27 Dan Dennedy * configure, src/modules/core/transition_composite.c: Fix regression in region filter (3251260). * Doxyfile, configure, src/framework/mlt_version.h: Set version to 0.7.0 * src/modules/avformat/consumer_avformat.c, src/modules/sox/filter_sox.c, src/modules/xml/producer_xml.c: Use mlt_properties_get_value where possible. * src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_tractor.c, src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h: Add mlt_properties_lock and _unlock. Fixes some concurrency safetiness problems. 2011-03-24 Dan Dennedy * src/modules/decklink/configure, src/modules/kino/configure, src/modules/linsys/configure: Enable linsys by default on Linux. Disable linsys and decklink by default on OS X and Windows. 2011-03-23 Dan Dennedy * src/framework/mlt_consumer.c, src/modules/decklink/consumer_decklink.cpp: Fix a couple null pointer bugs. 2011-03-20 Dan Dennedy * src/modules/jackrack/filter_jackrack.c, src/modules/jackrack/plugin.h, src/modules/jackrack/process.c: Fix build of jackrack module on mingw. 2011-03-19 Dan Dennedy * profiles/atsc_1080p_50, profiles/atsc_1080p_5994, profiles/atsc_1080p_60: Add high frame rate 1080p profiles. 2011-03-09 Dan Dennedy * src/modules/frei0r/filter_frei0r.c, src/modules/frei0r/frei0r_helper.c, src/modules/frei0r/frei0r_helper.h, src/modules/frei0r/producer_frei0r.c, src/modules/frei0r/transition_frei0r.c: Refactor frei0r and fix time parameter. Refactored to use mlt_filter_get_position and mlt_transition_get_position. frei0r's time parameter is seconds, but we were passing frame count. * src/modules/core/transition_region.c, src/modules/plus/transition_affine.c: Refactor to mlt_transition_get_position() * src/framework/mlt_transition.c, src/framework/mlt_transition.h, src/mlt++/MltTransition.cpp, src/mlt++/MltTransition.h: Add mlt_transition_get_position() * src/modules/core/filter_luma.c, src/modules/core/filter_watermark.c, src/modules/dgraft/filter_telecide.c, src/modules/kdenlive/filter_freeze.c, .../motion_est/filter_autotrack_rectangle.c, src/modules/motion_est/filter_crop_detect.c, src/modules/oldfilm/filter_vignette.c, src/modules/plus/filter_affine.c, src/modules/vmfx/filter_shape.c: Refactor to mlt_filter_get_position(). 2011-03-08 Dan Dennedy * src/framework/mlt_filter.c, src/framework/mlt_transition.c: Use the producer when filter/transition always active. * src/framework/mlt_filter.c, src/framework/mlt_filter.h, src/mlt++/MltFilter.cpp, src/mlt++/MltFilter.h: Add mlt_filter_get_position(). 2011-03-07 Dan Dennedy * src/modules/core/transition_composite.c, src/modules/core/transition_luma.c: Refactor to mlt_transition_get_progress_delta(). * src/framework/mlt_transition.c, src/framework/mlt_transition.h, src/mlt++/MltTransition.cpp, src/mlt++/MltTransition.h: Add mlt_transition_get_progress_delta(). * src/modules/core/transition_luma.c, src/modules/core/transition_mix.c: Refactor to mlt_transition_get_progress(). * src/framework/mlt_transition.c, src/framework/mlt_transition.h, src/mlt++/MltTransition.cpp, src/mlt++/MltTransition.h: Add mlt_transition_get_progress(). * src/modules/core/filter_brightness.c, src/modules/core/filter_obscure.c, src/modules/kdenlive/filter_boxblur.c, src/modules/kdenlive/filter_wave.c, src/modules/normalize/filter_volume.c, src/modules/oldfilm/filter_dust.c, src/modules/oldfilm/filter_grain.c, src/modules/oldfilm/filter_lines.c, src/modules/oldfilm/filter_oldfilm.c: Refactor to mlt_filter_get_progress(). * src/framework/mlt_filter.c, src/framework/mlt_filter.h, src/mlt++/MltFilter.cpp, src/mlt++/MltFilter.h: Add mlt_filter_get_progress(). 2011-03-10 Dan Dennedy * src/modules/swfdec/Makefile, src/modules/swfdec/configure: Add build support for swfdec 0.7. And prioritize newer versions over older ones. 2011-03-06 Dan Dennedy * src/modules/core/transition_composite.c, src/modules/plus/transition_affine.c: Refactor to use mlt_transition_get_length(). * src/framework/mlt_transition.c, src/framework/mlt_transition.h, src/mlt++/MltTransition.cpp, src/mlt++/MltTransition.h: Add mlt_transition_get_length(). * src/framework/mlt_filter.c, src/framework/mlt_filter.h, src/mlt++/MltFilter.cpp, src/mlt++/MltFilter.h: Add mlt_filter_get_length(). * src/modules/core/filter_audioconvert.c, src/modules/core/filter_mono.c, src/modules/core/producer_consumer.c: Refactor to mlt_audio_format_size(). * src/framework/mlt_frame.c, src/framework/mlt_frame.h: Add mlt_audio_format_size(). * src/modules/core/producer_noise.c, src/modules/normalize/filter_volume.c: Remove unused variables. * src/modules/avformat/filter_swscale.c, src/modules/avformat/producer_avformat.c, src/modules/core/filter_crop.c, src/modules/core/filter_resize.c, src/modules/core/producer_colour.c, src/modules/gtk2/filter_rescale.c, src/modules/kdenlive/filter_freeze.c, src/modules/kdenlive/producer_framebuffer.c: Refactor to use mlt_image_format_size(). * src/framework/mlt_frame.c, src/framework/mlt_frame.h: Add mlt_image_format_size() * src/framework/mlt_tractor.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_swscale.c, src/modules/avformat/producer_avformat.c, src/modules/core/filter_audiowave.c, src/modules/core/filter_crop.c, src/modules/core/filter_imageconvert.c, src/modules/core/filter_luma.c, src/modules/core/filter_rescale.c, src/modules/core/filter_resize.c, src/modules/core/filter_watermark.c, src/modules/core/producer_colour.c, src/modules/core/producer_consumer.c, src/modules/core/producer_hold.c, src/modules/core/producer_noise.c, src/modules/core/producer_ppm.c, src/modules/core/transition_composite.c, src/modules/core/transition_region.c, src/modules/dgraft/filter_telecide.c, src/modules/dv/producer_libdv.c, src/modules/frei0r/frei0r_helper.c, src/modules/frei0r/producer_frei0r.c, src/modules/gtk2/filter_rescale.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/kdenlive/filter_freeze.c, src/modules/kdenlive/filter_wave.c, src/modules/kdenlive/producer_framebuffer.c, src/modules/motion_est/producer_slowmotion.c, src/modules/plus/filter_affine.c, src/modules/plus/filter_charcoal.c, src/modules/qimage/producer_kdenlivetitle.c, src/modules/qimage/producer_qimage.c, src/modules/sdl/producer_sdl_image.c, src/modules/swfdec/producer_swfdec.c, src/modules/vmfx/producer_pgm.c, src/modules/xine/filter_deinterlace.c: Refactor to use mlt_frame_set_image/_alpha. * src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/mlt++/MltFrame.cpp, src/mlt++/MltFrame.h: Add mlt_frame_set_image and mlt_frame_set_alpha. * src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c: Alias bicubic for hyper in pango and pixbuf. * : Add gpl flag file to rotoscoping filter. 2011-03-02 Dan Dennedy * src/framework/mlt_frame.c, src/framework/mlt_frame.h: Add mlt_frame_unique_properties(). * src/modules/avformat/consumer_avformat.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_avdeinterlace.c, src/modules/avformat/filter_avresample.c, src/modules/avformat/filter_swscale.c, src/modules/avformat/producer_avformat.c, src/modules/avformat/vdpau.c: Rename 'this' in avformat module. 2011-03-01 Till Theato * src/modules/rotoscoping/filter_rotoscoping.c, src/modules/rotoscoping/filter_rotoscoping.yml: rotoscoping: remove parameter precision. Its influence on speed was very minimal while it caused some crashes. Also update YAML filter description. 2011-02-28 Dan Dennedy * src/framework/mlt_consumer.c, src/framework/mlt_deque.c, src/framework/mlt_events.c, src/framework/mlt_factory.c, src/framework/mlt_field.c, src/framework/mlt_filter.c, src/framework/mlt_frame.c, src/framework/mlt_geometry.c, src/framework/mlt_multitrack.c, src/framework/mlt_parser.c, src/framework/mlt_playlist.c, src/framework/mlt_pool.c, src/framework/mlt_producer.c, src/framework/mlt_profile.c, src/framework/mlt_properties.c, src/framework/mlt_property.c, src/framework/mlt_property.h, src/framework/mlt_repository.c, src/framework/mlt_service.c, src/framework/mlt_tokeniser.h, src/framework/mlt_tractor.c, src/framework/mlt_transition.c: Rename this to self in the framework. This makes doxygen output better match the headers, and it improves life within a code-parsing IDE like Qt Creator. 2011-02-27 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: Add support for FFmpeg AVMetadata API. 2011-02-20 Dan Dennedy * src/modules/frei0r/Makefile, src/modules/frei0r/factory.c, src/modules/frei0r/frei0r_helper.c, src/modules/frei0r/not_thread_safe.txt: Mark some frei0r plugins as not thread safe. 2011-02-19 Dan Dennedy * docs/install.txt, docs/mlt-xml.txt, docs/services.txt, setenv: Remove info about mainconcept and bluefish services. * src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/modules/core/producer_consumer.c, src/modules/core/producer_hold.c, src/modules/core/producer_noise.c, src/modules/frei0r/factory.c, src/modules/motion_est/producer_slowmotion.c: Add profile parameter to mlt_producer_new. 2011-02-19 j-b-m * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/qimage_wrapper.cpp: Store exif orientation. Patch attached internally stores the exif orientation so that it can be accessible to the framework and apps using it. Useful it in Kdenlive to correctly rotate images when creating proxy images. 2011-02-13 Dan Dennedy * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/modules/sdl/consumer_sdl_preview.c: Fix deadlocks in sdl_preview with parallel-consumer. 2011-01-27 Till Theato * src/modules/rotoscoping/Makefile, src/modules/rotoscoping/factory.c, src/modules/rotoscoping/filter_rotoscoping.c, src/modules/rotoscoping/filter_rotoscoping.yml: Rotoscoping: Set default mode to alpha and add YAML filter description 2010-11-23 Dan Dennedy * src/modules/frei0r/filter_frei0r.c, src/modules/frei0r/frei0r_helper.c, src/modules/frei0r/frei0r_helper.h, src/modules/frei0r/producer_frei0r.c, src/modules/frei0r/transition_frei0r.c: Reduce service lock contention in frei0r module. 2010-10-04 Dan Dennedy * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_frame.h: Use a single queue for parallel workers. This is a major change from the previous model of moving work items (frames) from one queue to another. This new model improves the behavior of realtime mode and performance overall. In the new model, a single queue is used along with an is_processed flag on the frame. Also, there is an index into the queue (process_head) that indicates from which point should a worker consider fetching the next unprocessed frame. There are situations in realtime mode where the processing of a frame takes longer than the queue (or from head to its fetch index). Over extended periods of this heavy processing, the video frame in the consumer may never be updated (rendered=1)! To remedy this, the consumer detects this and automatically moves the process_head towards the tail, but even this may not be good enough. The only real remedy is to increase buffers and suffer with poor latency. If lower latency is preferred, then it may be better to not use realtime mode and permit audio discontinuity. * src/framework/mlt_deque.c, src/framework/mlt_deque.h: Add mlt_deque_peek() with index. 2010-06-14 Dan Dennedy * src/framework/mlt_consumer.c, src/framework/mlt_frame.c, src/framework/mlt_tractor.c, src/modules/core/filter_imageconvert.c, src/modules/sdl/consumer_sdl.c: Fix image format consistency and conversion. 2010-06-11 Dan Dennedy * src/framework/mlt_consumer.c, src/framework/mlt_tractor.c: Remove the tractor service locking. This completely inhibited parallelism, but removing it also exposes more race conditions that require resolution. 2010-03-04 Dan Dennedy * .../motion_est/filter_autotrack_rectangle.c, src/modules/motion_est/filter_crop_detect.c, src/modules/motion_est/filter_motion_est.c, src/modules/normalize/filter_volume.c, src/modules/oldfilm/filter_dust.c, src/modules/oldfilm/filter_lines.c, src/modules/plus/filter_affine.c, src/modules/plus/transition_affine.c, src/modules/qimage/producer_kdenlivetitle.c, src/modules/qimage/producer_qimage.c, src/modules/sox/filter_sox.c, src/modules/vorbis/producer_vorbis.c: Add service locks for parallelism. * src/modules/avformat/filter_avresample.c, src/modules/avformat/filter_swscale.c, src/modules/avformat/producer_avformat.c, src/modules/core/filter_data_show.c, src/modules/core/filter_luma.c, src/modules/core/filter_watermark.c, src/modules/core/producer_colour.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/core/transition_region.c, src/modules/effectv/filter_burn.c, src/modules/frei0r/filter_frei0r.c, src/modules/frei0r/producer_frei0r.c, src/modules/frei0r/transition_frei0r.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/kdenlive/filter_freeze.c, src/modules/kdenlive/producer_framebuffer.c, src/modules/resample/filter_resample.c: Add service locks for parallelism. RGB filters and transitions from frei0r and burningtv are still not safe enough. * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h: Add parallelism to mlt_consumer. To use set real_time greater than 1 for frame-dropping or less than -1 for no frame-dropping. It works better with a liberal buffer size. You can still set prefill less than buffer size, but it must be at least the same number as real_time, preferably a little higher to help with frame ordering. 2010-02-20 Dan Dennedy * src/framework/mlt_deque.c, src/framework/mlt_deque.h: Add mlt_deque_insert(). 2010-02-16 Dan Dennedy * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h: Qualify queue, mutex, and cond vars with frame_queue_. 2011-01-23 Dan Dennedy * configure, src/framework/mlt_version.h: Move to an interim version number. 2011-01-17 Dan Dennedy * src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_still.c: SDL tweaks for Windows discovered when embedded. * src/framework/Makefile, src/mlt++/Makefile, src/mlt++/config.h: On Windows install .def and version-less DLLs to let apps build against us. * src/framework/mlt_factory.c, src/modules/avformat/configure, src/modules/frei0r/factory.c, src/modules/jackrack/plugin_mgr.c: On Windows locate plugins and data by directory relative to current directory. lib\mlt lib\frei0r-1 lib\ladspa share\mlt share\ffmpeg 2010-12-31 Dan Dennedy * src/modules/xml/consumer_xml.c, src/modules/xml/producer_xml.c: Cleanup libxml changes for MinGW. * src/modules/jackrack/configure, src/modules/jackrack/jack_rack.c: Fix JackRack build on MinGW. * src/modules/qimage/Makefile, src/modules/qimage/configure, src/modules/qimage/producer_qimage.c, src/modules/qimage/qimage_wrapper.cpp, src/modules/qimage/qimage_wrapper.h: Fix qimage build for MinGW. 2010-12-30 Dan Dennedy * src/modules/xml/consumer_xml.c, src/modules/xml/producer_xml.c: Fix libxml2 build on MinGW. * src/modules/gtk2/Makefile, src/modules/gtk2/consumer_gtk2.c, src/modules/gtk2/producer_pixbuf.c: Fix gtk2 build on mingw. 2010-12-15 Dan Dennedy * src/melt/Makefile, src/melt/io.c, src/melt/melt.c, src/modules/sdl/consumer_sdl.c: Fix SDL and keyboard input on Win32. 2010-12-03 Dan Dennedy * configure, src/framework/Makefile, src/melt/Makefile, src/melt/io.c, src/mlt++/Makefile, src/mlt++/MltFactory.cpp, src/mlt++/MltFactory.h, src/mlt++/config.h, src/mlt++/configure, src/modules/avformat/Makefile, src/modules/core/Makefile, src/modules/core/producer_loader.c, src/modules/kino/configure, src/modules/motion_est/Makefile, src/modules/sdl/Makefile, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_audio.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c, src/win32/fnmatch.c, src/win32/fnmatch.h, src/win32/win32.c: Initial port to Windows using MinGW. Much of the credit goes to Michael Zenov. 2011-01-23 Dan Dennedy * Doxyfile, configure, docs/melt.1, src/framework/mlt_version.h: Set version to 0.6.2. 2011-01-16 Till Theato * src/modules/rotoscoping/Makefile, src/modules/rotoscoping/cJSON.c, src/modules/rotoscoping/cJSON.h, src/modules/rotoscoping/filter_rotoscoping.c: Rotoscoping: Add support for simple keyframes - current limits: - number of points has to be equal for all keyframes - points have to be in "correct" order (1. point in 1. kf will be moved to 1. point in 2. kf, ...) - the parameter "polygon" is now formated using json: - no keyframes: polygon="[[x,y], [x,y], ...]" - keyframes: polygon= '{ "framepos1" : [[x,y], [x,y], ...], "framepos2" : [[x,y], [x,y], ...], ...}' 2011-01-15 Till Theato * src/modules/rotoscoping/Makefile, src/modules/rotoscoping/factory.c, src/modules/rotoscoping/filter_rotoscoping.c: Add rotoscoping filter (WIP): It hides everything not in the polygon defined by the vertices given through the "polygon" parameter 2011-01-11 Dan Dennedy * configure, src/mlt++/configure, src/modules/avformat/configure, src/modules/kino/endian_types.h, src/modules/kino/riff.cc, src/modules/qimage/configure, src/modules/sox/configure: Enable build on NetBSD (3090684) * src/modules/kino/Makefile, src/modules/qimage/Makefile: Use CXX rather than CC for linking C++ (3090682) * src/modules/sdl/consumer_sdl_audio.c, src/modules/sdl/consumer_sdl_preview.c: Fix undefined bahavior in SDL module (3066195). The standard says the post-increment can have effect at any point between the previous and the next sequence point (or something similar), so the behavior of "this->refresh_count = this->refresh_count ++" is undefined. Patch by Cristian Morales Vega 2011-01-10 Dan Dennedy * src/modules/plus/interp.h, src/modules/plus/transition_affine.c: Add geometry opacity interpretation to affine. Also, fixes interpolation method selection and removes a redundant bounds test. 2011-01-10 j-b-m * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/producer_qimage.c: Add force_aspect_ratio to image producers. 2011-01-10 Dan Dennedy * configure, src/framework/mlt_version.h: Move to an interim version. 2011-01-01 Dan Dennedy * Doxyfile, configure, docs/melt.1, src/framework/mlt_version.h: set version to 0.6.0 * src/modules/feeds/NTSC/etv.properties, src/modules/feeds/PAL/etv.properties: Make etv data feeds same and scalable between NTSC and PAL. * demo/mlt_attributes, src/modules/feeds/NTSC/data_fx.properties, src/modules/feeds/NTSC/etv.properties: Make feeds consistent between NTSC and PAL. Fix mlt_attributes demo. * demo/README, demo/mlt_slideshow, demo/mlt_slideshow_black: Convert "Scotland" in demos to "photos" * demo/svg.mlt, src/modules/xml/producer_xml.c: Fix parsing mixed XML documents and svg.mlt example. 2010-12-27 Dan Dennedy * src/mlt++/MltProducer.cpp, src/mlt++/MltProducer.h: Revert Producer::set_speed and add Producer::pause. The new Producer::pause contains the wait for consumer-sdl-paused. 2010-12-22 Dan Dennedy * src/framework/mlt_frame.c, src/framework/mlt_frame.h: Add mlt_frame_write_ppm to visualize debugging. 2010-12-19 Dan Dennedy * src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c: Increase the speed of switching between sdl_still and sdl. Based on patch from Jonathan Thomas. It does this by not calling the SDL_InitSubSystem( SDL_INIT_AUDIO ) and SDL_QuitSubSystem( SDL_INIT_AUDIO ) methods every time it switches, but rather when the SDL Preview consumer is started and stopped. 2010-12-16 Dan Dennedy * src/framework/Makefile, src/framework/mlt.h, src/framework/mlt_version.c, src/framework/mlt_version.h, src/swig/mlt.i: Add mlt_version API. Contributed by Jonathan Thomas. 2010-12-15 Dan Dennedy * src/mlt++/MltProducer.cpp, src/modules/sdl/consumer_sdl_preview.c: Synchronize Producer.set_speed(0) with sdl_preview. This also helps prevent deadlock while waiting for consumer-sdl-paused event. Not 100% yet, but 100% requires script (swig) apps to handle the event asynchronously via an event listener, which is not available yet for most - only ruby. Furthermore, they would really like to be able to pass opaque data to the asynchronous handler, which is not yet available in the framework. A good example here is pausing playback prior to seeking to a specific frame. The app should be able to make a consumer-paused event handler to which it can pass the new position, so it can properly seek after the pause has officially occurred. Without the ability to pass opaque data, it must save the new position as an instance variable to use within the handler - once it has support for event listeners that is. 2010-12-09 Dan Dennedy * src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h: Added Mlt::Properties::wait_for(string). * src/framework/mlt_log.c, src/melt/melt.c, src/modules/avformat/consumer_avformat.c: Add consumer-fatal-error event to avformat consumer. This addresses Kdenlive bug 1894. When the avformat consumer has a fatal error, it will fire an event. Melt intercepts the event and exits with failure. 2010-12-08 Dan Dennedy * configure, src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_types.h, src/melt/melt.c, src/mlt++/MltConsumer.cpp, src/mlt++/MltConsumer.h: Add mlt_consumer_position (Mlt::Consumer::position). 2010-11-30 Dan Dennedy * demo/mlt_swf_variables, demo/txtField.swf: Add example of using SWF with variables. 2010-11-07 Dan Dennedy * src/modules/core/loader.dict, src/modules/swfdec/Makefile, src/modules/swfdec/producer_swfdec.c: Add swfdec producer. No audio or variables/parameters yet. 2010-11-06 Dan Dennedy * src/modules/decklink/DeckLinkAPI.h, src/modules/decklink/DeckLinkAPIDispatch.cpp, src/modules/decklink/LinuxCOM.h, src/modules/decklink/Makefile, src/modules/decklink/consumer_decklink.cpp: Add Blackmagic Design DeckLink consumer. 2010-10-20 Dan Dennedy * src/framework/mlt_tokeniser.c, src/modules/frei0r/frei0r_helper.c: Add support for frei0r string parameter. 2010-10-17 j-b-m * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/producer_kdenlivetitle.c: Fix serializing xmldata in kdenlivetitle (kdenlive-1841). Patch below fixes an issue with the kdenlivetitle producer. Basically, the problem was that when loading a kdenlivetitle from a file, all the properties were serialized and passed to the xml consumer. The problem became more obvious with the "embeded" images in titles, which then caused images to be embedded inside the kdenlive project file, causing problems like reported in this issue: http://kdenlive.org/mantis/view.php?id=1841 With the patch, titles loaded from a file will not copy the xmldata. 2010-10-17 Dan Dennedy * src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_audio.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: Fix including SDL headers (3087522). 2010-10-13 Dan Dennedy * src/melt/melt.c, src/modules/avformat/producer_avformat.c: Add colorspace to auto-profile. * src/modules/xml/consumer_xml.c, src/modules/xml/producer_xml.c: (De)serialize colorspace in profile. * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: Fix version support for AVCodec:colorspace. 2010-10-07 Dan Dennedy * src/melt/melt.c, src/modules/core/producer_consumer.c, src/modules/core/producer_loader.c, src/modules/melt/producer_melt.c, src/modules/xml/producer_xml.c: Move logic for when to auto-insert consumer producer. Move it into the loader producer so apps other than melt can use it too. To use it, an app must set the profile to explicit. * src/framework/mlt_profile.c, src/framework/mlt_profile.h: Add mlt_profile_clone(). 2010-08-28 Dan Dennedy * src/melt/melt.c, src/modules/melt/producer_melt.c: Add an automatic profile feature to melt. Here are the main use cases this feature provides: - Given a regular (non-mlt-xml) media file, melt reads the media attributes and generates an equivalent MLT profile. This makes it easier to transcode without changing or specifying resolution, aspect, and framerate. - Given a MLT XML file containing a profile attribute or element, melt loads the specified profile. A composition typically contains profile- without you having to remember. - Given a MLT XML containing a profile but also specifying a -profile option, melt automatically uses the 'consumer' producer with the requested profiles. This is similar to the above case, but when explicitly choosing a profile different than the composition one should use the consumer producer. This just makes melt smarter and more automatic. * src/modules/xml/consumer_xml.c, src/modules/xml/mlt-xml.dtd, src/modules/xml/producer_xml.c: Add (de)serialization of profile to XML. In addition to the 'profile' element, one can also set the 'profile' attribute of the root element to a named profile. 2010-10-04 Dan Dennedy * src/modules/avformat/configure, src/modules/avformat/consumer_avformat.c: Add support for short-hand vpre to avformat consumer. For example, when vcodec=libx264, you can use vpre=medium as shorthand for $prefix/share/ffmpeg/libx264-medium.ffpreset. * src/modules/avformat/audioconvert.h, src/modules/avformat/configure, src/modules/avformat/consumer_avformat.c, src/modules/avformat/factory.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_avdeinterlace.c, src/modules/avformat/filter_avresample.c, src/modules/avformat/filter_swscale.c, src/modules/avformat/producer_avformat.c, src/modules/avformat/vdpau.c: FFmpeg build improvements (3078007). Handle --avformat-svn-version=0.5. Fix building without swscale. Fix compiling new colorspace stuff against FFmpeg <= v0.5. FFmpeg libs are increasing; only support contemporary header layout. 2010-09-28 Dan Dennedy * src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_audio.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: Fix race conditions in SDL (kdenlive-1711). Contributed patch by 'jem' - thanks! 2010-09-26 Dan Dennedy * src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/producer_avformat.c: Set default colorspace (from profile) on frames. Also, allow affirmatively setting luma to _not_ full range (force_full_luma=0). * profiles/atsc_1080i_50, profiles/atsc_1080i_5994, profiles/atsc_1080i_60, profiles/atsc_1080p_2398, profiles/atsc_1080p_24, profiles/atsc_1080p_25, profiles/atsc_1080p_2997, profiles/atsc_1080p_30, profiles/atsc_720p_2398, profiles/atsc_720p_24, profiles/atsc_720p_25, profiles/atsc_720p_2997, profiles/atsc_720p_30, profiles/atsc_720p_50, profiles/atsc_720p_5994, profiles/atsc_720p_60, profiles/cif_15, profiles/cif_ntsc, profiles/cif_pal, profiles/cvd_ntsc, profiles/cvd_pal, profiles/dv_ntsc, profiles/dv_ntsc_wide, profiles/dv_pal, profiles/dv_pal_wide, profiles/hdv_1080_25p, profiles/hdv_1080_30p, profiles/hdv_1080_50i, profiles/hdv_1080_60i, profiles/hdv_720_25p, profiles/hdv_720_30p, profiles/hdv_720_50p, profiles/hdv_720_60p, profiles/qcif_15, profiles/qcif_ntsc, profiles/qcif_pal, profiles/quarter_15, profiles/quarter_ntsc, profiles/quarter_ntsc_wide, profiles/quarter_pal, profiles/quarter_pal_wide, profiles/sdi_486i_5994, profiles/square_ntsc, profiles/square_ntsc_wide, profiles/square_pal, profiles/square_pal_wide, profiles/svcd_ntsc, profiles/svcd_ntsc_wide, profiles/svcd_pal, profiles/svcd_pal_wide, profiles/vcd_ntsc, profiles/vcd_pal: Add colorspace to all profile presets. * src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/producer_avformat.c: Rename variables and properties around luma range for clarity. Frame property "force_full_luma" controls this and can be set via producer property "set.force_full_luma." However, it is not really ready for use until libswscale can respect its full_range parameter in a RGB to YUV conversion. 2010-09-13 Dan Dennedy * src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/producer_avformat.c: Rename yuv_std to colorspace. 2010-08-24 Dan Dennedy * src/framework/mlt_profile.h, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/producer_avformat.c: Add input YUV colorspace (601 vs 709) handling. Still need to work on the output side including normalization and setting the encoder. * src/framework/mlt_frame.c, src/framework/mlt_types.h, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_swscale.c, src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/producer_qimage.c, src/modules/sdl/producer_sdl_image.c: Revert new image types. I think we can just use frame properties. * src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/producer_avformat.c: Get initial skipping of luma scaling to work. When the avformat producer property skip_luma_scale is set to 1, then we do not scale the luma on the first YCbCr to RGB conversion. This is only done once because swscale always downscales luma when converting RGB to YCbCr, and we need to keep the conversions symmetrical to prevent luma contraction (loss of contrast). 2010-08-23 Dan Dennedy * src/framework/mlt_frame.c, src/framework/mlt_profile.h, src/framework/mlt_types.h, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_swscale.c, src/modules/avformat/producer_avformat.c, src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/producer_qimage.c, src/modules/sdl/producer_sdl_image.c: Improve colorspace handling (work in progress) Trying to add support for non-scaling luma between YCbCr and RGB conversions as well as support for ITU Rec. 709 luma conversion for HD formats. 2010-09-13 Dan Dennedy * Doxyfile, configure, docs/melt.1, src/framework/mlt.h: Set version to 0.5.10. 2010-09-12 Dan Dennedy * configure, src/modules/core/producer_loader.c: Enable filter avcolor_space on OS X. It works now! * Doxyfile, NEWS, configure, docs/melt.1, src/framework/mlt.h: Set version to 0.5.8. * src/modules/avformat/filter_avcolour_space.c, src/modules/core/filter_imageconvert.c: Enhance image conversion logging. 2010-09-10 Dan Dennedy * src/modules/core/filter_crop.c, src/modules/core/filter_resize.c: Validate alpha channel size before cropping and padding it. Eventually, I need to add mlt_frame_get_alpha() that returns a size and mlt_frame_set_alpha() encapsulates handling of the alpha channel. 2010-09-07 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_swscale.c, src/modules/avformat/producer_avformat.c: Revert 3a419b4 (Use caching for swscale contexts). This was just making it too unstable (bug 3060324). 2010-09-05 Dan Dennedy * src/modules/avformat/filter_avcolour_space.c, src/modules/core/filter_imageconvert.c: Apply alpha on frame to rgba image (kdenlive-1786). 2010-08-22 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_swscale.c, src/modules/avformat/producer_avformat.c: Use caching for swscale contexts. 2010-08-21 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_swscale.c, src/modules/avformat/producer_avformat.c: Enable swscale CPU flags. For FFmpeg builds that use runtime CPU detection. This should make things faster and it seems to be same quality as C routines. * demo/mlt_slideshow2, src/modules/core/filter_luma.c: Enhance luma filter to work with animated filters. Previously, in a slideshow the luma filter would apply the dissolve or wipe repeatedly over a slide. For example, with a slide duration of 75 frames and a luma period of 25 (expressed as 24), the wipe occurs 3 times. However, since the slides were static, you did not notice it until the transition at the beginning of a new slide - when you do want to see it. However, upon adding an affine filter to animate a smooth pan/zoom, you do notice the extra repetitions - the slides appear to blend with one another when they are not transitioning. This change fixes that with new properties 'cycle' and 'duration'. Cycle is basically a replacement for 'period' that fixes the semantics to properly represent a duration. Where you would previously express, for example, period=24, you now say cycle=25. The 'duration' property prevents the repeating and expresses that the transition should only occur within the first N frames of the cycle. See demo/mlt_slideshow2 for an example of using it in conjunction with the affine filter! 2010-08-20 Dan Dennedy * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/qimage_wrapper.cpp: Fix distorted frame in slideshow transitions. Applies to the .all.ext slideshow approach. May also apply to image sequences with mixed resolutions. 2010-08-19 Dan Dennedy * src/modules/core/Makefile, src/modules/core/factory.c, src/modules/core/filter_audiowave.c: Add audiowave filter. This replaces the video with the audio waveform. Currently, it only works on producers that also provide video. 2010-08-18 Dan Dennedy * src/framework/mlt_frame.c, src/swig/mlt.i, src/swig/python/waveforms.py: Fix waveform generation. It was not obtaining a valid fps. Also, changed rendering to something more expected - negative as negative and channels stacked. Also, add a Python binding to this call to return 8-bit grayscale image as a Python string. Finally, add a Python example. 2010-08-16 Dan Dennedy * src/modules/core/Makefile, src/modules/core/factory.c, src/modules/core/filter_panner.c: Add a panning filter. This does a simple left/right balance when channel=-1 (default). When channel >= 0, you can adjust an individual channel's left/right position. Whereas the simple balance will not cause one channel to appear in another channel, the individual channel does. The start/end properties are floats in the range [-1.0, 1.0]. A start property alone makes it constant over the duration of the filter. There is some handling for more than 2 channels by providing front/rear fade and ganging (balance front and rear together or fade left and right together). 2010-08-15 Dan Dennedy * src/modules/core/factory.c, src/modules/core/filter_channelcopy.c: Add filter channelswap. It is a permutation of channelcopy that can be used from channelcopy as well by setting swap=1. 2010-08-14 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_swscale.c, src/modules/avformat/producer_avformat.c: Improve quality of libswscale conversions and scaling. 2010-08-12 Dan Dennedy * src/framework/mlt_frame.h, src/modules/core/filter_imageconvert.c, src/modules/core/producer_colour.c, src/modules/vmfx/filter_chroma.c, src/modules/vmfx/filter_chroma_hold.c: Cleanup existing native color space conversions. This change clarifies that the existing conversions are according to the ITU 601 standard and scaled to and from full gamut RGB. Also, adjust 2 coefficients according to Charles Poynton's matrices. This does not yet attempt to make any substantial improvements. Finally, it replaces the verbose logic and redundancy in the image conversion routine with a concise function dispatch table. 2010-08-08 Dan Dennedy * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/qimage_wrapper.cpp: Make libexif include compatible with more systems/versions. 2010-08-07 Dan Dennedy * src/modules/core/transition_luma.c, src/modules/frei0r/transition_frei0r.c, src/modules/plus/transition_affine.c: Fix scaling method on B frames of some transitions. 2010-08-04 Dan Dennedy * src/modules/avformat/consumer_avformat.c, src/modules/dv/consumer_libdv.c, src/modules/linsys/consumer_SDIstream.c, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_still.c: Move firing consumer-frame-show to after done with image. 2010-07-29 j-b-m * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/qimage_wrapper.cpp: Cleanup & fix memleak modified: gtk2/producer_pixbuf.c modified: qimage/qimage_wrapper.cpp 2010-07-28 j-b-m * src/modules/gtk2/Makefile, src/modules/gtk2/configure, src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/Makefile, src/modules/qimage/configure, src/modules/qimage/qimage_wrapper.cpp, src/modules/qimage/readexif.h: Use libexif to read exif orientation in images modified: src/modules/gtk2/Makefile modified: src/modules/gtk2/configure modified: src/modules/gtk2/producer_pixbuf.c modified: src/modules/qimage/Makefile modified: src/modules/qimage/configure modified: src/modules/qimage/qimage_wrapper.cpp deleted: src/modules/qimage/readexif.h 2010-07-27 j-b-m * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/qimage_wrapper.cpp, src/modules/qimage/readexif.h: Read EXIF info inside MLT, based on jpegexiforient modified: src/modules/gtk2/producer_pixbuf.c modified: src/modules/qimage/qimage_wrapper.cpp new file: src/modules/qimage/readexif.h 2010-07-20 j-b-m * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/qimage_wrapper.cpp: Fix exif rotation angle modified: src/modules/gtk2/producer_pixbuf.c modified: src/modules/qimage/qimage_wrapper.cpp 2010-07-14 Dan Dennedy * configure, src/modules/avformat/producer_avformat.c: Fix crash when repeating frames after failure to decode video. 2010-06-20 Dan Dennedy * Doxyfile, configure, docs/melt.1, src/framework/mlt.h: Set version to 0.5.6. * src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/avformat/factory.c: Fixup local ffmpeg build. Set PIC compiler flag, make libavdevice optional, and set recommended version to 0.6 branch. 2010-06-15 Dan Dennedy * src/modules/jackrack/filter_jackrack.c, src/modules/jackrack/plugin_desc.h: Fix a few compiler warnings in jackrack. 2010-06-02 Dan Dennedy * src/modules/plus/filter_affine.c, src/modules/plus/interp.h, src/modules/plus/transition_affine.c: Revise affine to use interpolation and sub-pixel positioning. 2010-05-18 Dan Dennedy * src/modules/sdl/consumer_sdl_osx.h, src/modules/sdl/consumer_sdl_osx.m: Fix leaking OS X Cocoa objects in SDL consumers. * src/modules/sdl/Makefile, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_still.c: Fix leaking OS X Cocoa objects in SDL consumers. 2010-05-07 Marco Gittler * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/producer_kdenlivetitle.c: interlaced titles 2010-05-02 Dan Dennedy * src/swig/csharp/build, src/swig/java/build, src/swig/lua/build, src/swig/perl/Makefile.PL, src/swig/perl/build, src/swig/php/build, src/swig/python/build, src/swig/ruby/build, src/swig/tcl/build: Fix missing PIC flags for bindings (2931009) Also, use g++ for linking bindings because some systems (OS X) do not otherwise know to link with libstdc++. 2010-04-25 Dan Dennedy * configure, src/modules/core/filter_resize.c: Fix bad stride in yuv422 due to non-even width requests. 2010-04-19 Dan Dennedy * Doxyfile, configure, docs/melt.1, src/framework/mlt.h: Set version to 0.5.4. * src/framework/mlt_frame.c, src/modules/avformat/producer_avformat.c: Improve error handling on video decode failure (kdenlive-1553). 2010-04-18 Dan Dennedy * configure, src/modules/avformat/filter_avcolour_space.c: Only use newish version of libswcale. Some early revisions of 0.7.1 would cause garbage on last column of image with non-even width. 2010-04-08 Dan Dennedy * src/swig/configure, src/swig/csharp/build, src/swig/csharp/play.cs, src/swig/csharp/play.sh: Add C# bindings. Thank you to Steeve Descarpentries for the initial contribution. 2010-04-07 Dan Dennedy * src/modules/linsys/consumer_SDIstream.c, src/modules/linsys/sdi_generator.c, src/modules/linsys/sdi_generator.h: Add automatic driver configuration to sdi consumer. This uses the MLT profile to determine the configuration values: video buffer size, audio buffer size, video frame mode (resolution, frame rate), video data mode (8 bit or v210), number of audio channels, audio sampling rate, audio sample size. It does _not_ set the clock source or the number of buffers for audio and video. 2010-03-10 Dan Dennedy * Doxyfile, configure, docs/melt.1, src/framework/mlt.h: Set version to 0.5.2. * src/modules/linsys/consumer_SDIstream.c, src/modules/linsys/sdi_generator.c, src/modules/linsys/sdi_generator.h: Improve performance of sdi consumer (patch from BCE). consumer_SDIstream.c - convertYCBCRtoRGB: different calculation sdi_generator.h - SDIAUDIO transmitter event definitions sdi_generator.c - pack changed to pack8 instead of packv210 - Transmitter events are checked only once a frame - create_HD_SDI_Line and create_SD_SDI_Line do not calculate the current position in the video_buffer for each sample. Now it is done once a line. * src/mlt++/Makefile, src/mlt++/MltFilteredProducer.cpp, src/mlt++/MltFilteredProducer.h: Fix MltFilteredProducer not building. 2010-02-28 Dan Dennedy * src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_swscale.c, src/modules/core/producer_loader.c: Add resolution as init arg to libswscale filters. * src/framework/mlt_frame.c, src/modules/effectv/filter_burn.c: Fix a couple of compile warnings. 2010-02-25 Dan Dennedy * src/modules/avformat/filter_avcolour_space.c, src/modules/core/producer_loader.c: Make FFmpeg the primary image converter if available. Except on OS X. 2010-02-24 Dan Dennedy * src/modules/xine/Makefile, src/modules/xine/yadif.c: Fix build on --disable-sse(2) or non-sse(2) architectures. 2010-02-22 Dan Dennedy * configure, src/modules/sdl/consumer_sdl_preview.c: Fix video glitches when switching still and normal sdl consumers. 2010-02-15 Dan Dennedy * Doxyfile, configure, docs/melt.1, src/framework/mlt.h: Set version to 0.5.0. * NEWS, src/modules/avformat/configure: Add v0.5.0 release notes. 2010-02-11 Dan Dennedy * src/modules/linsys/consumer_SDIstream.c, src/modules/linsys/sdi_generator.c, src/modules/linsys/sdi_generator.h: Add HD-SDI support to Linsys SDI module. This has only been tested with the VidPort. At this time, you must run the linsys sdiaudiocfg and sdivideocfg utilities to configure your card. In time, we hope to remove this step. * src/modules/linsys/Makefile, src/modules/linsys/configure: Add --linsys-with-jpeg configure option. 2010-02-10 Dan Dennedy * profiles/atsc_1080i_50, profiles/atsc_1080i_5994, profiles/atsc_1080i_60, profiles/atsc_1080p_2398, profiles/atsc_1080p_24, profiles/atsc_1080p_25, profiles/atsc_1080p_2997, profiles/atsc_1080p_30, profiles/atsc_720p_2398, profiles/atsc_720p_24, profiles/atsc_720p_25, profiles/atsc_720p_2997, profiles/atsc_720p_30, profiles/atsc_720p_50, profiles/atsc_720p_5994, profiles/atsc_720p_60, profiles/hdv_1080_25p, profiles/hdv_1080_30p, profiles/hdv_1080_50i, profiles/hdv_1080_60i, profiles/hdv_720_25p, profiles/hdv_720_30p, profiles/hdv_720_50p, profiles/hdv_720_60p, profiles/qcif_15, profiles/quarter_15, profiles/quarter_ntsc, profiles/sdi_486i_5994, src/framework/mlt_profile.c: Revise Hz->fps in profiles and add more ATSC profiles. 2010-02-04 Dan Dennedy * src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_audio.c, src/modules/sdl/consumer_sdl_preview.c: Default SDL to use the onefield deinterlace filter. The previous default in the deinterlace filter was linearblend. The new default is yadif. However, onefield is faster is gives cleaner results than linearblend where preserving most resolution is not a factor. Since most usess of SDL are applications with preview windows smaller than actual resolution, it makes sense to use onefield by default in the SDL consumers. * src/modules/xine/Makefile, src/modules/xine/deinterlace.h, src/modules/xine/filter_deinterlace.c, src/modules/xine/vf_yadif_template.h, src/modules/xine/yadif.c, src/modules/xine/yadif.h: Add YADIF methods in deinterlace filter. 2010-02-03 Dan Dennedy * src/framework/mlt_frame.h, src/framework/mlt_service.c, src/framework/mlt_service.h: Hide need_previous_next property from serialization. 2010-02-02 Dan Dennedy * src/framework/mlt_filter.h, src/framework/mlt_frame.h, src/framework/mlt_service.c, src/framework/mlt_service.h: Add fetching previous and next frames in producers. This is only enabled when the property need-previous-next is set true on the producer. This also adds firing a service-changed event on the filter when it gets attached so the filter can set this property on the producer to which it is attached. These frame references are set as "previous frame" and "next frame" properties on the current frame. It is also important to note that these frames do not have ANY filters applied to them, which is important for YADIF and telecide filters, which process before all other filters. 2010-01-21 Dan Dennedy * src/modules/avformat/producer_avformat.c, src/modules/avformat/vdpau.c: Let environment variable MLT_NO_VDPAU=1 disable VDPAU. 2010-01-19 Dan Dennedy * src/modules/avformat/configure, src/modules/avformat/factory.c, src/modules/avformat/producer_avformat.c: Add support for libavdevice (v4l/v4l2). Thanks to hints from Volodymyr M. Lisivka. LD_PRELOAD=/usr/lib/libv4l/v4l2convert.so is required to get some formats to work. * src/framework/mlt_frame.c, src/modules/core/filter_rescale.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/producer_qimage.c: Return and handle errors on failure to produce image (kdenlive-1312). 2010-01-16 Dan Dennedy * Doxyfile, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/framework/mlt_service.h: Add mlt_frame doxygen docs. 2010-01-10 Dan Dennedy * src/modules/avformat/producer_avformat.c, src/modules/xine/filter_deinterlace.c: Fix setting progressive property on repeated frames (kdenlive-1335). 2010-01-06 Marco Gittler * src/modules/oldfilm/filter_oldfilm.c, src/modules/oldfilm/filter_oldfilm.yml: user array with 100 values yml file updated 2009-12-16 Dan Dennedy * src/framework/mlt_service.c, src/framework/mlt_service.h, src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/producer_qimage.c: Add mlt_service_cache_purge and remove purge in mlt_service_close. The avformat producer holds references to cache items within frame objects. This means mlt_service_close can not purge the cache because frames may be closed after the producer. 2009-12-14 Dan Dennedy * configure, src/framework/mlt.h: Bump to unreleased version. * src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: Revert a bunch of changes made to SDL for VDPAU. This set of changes conflicted with Kdenlive, which requires two consumers that need to release SDL on stop. Now, VDPAU support does not need SDL as it gets its own X11 Display pointer. * src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/avformat/vdpau.c: Make VDPAU independent of SDL X11 Display. This prevents VDPAU from crashing on calls to SDL_Quit() and allows it to be used with non-SDL consumers! (Still requires an X11 session.) 2009-12-13 Dan Dennedy * src/modules/avformat/factory.c, src/modules/avformat/producer_avformat.c: Add producer variant avformat-novalidate. The purpose of this is to increase the speed of loading playlists with known good files. Use with care. This assumes a few properties have been set, in particular "length." This was only tested thus far by modifying the output of consumer xml to change mlt_service from "avformat" to "avformat-novalidate". 2009-12-12 Dan Dennedy * src/modules/avformat/producer_avformat.c, src/modules/avformat/vdpau.c: Add cache support to avformat producer. This also includes a change to make VDPAU work on some versions of FFmpeg beyond Sept 15, 2009 (do not know exactly when). * src/framework/mlt_service.c, src/framework/mlt_service.h: Add mlt_service_cache_set_size() to limit the cache size. * src/framework/mlt_cache.c, src/framework/mlt_cache.h: Add mlt_cache_set_size() to limit the amount of caching. 2009-11-28 Dan Dennedy * src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/avformat/producer_avformat.c, src/modules/avformat/vdpau.c: Add support for decoding H.264 with VDPAU. This applies to all H.264 at the moment unless novdpau=1 is set on the producer. Also, this can only handle up to about 10 - 15 clips using VDPAU in the project at the moment until the avformat producer is changed to use mlt_cache. * src/framework/mlt_consumer.c, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: Make the SDL consumer cooperate with VDPAU. This moves the SDL_Quit calls from the consumer_stop to the consumer_close functions. Also, it exports the X11 Display pointer to the mlt_environment and the global SDL mutex to the consumer class. 2009-12-08 Dan Dennedy * Doxyfile, NEWS, configure, docs/melt.1, src/framework/mlt.h: Set version to 0.4.10 and update release notes. * configure, src/framework/mlt.h, src/modules/avformat/producer_avformat.c: Fix underlinking libm by removing math function. 2009-12-07 Dan Dennedy * Doxyfile, configure, docs/melt.1, src/framework/mlt.h: Set version to 0.4.8. * src/modules/core/loader.ini, src/modules/core/producer_loader.c: Fix some cases image and audio formats not converting (kdenlive-1259). 2009-11-29 Marco Gittler * src/modules/oldfilm/filter_vignette.c, src/modules/oldfilm/filter_vignette.yml: use float for vignette effect fixed also bug in wrong y center * src/modules/oldfilm/filter_vignette.c, src/modules/oldfilm/filter_vignette.yml: use extra paramters for vignette settings 2009-10-10 Dan Dennedy * configure, src/framework/mlt.h: Bump the version to 0.4.7. * src/modules/linsys/consumer_SDIstream.c, src/modules/linsys/sdi_generator.c: Convert some printfs to mlt_log. * src/modules/linsys/consumer_SDIstream.c, src/modules/linsys/sdi_generator.c: Cleanup unused parameters. * src/modules/linsys/consumer_SDIstream.c, src/modules/linsys/sdi_generator.c: Add support for >2 audio channels to Linsys SDI consumer. This does not yet have any remapping support. 2009-10-07 Dan Dennedy * AUTHORS, Doxyfile, NEWS, configure, docs/melt.1, src/framework/mlt.h: Set version to 0.4.6 and update release notes. * src/modules/avformat/Makefile, src/modules/avformat/configure: Add configure option --avformat-svn-version. Also update recommended version to Sept 15, 2009 and other cleanup. 2009-10-04 j-b-m * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/producer_kdenlivetitle.c: Fix behaviour of title clips when in and out points are given modified: src/modules/qimage/kdenlivetitle_wrapper.cpp modified: src/modules/qimage/producer_kdenlivetitle.c 2009-09-20 Dan Dennedy * src/mlt++/MltField.cpp, src/mlt++/MltField.h, src/mlt++/MltProducer.cpp, src/mlt++/MltProducer.h, src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h, src/mlt++/MltRepository.cpp, src/mlt++/MltRepository.h, src/mlt++/MltTractor.cpp, src/mlt++/MltTractor.h, src/mlt++/MltTransition.cpp, src/mlt++/MltTransition.h, src/swig/mlt.i: Update bindings. 2009-09-19 Dan Dennedy * src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h: Add Properties constructor from opaque pointer. 2009-09-15 Dan Dennedy * src/swig/Makefile, src/swig/java/build, src/swig/lua/build, src/swig/perl/build, src/swig/php/build, src/swig/python/build, src/swig/ruby/build, src/swig/tcl/build: Fix distclean make target under swig and cleanup object files. 2009-09-13 Dan Dennedy * src/modules/core/factory.c, src/modules/core/producer_loader.c, src/modules/kdenlive/producer_framebuffer.c: Invert position of normalization filters with framebuffer producer. Previously, the framebuffer producer loaded a normalized producer, which can give undesired results with things like crop and really any time you want to filter the unpadded images of the speed-altered video. Now, the framebuffer uses the new "abnormal" producer to load the clip without normalization filters and sets appropriate frame properties to allow the normalizing filters attached to the framebuffer to act appropriately. This new abnormal filter is simply an alias to the existing loader filter, which uses the name by which it is invoked to toggle the behaviour of whether to attach normalizing filters. 2009-09-10 Dan Dennedy * Makefile, src/swig/Makefile, src/swig/configure: Improve swig build with help from Michael Forney. 2009-08-26 Dan Dennedy * src/modules/sdl/Makefile, src/modules/sdl/consumer_sdl_audio.c, src/modules/sdl/factory.c: Add audio-only SDL consumer (for Kdenlive on OS X). * src/modules/sdl/Makefile, src/modules/sdl/consumer_sdl_audio.c, src/modules/sdl/factory.c: Add audio-only SDL consumer (for Kdenlive on OS X). 2009-08-19 Dan Dennedy * src/modules/linsys/Makefile, src/modules/linsys/configure, src/modules/linsys/consumer_SDIstream.c, src/modules/linsys/factory.c, src/modules/linsys/sdi_generator.c: Add Linsys SDI consumer from B.C.E. 2009-08-03 Dan Dennedy * src/framework/Makefile, src/framework/mlt_consumer.c, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/framework/mlt_tractor.c, src/framework/mlt_types.h, src/mlt++/MltFrame.cpp, src/mlt++/MltFrame.h, src/mlt++/configure, src/modules/avformat/consumer_avformat.c, src/modules/avformat/filter_avresample.c, src/modules/avformat/producer_avformat.c, src/modules/core/Makefile, src/modules/core/factory.c, src/modules/core/filter_audioconvert.c, src/modules/core/filter_channelcopy.c, src/modules/core/filter_mono.c, src/modules/core/filter_transition.c, src/modules/core/loader.ini, src/modules/core/producer_consumer.c, src/modules/core/transition_mix.c, src/modules/dv/consumer_libdv.c, src/modules/dv/producer_libdv.c, src/modules/jackrack/filter_jackrack.c, src/modules/jackrack/filter_ladspa.c, src/modules/normalize/filter_volume.c, src/modules/resample/filter_resample.c, src/modules/sdl/consumer_sdl.c, src/modules/sox/filter_sox.c, src/modules/vorbis/producer_vorbis.c: Refactor audio conversion and mixing. * src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: Fix some SDL concurrency issues I am seeing in Kdenlive on my quad core. 2009-08-02 j-b-m * src/modules/qimage/configure, src/modules/qimage/kdenlivetitle_wrapper.cpp: Add support for svg items in titles modified: configure modified: kdenlivetitle_wrapper.cpp * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: Fix errors in caching + mem leaks, fix resize issue modified: kdenlivetitle_wrapper.cpp modified: kdenlivetitle_wrapper.h modified: producer_kdenlivetitle.c 2009-08-01 j-b-m * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: Rewrote caching, similar to qimage producer modified: kdenlivetitle_wrapper.cpp modified: kdenlivetitle_wrapper.h modified: producer_kdenlivetitle.c 2009-07-31 j-b-m * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: Use QImage instead of QPixmap, add myself in copyright modified: kdenlivetitle_wrapper.cpp modified: kdenlivetitle_wrapper.h modified: producer_kdenlivetitle.c * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h: don't use cache, just normal properties to store scene modified: kdenlivetitle_wrapper.cpp modified: kdenlivetitle_wrapper.h * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: Rescale title when they are played with a different profile modified: kdenlivetitle_wrapper.cpp modified: kdenlivetitle_wrapper.h modified: producer_kdenlivetitle.c 2009-07-30 j-b-m * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/producer_kdenlivetitle.c: Fix image size, fix utf-8 characters in titles modified: kdenlivetitle_wrapper.cpp modified: producer_kdenlivetitle.c 2009-07-29 j-b-m * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: Fix use of several title producers in one instance of Kdenlive modified: kdenlivetitle_wrapper.cpp modified: kdenlivetitle_wrapper.h modified: producer_kdenlivetitle.c 2009-07-27 j-b-m * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: Cleanup + fix crashes when used in Kdenlive modified: kdenlivetitle_wrapper.cpp modified: kdenlivetitle_wrapper.h modified: producer_kdenlivetitle.c 2009-07-24 j-b-m * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/producer_kdenlivetitle.c: Fix mem leak modified: src/modules/qimage/kdenlivetitle_wrapper.cpp modified: src/modules/qimage/producer_kdenlivetitle.c 2009-07-26 j-b-m * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h: Cleanup & fix crash modified: kdenlivetitle_wrapper.cpp modified: kdenlivetitle_wrapper.h * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h: Cleanup & fix crash modified: kdenlivetitle_wrapper.cpp modified: kdenlivetitle_wrapper.h 2009-07-24 j-b-m * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/producer_kdenlivetitle.c: Fix mem leak modified: src/modules/qimage/kdenlivetitle_wrapper.cpp modified: src/modules/qimage/producer_kdenlivetitle.c * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: Fix crash + position in time modified: src/modules/qimage/kdenlivetitle_wrapper.cpp modified: src/modules/qimage/kdenlivetitle_wrapper.h modified: src/modules/qimage/producer_kdenlivetitle.c * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: * Fix memleaks * Cleanup * Reload xml when setting "reload_xml" property modified: src/modules/qimage/kdenlivetitle_wrapper.cpp modified: src/modules/qimage/kdenlivetitle_wrapper.h modified: src/modules/qimage/producer_kdenlivetitle.c * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: Add feature to dynamically replace text in a block modified: kdenlivetitle_wrapper.cpp modified: kdenlivetitle_wrapper.h modified: producer_kdenlivetitle.c 2009-07-24 Marco Gittler * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: kdenlivetitle: reindent code / readded qimage_producer * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h: reindent c++ * src/modules/qimage/factory.c, src/modules/qimage/qimage_wrapper.cpp: readded deleted qimage producer in factory 2009-07-19 Marco Gittler * src/modules/qimage/configure, src/modules/qimage/producer_kdenlivetitle.c: kdenlivetitle: added QtXml during configure, add rescource to producer 2009-07-18 Marco Gittler * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: working color conversion 2009-07-15 Marco Gittler * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: memcpy works now * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: memhandling changed 2009-07-14 Dan Dennedy * src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/core/Makefile, src/modules/dgraft/Makefile, src/modules/dv/Makefile, src/modules/effectv/Makefile, src/modules/frei0r/Makefile, src/modules/gtk2/Makefile, src/modules/jackrack/Makefile, src/modules/kdenlive/Makefile, src/modules/kino/Makefile, src/modules/melt/Makefile, src/modules/motion_est/Makefile, src/modules/normalize/Makefile, src/modules/oldfilm/Makefile, src/modules/plus/Makefile, src/modules/qimage/Makefile, src/modules/resample/Makefile, src/modules/sdl/Makefile, src/modules/sox/Makefile, src/modules/vmfx/Makefile, src/modules/vorbis/Makefile, src/modules/xine/Makefile, src/modules/xml/Makefile: Fix build on OS X and possibly others. Gives higher priority to local lib and include dirs than system or SDL-based lib and include dirs. Also, moves previous -lm fix to from general build to --avformat-svn and --avformat-static builds. 2009-07-14 Marco Gittler * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/producer_kdenlivetitle.c: cleanup * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: test alpha channel 2009-07-11 Marco Gittler * src/modules/core/loader.dict, src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h: kdenlivetitle_wrapper: interpolate from start-> end, added title to dict 2009-07-10 Marco Gittler * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: kdenlivetitle_wrapper: load kdenlive titles * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h: kdenlivetitle_wrapper: use QApplication, else QGrahicsScene ist not working * src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: kdenlivetitle_wrapper.{cpp,h}, producer_kdenlivetitle.c: LGPL header and byte move for right RGBA values * src/modules/qimage/Makefile, src/modules/qimage/factory.c, src/modules/qimage/kdenlivetitle_wrapper.cpp, src/modules/qimage/kdenlivetitle_wrapper.h, src/modules/qimage/producer_kdenlivetitle.c: first work on kdenlive title producer should later read the xml-file from kdenlive and let the title have scroll and zoom 2009-07-03 Dan Dennedy * configure, docs/policies.txt, src/framework/mlt.h, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/framework/mlt_log.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_avdeinterlace.c, src/modules/avformat/filter_swscale.c, src/modules/avformat/producer_avformat.c, src/modules/core/Makefile, src/modules/core/factory.c, src/modules/core/filter_brightness.c, src/modules/core/filter_crop.c, src/modules/core/filter_gamma.c, src/modules/core/filter_greyscale.c, src/modules/core/filter_imageconvert.c, src/modules/core/filter_luma.c, src/modules/core/filter_mirror.c, src/modules/core/filter_obscure.c, src/modules/core/filter_rescale.c, src/modules/core/filter_resize.c, src/modules/core/filter_watermark.c, src/modules/core/loader.ini, src/modules/core/producer_colour.c, src/modules/core/producer_consumer.c, src/modules/core/producer_ppm.c, src/modules/core/transition_luma.c, src/modules/effectv/filter_burn.c, src/modules/frei0r/filter_frei0r.c, src/modules/frei0r/frei0r_helper.c, src/modules/frei0r/frei0r_helper.h, src/modules/frei0r/producer_frei0r.c, src/modules/frei0r/transition_frei0r.c, src/modules/gtk2/filter_rescale.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/kdenlive/filter_boxblur.c, src/modules/kdenlive/filter_wave.c, src/modules/kdenlive/producer_framebuffer.c, src/modules/motion_est/filter_crop_detect.c, src/modules/motion_est/filter_motion_est.c, src/modules/motion_est/filter_vismv.c, src/modules/motion_est/producer_slowmotion.c, src/modules/oldfilm/filter_dust.c, src/modules/oldfilm/filter_grain.c, src/modules/oldfilm/filter_lines.c, src/modules/oldfilm/filter_oldfilm.c, src/modules/oldfilm/filter_tcolor.c, src/modules/oldfilm/filter_vignette.c, src/modules/plus/filter_affine.c, src/modules/plus/filter_charcoal.c, src/modules/plus/filter_invert.c, src/modules/plus/filter_sepia.c, src/modules/plus/transition_affine.c, src/modules/qimage/producer_qimage.c, src/modules/qimage/qimage_wrapper.cpp, src/modules/qimage/qimage_wrapper.h, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_still.c, src/modules/sdl/producer_sdl_image.c, src/modules/vmfx/filter_chroma.c, src/modules/vmfx/filter_chroma_hold.c, src/modules/vmfx/filter_mono.c, src/modules/vmfx/filter_shape.c, src/modules/xine/filter_deinterlace.c: Massive refactoring of image conversion. This drops all image color space and pixel format conversions from the mlt_frame class. Instead, it adds a convert_image virtual function to the mlt_frame class that is called within mlt_frame_get_image(). The newly added imageconvert filter sets that virtual function and contains the various conversion routines. The loader producer automatically attaches this filter to the producer it creates. 2009-06-30 Dan Dennedy * Doxyfile, NEWS, configure, docs/melt.1, src/framework/mlt.h: Set to v0.4.4 and update release notes. 2009-06-23 Dan Dennedy * src/swig/configure, src/swig/lua/build, src/swig/lua/play.lua: Add SWIG Lua bindings. 2009-06-22 Dan Dennedy * configure, src/framework/Makefile, src/melt/configure, src/swig/Makefile, src/swig/configure, src/swig/java/build, src/swig/perl/build, src/swig/php/build, src/swig/python/build, src/swig/ruby/build, src/swig/tcl/build: Further integrate swig into build system. This is not enabled by default. It adds configure options --enable-swig and --swig-languages. * src/melt/Makefile, src/melt/configure, src/melt/melt.c: Add configure option --rename-melt. * src/modules/frei0r/Makefile, src/modules/frei0r/blacklist.txt, src/modules/frei0r/factory.c: Add blacklist to frei0r module. This is for Kdenlive bugs 913 and 917. It is populated with only facedetect for now. 2009-06-21 Dan Dennedy * src/modules/avformat/Makefile.orig, src/modules/avformat/Makefile.rej: Remove these bogus make files in avformat. * src/modules/avformat/Makefile.orig, src/modules/avformat/Makefile.rej, src/modules/avformat/consumer_avformat.c: Fix avformat consumer crashing on pcm_s16le. 2009-06-16 Dan Dennedy * src/modules/avformat/filter_avresample.c, src/modules/avformat/producer_avformat.c: Migrate to FFmpeg av_audio_resample_init. * src/melt/Makefile, src/melt/melt.c, src/modules/avformat/producer_avformat.c: Fix (kdenlive-824) >2 channels not downmixed. 2009-06-15 Dan Dennedy * configure, profiles/Makefile, src/framework/Makefile, src/melt/Makefile, src/modules/avformat/Makefile, src/modules/core/Makefile, src/modules/feeds/Makefile, src/modules/lumas/Makefile, src/modules/oldfilm/Makefile, src/modules/xml/Makefile: Add datadir and mandir options to configure. * src/modules/kino/avi.cc, src/modules/kino/filehandler.cc, src/modules/kino/kino_wrapper.cc: Apply patch from Debian to fix compilation of kino module. 2009-06-10 Dan Dennedy * docs/melt.1, docs/policies.txt, src/melt/melt.c: Add man page for melt. Not yet installed. 2009-06-03 Dan Dennedy * configure, src/framework/mlt.h: Set to interim version 0.4.3 2009-05-30 Dan Dennedy * Doxyfile, NEWS, configure, src/framework/mlt.h: Bump versions and update release notes. 2009-05-29 Dan Dennedy * src/modules/oldfilm/filter_tcolor.yml, src/modules/oldfilm/filter_vignette.yml: Fix YAML validation errors and spelling of Vignette. 2009-05-26 Dan Dennedy * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/qimage_wrapper.cpp, src/modules/qimage/qimage_wrapper.h: Fix image sequences sometimes not advancing. * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/producer_qimage.c: Change the ttl default value for image sequences. When using printf-style image sequences only, the default ttl is now 1. 2009-05-20 Dan Dennedy * configure, src/framework/mlt.h: Bump to an interim version. 2009-05-17 Dan Dennedy * Makefile, NEWS: Add v0.4.0 release notes. * Doxyfile, configure, src/framework/mlt.h: Bump version to 0.4.0 2009-05-13 Dan Dennedy * profiles/atsc_1080i_50, profiles/atsc_1080i_60, profiles/atsc_1080p_2398, profiles/atsc_1080p_24, profiles/atsc_1080p_25, profiles/atsc_1080p_2997, profiles/atsc_1080p_30, profiles/atsc_720p_30, profiles/dv_ntsc, profiles/dv_ntsc_wide, profiles/dv_pal, profiles/dv_pal_wide, profiles/hdv_1080_25p, profiles/hdv_1080_30p, profiles/hdv_1080_50i, profiles/hdv_1080_60i, profiles/hdv_720_25p, profiles/hdv_720_30p, profiles/hdv_720_50p, profiles/hdv_720_60p, profiles/quarter_ntsc, profiles/quarter_ntsc_wide, profiles/quarter_pal, profiles/quarter_pal_wide, profiles/square_ntsc, profiles/square_ntsc_wide, profiles/square_pal, profiles/square_pal_wide, profiles/svcd_ntsc_wide, profiles/svcd_pal_wide: Make profile descriptions more user friendly. 2009-05-11 Dan Dennedy * src/modules/gtk2/have_mmx.S, src/modules/gtk2/scale_line_22_yuv_mmx.S: Apply patch from Orcan Ogetbil that adds .note.GNU-stack section. 2009-05-09 Dan Dennedy * ChangeLog, Makefile: Change dist make target to use git-archive. * src/swig/configure, src/swig/java/Play.java, src/swig/java/build, src/swig/mlt.i, src/swig/mltpp.i, src/swig/perl/Makefile.PL, src/swig/php/build, src/swig/python/build, src/swig/ruby/build, src/swig/ruby/play.rb, src/swig/ruby/thumbs.rb, src/swig/tcl/build, src/swig/tcl/play.tcl: Fixup the swig bindings. * configure, src/examples/Makefile, src/framework/Makefile, src/framework/mlt_geometry.c, src/framework/mlt_producer.c, src/mlt++/Makefile, src/mlt++/configure, src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c, src/modules/core/Makefile, src/modules/dgraft/filter_telecide.c, src/modules/dv/Makefile, src/modules/effectv/Makefile, src/modules/frei0r/Makefile, src/modules/gtk2/Makefile, src/modules/jackrack/Makefile, src/modules/jackrack/configure, src/modules/kino/Makefile, src/modules/normalize/Makefile, src/modules/plus/Makefile, src/modules/qimage/Makefile, src/modules/resample/filter_resample.c, src/modules/sdl/Makefile, src/modules/vmfx/filter_chroma.c, src/modules/xml/consumer_xml.c: Fix over- and under-linking. * src/mlt++/Mlt.h, src/mlt++/MltConsumer.cpp, src/mlt++/MltConsumer.h, src/mlt++/MltDeque.cpp, src/mlt++/MltDeque.h, src/mlt++/MltEvent.cpp, src/mlt++/MltEvent.h, src/mlt++/MltFactory.cpp, src/mlt++/MltFactory.h, src/mlt++/MltField.cpp, src/mlt++/MltField.h, src/mlt++/MltFilter.cpp, src/mlt++/MltFilter.h, src/mlt++/MltFilteredConsumer.cpp, src/mlt++/MltFilteredConsumer.h, src/mlt++/MltFilteredProducer.cpp, src/mlt++/MltFilteredProducer.h, src/mlt++/MltFrame.cpp, src/mlt++/MltFrame.h, src/mlt++/MltGeometry.cpp, src/mlt++/MltGeometry.h, src/mlt++/MltMultitrack.cpp, src/mlt++/MltMultitrack.h, src/mlt++/MltParser.cpp, src/mlt++/MltParser.h, src/mlt++/MltPlaylist.cpp, src/mlt++/MltPlaylist.h, src/mlt++/MltProducer.cpp, src/mlt++/MltProducer.h, src/mlt++/MltProfile.cpp, src/mlt++/MltProfile.h, src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h, src/mlt++/MltPushConsumer.cpp, src/mlt++/MltPushConsumer.h, src/mlt++/MltRepository.cpp, src/mlt++/MltRepository.h, src/mlt++/MltService.cpp, src/mlt++/MltService.h, src/mlt++/MltTokeniser.cpp, src/mlt++/MltTokeniser.h, src/mlt++/MltTractor.cpp, src/mlt++/MltTractor.h, src/mlt++/MltTransition.cpp, src/mlt++/MltTransition.h: Fix LGPL information in comment headers of mlt++. * Makefile, README, demo/README, demo/consumers.ini, demo/demo, demo/demo.ini, demo/entity.mlt, demo/entity.westley, demo/mlt_all, demo/mlt_attributes, demo/mlt_audio_stuff, demo/mlt_avantika_title, demo/mlt_bouncy, demo/mlt_bouncy_ball, demo/mlt_clock_in_and_out, demo/mlt_composite_transition, demo/mlt_effect_in_middle, demo/mlt_fade_black, demo/mlt_fade_in_and_out, demo/mlt_intro, demo/mlt_jcut, demo/mlt_lcut, demo/mlt_levels, demo/mlt_my_name_is, demo/mlt_news, demo/mlt_obscure, demo/mlt_push, demo/mlt_slideshow, demo/mlt_slideshow_black, demo/mlt_squeeze, demo/mlt_squeeze_box, demo/mlt_ticker, demo/mlt_title_over_gfx, demo/mlt_titleshadow_watermark, demo/mlt_voiceover, demo/mlt_watermark, demo/new.mlt, demo/new.westley, demo/pango.mlt, demo/pango.westley, demo/svg.mlt, demo/svg.westley, docs/framework.txt, docs/install.txt, docs/melt.txt, docs/mlt++.txt, docs/mlt-xml.txt, docs/policies.txt, docs/services.txt, mlt++/.gitignore, mlt++/Makefile, mlt++/configure, src/framework/mlt_factory.c, src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/framework/mlt_properties.c, src/melt/io.c, src/melt/io.h, src/melt/melt.c, src/modules/core/factory.c, src/modules/core/filter_watermark.c, src/modules/core/loader.dict, src/modules/core/producer_consumer.c, src/modules/core/producer_hold.c, src/modules/core/producer_loader.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/core/transition_region.c, src/modules/kdenlive/producer_framebuffer.c, src/modules/kino/avi.h, src/modules/kino/riff.cc, src/modules/melt/factory.c, src/modules/melt/producer_melt.c, src/modules/motion_est/Makefile, src/modules/motion_est/README, src/modules/motion_est/producer_slowmotion.c, src/modules/plus/filter_affine.c, src/modules/xml/consumer_xml.c, src/modules/xml/factory.c, src/modules/xml/mlt-xml.dtd, src/modules/xml/producer_xml.c, src/swig/Makefile, src/swig/configure, src/swig/java/Play.java, src/swig/java/build, src/swig/mltpp.i, src/swig/perl/Makefile.PL, src/swig/perl/play.pl, src/swig/php/build, src/swig/php/play.php, src/swig/python/build, src/swig/python/play.py, src/swig/ruby/build, src/swig/ruby/play.rb, src/swig/ruby/thumbs.rb, src/swig/tcl/build, src/swig/tcl/play.tcl, src/tests/charlie.c, src/tests/hello.c: Complete reorganization and renaming to usable state. 2009-05-07 Dan Dennedy * src/modules/mvsp/Makefile, src/modules/mvsp/configure, src/modules/mvsp/consumer_mvsp.c, src/modules/mvsp/factory.c: Remove mvsp - moving to melted project. * .gitignore, Makefile, configure, mlt++.pc.in, setenv, src/examples/Makefile, src/melt/Makefile, src/mlt++/Makefile, src/mlt++/Mlt.h, src/mlt++/configure, src/modules/core/Makefile, src/modules/core/factory.c, src/modules/feeds/Makefile, src/modules/fezzik/Makefile, src/modules/fezzik/factory.c, src/modules/melt/Makefile, src/modules/mvsp/Makefile, src/modules/mvsp/configure, src/modules/mvsp/consumer_mvsp.c, src/modules/mvsp/factory.c, src/modules/valerie/Makefile, src/modules/valerie/consumer_valerie.c, src/modules/valerie/factory.c, src/modules/xml/Makefile, src/modules/xml/configure: Fix the build afer the reorg. * docs/inigo.txt, docs/melt.txt, docs/mlt-xml.txt, docs/westley.txt, src/inigo/Makefile, src/inigo/inigo.c, src/inigo/io.c, src/inigo/io.h, src/melt/Makefile, src/melt/io.c, src/melt/io.h, src/melt/melt.c, src/modules/core/data_fx.properties, src/modules/core/loader.dict, src/modules/core/loader.ini, src/modules/core/producer_hold.c, src/modules/core/producer_loader.c, src/modules/data_fx.properties, src/modules/fezzik.dict, src/modules/fezzik.ini, src/modules/fezzik/producer_fezzik.c, src/modules/fezzik/producer_hold.c, src/modules/inigo/Makefile, src/modules/inigo/factory.c, src/modules/inigo/producer_inigo.c, src/modules/melt/Makefile, src/modules/melt/factory.c, src/modules/melt/producer_melt.c, src/modules/westley/Makefile, src/modules/westley/configure, src/modules/westley/consumer_westley.c, src/modules/westley/factory.c, src/modules/westley/producer_westley.c, src/modules/westley/westley.dtd, src/modules/xml/Makefile, src/modules/xml/configure, src/modules/xml/consumer_xml.c, src/modules/xml/factory.c, src/modules/xml/mlt-xml.dtd, src/modules/xml/producer_xml.c, src/tests/README: Rename inigo, fezzik, and westley. * docs/mlt++.txt, mlt++/README: Merge mlt++/README into docs/mlt++.txt. * docs/mlt++.txt, mlt++/HOWTO, mlt++/src/Makefile, mlt++/src/Mlt.h, mlt++/src/MltConsumer.cpp, mlt++/src/MltConsumer.h, mlt++/src/MltDeque.cpp, mlt++/src/MltDeque.h, mlt++/src/MltEvent.cpp, mlt++/src/MltEvent.h, mlt++/src/MltFactory.cpp, mlt++/src/MltFactory.h, mlt++/src/MltField.cpp, mlt++/src/MltField.h, mlt++/src/MltFilter.cpp, mlt++/src/MltFilter.h, mlt++/src/MltFilteredConsumer.cpp, mlt++/src/MltFilteredConsumer.h, mlt++/src/MltFilteredProducer.cpp, mlt++/src/MltFilteredProducer.h, mlt++/src/MltFrame.cpp, mlt++/src/MltFrame.h, mlt++/src/MltGeometry.cpp, mlt++/src/MltGeometry.h, mlt++/src/MltMultitrack.cpp, mlt++/src/MltMultitrack.h, mlt++/src/MltParser.cpp, mlt++/src/MltParser.h, mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h, mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/src/MltProfile.cpp, mlt++/src/MltProfile.h, mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h, mlt++/src/MltPushConsumer.cpp, mlt++/src/MltPushConsumer.h, mlt++/src/MltRepository.cpp, mlt++/src/MltRepository.h, mlt++/src/MltService.cpp, mlt++/src/MltService.h, mlt++/src/MltTokeniser.cpp, mlt++/src/MltTokeniser.h, mlt++/src/MltTractor.cpp, mlt++/src/MltTractor.h, mlt++/src/MltTransition.cpp, mlt++/src/MltTransition.h, mlt++/src/config.h, mlt++/swig/Makefile, mlt++/swig/configure, mlt++/swig/java/Play.java, mlt++/swig/java/Play.sh, mlt++/swig/java/build, mlt++/swig/mltpp.i, mlt++/swig/perl/Makefile.PL, mlt++/swig/perl/build, mlt++/swig/perl/play.pl, mlt++/swig/php/build, mlt++/swig/php/play.php, mlt++/swig/python/build, mlt++/swig/python/play.py, mlt++/swig/ruby/build, mlt++/swig/ruby/play.rb, mlt++/swig/ruby/thumbs.rb, mlt++/swig/tcl/build, mlt++/swig/tcl/play.tcl, mlt++/test/Makefile, mlt++/test/play.cpp, src/examples/Makefile, src/examples/play.cpp, src/mlt++/Makefile, src/mlt++/Mlt.h, src/mlt++/MltConsumer.cpp, src/mlt++/MltConsumer.h, src/mlt++/MltDeque.cpp, src/mlt++/MltDeque.h, src/mlt++/MltEvent.cpp, src/mlt++/MltEvent.h, src/mlt++/MltFactory.cpp, src/mlt++/MltFactory.h, src/mlt++/MltField.cpp, src/mlt++/MltField.h, src/mlt++/MltFilter.cpp, src/mlt++/MltFilter.h, src/mlt++/MltFilteredConsumer.cpp, src/mlt++/MltFilteredConsumer.h, src/mlt++/MltFilteredProducer.cpp, src/mlt++/MltFilteredProducer.h, src/mlt++/MltFrame.cpp, src/mlt++/MltFrame.h, src/mlt++/MltGeometry.cpp, src/mlt++/MltGeometry.h, src/mlt++/MltMultitrack.cpp, src/mlt++/MltMultitrack.h, src/mlt++/MltParser.cpp, src/mlt++/MltParser.h, src/mlt++/MltPlaylist.cpp, src/mlt++/MltPlaylist.h, src/mlt++/MltProducer.cpp, src/mlt++/MltProducer.h, src/mlt++/MltProfile.cpp, src/mlt++/MltProfile.h, src/mlt++/MltProperties.cpp, src/mlt++/MltProperties.h, src/mlt++/MltPushConsumer.cpp, src/mlt++/MltPushConsumer.h, src/mlt++/MltRepository.cpp, src/mlt++/MltRepository.h, src/mlt++/MltService.cpp, src/mlt++/MltService.h, src/mlt++/MltTokeniser.cpp, src/mlt++/MltTokeniser.h, src/mlt++/MltTractor.cpp, src/mlt++/MltTractor.h, src/mlt++/MltTransition.cpp, src/mlt++/MltTransition.h, src/mlt++/config.h, src/swig/Makefile, src/swig/configure, src/swig/java/Play.java, src/swig/java/Play.sh, src/swig/java/build, src/swig/mltpp.i, src/swig/perl/Makefile.PL, src/swig/perl/build, src/swig/perl/play.pl, src/swig/php/build, src/swig/php/play.php, src/swig/python/build, src/swig/python/play.py, src/swig/ruby/build, src/swig/ruby/play.rb, src/swig/ruby/thumbs.rb, src/swig/tcl/build, src/swig/tcl/play.tcl: Reorganize mlt++ files. * docs/dvcp.txt, docs/testing-20040110.txt, docs/testing.txt, docs/valerie.txt, mlt++/AUTHORS, mlt++/COPYING, mlt++/CUSTOMISING, mlt++/ChangeLog, mlt++/mlt++.sln, mlt++/mlt++.vcproj, mlt++/src/MltMiracle.cpp, mlt++/src/MltMiracle.h, mlt++/src/MltResponse.cpp, mlt++/src/MltResponse.h, mlt++/swig/ruby/miracle.rb, mlt++/test/server.cpp, mlt-miracle.pc.in, mlt-valerie.pc.in, src/albino/Makefile, src/albino/albino.c, src/humperdink/Makefile, src/humperdink/client.c, src/humperdink/client.h, src/humperdink/io.c, src/humperdink/io.h, src/humperdink/remote.c, src/miracle/Makefile, src/miracle/configure, src/miracle/miracle.c, src/miracle/miracle_commands.c, src/miracle/miracle_commands.h, src/miracle/miracle_connection.c, src/miracle/miracle_connection.h, src/miracle/miracle_local.c, src/miracle/miracle_local.h, src/miracle/miracle_log.c, src/miracle/miracle_log.h, src/miracle/miracle_server.c, src/miracle/miracle_server.h, src/miracle/miracle_unit.c, src/miracle/miracle_unit.h, src/miracle/miracle_unit_commands.c, src/miracle/miracle_unit_commands.h, src/valerie/Makefile, src/valerie/configure, src/valerie/valerie.c, src/valerie/valerie.h, src/valerie/valerie_notifier.c, src/valerie/valerie_notifier.h, src/valerie/valerie_parser.c, src/valerie/valerie_parser.h, src/valerie/valerie_remote.c, src/valerie/valerie_remote.h, src/valerie/valerie_response.c, src/valerie/valerie_response.h, src/valerie/valerie_socket.c, src/valerie/valerie_socket.h, src/valerie/valerie_status.c, src/valerie/valerie_status.h, src/valerie/valerie_tokeniser.c, src/valerie/valerie_tokeniser.h, src/valerie/valerie_util.c, src/valerie/valerie_util.h: Remove files that no longer belong. 2009-05-03 ddennedy * configure, src/albino/Makefile, src/humperdink/Makefile, src/miracle/Makefile, src/modules/avformat/Makefile, src/modules/core/Makefile, src/modules/dgraft/Makefile, src/modules/effectv/Makefile, src/modules/fezzik/Makefile, src/modules/frei0r/Makefile, src/modules/inigo/Makefile, src/modules/kdenlive/Makefile, src/modules/kino/Makefile, src/modules/motion_est/Makefile, src/modules/normalize/Makefile, src/modules/oldfilm/Makefile, src/modules/plus/Makefile, src/modules/qimage/Makefile, src/modules/sox/configure, src/modules/valerie/Makefile, src/modules/vmfx/Makefile, src/modules/xine/Makefile, src/tests/Makefile, src/valerie/Makefile: Apply cosmetic cleanup part of ldflags_order patch from Alberto Villa. * src/modules/avformat/configure, src/modules/qimage/configure: Apply FreeBSD fixes part of ldflags_order patch from Alberto Villa. * src/modules/avformat/Makefile, src/modules/dv/Makefile, src/modules/gtk2/Makefile, src/modules/jackrack/Makefile, src/modules/sdl/Makefile, src/modules/sox/Makefile, src/modules/westley/Makefile: Apply ldflags-order part of ldflags_order patch from Alberto Villa. Alberto wrote: "on freebsd (as well as on linuces without /usr/local/lib in default ld path) building concurrent versions of mlt is not possible, because of the wrong linking of -lmlt while using LDFLAGS=-L/usr/local/lib this patch fixes the issue using pkg-config" 2009-04-18 ddennedy * src/modules/resample/Makefile, src/modules/vorbis/Makefile: Apply patch from Alberto Villa to use pkg-config for resample and vorbis modules. 2009-04-16 ddennedy * configure, src/framework/mlt.h, src/modules/kino/configure: Use pkg-config instead of lqt-config. 2009-04-15 ddennedy * mlt++/ChangeLog, mlt++/Makefile: Add ChangeLog and remove svn log from dist make target. * ChangeLog, Makefile: Update ChangeLog and remove svn log from the make install target. * NEWS, configure, src/framework/mlt.h, src/modules/avformat/configure: bump to version 0.3.8 2009-04-10 ddennedy * mlt++/test/play.cpp, mlt++/test/server.cpp: cleanup some warnings * mlt++/src/MltResponse.cpp, mlt++/src/MltResponse.h: const update for MltResponse * mlt++/src/MltResponse.cpp, mlt++/src/MltResponse.h: Constness changes * mlt++/src/MltTransition.cpp, mlt++/src/MltTransition.h: Constness changes * mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h: Constness changes * mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h: Constness changes * mlt++/src/MltConsumer.cpp, mlt++/src/MltConsumer.h: Constness changes * mlt++/src/MltProperties.cpp, mlt++/src/MltResponse.cpp: Constness changes * mlt++/src/MltProperties.cpp, mlt++/src/MltPushConsumer.cpp: Constness changes * mlt++/src/MltFilter.cpp, mlt++/src/MltFilter.h, mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h: Constness changes * mlt++/src/MltConsumer.cpp, mlt++/src/MltField.cpp, mlt++/src/MltFilter.cpp, mlt++/src/MltFrame.cpp, mlt++/src/MltMultitrack.cpp, mlt++/src/MltPlaylist.cpp, mlt++/src/MltProducer.cpp, mlt++/src/MltTractor.cpp, mlt++/src/MltTransition.cpp: Fix up warnings about explicit base initializers in copy constructors 2009-04-07 Ray Lehtiniemi * src/framework/mlt_consumer.c, src/miracle/miracle_connection.c, src/modules/kino/riff.cc: Fix up a few ignored return values * src/modules/avformat/consumer_avformat.c, src/modules/core/filter_watermark.c, src/modules/core/transition_composite.c, src/modules/core/transition_region.c, src/modules/westley/producer_westley.c: Constness changes * src/framework/mlt_properties.c, src/humperdink/client.c, src/miracle/miracle_connection.c, src/modules/avformat/consumer_avformat.c, src/modules/core/filter_data_show.c, src/modules/kino/filehandler.cc, src/valerie/valerie_response.c, src/valerie/valerie_response.h: Constness changes * src/framework/mlt_tokeniser.c, src/framework/mlt_tokeniser.h, src/miracle/miracle_server.c, src/miracle/miracle_server.h, src/valerie/valerie.c, src/valerie/valerie.h: Constness changes * src/humperdink/io.c, src/humperdink/io.h, src/modules/core/transition_composite.c, src/modules/gtk2/producer_pango.c, src/modules/westley/consumer_westley.c, src/valerie/valerie.c, src/valerie/valerie.h, src/valerie/valerie_parser.c, src/valerie/valerie_parser.h, src/valerie/valerie_socket.c, src/valerie/valerie_socket.h: Constness changes * src/framework/mlt_events.c, src/framework/mlt_events.h, src/inigo/inigo.c, src/modules/avformat/factory.c, src/modules/plus/transition_affine.c, src/modules/westley/producer_westley.c, src/modules/xine/deinterlace.c, src/modules/xine/deinterlace.h: Constness changes * src/miracle/miracle_local.c, src/valerie/valerie.c, src/valerie/valerie.h, src/valerie/valerie_status.c, src/valerie/valerie_tokeniser.c, src/valerie/valerie_tokeniser.h: Constness changes * src/humperdink/client.c, src/humperdink/io.c, src/humperdink/io.h, src/miracle/miracle_log.c, src/miracle/miracle_log.h, src/valerie/valerie.c, src/valerie/valerie.h, src/valerie/valerie_response.c, src/valerie/valerie_response.h: Constness changes * src/framework/mlt_multitrack.c, src/modules/effectv/image.c, src/modules/gtk2/producer_pango.c, src/modules/jackrack/jack_rack.c, src/modules/motion_est/filter_motion_est.c, src/modules/xine/xineutils.h: Constness changes 2009-03-31 Ray Lehtiniemi * src/framework/mlt_properties.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: Constness changes 2009-03-04 Ray Lehtiniemi * src/framework/mlt_events.c, src/framework/mlt_events.h, src/framework/mlt_factory.c, src/framework/mlt_factory.h, src/framework/mlt_repository.c, src/framework/mlt_repository.h, src/valerie/valerie_response.c, src/valerie/valerie_response.h: Constness changes 2009-03-10 ddennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_avdeinterlace.c, src/modules/avformat/filter_swscale.c: avformat: fix compilation due to recent PIX_FMT changes in libavutil v50. 2009-03-03 ddennedy * src/modules/frei0r/factory.c, src/modules/frei0r/producer_frei0r.c: frei0r/factory.c, producer_frei0r.c: suppress compiler warnings 2009-02-23 ddennedy * src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: consumer_sdl*.c: apply patch from Jean-Baptiste Mardelle to add window_background property 2009-02-20 ddennedy * src/modules/vmfx/filter_chroma.c, src/modules/vmfx/filter_chroma_hold.c: filter_chroma.c: update to use new property-based color value 2009-02-20 blendamedt * src/modules/frei0r/Makefile, src/modules/frei0r/factory.c, src/modules/frei0r/frei0r_helper.c: added frei0r producers (patch from jb) thx to jb 2009-02-17 ddennedy * src/albino/Makefile, src/humperdink/Makefile, src/inigo/Makefile, src/miracle/Makefile: albino/Makefile, inigo/Makefile, humperdink/Makefile, miracle/Makefile: apply patch from Alberto Villa to fix underlinking on FreeBSD 2009-02-16 ddennedy * src/modules/frei0r/factory.c, src/modules/frei0r/frei0r_helper.c: frei0r/factory.c, frei0r_helper.c: add support for color parameter type with whitespace cleanup courtesy of eclipse. 2009-02-14 ddennedy * src/modules/core/Makefile, src/modules/core/factory.c, src/modules/core/filter_crop.c, src/modules/fezzik.ini: filter_crop.c: add cropping filter (kdenlive-509) 2009-02-12 ddennedy * profiles/cif_15, profiles/qcif_15, profiles/quarter_15: profiles/*_15: add some 15fps profiles 2009-02-10 ddennedy * src/modules/qimage/producer_qimage.c, src/modules/qimage/qimage_wrapper.cpp, src/modules/qimage/qimage_wrapper.h: producer_qimage.c, qimage_wrapper.{h,cpp}: enhance qimage producer to use the new mlt_cache (kdenlive-575) * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c, src/modules/vorbis/producer_vorbis.c: producer_vorbis.c, producer_avformat.c, consumer_avformat.c: update headers in services for framework changes with addition of mlt_cache * configure, src/framework/Makefile, src/framework/mlt.h, src/framework/mlt_cache.c, src/framework/mlt_cache.h, src/framework/mlt_factory.c, src/framework/mlt_factory.h, src/framework/mlt_service.c, src/framework/mlt_service.h, src/framework/mlt_types.h: mlt_cache.[hc], mlt_types.h, mlt_service.[hc], mlt_factory.[hc], mlt.h: add mlt_cache and related service functions (kdenlive-575) 2009-02-04 ddennedy * mlt++/debian/changelog, mlt++/debian/control, mlt++/debian/copyright, mlt++/debian/rules: remove debian package subdirectory (they provide their own) * debian/changelog, debian/control, debian/copyright, debian/rules: remove the debian package subdirectory (they provide their own) 2009-02-02 ddennedy * configure, src/framework/mlt.h, src/modules/avformat/configure: bump to version 0.3.6 2009-01-29 ddennedy * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/producer_qimage.c, src/modules/sdl/producer_sdl_image.c: producer_pixbuf.c, producer_qimage.c, producer_sdl_image.c: bugfix (kdenlive-575) large memory consumption loading many pictures. 2009-01-26 ddennedy * mlt++/swig/configure, mlt++/swig/php/build, mlt++/swig/php/play.php: swig/configure, swig/php/*: add php bindings 2009-01-21 ddennedy * src/framework/mlt.h, src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_deque.c, src/framework/mlt_deque.h, src/framework/mlt_events.c, src/framework/mlt_events.h, src/framework/mlt_factory.c, src/framework/mlt_factory.h, src/framework/mlt_field.c, src/framework/mlt_field.h, src/framework/mlt_filter.c, src/framework/mlt_filter.h, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/framework/mlt_multitrack.c, src/framework/mlt_multitrack.h, src/framework/mlt_parser.c, src/framework/mlt_parser.h, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_pool.c, src/framework/mlt_pool.h, src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/framework/mlt_profile.c, src/framework/mlt_profile.h, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/framework/mlt_repository.c, src/framework/mlt_repository.h, src/framework/mlt_service.c, src/framework/mlt_service.h, src/framework/mlt_tokeniser.c, src/framework/mlt_tokeniser.h, src/framework/mlt_tractor.c, src/framework/mlt_tractor.h, src/framework/mlt_transition.c, src/framework/mlt_transition.h, src/framework/mlt_types.h: Add doxygen documentation for mlt_profile, mlt_pool, mlt_repository, and mlt_factory. Update copyrights to 2009. Add cross references from files to data structures in doxygen. 2009-01-13 ddennedy * src/framework/Makefile, src/framework/mlt.h, src/framework/mlt_consumer.c, src/framework/mlt_events.c, src/framework/mlt_log.c, src/framework/mlt_log.h, src/framework/mlt_pool.c, src/framework/mlt_producer.c, src/framework/mlt_properties.c, src/framework/mlt_repository.c, src/framework/mlt_tractor.c, src/framework/mlt_transition.c: mlt_log.[hc], mlt_transition.c, mlt_tractor.c, mlt_repository.c, mlt_properties.c, mlt_producer.c, mlt_pool.c, mlt_events.c, mlt_consumer.c, mlt.h, Makefile: add logging system based on FFmpeg's. 2009-01-08 ddennedy * src/framework/mlt_frame.h, src/framework/mlt_multitrack.c, src/framework/mlt_multitrack.h, src/framework/mlt_playlist.h, src/framework/mlt_service.h, src/framework/mlt_tractor.c, src/framework/mlt_tractor.h: mlt_tractor.[ch], mlt_multitrack.[ch]: improve doxygen documentation for the tractor and mulitrack classes 2009-01-06 ddennedy * src/modules/avformat/producer_avformat.c, src/modules/avformat/producer_avformat.yml: producer_avformat.{c,yml}: support special constructor argument values to list available demuxers and decoders: f-list[[,]acodec-list][[,]vcodec-list] 2009-01-05 ddennedy * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_filter.c, src/framework/mlt_filter.h, src/framework/mlt_frame.h, src/framework/mlt_multitrack.c, src/framework/mlt_multitrack.h, src/framework/mlt_producer.c, src/framework/mlt_service.c, src/framework/mlt_service.h, src/framework/mlt_transition.c, src/framework/mlt_transition.h: mlt_filter.[ch], mlt_transition.[ch], mlt_consumer.[ch]: improve doxygen for filter, transition, and consumer 2008-12-31 ddennedy * configure, src/modules/avformat/producer_avformat.c: producer_avformat.c: fix build on older versions of ffmpeg; whitespace cleanup by eclipse. 2008-12-29 ddennedy * NEWS, configure: NEWS, configure: set version to 0.3.4 and add release notes 2008-12-28 ddennedy * mlt++/swig/java/build, mlt++/swig/python/build, mlt++/swig/python/play.py, mlt++/swig/tcl/build: swig/{java,python,tcl}/build: fix linking error __stack_chk_fail_local. swig/python/play.py: fix syntax error reported by Jonathon Thomas. * src/modules/avformat/producer_avformat.c, src/modules/core/filter_rescale.c, src/modules/core/producer_consumer.c, src/modules/dv/producer_libdv.c: filter_rescale.c, producer_avformat.c, producer_libdv.c, producer_consumer.c: coerce a deinterlace when scaling an interlaced source. 2008-12-26 ddennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: producer_avformat.c, consumer_avformat.c: use av_set_string3 where available (gets rid of deprecation warning). 2008-12-22 ddennedy * src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/avformat/factory.c: avformat/configure, avformat/Makfile, avformat/factory.c: Add a --avformat-no-filters configure option to facilitate building a codecs and muxers only module. Change the module filename for a no-codecs build to libmltffmpeg.so to prevent a clash with a no-filters module (libmltavformat.so). 2008-12-20 ddennedy * src/modules/core/Makefile, src/modules/core/factory.c, src/modules/core/producer_consumer.c: core/Makefile, core/factory.c, core/producer_consumer.c: add new producer_consumer that will consume from an encapsulated producer under a different profile that the parent producer (kdenlive-323). * src/modules/avformat/Makefile, src/modules/avformat/factory.c, src/modules/avformat/filter_swscale.c, src/modules/fezzik.ini: avformat/Makefile, avformat/factory.c, avformat/filter_swscale.c: add new image scaler using FFmpeg libswcale. fezzik.ini: add swscale at higher priority than gtk2/rescale. 2008-12-18 ddennedy * src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/avformat/factory.c: avformat/configure, avformat/Makefile, avformat/factory.c: add configure option --avformat-no-codecs, which will build the avformat module without the producer and consumer - useful to people who want to make a version entirely without including FFmpeg's codecs, which present patent royalty licensing issues. * src/modules/avformat/Makefile, src/modules/avformat/factory.c, src/modules/avformat/filter_avdeinterlace.c: avformat/Makefile, avformat/factory.c, avformat/filter_avdeinterlace.c: Fix and enable the avdeinterlace filter for a non-MMX configuration. 2008-12-16 ddennedy * src/framework/mlt_events.c, src/framework/mlt_field.c, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_producer.c, src/framework/mlt_tractor.c: mlt_producer.c, mlt_playlist.h, mlt_field.h, mlt_playlist.c, mlt_tractor.c, mlt_events.c: add doxygen docs for events, field, and playlist. 2008-12-12 ddennedy * src/modules/gtk2/Makefile, src/modules/gtk2/pixops.c: gtk2/pixops.c, gtk2/Makefile: prevent MMX on all x86_64, not just OS X * src/modules/xine/Makefile, src/modules/xine/configure, src/modules/xine/deinterlace.c, src/modules/xine/xineutils.h: xine/Makefile, xine/xineutils.h, xine/deinterlace.c: respect mmx compilation flag instead of using own detection xine/configure: remove, no longer necessary * src/modules/gtk2/Makefile, src/modules/gtk2/configure, src/modules/gtk2/pixops.c: gtk2/Makefile, gtk2/configure, gtk2/pixops.c: disable MMX parts on OS X - does not build 2008-12-04 ddennedy * mlt++/swig/java/build, mlt++/swig/perl/Makefile.PL, mlt++/swig/python/build, mlt++/swig/ruby/build, mlt++/swig/tcl/build, mlt++/test/Makefile: test/Makefile, swig/*/build: replace more mlt-config with pkg-config * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_deque.c, src/framework/mlt_deque.h, src/framework/mlt_events.c, src/framework/mlt_events.h, src/framework/mlt_field.c, src/framework/mlt_field.h, src/framework/mlt_filter.h, src/framework/mlt_frame.h, src/framework/mlt_multitrack.c, src/framework/mlt_multitrack.h, src/framework/mlt_parser.c, src/framework/mlt_parser.h, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_pool.c, src/framework/mlt_pool.h, src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/framework/mlt_profile.c, src/framework/mlt_profile.h, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/framework/mlt_repository.c, src/framework/mlt_repository.h, src/framework/mlt_service.c, src/framework/mlt_service.h, src/framework/mlt_tokeniser.c, src/framework/mlt_tokeniser.h, src/framework/mlt_tractor.c, src/framework/mlt_tractor.h, src/framework/mlt_transition.c, src/framework/mlt_transition.h, src/framework/mlt_types.h: src/framework/*: improve the doxygen documentation (work in progress). This also includes removal of superfluous white space. 2008-12-02 ddennedy * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/producer_qimage.c, src/modules/sdl/producer_sdl_image.c: producer_pixbuf.c, producer_qimage.c, producer_sdl_image.c: bugfix (kdenlive-422) not validating input file for image producers. 2008-11-25 ddennedy * src/modules/avformat/audioconvert.h, src/modules/avformat/producer_avformat.c: producer_avformat.c: bugfix (kdenlive-297) audio distortion with audio formats other than signed 16-bit. 2008-11-13 blendamedt * src/modules/oldfilm/filter_vignette.c, src/modules/oldfilm/filter_vignette.yml: filter_vignette.{c,yml}: better standard values and correct start param name 2008-11-11 ddennedy * NEWS, configure: configure, NEWS: bump to version 0.3.2 and update release notes 2008-11-08 ddennedy * profiles/atsc_1080p_2398, profiles/atsc_1080p_24, profiles/atsc_1080p_25, profiles/atsc_1080p_2997, profiles/atsc_1080p_30, profiles/hdv_1080_25p, profiles/hdv_1080_30p, profiles/hdv_720_50p, profiles/hdv_720_60p: profiles/hdv_*, profiles/atsc_*: added more HD progressive mode profiles 2008-11-05 j-b-m * src/modules/kdenlive/Makefile, src/modules/kdenlive/factory.c, src/modules/kdenlive/filter_freeze.c: kdenlive/filter_freeze.c: added simple freeze filter 2008-10-30 blendamedt * src/modules/oldfilm/filter_vignette.c, src/modules/oldfilm/filter_vignette.yml: oldfilm/filter_vignette*: filter is now usable with keyframes 2008-10-29 ddennedy * src/albino/albino.c, src/inigo/inigo.c: albino.c, inigo.c: disable realtime scheduling (kdenlive-180). 2008-10-25 ddennedy * configure, src/modules/kino/endian_types.h, src/modules/kino/riff.cc, src/modules/sox/configure: configure, kino/enadian_types.h, kino/riff.c, sox/configure: apply patch from Alberto Villa to fix build on FreeBSD and to fix a sh expression bug in sox/configure. 2008-10-23 ddennedy * src/inigo/Makefile, src/inigo/inigo.c: inigo.c: added -version option 2008-09-22 j-b-m * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/qimage_wrapper.cpp: producer_pixbuf.c, qimage_wrapper.c: Add "force_reload" option to force image reloading in the image producers 2008-08-26 ddennedy * src/modules/sox/configure, src/modules/sox/filter_sox.c: sox/configure, filter_sox.c: fix building against sox 14.1.0. 2008-08-12 ddennedy * configure, src/modules/sdl/consumer_sdl.c: consumer_sdl.c: added support for fullscreen with no mouse through the "fullscreen" property. 2008-08-06 ddennedy * mlt++/swig/java/Play.java, mlt++/swig/java/Play.sh, mlt++/swig/java/build: swig/java: fixup the java bindings build script and example (bug 1523941) 2008-07-22 j-b-m * src/modules/qimage/producer_qimage.c, src/modules/qimage/qimage_wrapper.cpp, src/modules/qimage/qimage_wrapper.h: qimage module: add mutex, fix caching and use alpha only if necessary (mostly borrowed from producer_pixbuf) 2008-07-10 j-b-m * src/modules/qimage/configure, src/modules/qimage/producer_qimage.c, src/modules/qimage/qimage_wrapper.cpp, src/modules/qimage/qimage_wrapper.h: qimage module: add support for Qt4 (you can force compile against Qt3 with --force-qt3) 2008-07-01 blendamedt * src/modules/oldfilm/filter_vignette.c, src/modules/oldfilm/filter_vignette.yml: oldfilm/filter_vignette.{c,yml}: change format for parameters, to avoid converting problems with different locales 2008-06-30 ddennedy * src/framework/mlt_properties.c, src/framework/mlt_service.c: mlt_properties.c, mlt_service.c: bugfix to make reference counting and service closure truly thread-safe. As it was, reference count increment and decrement operations were not atomic and not protected comprehensively. 2008-06-26 ddennedy * mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/swig/mltpp.i: MltProducer.{h,cpp}, mltpp.i: remove Producer::get_frame that is unncessary and introduced a memory leak. 2008-06-01 ddennedy * src/modules/core/filter_resize.c, src/modules/core/transition_composite.c: filter_resize,c, filter_composite.c: bugfix redundant rounding. 2008-05-15 ddennedy * profiles/dv_ntsc, profiles/dv_ntsc_wide, profiles/dv_pal, profiles/dv_pal_wide, src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: profiles/dv_*, consumer_avformat.c, producer_avformat.c: bugfix (1912796) to override FFmpeg notion of sample aspect for DV. The values it uses might be more proper in certain contexts, but not in the way MLT currently operates. This change improves performance and quality when outputting to one of the "dv" profiles when using DV or other ITU-R 601-based video sources such as MPEG-2 for DVD Video and broadcast. 2008-05-12 ddennedy * src/modules/avformat/configure, src/modules/avformat/consumer_avformat.c: avformat/configure: fix compiling against shared ffmpeg due to changes in ffmpeg pkg-config 2008-05-09 ddennedy * src/framework/mlt_field.c, src/framework/mlt_field.h: mlt_field.[hc]: added mlt_field_disconnect_service * src/modules/dgraft/Makefile, src/modules/dgraft/factory.c, src/modules/dgraft/filter_telecide.c: modules/dgraft: added module for ports of Donald Graft's GPL filters. * src/modules/avformat/Makefile, src/modules/avformat/configure: avformat/Makefile, configure: fix --avformat-swscale and the removal of the ffmpeg 'lib' make target. 2008-04-23 ddennedy * mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/swig/mltpp.i: MltProducer.{h,cpp}, swig/mltpp.i: add method Producer::get_frame. * src/modules/core/filter_watermark.c, src/modules/core/transition_composite.c: filter_watermark.c, filter_composite.c: support explicit deinterlace of composited image. 2008-04-12 ddennedy * configure, src/modules/motion_est/configure: configure, motion_est/configure: remove module-specific crud from top-level configure script, and enable motion_est now by default. * src/modules/kino/avi.cc, src/modules/kino/filehandler.cc, src/modules/kino/kino_wrapper.cc: kino/kino_wrapper.cc, kino/filehandler.cc, kino/avi.cc: bugfix (1936991) compilation with gcc 4.3. 2008-03-22 blendamedt * src/modules/frei0r/frei0r_helper.c, src/modules/frei0r/transition_frei0r.c: frei0r/{frei0r_helper,transition_frei0r}.c: fixed wrong scaling and memory leak 2008-03-07 ddennedy * src/modules/frei0r/configure, src/modules/frei0r/factory.c: frei0r/configure: use CFLAGS so I can tell the test where to find frei0r.h frei0r/factory.c: add metadata_schema value to metadata 2008-03-06 ddennedy * src/framework/mlt_repository.c, src/framework/mlt_repository.h: mlt_repository.[hc]: add mlt_repository_languages helper function for localizing metadata 2008-03-04 blendamedt * src/modules/oldfilm/fdust.svg, src/modules/oldfilm/filter_dust.yml, src/modules/oldfilm/filter_grain.yml, src/modules/oldfilm/filter_lines.yml, src/modules/oldfilm/filter_oldfilm.yml, src/modules/oldfilm/filter_tcolor.yml, src/modules/oldfilm/filter_vignette.yml, src/modules/oldfilm/grain.svg, src/modules/oldfilm/lines.svg, src/modules/oldfilm/oldfilm.svg, src/modules/oldfilm/tcolor.svg, src/modules/oldfilm/vignette.svg: modules/oldfilm: yml files without icon, icon as separate file 2008-03-04 ddennedy * src/modules/sox/Makefile, src/modules/sox/configure: sox/configure, Makefile: try to make sox build smarter about library dependencies (pending Darwin compatibilty) * src/framework/metaschema.yaml, src/modules/avformat/producer_avformat.yml: metaschema.yaml, producer_avformat.yml: reset schema_version to 0.1 since we have not release anything yet with schema let alone metadata 2008-02-28 blendamedt * src/modules/frei0r/Makefile, src/modules/frei0r/configure, src/modules/frei0r/factory.c, src/modules/frei0r/filter_frei0r.c, src/modules/frei0r/frei0r_helper.c, src/modules/frei0r/frei0r_helper.h, src/modules/frei0r/transition_frei0r.c: initial frei0r support * src/modules/oldfilm/Makefile, src/modules/oldfilm/dust1.svg, src/modules/oldfilm/dust2.svg, src/modules/oldfilm/dust3.svg, src/modules/oldfilm/dust4.svg, src/modules/oldfilm/dust5.svg, src/modules/oldfilm/factory.c, src/modules/oldfilm/filter_dust.c, src/modules/oldfilm/filter_dust.yml, src/modules/oldfilm/filter_grain.c, src/modules/oldfilm/filter_grain.yml, src/modules/oldfilm/filter_lines.c, src/modules/oldfilm/filter_lines.yml, src/modules/oldfilm/filter_oldfilm.c, src/modules/oldfilm/filter_oldfilm.yml, src/modules/oldfilm/filter_tcolor.c, src/modules/oldfilm/filter_tcolor.yml, src/modules/oldfilm/filter_vignette.c, src/modules/oldfilm/filter_vignette.yml: updated oldfilm module + 2 new filters 2008-02-28 ddennedy * src/framework/Makefile, src/framework/metaschema.yaml, src/modules/avformat/producer_avformat.yml: framework/Makefile, metaschema.yaml: add a Kwalify schema for metadata producer_avformat.yml: update to schema 2008-02-27 ddennedy * mlt++/src/MltRepository.cpp, mlt++/src/MltRepository.h: MltRepository.{h,cpp}: update to latest mlt_repository.h change - finalization of callback declarations and metadata handling 2008-02-26 ddennedy * src/modules/avformat/Makefile, src/modules/avformat/factory.c, src/modules/avformat/producer_avformat.yml: avformat/factory.c, producer_avformat.yml, avformat/Makefile: add metadata for producer:avformat. * src/tests/Makefile, src/tests/dan.c: dan.c: example showing how to use the new yaml parsing and serialisation and the new registry metadata system * src/framework/mlt_properties.c, src/framework/mlt_properties.h: mlt_properties.[hc]: added really simply YAML Tiny parser and serialiser, mainly to support the registry metadata system. * src/framework/mlt_repository.c, src/framework/mlt_repository.h: mlt_repository.[hc]: implement the metadata registration and lookup interface 2008-02-24 ddennedy * src/modules/avformat/Makefile, src/modules/avformat/configure: avformat/configure, avformat/Makefile: add libavdevice for newer versions of ffmpeg when using --avformat-svn or --avformat-static 2008-02-16 ddennedy * mlt++/src/MltRepository.cpp, mlt++/src/MltRepository.h, mlt++/swig/mltpp.i: MltRepository.{h,cpp}, swig/mltpp.i: added consumers, filters, producers, transitions, register_metadata, and metadata methods to Repository class * src/framework/mlt_repository.c, src/framework/mlt_repository.h: mlt_consumer.[hc]: added new functions mlt_repository_consumers, mlt_repository_filters, mlt_repository_producers, mlt_repository_transitions, mlt_repository_register_metadata, and mlt_repository_metadata 2008-02-11 ddennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: consumer_avformat.c, producer_avformat.c: add FFmpeg multi-thread support via "threads" property or MLT_AVFORMAT_THREADS environment variable 2008-02-07 ddennedy * mlt++/configure, mlt++/src/Makefile: configure: add soversion variable src/Makefile: improve library versioning by linking on interface version (soversion) * configure, src/framework/Makefile, src/framework/mlt.h, src/miracle/Makefile, src/valerie/Makefile: configure: add soversion variable, move version variables to top for easier access framework/Makefile, miracle/Makefile, valerie/Makefile: improve library versioning by linking on interface version (soversion) mlt.h: add version info to header so apps can have build time adaptations * mlt++/src/Makefile, mlt++/src/Mlt.h, mlt++/src/MltFactory.cpp, mlt++/src/MltFactory.h, mlt++/src/MltRepository.cpp, mlt++/src/MltRepository.h, mlt++/swig/mltpp.i: Mlt.h, MltFactory.{h,cpp}, MltRepository.{h,cpp}, swig/mltpp.i: update to deal with changes and new capabilities in mlt_factory and mlt_repository. * src/framework/mlt_factory.c, src/framework/mlt_factory.h, src/framework/mlt_repository.c, src/framework/mlt_repository.h: cleanup some names since we are changing the interface mlt_repository.[hc]: change mlt_repository_fetch to mlt_repository_create mlt_factory.[hc]: change mlt_factory_prefix to mlt_factory_directory 2008-02-06 ddennedy * src/framework/mlt.h, src/framework/mlt_factory.c, src/framework/mlt_factory.h, src/framework/mlt_properties.c, src/framework/mlt_repository.c, src/framework/mlt_repository.h, src/modules/Makefile, src/modules/avformat/configure, src/modules/avformat/factory.c, src/modules/configure, src/modules/core/configure, src/modules/core/factory.c, src/modules/dv/configure, src/modules/dv/factory.c, src/modules/effectv/configure, src/modules/effectv/factory.c, src/modules/fezzik/configure, src/modules/fezzik/factory.c, src/modules/gtk2/configure, src/modules/gtk2/factory.c, src/modules/inigo/configure, src/modules/inigo/factory.c, src/modules/inigo/producer_inigo.c, src/modules/jackrack/configure, src/modules/jackrack/factory.c, src/modules/kdenlive/configure, src/modules/kdenlive/factory.c, src/modules/kino/configure, src/modules/kino/factory.c, src/modules/motion_est/configure, src/modules/motion_est/factory.c, src/modules/normalize/configure, src/modules/normalize/factory.c, src/modules/oldfilm/configure, src/modules/oldfilm/factory.c, src/modules/plus/configure, src/modules/plus/factory.c, src/modules/qimage/configure, src/modules/qimage/factory.c, src/modules/resample/configure, src/modules/resample/factory.c, src/modules/sdl/configure, src/modules/sdl/factory.c, src/modules/sox/configure, src/modules/sox/factory.c, src/modules/valerie/configure, src/modules/valerie/factory.c, src/modules/vmfx/configure, src/modules/vmfx/factory.c, src/modules/vorbis/configure, src/modules/vorbis/factory.c, src/modules/westley/configure, src/modules/westley/factory.c, src/modules/xine/configure, src/modules/xine/factory.c: mlt_repository.[hc]: - dynamically locate and register modules instead of reading .dat files - added mlt_repository_register() and macros for modules and apps(!) to register their service factory functions mlt_factory.[hc]: change mlt_factory_init() to return mlt_repository to app mlt_properties.c: let mlt_properties_dir_list() take a NULL filter pattern src/modules/*: - adapt to new module registration system - much simpler! - remove unncessary configure scripts (now optional!) 2008-02-04 ddennedy * Makefile, setenv, src/framework/Makefile, src/framework/mlt_consumer.c, src/framework/mlt_factory.c, src/framework/mlt_filter.c, src/framework/mlt_frame.c, src/framework/mlt_multitrack.c, src/framework/mlt_parser.c, src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/framework/mlt_properties.c, src/framework/mlt_property.c, src/framework/mlt_service.c, src/framework/mlt_tractor.c, src/framework/mlt_transition.c, src/modules/Makefile, src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/core/Makefile, src/modules/core/filter_data_show.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/dv/Makefile, src/modules/effectv/Makefile, src/modules/feeds/Makefile, src/modules/fezzik/Makefile, src/modules/fezzik/producer_fezzik.c, src/modules/gtk2/Makefile, src/modules/inigo/Makefile, src/modules/jackrack/Makefile, src/modules/kdenlive/Makefile, src/modules/kino/Makefile, src/modules/lumas/Makefile, src/modules/motion_est/Makefile, src/modules/normalize/Makefile, src/modules/oldfilm/Makefile, src/modules/plus/Makefile, src/modules/qimage/Makefile, src/modules/resample/Makefile, src/modules/sdl/Makefile, src/modules/sox/Makefile, src/modules/sox/configure, src/modules/valerie/Makefile, src/modules/vmfx/Makefile, src/modules/vmfx/filter_shape.c, src/modules/vorbis/Makefile, src/modules/westley/Makefile, src/modules/xine/Makefile: move binary modules to libdir - affects MLT_REPOSITORY added MLT_DATA environment variable to refer to share dir remove need for config.h 2008-02-02 ddennedy * mlt++/src/Makefile, mlt++/src/Mlt.h, mlt++/src/MltConsumer.cpp, mlt++/src/MltConsumer.h, mlt++/src/MltFactory.cpp, mlt++/src/MltFactory.h, mlt++/src/MltFilter.cpp, mlt++/src/MltFilter.h, mlt++/src/MltFilteredConsumer.cpp, mlt++/src/MltFilteredConsumer.h, mlt++/src/MltFilteredProducer.cpp, mlt++/src/MltFilteredProducer.h, mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/src/MltProfile.cpp, mlt++/src/MltProfile.h, mlt++/src/MltPushConsumer.cpp, mlt++/src/MltPushConsumer.h, mlt++/src/MltService.cpp, mlt++/src/MltService.h, mlt++/src/MltTractor.cpp, mlt++/src/MltTractor.h, mlt++/src/MltTransition.cpp, mlt++/src/MltTransition.h, mlt++/swig/mltpp.i, mlt++/swig/perl/play.pl, mlt++/swig/python/play.py, mlt++/swig/ruby/miracle.rb, mlt++/swig/ruby/play.rb, mlt++/swig/ruby/thumbs.rb, mlt++/swig/tcl/play.tcl, mlt++/test/play.cpp, mlt++/test/server.cpp: add MltProfile and update examples * src/framework/mlt_factory.c, src/framework/mlt_profile.c: mlt_factory.c: guard against accessing mlt_environment before it is ready mlt_profile.c: fix setting legacy MLT_NORMALISATION on mlt_environment * src/framework/mlt_factory.c, src/framework/mlt_profile.c: mlt_factory.c: guard against setting mlt_environment before it is available mlt_profile.c: use getenv instead of mlt_environment in case profile is created before factory * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_factory.c, src/framework/mlt_factory.h, src/framework/mlt_filter.c, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/framework/mlt_geometry.c, src/framework/mlt_multitrack.c, src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/framework/mlt_profile.c, src/framework/mlt_profile.h, src/framework/mlt_repository.c, src/framework/mlt_repository.h, src/framework/mlt_service.c, src/framework/mlt_service.h, src/framework/mlt_tractor.c, src/inigo/inigo.c, src/miracle/miracle_connection.c, src/miracle/miracle_unit.c, src/miracle/miracle_unit_commands.c, src/modules/avformat/consumer_avformat.c, src/modules/avformat/consumer_avformat.h, src/modules/avformat/factory.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_avcolour_space.h, src/modules/avformat/filter_avdeinterlace.c, src/modules/avformat/filter_avdeinterlace.h, src/modules/avformat/filter_avresample.c, src/modules/avformat/filter_avresample.h, src/modules/avformat/producer_avformat.c, src/modules/avformat/producer_avformat.h, src/modules/core/consumer_null.c, src/modules/core/consumer_null.h, src/modules/core/factory.c, src/modules/core/filter_brightness.c, src/modules/core/filter_brightness.h, src/modules/core/filter_channelcopy.c, src/modules/core/filter_channelcopy.h, src/modules/core/filter_data.h, src/modules/core/filter_data_feed.c, src/modules/core/filter_data_show.c, src/modules/core/filter_gamma.c, src/modules/core/filter_gamma.h, src/modules/core/filter_greyscale.c, src/modules/core/filter_greyscale.h, src/modules/core/filter_luma.c, src/modules/core/filter_luma.h, src/modules/core/filter_mirror.c, src/modules/core/filter_mirror.h, src/modules/core/filter_mono.c, src/modules/core/filter_mono.h, src/modules/core/filter_obscure.c, src/modules/core/filter_obscure.h, src/modules/core/filter_region.c, src/modules/core/filter_region.h, src/modules/core/filter_rescale.c, src/modules/core/filter_rescale.h, src/modules/core/filter_resize.c, src/modules/core/filter_resize.h, src/modules/core/filter_transition.c, src/modules/core/filter_transition.h, src/modules/core/filter_watermark.c, src/modules/core/filter_watermark.h, src/modules/core/producer_colour.c, src/modules/core/producer_colour.h, src/modules/core/producer_noise.c, src/modules/core/producer_noise.h, src/modules/core/producer_ppm.c, src/modules/core/producer_ppm.h, src/modules/core/transition_composite.c, src/modules/core/transition_composite.h, src/modules/core/transition_luma.c, src/modules/core/transition_luma.h, src/modules/core/transition_mix.c, src/modules/core/transition_mix.h, src/modules/core/transition_region.c, src/modules/core/transition_region.h, src/modules/dv/consumer_libdv.c, src/modules/dv/consumer_libdv.h, src/modules/dv/factory.c, src/modules/dv/producer_libdv.c, src/modules/dv/producer_libdv.h, src/modules/effectv/factory.c, src/modules/effectv/filter_burn.c, src/modules/effectv/filter_burn.h, src/modules/fezzik/factory.c, src/modules/fezzik/producer_fezzik.c, src/modules/fezzik/producer_fezzik.h, src/modules/fezzik/producer_hold.c, src/modules/fezzik/producer_hold.h, src/modules/gtk2/consumer_gtk2.c, src/modules/gtk2/consumer_gtk2.h, src/modules/gtk2/factory.c, src/modules/gtk2/filter_rescale.c, src/modules/gtk2/filter_rescale.h, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pango.h, src/modules/gtk2/producer_pixbuf.c, src/modules/gtk2/producer_pixbuf.h, src/modules/inigo/factory.c, src/modules/inigo/producer_inigo.c, src/modules/inigo/producer_inigo.h, src/modules/jackrack/factory.c, src/modules/jackrack/filter_jackrack.c, src/modules/jackrack/filter_jackrack.h, src/modules/jackrack/filter_ladspa.c, src/modules/jackrack/filter_ladspa.h, src/modules/kdenlive/factory.c, src/modules/kdenlive/filter_boxblur.c, src/modules/kdenlive/filter_boxblur.h, src/modules/kdenlive/filter_wave.c, src/modules/kdenlive/filter_wave.h, src/modules/kdenlive/producer_framebuffer.c, src/modules/kdenlive/producer_framebuffer.h, src/modules/kino/factory.c, src/modules/kino/producer_kino.c, src/modules/kino/producer_kino.h, src/modules/motion_est/factory.c, .../motion_est/filter_autotrack_rectangle.c, src/modules/motion_est/filter_crop_detect.c, src/modules/motion_est/filter_motion_est.c, src/modules/motion_est/filter_motion_est.h, src/modules/motion_est/filter_vismv.c, src/modules/motion_est/producer_slowmotion.c, src/modules/normalize/factory.c, src/modules/normalize/filter_volume.c, src/modules/normalize/filter_volume.h, src/modules/oldfilm/factory.c, src/modules/oldfilm/filter_dust.c, src/modules/oldfilm/filter_dust.h, src/modules/oldfilm/filter_grain.c, src/modules/oldfilm/filter_grain.h, src/modules/oldfilm/filter_lines.c, src/modules/oldfilm/filter_lines.h, src/modules/oldfilm/filter_oldfilm.c, src/modules/oldfilm/filter_oldfilm.h, src/modules/plus/factory.c, src/modules/plus/filter_affine.c, src/modules/plus/filter_affine.h, src/modules/plus/filter_charcoal.c, src/modules/plus/filter_charcoal.h, src/modules/plus/filter_invert.c, src/modules/plus/filter_invert.h, src/modules/plus/filter_sepia.c, src/modules/plus/filter_sepia.h, src/modules/plus/transition_affine.c, src/modules/plus/transition_affine.h, src/modules/qimage/factory.c, src/modules/qimage/producer_qimage.c, src/modules/qimage/producer_qimage.h, src/modules/qimage/qimage_wrapper.cpp, src/modules/resample/factory.c, src/modules/resample/filter_resample.c, src/modules/resample/filter_resample.h, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl.h, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c, src/modules/sdl/factory.c, src/modules/sdl/producer_sdl_image.c, src/modules/sdl/producer_sdl_image.h, src/modules/sox/configure, src/modules/sox/factory.c, src/modules/sox/filter_sox.c, src/modules/sox/filter_sox.h, src/modules/valerie/consumer_valerie.c, src/modules/valerie/consumer_valerie.h, src/modules/valerie/factory.c, src/modules/vmfx/factory.c, src/modules/vmfx/filter_chroma.c, src/modules/vmfx/filter_chroma.h, src/modules/vmfx/filter_chroma_hold.c, src/modules/vmfx/filter_chroma_hold.h, src/modules/vmfx/filter_mono.c, src/modules/vmfx/filter_mono.h, src/modules/vmfx/filter_shape.c, src/modules/vmfx/filter_shape.h, src/modules/vmfx/producer_pgm.c, src/modules/vmfx/producer_pgm.h, src/modules/vorbis/factory.c, src/modules/vorbis/producer_vorbis.c, src/modules/vorbis/producer_vorbis.h, src/modules/westley/consumer_westley.c, src/modules/westley/consumer_westley.h, src/modules/westley/factory.c, src/modules/westley/producer_westley.c, src/modules/westley/producer_westley.h, src/modules/xine/factory.c, src/modules/xine/filter_deinterlace.c, src/modules/xine/filter_deinterlace.h, src/valerie/valerie_remote.c: framework: remove global profile, rather share one mlt_profile across a service network and make it available from anywhere through mlt_service_profile(). miracle, valerie: profile changes inigo: added -profile and progress=1 to mimic kdenlive_renderer modules: profile changes. Since nearly every file was touched, remove superfluous headers and prepare for coming mlt_repository change. 2008-01-08 ddennedy * src/modules/oldfilm/Makefile, src/modules/oldfilm/configure, src/modules/oldfilm/factory.c, src/modules/oldfilm/filter_dust.c, src/modules/oldfilm/filter_dust.h, src/modules/oldfilm/filter_grain.c, src/modules/oldfilm/filter_grain.h, src/modules/oldfilm/filter_lines.c, src/modules/oldfilm/filter_lines.h, src/modules/oldfilm/filter_oldfilm.c, src/modules/oldfilm/filter_oldfilm.h: src/modules/oldfilm/*: add oldfilm module contributed by Marco Gittler 2007-12-08 ddennedy * src/modules/avformat/configure, src/modules/sox/configure: sox/configure: remove libsamplerate from linking by default 2007-12-04 ddennedy * src/framework/mlt_consumer.c, src/framework/mlt_frame.c, src/framework/mlt_multitrack.c, src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/modules/avformat/producer_avformat.c, src/modules/core/filter_data_show.c, src/modules/dv/producer_libdv.c, src/modules/inigo/producer_inigo.c, src/modules/vorbis/producer_vorbis.c, src/modules/westley/producer_westley.c: mlt_consumer.c, mlt_frame.c, mlt_multitrack.c, mlt_playlist.c, mlt_producer.c, producer_avformat.c, filter_data_show.c, producer_libdv.c, producer_inigo.c, producer_vorbis.c, producer_westley.c: remove statefulness of frame rate through framework and modules, and allow consumer properties to override profile settings. 2007-11-09 ddennedy * src/modules/sox/Makefile, src/modules/sox/configure, src/modules/sox/filter_sox.c: filter_sox.c, src/modules/sox/Makefile, src/modules/sox/configure: add support for sox v14.0.0. 2007-10-19 ddennedy * src/miracle/miracle_server.c, src/miracle/miracle_unit.c, src/modules/avformat/factory.c, src/modules/gtk2/pixops.c, src/modules/gtk2/producer_pango.c, src/modules/jackrack/jack_rack.c, src/modules/jackrack/plugin_settings.c, src/modules/kdenlive/filter_wave.c, src/modules/plus/transition_affine.c, src/modules/vmfx/filter_chroma.c, src/modules/vorbis/producer_vorbis.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: avformat/factory.c, jackrack/jack_rack.c, jackrack/plugin_settings.c, vmfx/filter_chroma.c, plus/transition_affine.c, westley/producer_westley.c, westley/consumer_westley.c, kdenlive/filter_wave.c, vorbis/producer_vorbis.c, gtk2/producer_pango.c, gtk2/pixops.c, miracle_server.c, miracle_unit.c: cleanup a whole bunch of compiler warnings * src/modules/motion_est/filter_motion_est.c, src/modules/motion_est/filter_vismv.c: filter_vismv.c: bugfix pointer to array of motion vectors 2007-10-13 ddennedy * src/framework/mlt_factory.c, src/framework/mlt_profile.c: mlt_profile.c, mlt_factory.c: bugfix loading profile by file specification and remove a small memory leak * setenv, src/framework/mlt_profile.c: mlt_profle.c: add support for MLT_PROFILES_DIR environment variable * src/modules/effectv/utils.c, src/modules/effectv/utils.h: effectv/utils.*: fix compilation on OS X 2007-07-30 ddennedy * configure, docs/policies.txt: configure: fix broken variables in pkg-config files policies.txt: add bug reporting procedure 2007-07-29 ddennedy * src/framework/mlt_consumer.c, src/framework/mlt_profile.c: mlt_profile.c: bugfix string allocation length mlt_consumer.c: bugfix removal of property-changed listener 2007-07-20 ddennedy * profiles/atsc_1080i_60, profiles/atsc_720p_30, profiles/atsc_wide_1080i, profiles/atsc_wide_720p: profiles/atsc_*: rename and change descriptions * profiles/hdv_1080_50i, profiles/hdv_1080_60i, profiles/hdv_720_25p, profiles/hdv_720_30p: * profiles/hdv_1080_50i, profiles/hdv_1080_60i, profiles/hdv_1080_ntsc, profiles/hdv_1080_pal, profiles/hdv_720_30p, profiles/hdv_720_60i: * profiles/hdv_720_25p, profiles/hdv_720_50p: * profiles/hdv_720_50p, profiles/hdv_720_60i, profiles/hdv_720_ntsc, profiles/hdv_720_pal: * profiles/atsc_wide_1080i, profiles/atsc_wide_720p, profiles/cif_ntsc, profiles/cif_pal, profiles/cvd_ntsc, profiles/cvd_pal, profiles/dv_ntsc, profiles/dv_ntsc_wide, profiles/dv_pal, profiles/dv_pal_wide, profiles/hdv_1080_ntsc, profiles/hdv_1080_pal, profiles/hdv_720_ntsc, profiles/hdv_720_pal, profiles/qcif_ntsc, profiles/qcif_pal, profiles/quarter_ntsc, profiles/quarter_ntsc_wide, profiles/quarter_pal, profiles/quarter_pal_wide, profiles/square_ntsc, profiles/square_ntsc_wide, profiles/square_pal, profiles/square_pal_wide, profiles/svcd_ntsc, profiles/svcd_ntsc_wide, profiles/svcd_pal, profiles/svcd_pal_wide, profiles/vcd_ntsc, profiles/vcd_pal, src/framework/mlt_factory.c, src/framework/mlt_factory.h, src/framework/mlt_profile.c, src/framework/mlt_profile.h: profiles/*: name->description mlt_factory.{h,cc}: added mlt_environment_set() mlt_profile.{h,cc}: fix setting legacy MLT_NORMALISATION, set MLT_PROFILE, and change "name" to "description" for clarity 2007-07-15 ddennedy * src/modules/avformat/Makefile, src/modules/avformat/configure: avformat/configure: add --avformat-svn-extra avformat/Makefile: rebuild module when local ffmpeg changes * profiles/Makefile, profiles/square_pal_wide: profiles/Makefile: do not install Makefile profiles/square_pal_wide: fix display aspect * ChangeLog, Makefile, configure, profiles/Makefile, profiles/atsc_wide_1080i, profiles/atsc_wide_720p, profiles/cif_ntsc, profiles/cif_pal, profiles/cvd_ntsc, profiles/cvd_pal, profiles/dv_ntsc, profiles/dv_ntsc_wide, profiles/dv_pal, profiles/dv_pal_wide, profiles/hdv_1080_ntsc, profiles/hdv_1080_pal, profiles/hdv_720_ntsc, profiles/hdv_720_pal, profiles/qcif_ntsc, profiles/qcif_pal, profiles/quarter_ntsc, profiles/quarter_ntsc_wide, profiles/quarter_pal, profiles/quarter_pal_wide, profiles/square_ntsc, profiles/square_ntsc_wide, profiles/square_pal, profiles/square_pal_wide, profiles/svcd_ntsc, profiles/svcd_ntsc_wide, profiles/svcd_pal, profiles/svcd_pal_wide, profiles/vcd_ntsc, profiles/vcd_pal, src/framework/Makefile, src/framework/mlt.h, src/framework/mlt_consumer.c, src/framework/mlt_factory.c, src/framework/mlt_frame.c, src/framework/mlt_geometry.c, src/framework/mlt_producer.c, src/framework/mlt_profile.c, src/framework/mlt_profile.h, src/framework/mlt_types.h, src/modules/dv/consumer_libdv.c, src/modules/sdl/consumer_sdl.c: Added new profiles system: mlt_profile, MLT_PROFILE, and profiles documents. 2007-07-14 ddennedy * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: consumer_avformat.c: save disabled, experimental flushing code 2007-07-01 j-b-m * src/modules/fezzik.dict, src/modules/qimage/Makefile, src/modules/qimage/configure, src/modules/qimage/producer_qimage.c, src/modules/qimage/qimage_wrapper.cpp, src/modules/qimage/qimage_wrapper.h: Add support for psd, xcf and exr images (KDE libraries needed for these formats). Make pcx and tiff images load correctly 2007-06-29 ddennedy * demo/mlt_title_over_gfx, demo/mlt_titleshadow_watermark, demo/mlt_voiceover: demo/mlt_title_over_gfx, demo/mlt_titleshadow_watermark, demo/mlt_voiceover: fix broken demos due to recent hidden track handling change in mlt_transition.c 2007-06-12 ddennedy * mlt++/Makefile, mlt++/src/Makefile, mlt++/test/Makefile: added uninstall make targets * Makefile, src/albino/Makefile, src/framework/Makefile, src/humperdink/Makefile, src/inigo/Makefile, src/miracle/Makefile, src/modules/Makefile, src/valerie/Makefile: added uninstall make targets 2007-06-10 ddennedy * src/modules/effectv/Makefile, src/modules/effectv/configure, src/modules/effectv/factory.c, src/modules/effectv/filter_burn.c, src/modules/effectv/filter_burn.h, src/modules/effectv/image.c, src/modules/effectv/utils.c, src/modules/effectv/utils.h: added effectv module with BurningTV filter provided by Stephane Fillod * docs/westley.txt, src/modules/fezzik.dict: fezzik.dict: prioritize avformat higher than libdv for better quality 2007-06-09 ddennedy * src/modules/avformat/Makefile, src/modules/avformat/configure: change --avformat-svn configure option to do a static build of ffmpeg libs only and statically link to mlt module. Also, make --avformat-svn aware of --avformat-swscale and --enable-gpl 2007-05-25 ddennedy * demo/README, demo/mlt_attributes, demo/mlt_intro, demo/mlt_jcut, demo/mlt_lcut, docs/inigo.txt: fix some demos broken by old changes 2007-05-23 ddennedy * src/framework/mlt_factory.c, src/framework/mlt_producer.c, src/modules/fezzik.ini: the framework may not depend upon specific modules--data_feed/show in this case 2007-04-10 ddennedy * ChangeLog, docs/policies.txt, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_boxblur.c, src/modules/core/filter_boxblur.h, src/modules/core/filter_wave.c, src/modules/core/filter_wave.h, src/modules/core/producer_framebuffer.c, src/modules/core/producer_framebuffer.h, src/modules/core/transition_luma.c, src/modules/gtk2/pixops.c, src/modules/gtk2/pixops.h, src/modules/jackrack/jack_rack.c, src/modules/jackrack/jack_rack.h, src/modules/jackrack/lock_free_fifo.c, src/modules/jackrack/lock_free_fifo.h, src/modules/jackrack/plugin.c, src/modules/jackrack/plugin.h, src/modules/jackrack/plugin_desc.c, src/modules/jackrack/plugin_desc.h, src/modules/jackrack/plugin_mgr.c, src/modules/jackrack/plugin_mgr.h, src/modules/jackrack/plugin_settings.c, src/modules/jackrack/plugin_settings.h, src/modules/jackrack/process.c, src/modules/jackrack/process.h, src/modules/kdenlive/Makefile, src/modules/kdenlive/configure, src/modules/kdenlive/factory.c, src/modules/kdenlive/filter_boxblur.c, src/modules/kdenlive/filter_boxblur.h, src/modules/kdenlive/filter_wave.c, src/modules/kdenlive/filter_wave.h, src/modules/kdenlive/producer_framebuffer.c, src/modules/kdenlive/producer_framebuffer.h, src/modules/normalize/filter_volume.c, src/modules/xine/filter_deinterlace.c: Cleanup copyrights and attributions, and move Jean-Baptiste's services to a new kdenlive module. 2007-03-31 ddennedy * ChangeLog, src/modules/sox/filter_sox.c: add sox 13.0.0 support 2007-03-30 j-b-m * ChangeLog, src/modules/core/filter_boxblur.c, src/modules/core/filter_boxblur.h, src/modules/core/filter_wave.c, src/modules/core/filter_wave.h: Update ChangeLog and fix license for blur and wave filters 2007-03-30 ddennedy * ChangeLog, src/modules/vmfx/configure, src/modules/vmfx/factory.c: Change registration of vmfx/mono to threshold to disambiguate with core/mono. * ChangeLog, GPL, README, configure, docs/install.txt, docs/policies.txt, docs/services.txt, docs/testing-20040110.txt, src/albino/albino.c, src/framework/mlt.h, src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_deque.c, src/framework/mlt_deque.h, src/framework/mlt_events.c, src/framework/mlt_events.h, src/framework/mlt_factory.c, src/framework/mlt_factory.h, src/framework/mlt_field.c, src/framework/mlt_field.h, src/framework/mlt_filter.c, src/framework/mlt_filter.h, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/framework/mlt_geometry.c, src/framework/mlt_geometry.h, src/framework/mlt_multitrack.c, src/framework/mlt_multitrack.h, src/framework/mlt_parser.c, src/framework/mlt_parser.h, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_pool.c, src/framework/mlt_pool.h, src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/framework/mlt_repository.c, src/framework/mlt_repository.h, src/framework/mlt_service.c, src/framework/mlt_service.h, src/framework/mlt_tractor.c, src/framework/mlt_tractor.h, src/framework/mlt_transition.c, src/framework/mlt_transition.h, src/framework/mlt_types.h, src/humperdink/client.c, src/humperdink/client.h, src/humperdink/io.c, src/humperdink/io.h, src/humperdink/remote.c, src/inigo/inigo.c, src/inigo/io.c, src/inigo/io.h, src/miracle/miracle.c, src/miracle/miracle_local.h, src/miracle/miracle_server.c, src/miracle/miracle_server.h, src/miracle/miracle_unit.c, src/miracle/miracle_unit.h, src/modules/avformat/consumer_avformat.c, src/modules/avformat/consumer_avformat.h, src/modules/avformat/factory.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_avcolour_space.h, src/modules/avformat/filter_avdeinterlace.c, src/modules/avformat/filter_avdeinterlace.h, src/modules/avformat/filter_avresample.c, src/modules/avformat/filter_avresample.h, src/modules/avformat/producer_avformat.c, src/modules/avformat/producer_avformat.h, src/modules/core/consumer_null.c, src/modules/core/consumer_null.h, src/modules/core/factory.c, src/modules/core/filter_brightness.c, src/modules/core/filter_brightness.h, src/modules/core/filter_channelcopy.c, src/modules/core/filter_channelcopy.h, src/modules/core/filter_data.h, src/modules/core/filter_data_feed.c, src/modules/core/filter_data_show.c, src/modules/core/filter_gamma.c, src/modules/core/filter_gamma.h, src/modules/core/filter_greyscale.c, src/modules/core/filter_greyscale.h, src/modules/core/filter_luma.c, src/modules/core/filter_luma.h, src/modules/core/filter_mirror.c, src/modules/core/filter_mirror.h, src/modules/core/filter_mono.c, src/modules/core/filter_mono.h, src/modules/core/filter_obscure.c, src/modules/core/filter_obscure.h, src/modules/core/filter_region.c, src/modules/core/filter_region.h, src/modules/core/filter_rescale.c, src/modules/core/filter_rescale.h, src/modules/core/filter_resize.c, src/modules/core/filter_resize.h, src/modules/core/filter_transition.c, src/modules/core/filter_transition.h, src/modules/core/filter_watermark.c, src/modules/core/filter_watermark.h, src/modules/core/producer_colour.c, src/modules/core/producer_colour.h, src/modules/core/producer_noise.c, src/modules/core/producer_noise.h, src/modules/core/producer_ppm.c, src/modules/core/producer_ppm.h, src/modules/core/transition_composite.c, src/modules/core/transition_composite.h, src/modules/core/transition_luma.c, src/modules/core/transition_luma.h, src/modules/core/transition_mix.c, src/modules/core/transition_mix.h, src/modules/core/transition_region.c, src/modules/core/transition_region.h, src/modules/dv/consumer_libdv.c, src/modules/dv/consumer_libdv.h, src/modules/dv/factory.c, src/modules/dv/producer_libdv.c, src/modules/dv/producer_libdv.h, src/modules/fezzik/factory.c, src/modules/fezzik/producer_fezzik.c, src/modules/fezzik/producer_fezzik.h, src/modules/fezzik/producer_hold.c, src/modules/fezzik/producer_hold.h, src/modules/gtk2/consumer_gtk2.c, src/modules/gtk2/consumer_gtk2.h, src/modules/gtk2/factory.c, src/modules/gtk2/filter_rescale.c, src/modules/gtk2/filter_rescale.h, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pango.h, src/modules/gtk2/producer_pixbuf.c, src/modules/gtk2/producer_pixbuf.h, src/modules/gtk2/scale_line_22_yuv_mmx.S, src/modules/inigo/factory.c, src/modules/inigo/producer_inigo.c, src/modules/inigo/producer_inigo.h, src/modules/lumas/luma.c, src/modules/plus/factory.c, src/modules/plus/filter_affine.c, src/modules/plus/filter_affine.h, src/modules/plus/filter_charcoal.c, src/modules/plus/filter_charcoal.h, src/modules/plus/filter_invert.c, src/modules/plus/filter_invert.h, src/modules/plus/filter_sepia.c, src/modules/plus/filter_sepia.h, src/modules/plus/transition_affine.c, src/modules/plus/transition_affine.h, src/modules/qimage/producer_qimage.c, src/modules/qimage/qimage_wrapper.cpp, src/modules/qimage/qimage_wrapper.h, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl.h, src/modules/sdl/consumer_sdl_osx_hack.h, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c, src/modules/sdl/factory.c, src/modules/sdl/producer_sdl_image.c, src/modules/sdl/producer_sdl_image.h, src/modules/sox/factory.c, src/modules/sox/filter_sox.c, src/modules/sox/filter_sox.h, src/modules/valerie/consumer_valerie.c, src/modules/valerie/consumer_valerie.h, src/modules/valerie/factory.c, src/modules/vorbis/factory.c, src/modules/vorbis/producer_vorbis.c, src/modules/vorbis/producer_vorbis.h, src/modules/westley/consumer_westley.c, src/modules/westley/consumer_westley.h, src/modules/westley/factory.c, src/modules/westley/producer_westley.c, src/modules/westley/producer_westley.h, src/valerie/valerie.h: Cleanup license declarations and remove dv1394d references. 2007-03-27 ddennedy * ChangeLog, src/modules/avformat/Makefile, src/modules/avformat/configure: fixup some swscale integration 2007-03-17 ddennedy * ChangeLog, docs/TODO, docs/policies.txt: added docs/policies.txt 2007-03-04 ddennedy * ChangeLog, src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/avformat/consumer_avformat.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/producer_avformat.c: add support for ffmpeg libswscale * demo/README, demo/consumers.ini: change default dv1394 device file 2007-02-19 j-b-m * src/modules/core/filter_boxblur.c, src/modules/core/filter_boxblur.h, src/modules/core/filter_wave.c, src/modules/core/filter_wave.h: Fix typo, credits and make functions static, (patch from stephane fillod - thanks) 2007-02-18 j-b-m * src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_boxblur.c, src/modules/core/filter_boxblur.h, src/modules/core/filter_wave.c, src/modules/core/filter_wave.h: Add blur and wave filters from Leny Grisel 2006-12-31 j-b-m * src/modules/avformat/producer_avformat.c, src/modules/vorbis/producer_vorbis.c: Read metadata from avformat and vorbis producers, using basic structure like: meta.attr.metadata_name.markup=metadata_value 2006-12-08 ddennedy * ChangeLog, configure, src/framework/mlt_consumer.h, src/framework/mlt_filter.h, src/framework/mlt_frame.h, src/framework/mlt_geometry.h, src/framework/mlt_multitrack.h, src/framework/mlt_producer.h, src/framework/mlt_service.h, src/framework/mlt_transition.h: Applied patch from Stephane Fillod to make configure run with bash since it uses bash-specific features. Also, patches headers to comments for pedantic compilation. 2006-11-18 j-b-m * src/modules/core/producer_framebuffer.c, src/modules/core/producer_framebuffer.h: Fix header + add freeze feature * src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/producer_framebuffer.c, src/modules/core/producer_framebuffer.h: New framebuffer producer. Provides slowmotion, reverse playing and stroboscope effect 2006-09-28 dezeroex * src/modules/avformat/producer_avformat.c, src/modules/dv/producer_libdv.c: Patch supplied by Jean-Baptiste. * src/modules/motion_est/filter_motion_est.c, src/modules/motion_est/sad_sse.h: Zypher's amd64 patch. http://sources.gentoo.org/viewcvs.py/gentoo-x86/media-libs/mlt/files/ 2006-09-25 ddennedy * ChangeLog, src/modules/sdl/Makefile: fix SDL compilation on some systems using modular x.org 2006-08-14 lilo_booter * src/modules/vmfx/Makefile, src/modules/vmfx/configure, src/modules/vmfx/factory.c, src/modules/vmfx/filter_mono.c: + A mono filter for mask generation (not v. useful) * src/modules/vmfx/filter_chroma.c, src/modules/vmfx/filter_chroma_hold.c: + Correction to uneven chroma samples 2006-05-22 ddennedy * src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/modules/gtk2/producer_pixbuf.c: apply patch from Jean Baptiste to add rgb24a support to producer_pixbuf 2006-03-29 lilo_booter * src/modules/qimage/Makefile, src/modules/qimage/configure, src/modules/qimage/qimage_wrapper.cpp: + And a fix for the PPC darwin * src/framework/mlt_frame.c, src/framework/mlt_frame.h: + Sigh - big endian issues on ppc based macs * src/modules/fezzik.dict, src/modules/qimage/Makefile, src/modules/qimage/configure, src/modules/qimage/factory.c, src/modules/qimage/producer_qimage.c, src/modules/qimage/producer_qimage.h, src/modules/qimage/qimage_wrapper.cpp, src/modules/qimage/qimage_wrapper.h: + QImage module added - default is still GTK2 when available * src/framework/mlt_frame.c, src/framework/mlt_frame.h: + Preparation for a QT image loader (to allow optional and functionally equivalent qt or gtk2 usage for image loading) 2006-03-28 lilo_booter * src/framework/mlt_properties.c, src/framework/mlt_properties.h: + Adds a utility function for listing files in a directory (aids with cross platform support) 2006-03-02 ddennedy * docs/services.txt, src/framework/mlt_manager.h, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_mono.c, src/modules/core/filter_mono.h: added mono audio filter 2006-02-23 lilo_booter * mlt++/mlt++.sln, mlt++/mlt++.vcproj, mlt++/src/Mlt.h, mlt++/src/MltConsumer.h, mlt++/src/MltDeque.h, mlt++/src/MltEvent.h, mlt++/src/MltFactory.cpp, mlt++/src/MltFactory.h, mlt++/src/MltField.h, mlt++/src/MltFilter.h, mlt++/src/MltFilteredConsumer.h, mlt++/src/MltFilteredProducer.h, mlt++/src/MltFrame.cpp, mlt++/src/MltFrame.h, mlt++/src/MltGeometry.h, mlt++/src/MltMultitrack.h, mlt++/src/MltParser.h, mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h, mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h, mlt++/src/MltPushConsumer.h, mlt++/src/MltService.h, mlt++/src/MltTokeniser.h, mlt++/src/MltTractor.h, mlt++/src/MltTransition.h: + Win32 port - dev studio is required to avoid issues with C++ ABI compatibility + Fix for image render in NTSC NB: mlt patch to follow (this one isn't much use without it :-)) - mlt build is purely mingw32 of course * src/framework/mlt_frame.c, src/framework/mlt_frame.h: + Alternative between track mixing mechanism (using a low pass filter) 2006-02-15 ddennedy * docs/dvcp.txt, docs/inigo.txt: minor fixes 2006-01-08 ddennedy * src/modules/feeds/NTSC/data_fx.properties, src/modules/feeds/NTSC/obscure.properties: fix comment/docu typo 2005-12-05 lilo_booter * debian/control, debian/rules, src/miracle/Makefile: + Fix for libmiracle and alternative deb packaging * mlt++/configure, mlt++/src/Makefile: + Fix for Darwin and soname logic * src/framework/Makefile, src/miracle/Makefile, src/modules/avformat/configure, src/valerie/Makefile: + Fix for Darwin and soname logic * mlt++/debian/changelog, mlt++/debian/control, mlt++/debian/copyright, mlt++/debian/rules: + Functional debian build rules * debian/changelog, debian/control, debian/copyright, debian/rules: + Functional debian build rules * mlt++/Makefile, mlt++/configure, mlt++/src/Makefile, mlt++/test/Makefile: + MLT++ updates for 0.2.1 - distclean corrected, soname usage in linking * Makefile, configure, src/albino/Makefile, src/framework/Makefile, src/humperdink/Makefile, src/inigo/Makefile, src/miracle/Makefile, src/modules/Makefile, src/modules/avformat/Makefile, src/modules/core/Makefile, src/modules/dv/Makefile, src/modules/feeds/Makefile, src/modules/fezzik/Makefile, src/modules/gtk2/Makefile, src/modules/inigo/Makefile, src/modules/jackrack/Makefile, src/modules/kino/Makefile, src/modules/lumas/Makefile, src/modules/motion_est/Makefile, src/modules/normalize/Makefile, src/modules/plus/Makefile, src/modules/resample/Makefile, src/modules/sdl/Makefile, src/modules/sox/Makefile, src/modules/valerie/Makefile, src/modules/vmfx/Makefile, src/modules/vorbis/Makefile, src/modules/westley/Makefile, src/modules/xine/Makefile, src/valerie/Makefile: + Final updates for 0.2.1 - distclean corrected, soname usage in linking, version bump 2005-11-29 lilo_booter * src/framework/configure, src/miracle/configure, src/valerie/configure: + More fixes for lib64 * mlt++/Makefile, mlt++/configure: + Correction to a typo * mlt++/configure, mlt++/src/Makefile: + Added a --libdir switch to the configure and build and fixed test case compilation * Makefile, configure, src/framework/Makefile, src/miracle/Makefile, src/valerie/Makefile: + Added a --libdir switch to the configure and build 2005-11-10 lilo_booter * mlt++/Makefile, mlt++/src/Makefile: + DESTDIR patch from Anthony Green (green at redhat dot com) - many thanks :-) * Makefile, src/albino/Makefile, src/framework/Makefile, src/humperdink/Makefile, src/inigo/Makefile, src/miracle/Makefile, src/modules/Makefile, src/modules/avformat/Makefile, src/modules/core/Makefile, src/modules/dv/Makefile, src/modules/feeds/Makefile, src/modules/fezzik/Makefile, src/modules/gtk2/Makefile, src/modules/inigo/Makefile, src/modules/jackrack/Makefile, src/modules/kino/Makefile, src/modules/lumas/Makefile, src/modules/motion_est/Makefile, src/modules/normalize/Makefile, src/modules/plus/Makefile, src/modules/resample/Makefile, src/modules/sdl/Makefile, src/modules/sox/Makefile, src/modules/valerie/Makefile, src/modules/vmfx/Makefile, src/modules/vorbis/Makefile, src/modules/westley/Makefile, src/modules/xine/Makefile, src/valerie/Makefile: + DESTDIR patch from Anthony Green (green at redhat dot com) - many thanks :-) * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: Allows aac output, corrects ntsc sample collection, and picks up known info streams 2005-10-25 lilo_booter * src/modules/core/consumer_null.c, .../motion_est/filter_autotrack_rectangle.c, src/modules/sdl/consumer_sdl.c: src/modules/core/consumer_null.c src/modules/sdl/consumer_sdl.c + Terminate on pause functionality src/modules/motion_est/filter_autotrack_rectangle.c + Ensures that tracked area remains valid (out of bounds was causing core dumps) ? Currently, width/height is preserved on boundaries, but maybe it should shrink/grow? 2005-10-24 dezeroex * src/modules/motion_est/Makefile, src/modules/motion_est/factory.c, src/modules/motion_est/filter_motion_est.c, src/modules/motion_est/filter_motion_est.h, src/modules/motion_est/producer_slowmotion.c: Import the proof of concept slow motion producer. It provides basic slow motion through frame repeats and a more advanced interpolation. 2005-10-10 lilo_booter * src/framework/mlt_frame.c, src/framework/mlt_tractor.c, src/modules/core/filter_luma.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c: + Added an option to override alignment and transparent borders for compositing 2005-10-03 lilo_booter * src/modules/sdl/configure, src/modules/sdl/factory.c: + Correction for uninstalled sdl image lib * mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h: OS/X gcc/g++ 4.x fix * src/framework/mlt_events.h, src/framework/mlt_types.h: gcc/g++ 4.x fix * src/humperdink/client.c, src/humperdink/io.c, src/humperdink/io.h, src/humperdink/remote.c, src/inigo/io.c: Remove OS/X warning re: get_string * src/framework/mlt.h, src/inigo/inigo.c: + Whoops - removed dependency on sdl in the framework for darwin * mlt++/configure, mlt++/src/Makefile, mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h, mlt++/test/Makefile: + Whoops - had forgotten these OS/X patches... * src/modules/fezzik.dict, src/modules/sdl/Makefile, src/modules/sdl/configure, src/modules/sdl/factory.c, src/modules/sdl/producer_sdl_image.c: + Added producer_sdl_image as an alternative image and image sequence producer 2005-09-28 lilo_booter * mlt++/src/Makefile, mlt++/src/Mlt.h, mlt++/src/MltPushConsumer.cpp, mlt++/src/MltPushConsumer.h: + Added a push based consumer wrapper * src/framework/mlt_frame.c, src/framework/mlt_tractor.c, src/modules/core/filter_rescale.c, src/modules/core/filter_resize.c, src/modules/core/filter_watermark.c, src/modules/core/producer_colour.c, src/modules/core/transition_composite.c, src/modules/feeds/PAL/etv.properties: src/framework/mlt_frame.c + Corrections for resizing images and alpha (uneven widths) src/framework/mlt_tractor.c + Added an output aspect ratio (being the aspect ratio of the background) src/modules/core/filter_rescale.c + Force a rescale of the alpha in parallel with image src/modules/core/filter_resize.c + Rounding errors corrections src/modules/core/filter_watermark.c + Propogation of output aspect ratio in reverse case src/modules/core/producer_colour.c + Reassign aspect ratio after get_image src/modules/core/transition_composite.c + More uneven width corrections + Use of output aspect ratio when available src/modules/feeds/PAL/etv.properties + Temporary work around to keep composites correct 2005-09-23 lilo_booter * src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_avdeinterlace.c, src/modules/avformat/producer_avformat.c: filter_avcolour_space.c + Correction for uneven width filter_avdeinterlace.c + Correction for cases were the interlace state of frame is only known after rendering producer_avformat.c + Corrections for uneven width + Corrections for state propogation of top field first and interlaced state 2005-09-15 lilo_booter * src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/framework/mlt_producer.c, src/modules/avformat/configure, src/modules/avformat/producer_avformat.c, src/modules/core/filter_mirror.c, src/modules/core/producer_colour.c, src/modules/core/transition_composite.c, src/modules/plus/filter_sepia.c, src/modules/plus/transition_affine.c, src/modules/sdl/consumer_sdl.c: src/framework/mlt_frame.c + Removed unecessary even pixel position and width dependency + Rewrote resize methods to accomodate uneven widths src/framework/mlt_frame.h + Correct RGB2YUV - now 2^10 based and range checks removed (not needed) src/framework/mlt_producer.c + Check for unspecified eof property src/modules/avformat/producer_avformat.c + Provide forced aspect ratio property src/modules/core/filter_mirror.c + Correction for uneven width src/modules/core/producer_colour.c + Corrections for aspect ratio (default to 0) and allow override + Corrections for uneven width src/modules/core/transition_composite.c + Corrections for uneven pixel position and width + Removed deprecated operator code src/modules/plus/filter_sepia.c + Corrections for uneven width src/modules/plus/transition_affine.c + Corrections for uneven width src/modules/sdl/consumer_sdl.c + Corrections for uneven width 2005-09-07 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/framework/mlt_tractor.c, src/framework/mlt_types.h, src/modules/avformat/filter_avcolour_space.c, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_luma.c, src/modules/core/transition_composite.c, src/modules/gtk2/producer_pixbuf.c, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: src/framework/mlt_consumer.c + Added capabilities to allow the application to handle images via the consumer-frame-show event + Added cabilities to allow the application to control the image format src/framework/mlt_frame.c + Long standing discrepancy resolved - image format is now stored on the frame object src/framework/mlt_tractor.c src/framework/mlt_types.h + Added mlt_image_opengl which is supposed to provide an rgb image swapped around for the platform src/framework/mlt_frame.h + Added a basic YUV2RGB macro src/modules/avformat/filter_avcolour_space.c + Added a converter for the opengl swapped RGB image + Corrected support for rgb24a requests src/modules/core/configure src/modules/core/factory.c + Added an alias for color (since it seems to trouble so many people) src/modules/core/filter_luma.c + Added the format property to the generated frame src/modules/core/transition_composite.c + Added the format property to the generated frame src/modules/gtk2/producer_pixbuf.c + Swapped some properties to hidden from the serialiser src/modules/sdl/consumer_sdl.c + Support for application provided previews and colour space conversion src/modules/sdl/consumer_sdl_preview.c + Partial switch to mlt_properties_pass_list + Application provided preview support added src/modules/sdl/consumer_sdl_still.c + Application provided preview support added 2005-09-01 lilo_booter * src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_still.c: consumer_sdl.c consumer_sdl_still.c + Corrections to silly mistake regarding initialisation from previous checkin * src/modules/vmfx/Makefile, src/modules/vmfx/configure, src/modules/vmfx/factory.c, src/modules/vmfx/filter_chroma.c, src/modules/vmfx/filter_chroma.h, src/modules/vmfx/filter_chroma_hold.c, src/modules/vmfx/filter_chroma_hold.h, src/modules/vmfx/filter_shape.c, src/modules/vmfx/filter_shape.h, src/modules/vmfx/producer_pgm.c, src/modules/vmfx/producer_pgm.h: + Changed license of plugins to LGPL + Added a chroma hold filter + Small optimisation/correction to chroma filter 2005-08-29 lilo_booter * src/modules/lumas/Makefile, src/modules/sdl/consumer_sdl.c: lumas/Makefile + Correction for non-gui app build on darwin lumas/luma.c + Handle sdl events sdl/consumer_sdl.c + Audio on Darwin * src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: src/modules/sdl/consumer_sdl.c src/modules/sdl/consumer_sdl_preview.c src/modules/sdl/consumer_sdl_still.c + Corrections to preview mode switching * configure, src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: configure + Correction to ldflags for Darwin src/modules/avformat/Makefile src/modules/avformat/configure + Correction for avformat on Darwin src/modules/sdl/consumer_sdl.c src/modules/sdl/consumer_sdl_preview.c src/modules/sdl/consumer_sdl_still.c + Forgot to create the surface on the start (doh) * configure, src/framework/mlt.h, src/inigo/inigo.c, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: configure + Darwin sdl linking and cflags on all use of mlt (annoying, but looks unavoidable) src/framework/mlt.h + Include sdl header on Darwin src/inigo/inigo.c + Correction for Darwin key reading from terminal src/modules/sdl/consumer_sdl.c src/modules/sdl/consumer_sdl_preview.c src/modules/sdl/consumer_sdl_still.c + Moved initialisation of sdl components to the start/stop methods (Darwin requirement) 2005-08-28 lilo_booter * src/modules/vmfx/Makefile, src/modules/vmfx/configure, src/modules/vmfx/factory.c, src/modules/vmfx/filter_chroma.c, src/modules/vmfx/filter_chroma.h: + Added rudimentary chroma to alpha filter (optimised on green by default) 2005-08-26 lilo_booter * src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.h: src/framework/mlt_properties.c src/framework/mlt_properties.h + Added get and set for int64_t src/framework/mlt_property.h + Corrected int64_t 2005-08-26 dezeroex * src/modules/motion_est/README, .../motion_est/filter_autotrack_rectangle.c: Add the obscure=1 option to filter_autotrack_rectangle and update the README with an example. 2005-08-24 lilo_booter * src/modules/fezzik.dict, src/modules/vmfx/Makefile, src/modules/vmfx/configure, src/modules/vmfx/factory.c, src/modules/vmfx/filter_shape.c, src/modules/vmfx/filter_shape.h, src/modules/vmfx/producer_pgm.c, src/modules/vmfx/producer_pgm.h: + Added VMFX module + New filter (shape) which provides alpha manipulations and an alternative wipe mechanism + New producer (pgm) which provides basic functionality for portable grey maps 2005-08-21 dezeroex * src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_property.h: Introduce some more civilized ways to copy properties. See code comments for usage. 2005-08-19 lilo_booter * src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c: producer_pango.c producer_pixbuf.c + More efficient use of pixbuf objects and sequences/mlt pango lists 2005-08-15 dezeroex * src/framework/mlt_frame.c, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_producer.c, src/framework/mlt_property.c, src/framework/mlt_types.h: Fix build errors caused by the (hypothetical) conversion of mlt_position from an int to a float, preserving original behavior. * src/inigo/inigo.c, src/modules/core/filter_luma.c, src/modules/motion_est/filter_crop_detect.c, src/modules/sdl/consumer_sdl.c: Fix build errors caused by the (hypothetical) conversion of mlt_position from an int to a float, preserving original behavior. 2005-08-04 dezeroex * src/modules/avformat/Makefile, src/modules/avformat/configure: ffmpeg split of the libavutil library. 2005-07-30 dezeroex * src/modules/motion_est/README, src/modules/motion_est/filter_motion_est.c: Added a README file with lots of juicy info. Added a denoise motion vectors function, enabled by default; the results seem very good. Removed some unused development code. 2005-07-26 lilo_booter * mlt++/swig/Makefile, mlt++/swig/configure, mlt++/swig/perl/Makefile.PL, mlt++/swig/python/build, mlt++/swig/tcl/build: + Cleaned up swig build so it doesn't require an mlt++ install first - Temporarily disabled java 2005-07-25 lilo_booter * src/modules/kino/avi.cc, src/modules/kino/avi.h, src/modules/kino/riff.cc, src/modules/kino/riff.h: + fixes for opendml dv avi 2005-07-21 lilo_booter * src/framework/mlt_playlist.c, src/framework/mlt_service.c: - Remove warnings 2005-07-20 lilo_booter * src/framework/mlt_filter.c, src/framework/mlt_service.c: mlt_filter.c mlt_service.c + Filter disable property 2005-07-19 lilo_booter * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: consumer_avformat.c producer_avformat.c + Sync with current ffmpeg CVS - PLEASE UPDATE FFMPEG FIRST 2005-07-18 lilo_booter * src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c: producer_pango.c + Added cloning + Added the very silly .mpl (MLT Pango List) format [details to follow] + Corrected invalid content producer_pixbuf.c + Corrected invalid content 2005-07-16 lilo_booter * src/framework/mlt_frame.c, src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/framework/mlt_service.c, src/framework/mlt_tractor.c, src/modules/core/filter_resize.c, src/modules/core/filter_transition.c, src/modules/core/transition_composite.c, src/modules/dv/producer_libdv.c: rc/framework/mlt_frame.c + image_count added to assist the 'transition filter' in knowing when to act... src/framework/mlt_playlist.c + Complete rework of fx cuts - now only the fx are output on a frame src/framework/mlt_producer.c + Aspect ratio of cuts inherited from parent src/framework/mlt_service.c + Get frame reworked and cleaned up src/framework/mlt_tractor.c - Removed erroneous width/height pass down prior to image fetching + Corrected types on other properties for pass down + Complete rework of fx cuts - they're now received as producer-less frames from a track + Added image_count logic for transition filter assistance src/modules/core/filter_resize.c + Added state retention of aspect ratio (may withdraw this later - it assumes producer knows a/r on frame creation/prior to image fetch) src/modules/core/filter_transition.c + Checks that two images are available before processing + Checks test image/audio cases src/modules/core/transition_composite.c + Major correction in aspect ratio handling (the b frame image is 'distorted' to the consumers aspect ratio) + Minor clean up of silly and/or/xor - now have 'operator=[and/or/xor]' (more clean up to follow) src/modules/dv/producer_libdv.c + Frame stored width and height are no longer assumed to be 'safe' here (investigating) 2005-07-10 lilo_booter * src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: consumer_sdl_preview.c consumer_sdl_still.c + Fixes a deadlock condition * src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/framework/mlt_repository.c, src/modules/kino/filehandler.cc, src/modules/kino/filehandler.h: framework/mlt_frame.c framework/mlt_frame.h + Added sample calculator (samples to current frame) framework/mlt_repository.c + Symbols exported from plugins modules/kino/filehandler.cc modules/kino/filehandler.h + Audio handling of dv mov 2005-07-09 dezeroex * configure, src/modules/motion_est/configure: Prevent motion estimation components from building unless requested. 2005-07-08 dezeroex * src/modules/motion_est/Makefile, src/modules/motion_est/configure: removed a debugging target. * src/modules/motion_est/Makefile, src/modules/motion_est/arrow_code.c, src/modules/motion_est/arrow_code.h, src/modules/motion_est/configure, src/modules/motion_est/factory.c, .../motion_est/filter_autotrack_rectangle.c, src/modules/motion_est/filter_crop_detect.c, src/modules/motion_est/filter_motion_est.c, src/modules/motion_est/filter_motion_est.h, src/modules/motion_est/filter_vismv.c, src/modules/motion_est/sad_sse.h: Initial import of the motion estimation filter. 2005-07-05 lilo_booter * src/framework/mlt_frame.c, src/framework/mlt_playlist.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/fezzik.dict, src/modules/gtk2/producer_pixbuf.c, src/modules/westley/producer_westley.c: src/framework/mlt_frame.c + Correction for aspect ratio of synthesized test card src/framework/mlt_playlist.c + Special case for handling fx cuts src/modules/fezzik.dict + Convenience jfx and jef extensions for jahshaka src/modules/core/transition_composite.c + Ensure that scaling and correct image extraction is handled src/modules/core/transition_luma.c + Ensure that scaling and correct image extraction is handled src/modules/gtk2/producer_pixbuf.c + Allow user overrides for progressive and aspect_ration src/modules/westley/producer_westley.c + Special case for fx cuts 2005-06-27 lilo_booter * mlt++/CUSTOMISING, mlt++/test/server.cpp: CUSTOMISING + Replaced TBD for frame rendering notification event test/server.cpp + Added an example frame rendering callback that removes all shotcut related fx 2005-06-26 lilo_booter * src/modules/core/filter_transition.c, src/modules/core/filter_transition.h: src/modules/core/filter_transition.c src/modules/core/filter_transition.h + Initial release * src/framework/mlt_deque.c, src/framework/mlt_deque.h, src/framework/mlt_frame.c, src/framework/mlt_tractor.c, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/transition_composite.c, src/modules/core/transition_composite.h: src/framework/mlt_deque.c src/framework/mlt_deque.h + Added support for doubles src/framework/mlt_frame.c + Switched order of source/dest audio mix extraction (for transition as filter usage) src/framework/mlt_tractor.c - Removed warning introduced from previous checkin (missing ctype.h) + Temporary work around to allow frames to carry multiple frames (for transition as filter usage) src/modules/core/Makefile src/modules/core/configure src/modules/core/factory.c + Support for new transition filter :-) src/modules/core/transition_composite.c src/modules/core/transition_composite.h - Removed frame properties dependence for process/get_image state communication + Extended alpha blending modes to 'and' and 'xor' logic (may change property triggering soon) + Provided support for transition as filter usage + Cleaned up public copy region functionality * mlt++/CUSTOMISING, mlt++/swig/ruby/thumbs.rb: CUSTOMISING + Added an example of how to hide a track on reception swig/ruby/thumbs.rb + Changed generator to run, rather than sleep and poll 2005-06-24 lilo_booter * src/framework/mlt_geometry.c, src/framework/mlt_tractor.c, src/modules/core/transition_composite.c, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_still.c: src/framework/mlt_geometry.c src/modules/core/transition_composite.c src/modules/sdl/consumer_sdl.c src/modules/sdl/consumer_sdl_still.c + replaced floats with doubles (attempt to avoid rounding errors?) src/framework/mlt_tractor.c + corrections for fx_cuts (allows animated fx) 2005-06-22 lilo_booter * src/framework/mlt_frame.h, src/framework/mlt_tractor.c, src/modules/core/filter_watermark.c, src/modules/core/producer_noise.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/plus/filter_affine.c, src/modules/plus/transition_affine.c: src/framework/mlt_consumer.c + Attempt to make all frames have the correct aspect_ratio (works in many but not all cases) src/framework/mlt_frame.h + Provide macro access to the video and image RPN queues src/framework/mlt_tractor.c + Provides orphaned filters src/modules/core/producer_noise.c - remove specification of aspect ratio src/modules/core/filter_watermark.c src/modules/core/transition_composite.c src/modules/core/transition_luma.c src/modules/plus/filter_affine.c src/modules/plus/transition_affine.c + Corrections for frames with an aspect ratio = 0 (supplement to mlt_consumer mod) 2005-06-21 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_producer.c, src/inigo/inigo.c, src/modules/avformat/consumer_avformat.c, src/modules/core/filter_resize.c, src/modules/core/producer_colour.c, src/modules/core/producer_noise.c, src/modules/dv/consumer_libdv.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/kino/Makefile, src/modules/kino/avi.cc, src/modules/kino/avi.h, src/modules/kino/configure, src/modules/kino/filehandler.cc, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: src/framework/mlt_consumer.c src/framework/mlt_consumer.h + Added a general profile handling for size, aspect ratio and display ratio src/framework/mlt_producer.c + Correction to aspect ratio properties src/inigo/inigo.c + Minimalist support for sdl_preview (still not very good) src/modules/avformat/consumer_avformat.c + Takes consumer profile into account src/modules/core/filter_resize.c + Corrections for synthesised producers and aspect ratio (inherits from consumer) src/modules/core/producer_colour.c src/modules/core/producer_noise.c src/modules/gtk2/producer_pango.c + Ensures that resize picks up consumer aspect ratio src/modules/dv/consumer_libdv.c + Honour wide screen output src/modules/gtk2/producer_pixbuf.c + Correction for 1:1 aspect ratio src/modules/kino/Makefile src/modules/kino/avi.cc src/modules/kino/avi.h src/modules/kino/configure src/modules/kino/filehandler.cc + Attempt to allow mov dv files to provide audio src/modules/sdl/consumer_sdl.c src/modules/sdl/consumer_sdl_preview.c src/modules/sdl/consumer_sdl_still.c + Takes consumer profile into account 2005-06-04 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_tractor.c, src/modules/avformat/filter_avdeinterlace.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/xine/filter_deinterlace.c: Consumer deinterlace_method property added * src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_avdeinterlace.c, src/modules/core/filter_resize.c, src/modules/xine/filter_deinterlace.c: Sanity checks for normalising filters 2005-05-28 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_factory.c, src/framework/mlt_producer.c: Frame rate properites and factory initialisation 2005-05-24 lilo_booter * src/modules/kino/filehandler.cc, src/modules/kino/filehandler.h: DVCPRO fix 2005-05-09 lilo_booter * src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/avformat/factory.c: Build modification to ffmpeg/avformat 2005-05-04 lilo_booter * src/modules/dv/configure, src/modules/gtk2/configure, src/modules/jackrack/configure, src/modules/kino/configure, src/modules/resample/configure, src/modules/sdl/configure, src/modules/sox/configure, src/modules/vorbis/configure, src/modules/westley/configure, src/modules/xine/configure: Bourne shell compliance * src/modules/avformat/Makefile, src/modules/avformat/configure: Corrections to --avformat-cvs option * src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/avformat/consumer_avformat.c, src/modules/avformat/factory.c, src/modules/avformat/producer_avformat.c: FFMPEG revisions to match current CVS (part 1) 2005-04-22 ddennedy * docs/services.txt, src/modules/configure, src/modules/jackrack/Makefile, src/modules/jackrack/configure, src/modules/jackrack/control_message.h, src/modules/jackrack/factory.c, src/modules/jackrack/filter_jackrack.c, src/modules/jackrack/filter_ladspa.c, src/modules/jackrack/filter_ladspa.h, src/modules/jackrack/jack_rack.c, src/modules/jackrack/jack_rack.h, src/modules/jackrack/plugin.c, src/modules/jackrack/plugin.h, src/modules/jackrack/plugin_desc.c, src/modules/jackrack/plugin_mgr.c, src/modules/jackrack/plugin_mgr.h, src/modules/jackrack/process.c, src/modules/jackrack/process.h, src/modules/jackrack/ui.c, src/modules/jackrack/ui.h: cleanup and reduce code in jackrack support code and add new jack-less filter_ladspa. 2005-04-15 lilo_booter * src/modules/kino/Makefile, src/modules/kino/avi.cc, src/modules/kino/avi.h, src/modules/kino/configure, src/modules/kino/endian_types.h, src/modules/kino/error.cc, src/modules/kino/error.h, src/modules/kino/factory.c, src/modules/kino/filehandler.cc, src/modules/kino/filehandler.h, src/modules/kino/kino_wrapper.cc, src/modules/kino/kino_wrapper.h, src/modules/kino/producer_kino.c, src/modules/kino/producer_kino.h, src/modules/kino/riff.cc, src/modules/kino/riff.h: Initial version * src/modules/dv/producer_libdv.c, src/modules/fezzik.dict: Preparation for kino support 2005-04-14 dezeroex * src/modules/sdl/Makefile, src/modules/sdl/consumer_sdl_still.c: Build fixes. * configure, src/albino/albino.c, src/inigo/inigo.c, src/miracle/miracle.c: OS X uses -DDARWIN in /System/Library/Frameworks/CoreFoundation.framework/Headers/CFBase.h; This in combination with #include caused compilation errors while porting consumer_sdl to OS X. 2005-04-13 lilo_booter * src/modules/sox/Makefile, src/modules/sox/configure: Disable sox when unavailable * src/modules/dv/configure, src/modules/vorbis/configure: Disable libdv when unavailable * src/modules/gtk2/Makefile, src/modules/gtk2/configure, src/modules/gtk2/factory.c: Conditional compilation of gtk2 components 2005-04-12 lilo_booter * configure, setenv, src/albino/Makefile, src/albino/albino.c, src/framework/Makefile, src/humperdink/Makefile, src/humperdink/io.c, src/inigo/Makefile, src/inigo/inigo.c, src/inigo/io.c, src/miracle/Makefile, src/miracle/miracle.c, src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/core/Makefile, src/modules/core/configure, src/modules/dv/Makefile, src/modules/dv/configure, src/modules/fezzik/Makefile, src/modules/fezzik/configure, src/modules/gtk2/Makefile, src/modules/gtk2/configure, src/modules/inigo/Makefile, src/modules/inigo/configure, src/modules/jackrack/Makefile, src/modules/jackrack/configure, src/modules/normalize/Makefile, src/modules/normalize/configure, src/modules/plus/Makefile, src/modules/plus/configure, src/modules/resample/Makefile, src/modules/resample/configure, src/modules/sdl/Makefile, src/modules/sdl/configure, src/modules/sox/Makefile, src/modules/sox/configure, src/modules/valerie/Makefile, src/modules/valerie/configure, src/modules/vorbis/Makefile, src/modules/vorbis/configure, src/modules/westley/Makefile, src/modules/westley/configure, src/modules/xine/Makefile, src/modules/xine/configure, src/tests/Makefile, src/valerie/Makefile, src/valerie/valerie_socket.c: OS/X Patch from Torsten Spindler * src/framework/mlt_factory.c, src/framework/mlt_factory.h, src/framework/mlt_repository.c, src/framework/mlt_repository.h: More const usage 2005-04-09 lilo_booter * src/framework/mlt_consumer.c, src/modules/gtk2/Makefile, src/modules/resample/filter_resample.c: Auto deinterlace on pause, fix for audio resampling/test audio and MMX checks in gtk2 2005-04-05 lilo_booter * src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/avformat/factory.c, src/modules/avformat/filter_avresample.c, src/modules/gtk2/Makefile, src/modules/jackrack/filter_jackrack.c, src/modules/sox/filter_sox.c: avformat-cvs build fix and audio filter correction 2005-04-05 ddennedy * src/albino/albino.c, src/miracle/miracle.c: make miracle and albino local use fifo instead of rr rt schedule * src/albino/albino.c, src/framework/mlt_consumer.c, src/inigo/inigo.c, src/miracle/miracle.c, src/miracle/miracle_server.c, src/modules/avformat/consumer_avformat.c, src/modules/core/consumer_null.c, src/modules/dv/consumer_libdv.c, src/modules/dv/producer_libdv.c, src/modules/fezzik/producer_hold.c, src/modules/gtk2/producer_pixbuf.c, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c, src/modules/xine/filter_deinterlace.c: realtime scheduling updates; suppress libdv errors; add frame property deinterlace_method; default producer_hold to use onefield; add begin property to producer_pixbuf 2005-03-16 lilo_booter * mlt++/CUSTOMISING, mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h, mlt++/src/MltResponse.cpp, mlt++/src/MltResponse.h, mlt++/test/server.cpp: Server customisation * src/framework/mlt_consumer.c, src/framework/mlt_producer.c: Frame rendering event 2005-03-13 lilo_booter * docs/dvcp.txt, src/miracle/miracle_local.c, src/miracle/miracle_unit.c, src/miracle/miracle_unit.h, src/miracle/miracle_unit_commands.c, src/miracle/miracle_unit_commands.h, src/modules/avformat/factory.c, src/valerie/valerie.c, src/valerie/valerie.h: Threading considerations and DVCP WIPE introduced 2005-03-09 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_producer.c, src/modules/core/transition_composite.c, src/modules/plus/transition_affine.c: Minor corrections and more affine experiments 2005-02-21 lilo_booter * src/miracle/miracle_unit.c, src/modules/avformat/consumer_avformat.c: Minor mods to playout via avformat and miracle unit generation on an xfer 2005-02-18 lilo_booter * src/framework/mlt_frame.c, src/modules/core/producer_colour.c, src/modules/core/transition_composite.c, src/modules/plus/transition_affine.c: Minor corrections with alpha and affines 2005-02-12 lilo_booter * src/framework/mlt_producer.c, src/framework/mlt_tractor.c, src/modules/core/producer_colour.c, src/modules/core/transition_composite.c, src/modules/feeds/PAL/etv.properties, src/modules/gtk2/producer_pango.c, src/modules/plus/filter_affine.c, src/modules/plus/transition_affine.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: Alphas and global feeds revisted 2005-02-06 lilo_booter * src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: Speed switch corrections 2005-02-05 lilo_booter * src/modules/core/transition_composite.c, src/modules/core/transition_luma.c: Optional 8 or 16 bit pgm or png lumas; fixes for non-existence * src/modules/lumas/configure, src/modules/lumas/create_lumas: Optional 8 or 16 bit pgm or png 2005-02-03 lilo_booter * src/modules/plus/filter_affine.c, src/modules/plus/transition_affine.c: more affine silliness 2005-02-02 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_frame.c, src/framework/mlt_tractor.c, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: SMP/HT fixes 2005-02-01 lilo_booter * src/framework/mlt_deque.c, src/framework/mlt_deque.h, src/framework/mlt_frame.c, src/framework/mlt_frame.h: 64 bit fix and deque int holding 2005-01-31 lilo_booter * src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: Consumer reworked * src/modules/feeds/PAL/border.properties, src/modules/feeds/PAL/data_fx.properties: Minor corrections * src/framework/mlt_filter.c, src/framework/mlt_service.c: Wild card filter tracks 2005-01-25 lilo_booter * src/modules/feeds/PAL/border.properties, src/modules/feeds/PAL/example.properties: Test case feeds added * src/modules/avformat/filter_avresample.c, src/modules/avformat/producer_avformat.c, src/modules/core/filter_channelcopy.c, src/modules/core/filter_watermark.c, src/modules/core/producer_noise.c, src/modules/core/producer_ppm.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/core/transition_mix.c, src/modules/core/transition_region.c, src/modules/dv/producer_libdv.c, src/modules/feeds/PAL/etv.properties, src/modules/jackrack/filter_jackrack.c, src/modules/normalize/filter_volume.c, src/modules/plus/transition_affine.c, src/modules/resample/filter_resample.c, src/modules/sox/filter_sox.c, src/modules/vorbis/producer_vorbis.c: Remaining audio handling switched to stacks; Minor corrections to compositing and mixing; localisation for pango * src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: Localised data storage and utf-8 properties * src/framework/mlt_consumer.c, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/framework/mlt_producer.c, src/framework/mlt_tractor.c, src/framework/mlt_transition.c, src/framework/mlt_transition.h: Transitions reworked (always_active capabilities); remaining audio handling switched to stacks 2005-01-19 lilo_booter * src/modules/feeds/PAL/etv.properties, src/modules/gtk2/producer_pango.c: iconv fixes 2005-01-16 lilo_booter * demo/mlt_slideshow_black, docs/services.txt, src/modules/core/transition_composite.c, src/modules/feeds/PAL/etv.properties: Minor modifications to compositing options and etv fx 2005-01-14 lilo_booter * mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h: Const string usage in properties * demo/demo, demo/mlt_watermark, src/framework/mlt_producer.c, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/framework/mlt_tractor.c, src/modules/core/filter_data_show.c, src/modules/core/filter_obscure.c, src/modules/core/transition_composite.c, src/modules/core/transition_region.c, src/modules/feeds/PAL/data_fx.properties, src/modules/feeds/PAL/obscure.properties, src/modules/fezzik.ini, src/modules/gtk2/producer_pango.c: Sundry minor fixes and optimisations 2005-01-03 lilo_booter * mlt++/src/MltGeometry.cpp, mlt++/src/MltGeometry.h: Next/Prev key extraction * src/framework/mlt_geometry.c, src/framework/mlt_geometry.h: Next/Prev key extraction * src/modules/feeds/PAL/data_fx.properties, src/modules/feeds/PAL/obscure.properties: Smaller mask width/height * mlt++/src/MltMiracle.cpp, mlt++/src/MltMiracle.h, mlt++/swig/mltpp.i: Fetch unit from miracle server * src/miracle/miracle_server.c, src/miracle/miracle_server.h: Fetch unit from miracle server 2004-12-31 lilo_booter * demo/demo.ini, src/framework/mlt_producer.c, src/framework/mlt_properties.c, src/framework/mlt_property.c, src/framework/mlt_transition.c: Corrections after valgrinding * demo/demo.ini, demo/mlt_attributes, demo/mlt_news, demo/mlt_slideshow, demo/mlt_slideshow_black, demo/mlt_squeeze, demo/mlt_ticker, demo/mlt_watermark: Corrections and minor fixes to use new geometry spec; couple of new test cases * src/modules/core/filter_data_feed.c, src/modules/core/filter_data_show.c, src/modules/core/filter_watermark.c, src/modules/core/transition_composite.c, src/modules/inigo/producer_inigo.c: Sundry minor updates * src/modules/feeds/NTSC/obscure.properties, src/modules/feeds/PAL/data_fx.properties: Feeds updates * src/framework/mlt_geometry.c, src/framework/mlt_geometry.h: Improved geometry 2004-12-27 ddennedy * docs/services.txt, src/modules/jackrack/filter_jackrack.c: add filter/jackrack to services.txt and apply a performance tweak to filter_jackrack * src/modules/jackrack/Makefile, src/modules/jackrack/configure, src/modules/jackrack/control_message.h, src/modules/jackrack/factory.c, src/modules/jackrack/filter_jackrack.c, src/modules/jackrack/filter_jackrack.h, src/modules/jackrack/jack_rack.c, src/modules/jackrack/jack_rack.h, src/modules/jackrack/lock_free_fifo.c, src/modules/jackrack/lock_free_fifo.h, src/modules/jackrack/plugin.c, src/modules/jackrack/plugin.h, src/modules/jackrack/plugin_desc.c, src/modules/jackrack/plugin_desc.h, src/modules/jackrack/plugin_mgr.c, src/modules/jackrack/plugin_mgr.h, src/modules/jackrack/plugin_settings.c, src/modules/jackrack/plugin_settings.h, src/modules/jackrack/process.c, src/modules/jackrack/process.h, src/modules/jackrack/ui.c, src/modules/jackrack/ui.h: added jackrack filter * demo/consumers.ini, docs/services.txt, setenv, setenv_mc, src/modules/dv/producer_libdv.c, src/modules/fezzik.dict, src/modules/fezzik.ini: fix aspect ratios in producer_libdv tweak fezzik priorities minor fixes to setenv and demo/consumers.ini 2004-12-27 lilo_booter * demo/mlt_bouncy_ball, demo/mlt_my_name_is, demo/mlt_title_over_gfx, src/framework/mlt_tractor.c, src/modules/core/filter_rescale.c, src/modules/core/filter_resize.c, src/modules/core/filter_watermark.c, src/modules/core/transition_composite.c, src/modules/core/transition_region.c, src/modules/data_fx.properties, src/modules/feeds/PAL/data_fx.properties, src/modules/plus/filter_affine.c, src/modules/plus/transition_affine.c: Composite distort, fill and titles rework * src/modules/core/transition_composite.c, src/modules/feeds/Makefile: Feeds pseudo module added * src/modules/feeds/Makefile, src/modules/feeds/NTSC/data_fx.properties, src/modules/feeds/PAL/data_fx.properties, src/modules/feeds/PAL/obscure.properties: Feeds pseudo module added * docs/services.txt, src/framework/mlt_frame.c, src/framework/mlt_geometry.c, src/modules/core/filter_data_show.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/data_fx.properties, src/modules/inigo/producer_inigo.c, src/modules/lumas/create_lumas, src/modules/lumas/luma.c: Luma and composite fixes 2004-12-24 lilo_booter * mlt++/src/Makefile, mlt++/src/Mlt.h, mlt++/src/MltGeometry.cpp, mlt++/src/MltGeometry.h, mlt++/swig/mltpp.i: Geometry * src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/lumas/Makefile, src/modules/lumas/create_lumas, src/modules/lumas/luma.c: Luma generation and use * demo/mlt_bouncy_ball, demo/mlt_push, demo/mlt_ticker, src/framework/Makefile, src/framework/mlt.h, src/framework/mlt_geometry.c, src/framework/mlt_geometry.h, src/framework/mlt_types.h, src/modules/core/filter_obscure.c, src/modules/core/transition_composite.c, src/modules/data_fx.properties, src/modules/xine/deinterlace.c: Framework inclusion of geometry 2004-12-20 lilo_booter * src/framework/mlt_playlist.c, src/modules/core/transition_composite.c, src/modules/data_fx.properties: New geometry specification 2004-12-17 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_playlist.c, src/framework/mlt_tractor.c, src/modules/core/filter_data_feed.c, src/modules/core/transition_composite.c, src/modules/core/transition_region.c, src/modules/data_fx.properties, src/modules/gtk2/producer_pango.c, src/modules/westley/producer_westley.c, src/valerie/valerie_remote.c: Feed rework and fixes to westley and composite 2004-12-14 lilo_booter * src/framework/mlt_producer.c, src/framework/mlt_service.c: Mutex locking in the get frame 2004-12-12 lilo_booter * mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h: blank_at method added * src/framework/mlt_playlist.c, src/framework/mlt_playlist.h: blank_at method added 2004-12-11 lilo_booter * mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h: split_at method added * src/framework/mlt_playlist.c, src/framework/mlt_playlist.h: split_at method added 2004-12-09 lilo_booter * mlt++/src/MltTractor.cpp, mlt++/src/MltTractor.h: Tractor constructor modifications * src/framework/mlt_playlist.c, src/framework/mlt_service.c, src/modules/inigo/producer_inigo.c: Corrections to playlist manipulations and producer type determination 2004-12-03 lilo_booter * src/framework/mlt_consumer.c, src/modules/data_fx.properties, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: Possible fixes to xlib errors 2004-12-01 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_factory.c, src/framework/mlt_field.c, src/framework/mlt_filter.c, src/framework/mlt_filter.h, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/framework/mlt_multitrack.c, src/framework/mlt_multitrack.h, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/framework/mlt_properties.c, src/framework/mlt_property.c, src/framework/mlt_service.c, src/framework/mlt_service.h, src/framework/mlt_tractor.c, src/framework/mlt_tractor.h, src/framework/mlt_transition.c, src/framework/mlt_transition.h, src/framework/mlt_types.h, src/inigo/inigo.c, src/miracle/miracle_unit.c, src/miracle/miracle_unit_commands.c, src/modules/avformat/consumer_avformat.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_avdeinterlace.c, src/modules/avformat/filter_avresample.c, src/modules/avformat/producer_avformat.c, src/modules/core/consumer_null.c, src/modules/core/filter_brightness.c, src/modules/core/filter_channelcopy.c, src/modules/core/filter_data_feed.c, src/modules/core/filter_data_show.c, src/modules/core/filter_gamma.c, src/modules/core/filter_luma.c, src/modules/core/filter_mirror.c, src/modules/core/filter_obscure.c, src/modules/core/filter_region.c, src/modules/core/filter_rescale.c, src/modules/core/filter_resize.c, src/modules/core/filter_watermark.c, src/modules/core/producer_colour.c, src/modules/core/producer_noise.c, src/modules/core/producer_ppm.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/core/transition_mix.c, src/modules/core/transition_region.c, src/modules/data_fx.properties, src/modules/dv/consumer_libdv.c, src/modules/dv/producer_libdv.c, src/modules/fezzik.ini, src/modules/fezzik/producer_fezzik.c, src/modules/fezzik/producer_hold.c, src/modules/gtk2/consumer_gtk2.c, src/modules/gtk2/filter_rescale.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/inigo/producer_inigo.c, src/modules/normalize/filter_volume.c, src/modules/plus/filter_affine.c, src/modules/plus/filter_charcoal.c, src/modules/plus/filter_sepia.c, src/modules/plus/transition_affine.c, src/modules/resample/filter_resample.c, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c, src/modules/sox/filter_sox.c, src/modules/valerie/consumer_valerie.c, src/modules/vorbis/producer_vorbis.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c, src/modules/xine/filter_deinterlace.c, src/valerie/valerie_remote.c: Big modification - switch to macros for parent class access 2004-11-25 lilo_booter * mlt++/src/Makefile, mlt++/src/Mlt.h, mlt++/src/MltDeque.cpp, mlt++/src/MltDeque.h, mlt++/src/MltFactory.cpp, mlt++/src/MltFactory.h, mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/src/MltTransition.cpp, mlt++/src/MltTransition.h: Deque added; simplified producer parent access; transition in and out * src/framework/mlt_factory.c, src/framework/mlt_factory.h, src/framework/mlt_multitrack.c, src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/framework/mlt_properties.c, src/framework/mlt_service.c, src/framework/mlt_tractor.c, src/modules/sdl/consumer_sdl_still.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: Extendable factories; general producer related modifications; westley storage; sdl_still increased latency 2004-11-22 lilo_booter * mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h, mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/src/MltProperties.cpp, mlt++/src/MltService.cpp, mlt++/src/MltService.h, mlt++/test/Makefile: More playlist modifications; service locking * src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_producer.c, src/framework/mlt_service.c, src/framework/mlt_service.h: More playlist modifications; service locking; sticky services on frame 2004-11-17 lilo_booter * mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h, mlt++/src/MltTractor.cpp, mlt++/src/MltTractor.h: Ref count and event firing method on properties; locate_cut on tractor * src/framework/mlt_consumer.c, src/framework/mlt_frame.c, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/modules/sdl/consumer_sdl_still.c, src/modules/valerie/consumer_valerie.c: Added ref_count method to properties; temporary work around for test card; titles with valerie 2004-11-11 lilo_booter * mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h, mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h, mlt++/src/MltTractor.cpp, mlt++/src/MltTractor.h: Playlist reorganisation * src/framework/mlt_consumer.c, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/framework/mlt_transition.c, src/modules/dv/consumer_libdv.c: Playlist and blank rearrangement, fix for mlt_consumer and NULL 2004-11-07 lilo_booter * mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h, mlt++/src/MltTractor.cpp, mlt++/src/MltTractor.h: Simplified playlist and track access * src/framework/mlt_playlist.c, src/framework/mlt_playlist.h: Simplified playlist access 2004-11-05 lilo_booter * mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h: Added cut related methods 2004-11-01 lilo_booter * src/modules/gtk2/consumer_gtk2.c, src/modules/gtk2/producer_pixbuf.c, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: Fixes threaded pixbuf usage and removes flash when swicthing between sdl preview modes 2004-10-31 lilo_booter * mlt++/src/Makefile, mlt++/src/Mlt.h, mlt++/src/MltTokeniser.cpp, mlt++/src/MltTokeniser.h, mlt++/test/server.cpp: Added courtesy tokenising class * src/framework/mlt_tokeniser.c, src/modules/fezzik.dict, src/modules/gtk2/factory.c, src/modules/inigo/producer_inigo.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/westley/producer_westley.c: fixes for westley deserialise, preview handling and tokenising amendment 2004-10-27 lilo_booter * mlt++/configure, mlt++/swig/configure, mlt++/swig/ruby/build, mlt++/swig/ruby/miracle.rb: Config changes * src/framework/mlt_consumer.c, src/framework/mlt_frame.c, src/framework/mlt_producer.c, src/framework/mlt_tractor.c, src/inigo/inigo.c, src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c, src/modules/core/filter_resize.c, src/modules/core/filter_watermark.c, src/modules/core/producer_colour.c, src/modules/core/producer_noise.c, src/modules/core/transition_composite.c, src/modules/gtk2/producer_pixbuf.c, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: Attempt at an aspect ratio clean up 2004-10-24 lilo_booter * mlt-config-template, src/framework/configure, src/miracle/configure, src/modules/gtk2/Makefile, src/modules/gtk2/configure, src/modules/gtk2/consumer_gtk2.c, src/modules/gtk2/consumer_gtk2.h, src/modules/gtk2/factory.c, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c, src/modules/westley/producer_westley.c, src/valerie/configure: Minor config fixes and gtk2 consumer added 2004-10-21 lilo_booter * src/framework/mlt_consumer.c, src/inigo/inigo.c, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c: SDL Preview second checkin 2004-10-20 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/modules/sdl/Makefile, src/modules/sdl/configure, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl.h, src/modules/sdl/consumer_sdl_preview.c, src/modules/sdl/consumer_sdl_still.c, src/modules/sdl/factory.c: SDL Preview provisional checkin 2004-10-19 lilo_booter * src/framework/mlt_frame.c, src/modules/core/transition_mix.c: audio mix and repeated frames 2004-10-17 lilo_booter * mlt++/src/MltMiracle.cpp, mlt++/src/MltMiracle.h: id and log level for server * src/framework/mlt_properties.c, src/miracle/miracle_server.c, src/miracle/miracle_server.h: Convenience functionality for properties load and miracle_server_id function 2004-10-14 lilo_booter * mlt++/src/MltConsumer.cpp, mlt++/src/MltConsumer.h, mlt++/test/play.cpp: buffer fix and tractor handling * src/modules/westley/consumer_westley.c, src/valerie/valerie_remote.c: buffer fix and tractor handling * src/miracle/miracle_connection.c, src/miracle/miracle_local.c, src/miracle/miracle_server.c, src/miracle/miracle_unit_commands.c, src/miracle/miracle_unit_commands.h, src/modules/valerie/consumer_valerie.c, src/modules/westley/producer_westley.c, src/valerie/valerie.c, src/valerie/valerie.h, src/valerie/valerie_parser.c, src/valerie/valerie_parser.h, src/valerie/valerie_remote.c: Improved push capabilities * mlt++/src/MltMiracle.cpp, mlt++/src/MltMiracle.h: Improved push capabilities 2004-10-13 lilo_booter * src/framework/mlt_service.c, src/modules/fezzik/producer_fezzik.c, src/modules/valerie/consumer_valerie.c, src/modules/westley/producer_westley.c: Fix for deep westleys and filter in/out points * docs/services.txt, src/framework/mlt_consumer.c, src/framework/mlt_frame.c, src/framework/mlt_playlist.c, src/framework/mlt_properties.c, src/framework/mlt_tractor.c, src/inigo/inigo.c, src/miracle/miracle_connection.c, src/miracle/miracle_connection.h, src/miracle/miracle_server.c, src/miracle/miracle_server.h, src/modules/core/filter_rescale.c, src/modules/core/filter_watermark.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/plus/transition_affine.c: Some fixes for alpha masks 2004-10-11 lilo_booter * src/modules/avformat/configure, src/modules/avformat/producer_avformat.c: Fix for current cvs 2004-10-08 lilo_booter * mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h: Same and following clip identification * docs/framework.txt, docs/inigo.txt, docs/install.txt: Some documentation updates - more to follow 2004-10-07 lilo_booter * src/framework/mlt_filter.c, src/framework/mlt_producer.c, src/framework/mlt_service.c, src/framework/mlt_tractor.c, src/modules/avformat/consumer_avformat.c, src/modules/core/filter_data_show.c, src/modules/core/filter_watermark.c, src/modules/plus/filter_affine.c: Revised attached filter handling and clones 2004-10-06 lilo_booter * src/framework/mlt_frame.c, src/framework/mlt_multitrack.c, src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/framework/mlt_tractor.c, src/framework/mlt_transition.c, src/modules/core/transition_mix.c: More corrections to frame position and audio/track handling * src/framework/mlt_frame.c, src/framework/mlt_multitrack.c, src/framework/mlt_playlist.c, src/framework/mlt_tractor.c, src/modules/core/transition_mix.c: Corrects position and test_audio handling 2004-10-05 lilo_booter * src/framework/mlt_multitrack.c, src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/framework/mlt_tractor.c, src/inigo/inigo.c: Multitrack rearrangement and tractor cleanup * mlt++/src/Makefile, mlt++/src/Mlt.h, mlt++/src/MltFrame.cpp, mlt++/src/MltFrame.h, mlt++/src/MltParser.cpp, mlt++/src/MltParser.h, mlt++/src/MltService.cpp, mlt++/src/MltService.h, mlt++/swig/mltpp.i: Added the parser object and moved type identity into mlt * src/framework/mlt_parser.c, src/framework/mlt_producer.c: Yikes - another corrections to cloning (oops) * src/framework/mlt_multitrack.c, src/framework/mlt_producer.c: Corrections to cloning * src/framework/Makefile, src/framework/mlt.h, src/framework/mlt_factory.c, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/framework/mlt_multitrack.c, src/framework/mlt_parser.c, src/framework/mlt_parser.h, src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/framework/mlt_service.c, src/framework/mlt_service.h, src/framework/mlt_types.h, src/modules/data_fx.properties, src/modules/inigo/producer_inigo.c, src/modules/plus/filter_affine.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: Cloning optimisations and introduction of the service parser 2004-10-02 lilo_booter * src/framework/mlt_factory.c, src/framework/mlt_service.c, src/framework/mlt_tractor.c, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_data.h, src/modules/core/filter_data_feed.c, src/modules/core/filter_data_show.c, src/modules/core/filter_watermark.c, src/modules/core/transition_composite.c, src/modules/data_fx.properties, src/modules/dv/producer_libdv.c, src/modules/inigo/producer_inigo.c: Data feed and show filters 2004-09-29 lilo_booter * mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h, mlt++/swig/mltpp.i: new mix related methods * src/framework/mlt_frame.c, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h: clip and mix manipulation on playlist 2004-09-28 lilo_booter * src/framework/mlt_filter.c, src/framework/mlt_service.c, src/modules/core/filter_watermark.c, src/modules/core/transition_composite.c, src/modules/core/transition_region.c, src/modules/inigo/producer_inigo.c, src/modules/plus/filter_affine.c, src/modules/plus/transition_affine.c: Corrections to filter attachment and in/out point handling * src/framework/mlt_playlist.c, src/modules/inigo/producer_inigo.c: Ensure join inherits all attached filters; inigo can attach to producer or previous attachment * src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/modules/inigo/producer_inigo.c: Checkpoint for current managed cuts (prototype on mix) 2004-09-27 lilo_booter * src/modules/core/filter_rescale.c, src/modules/core/transition_composite.c: First attempt at a composite clean up 2004-09-26 lilo_booter * mlt++/README, mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h: Playlist repeat clip functionality * src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/modules/inigo/producer_inigo.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: Splits, joins and repeats 2004-09-25 lilo_booter * src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: Corrects cuts with filters * src/framework/mlt_playlist.c, src/framework/mlt_transition.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: Finalisation of first phase of cut handling (unmanaged) 2004-09-24 lilo_booter * src/framework/mlt_multitrack.c, src/framework/mlt_playlist.c, src/modules/inigo/producer_inigo.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: Cut management part 2 - corrects playlist split/join and a little bit of mix * mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/swig/mltpp.i: Cut management part 1 * src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/framework/mlt_properties.c, src/framework/mlt_service.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: Cut management part 1 2004-09-23 lilo_booter * mlt++/src/MltService.cpp, mlt++/swig/mltpp.i: get_frame and ruby listen fix 2004-09-22 lilo_booter * mlt++/src/MltFrame.cpp, mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h, mlt++/swig/mltpp.i: Event and frame handling * mlt++/configure, mlt++/src/MltMiracle.cpp: Server shutdown * src/framework/mlt_factory.c, src/framework/mlt_properties.c, src/miracle/miracle.c, src/miracle/miracle_local.c, src/miracle/miracle_server.c, src/miracle/miracle_server.h, src/modules/core/filter_watermark.c, src/modules/core/transition_composite.c: Fix to compositing/watermark; miracle/mlt shutdown cleanup * src/framework/mlt_service.c, src/modules/core/filter_watermark.c, src/modules/core/transition_composite.c: In/out point handling on attached filters revisted 2004-09-20 lilo_booter * demo/consumers.ini, src/modules/avformat/producer_avformat.c, src/modules/gtk2/producer_pixbuf.c: Minor fixes 2004-09-19 lilo_booter * mlt++/src/Makefile, mlt++/src/Mlt.h, mlt++/src/MltMiracle.cpp, mlt++/src/MltMiracle.h, mlt++/src/MltResponse.cpp, mlt++/src/MltResponse.h, mlt++/swig/mltpp.i: Added the response object * mlt++/HOWTO, mlt++/src/Makefile, mlt++/src/Mlt.h, mlt++/src/MltMiracle.cpp, mlt++/src/MltMiracle.h, mlt++/swig/mltpp.i, mlt++/swig/ruby/miracle.rb, mlt++/test/Makefile, mlt++/test/play.cpp, mlt++/test/server.cpp: Adding miracle * src/miracle/miracle.c, src/miracle/miracle_server.c, src/miracle/miracle_server.h: Extending miracles functionality 2004-09-18 lilo_booter * Makefile, src/humperdink/Makefile, src/modules/dv/producer_libdv.c: Build fix and temporary libdv compatability 2004-09-17 lilo_booter * src/framework/mlt_service.c, src/framework/mlt_service.h, src/miracle/miracle_connection.c, src/miracle/miracle_local.c, src/miracle/miracle_unit.c, src/miracle/miracle_unit.h, src/miracle/miracle_unit_commands.c, src/miracle/miracle_unit_commands.h, src/modules/avformat/Makefile, src/modules/core/filter_watermark.c, src/modules/core/producer_colour.c, src/modules/core/transition_region.c, src/modules/gtk2/factory.c, src/modules/inigo/producer_inigo.c, src/modules/plus/transition_affine.c, src/modules/sdl/consumer_sdl.c, src/modules/sox/Makefile, src/modules/valerie/Makefile, src/modules/valerie/configure, src/modules/valerie/consumer_valerie.c, src/modules/valerie/consumer_valerie.h, src/modules/valerie/factory.c, src/modules/westley/configure, src/modules/westley/consumer_westley.c, src/modules/westley/factory.c, src/modules/westley/producer_westley.c, src/modules/westley/producer_westley.h, src/valerie/Makefile, src/valerie/valerie.c, src/valerie/valerie.h, src/valerie/valerie_parser.c, src/valerie/valerie_parser.h, src/valerie/valerie_remote.c: Consumer valerie, pushes, and assorted modifications 2004-09-14 lilo_booter * src/framework/mlt_frame.c, src/modules/core/transition_luma.c: Work arounds for scaling related issues 2004-09-09 lilo_booter * src/framework/mlt_playlist.c, src/inigo/inigo.c, src/modules/inigo/producer_inigo.c: Fixes for removed tracks before/after mix * mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h: Adding the mix part 1 * src/framework/mlt_field.c, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/modules/inigo/producer_inigo.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: Adding the mix part 1 2004-09-08 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_producer.c, src/framework/mlt_service.c, src/modules/avformat/consumer_avformat.c, src/modules/core/consumer_null.c, src/modules/dv/consumer_libdv.c, src/modules/sdl/consumer_sdl.c: More work with events 2004-09-07 lilo_booter * docs/services.txt, docs/westley.txt, src/modules/westley/producer_westley.c: Major westley rewrite - allows attachable filters 2004-09-06 lilo_booter * mlt++/src/MltFilteredConsumer.cpp, mlt++/src/MltFilteredConsumer.h, mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/src/MltService.cpp, mlt++/src/MltService.h, mlt++/swig/mltpp.i: Service attach filters * src/framework/mlt_producer.c, src/framework/mlt_service.c, src/framework/mlt_service.h, src/inigo/inigo.c, src/modules/core/filter_region.c, src/modules/core/filter_watermark.c, src/modules/core/transition_region.c, src/modules/dv/producer_libdv.c, src/modules/inigo/producer_inigo.c, src/modules/sdl/consumer_sdl.c, src/modules/westley/consumer_westley.c: Filter attachments to services 2004-09-03 lilo_booter * mlt++/HOWTO, mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h, mlt++/swig/mltpp.i, mlt++/swig/perl/play.pl: More event stuff * src/framework/mlt_multitrack.c, src/framework/mlt_tractor.c: Multitrack and tractor producer-changed event 2004-09-02 lilo_booter * mlt++/src/Makefile, mlt++/src/Mlt.h, mlt++/src/MltEvent.cpp, mlt++/src/MltEvent.h, mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h, mlt++/swig/mltpp.i, mlt++/swig/ruby/play.rb, mlt++/test/play.cpp: Event modifications * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_events.c, src/framework/mlt_events.h, src/framework/mlt_playlist.c, src/modules/avformat/consumer_avformat.c, src/modules/core/consumer_null.c, src/modules/dv/consumer_libdv.c, src/modules/sdl/consumer_sdl.c, src/modules/westley/consumer_westley.c: event fix for playlist and consumer-stopped event * src/framework/Makefile, src/framework/mlt_events.c, src/framework/mlt_events.h, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_producer.c, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_service.c, src/framework/mlt_types.h, src/modules/plus/transition_affine.c: First draft of event handling 2004-08-31 lilo_booter * mlt++/HOWTO, mlt++/src/Makefile, mlt++/src/MltConsumer.cpp, mlt++/src/MltConsumer.h, mlt++/src/MltFilter.cpp, mlt++/src/MltFilter.h, mlt++/src/MltFrame.cpp, mlt++/src/MltFrame.h, mlt++/src/MltMultitrack.cpp, mlt++/src/MltMultitrack.h, mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h, mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/src/MltService.cpp, mlt++/src/MltService.h, mlt++/src/MltTractor.cpp, mlt++/src/MltTractor.h, mlt++/src/MltTransition.cpp, mlt++/src/MltTransition.h: Run time type identification * configure, src/framework/Makefile, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/modules/westley/consumer_westley.c, src/valerie/Makefile: Minor make/configure mods and mlt_frame_waveform mod 2004-08-29 ddennedy * src/framework/mlt_frame.c, src/framework/mlt_frame.h: add waveform method to frame 2004-08-28 lilo_booter * mlt++/README, mlt++/src/MltMultitrack.cpp, mlt++/src/MltMultitrack.h, mlt++/src/MltTractor.cpp, mlt++/src/MltTractor.h, mlt++/swig/mltpp.i: Tractor enhancements * src/framework/mlt_multitrack.h, src/framework/mlt_playlist.c, src/framework/mlt_tractor.c, src/framework/mlt_tractor.h: Tractor enhancements * mlt++/src/Makefile, mlt++/src/Mlt.h, mlt++/src/MltField.cpp, mlt++/src/MltField.h, mlt++/src/MltMultitrack.cpp, mlt++/src/MltMultitrack.h, mlt++/src/MltTractor.cpp, mlt++/src/MltTractor.h, mlt++/swig/mltpp.i: Multitrack classes added * docs/framework.txt, src/framework/mlt_field.c, src/framework/mlt_field.h, src/framework/mlt_tractor.c, src/framework/mlt_tractor.h, src/modules/inigo/producer_inigo.c, src/modules/westley/producer_westley.c: New tractor constructor * mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h, mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/swig/mltpp.i: Producer filter extraction method 2004-08-27 lilo_booter * mlt++/src/Makefile, mlt++/src/Mlt.h, mlt++/src/MltFilteredProducer.cpp, mlt++/src/MltFilteredProducer.h, mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/src/MltService.cpp, mlt++/src/MltService.h, mlt++/swig/mltpp.i: Removed FilteredProducer * src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/modules/fezzik/producer_fezzik.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: Producer filter attach/detach methods; major rework on westley consumer, minor on producer 2004-08-26 lilo_booter * mlt++/Makefile, mlt++/test/Makefile, mlt++/test/play.cpp: Build modifications * mlt++/src/MltConsumer.cpp, mlt++/src/MltConsumer.h, mlt++/src/MltFilter.cpp, mlt++/src/MltFilter.h, mlt++/src/MltFilteredConsumer.cpp, mlt++/src/MltFilteredConsumer.h, mlt++/src/MltFrame.cpp, mlt++/src/MltFrame.h, mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h, mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h, mlt++/src/MltService.cpp, mlt++/src/MltService.h, mlt++/src/MltTransition.cpp, mlt++/src/MltTransition.h, mlt++/swig/perl/play.pl: Mlt Ref Counts and Playlist split/join * docs/framework.txt, setenv_mc, src/framework/mlt_consumer.c, src/framework/mlt_field.c, src/framework/mlt_filter.c, src/framework/mlt_frame.c, src/framework/mlt_multitrack.c, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_service.c, src/framework/mlt_service.h, src/framework/mlt_tractor.c, src/framework/mlt_transition.c, src/modules/core/producer_colour.c, src/modules/core/producer_noise.c, src/modules/core/producer_ppm.c, src/modules/dv/producer_libdv.c, src/modules/fezzik/producer_hold.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/westley/consumer_westley.c: Mlt Ref Counts and Playlist split/join 2004-08-23 lilo_booter * mlt++/src/Makefile, mlt++/swig/mltpp.i: Workaround for perl 2004-08-21 lilo_booter * mlt++/src/MltConsumer.cpp, mlt++/src/MltFilter.cpp, mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h, mlt++/src/MltTransition.cpp: Constructor clean up * mlt++/src/MltConsumer.cpp, mlt++/src/MltConsumer.h: consumer purge * src/miracle/miracle_local.c, src/miracle/miracle_unit.c: Unit purge * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h: consumer purge 2004-08-20 lilo_booter * mlt++/src/MltFilter.cpp, mlt++/src/MltFilter.h, mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h, mlt++/swig/configure, mlt++/swig/java/build, mlt++/swig/ruby/build, mlt++/swig/ruby/thumbs.rb: mlt_position, /usr/bin/env and Instance fix 2004-08-19 lilo_booter * src/modules/core/filter_rescale.c, src/modules/gtk2/factory.c: Colour space conversion with gdkpixbuf scaling 2004-08-18 lilo_booter * mlt++/src/MltFrame.cpp, mlt++/src/MltFrame.h, mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/src/MltService.cpp, mlt++/swig/mltpp.i, mlt++/swig/ruby/play.rb: image handling 2004-08-17 lilo_booter * mlt++/swig/java/Play.java, mlt++/swig/ruby/play.rb, mlt++/swig/ruby/thumbs.rb: Fixes for mods to api * mlt++/src/Makefile, mlt++/src/Mlt.h, mlt++/src/MltConsumer.cpp, mlt++/src/MltConsumer.h, mlt++/src/MltFilteredConsumer.cpp, mlt++/src/MltFilteredConsumer.h, mlt++/src/MltFilteredProducer.cpp, mlt++/src/MltFilteredProducer.h, mlt++/src/MltService.cpp, mlt++/src/MltService.h, mlt++/swig/mltpp.i: Filtered producers and consumers 2004-08-16 lilo_booter * mlt++/swig/configure, mlt++/swig/java/Play.java, mlt++/swig/java/Play.sh, mlt++/swig/java/build, mlt++/swig/mltpp.i, mlt++/swig/perl/Makefile.PL, mlt++/swig/perl/build, mlt++/swig/python/build, mlt++/swig/python/play.py, mlt++/swig/ruby/build, mlt++/swig/ruby/play.rb, mlt++/swig/ruby/thumbs.rb, mlt++/swig/tcl/build, mlt++/swig/tcl/play.tcl: Experimental swig bindings * mlt++/README, mlt++/src/MltFactory.cpp, mlt++/src/MltFactory.h, mlt++/src/MltFilter.cpp, mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h, mlt++/src/MltProducer.cpp, mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h, mlt++/src/MltService.cpp, mlt++/src/MltService.h, mlt++/src/MltTransition.cpp, mlt++/test/Makefile: More cleanups * mlt++/README, mlt++/src/MltConsumer.cpp, mlt++/src/MltConsumer.h, mlt++/src/MltFactory.cpp, mlt++/src/MltFactory.h, mlt++/src/MltFilter.cpp, mlt++/src/MltFilter.h, mlt++/src/MltFrame.cpp, mlt++/src/MltFrame.h, mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h, mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h, mlt++/src/MltService.cpp, mlt++/src/MltService.h, mlt++/src/MltTransition.cpp, mlt++/src/MltTransition.h, mlt++/test/play.cpp: Class rework and simplification * mlt++/src/Makefile, mlt++/src/Mlt.h: Added Mlt.h convenience header * mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h, mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h, mlt++/src/MltService.cpp: Complete methods for properties and playlist; reversed NULL handling on service class * mlt++/README, mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h, mlt++/test/play.cpp: Object validity checks * src/framework/mlt_consumer.c, src/framework/mlt_field.c, src/framework/mlt_filter.c, src/framework/mlt_frame.c, src/framework/mlt_multitrack.c, src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/framework/mlt_service.c, src/framework/mlt_tractor.c, src/framework/mlt_transition.c: NULL safety checks * mlt++/AUTHORS, mlt++/Makefile, mlt++/README, mlt++/configure, mlt++/src/Makefile, mlt++/src/MltService.cpp, mlt++/test/play.cpp: Build and docs modifications 2004-08-15 lilo_booter * mlt++/src/Makefile, mlt++/src/MltConsumer.cpp, mlt++/src/MltConsumer.h, mlt++/src/MltFactory.cpp, mlt++/src/MltFactory.h, mlt++/src/MltFilter.cpp, mlt++/src/MltFilter.h, mlt++/src/MltFrame.cpp, mlt++/src/MltFrame.h, mlt++/src/MltPlaylist.cpp, mlt++/src/MltPlaylist.h, mlt++/src/MltProducer.cpp, mlt++/src/MltProducer.h, mlt++/src/MltProperties.cpp, mlt++/src/MltProperties.h, mlt++/src/MltService.cpp, mlt++/src/MltService.h, mlt++/src/MltTransition.cpp, mlt++/src/MltTransition.h, mlt++/test/Makefile, mlt++/test/play.cpp: Initial revision 2004-08-10 lilo_booter * src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/avformat/factory.c, src/modules/avformat/filter_avcolour_space.c, src/modules/avformat/filter_avcolour_space.h: Colour space filter 2004-08-05 lilo_booter * src/modules/avformat/configure, src/modules/avformat/producer_avformat.c: gop size == 0 fix and update to current ffmpeg for cvs co * src/modules/dv/consumer_libdv.c, src/modules/dv/producer_libdv.c, src/modules/dv/producer_libdv.h: Fix for current libdv 2004-08-03 lilo_booter * src/modules/core/filter_watermark.c, src/modules/core/transition_region.c: Mutable shapes on regions 2004-07-31 lilo_booter * src/modules/core/filter_watermark.c, src/modules/core/transition_composite.c: Mutable watermark producer and small optimisation 2004-07-29 lilo_booter * src/modules/plus/filter_affine.c, src/modules/plus/transition_affine.c: Minor affine modifications * src/modules/plus/Makefile, src/modules/plus/configure, src/modules/plus/factory.c, src/modules/plus/filter_affine.c, src/modules/plus/filter_affine.h: Affine filter 2004-07-27 lilo_booter * src/modules/core/filter_watermark.c, src/modules/core/transition_composite.c: More mutable properties 2004-07-26 lilo_booter * src/modules/core/filter_luma.c, src/modules/core/filter_mirror.c, src/modules/core/transition_composite.c, src/modules/core/transition_region.c: Mutable properties * src/framework/mlt_playlist.c, src/framework/mlt_playlist.h: Allow attached filters when used in playlists 2004-07-23 lilo_booter * src/modules/core/filter_region.c, src/modules/core/transition_composite.c, src/modules/core/transition_region.c: Allows runtime modifications to region fx 2004-07-15 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_factory.c, src/framework/mlt_filter.c, src/framework/mlt_filter.h, src/framework/mlt_service.c, src/framework/mlt_service.h, src/modules/westley/consumer_westley.c: Filter cleanup and fixes 2004-07-08 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_service.c, src/framework/mlt_service.h, src/modules/xine/Makefile: Swig mods * src/modules/avformat/Makefile, src/modules/core/Makefile, src/modules/dv/Makefile, src/modules/fezzik/Makefile, src/modules/gtk2/Makefile, src/modules/inigo/Makefile, src/modules/normalize/Makefile, src/modules/plus/Makefile, src/modules/plus/transition_affine.c, src/modules/resample/Makefile, src/modules/sdl/Makefile, src/modules/sox/Makefile, src/modules/vorbis/Makefile, src/modules/westley/Makefile: Fixes for swig 2004-06-21 lilo_booter * src/modules/avformat/consumer_avformat.c, src/modules/core/filter_luma.c, src/modules/core/transition_luma.c: consumer avformat fix and silly stuff in lumas * src/modules/avformat/consumer_avformat.c, src/modules/inigo/producer_inigo.c: stdout fix for avformat consumer and change of defaults for inigo transition tracks 2004-06-20 lilo_booter * src/modules/plus/filter_sepia.c, src/modules/plus/transition_affine.c: Sepia fix and affine/alpha clean up * src/modules/plus/Makefile, src/modules/plus/configure, src/modules/plus/factory.c, src/modules/plus/filter_sepia.c, src/modules/plus/filter_sepia.h, src/modules/plus/transition_affine.c: affine with alpha and a broken sepia 2004-06-14 lilo_booter * configure, src/modules/configure, src/modules/core/configure, src/modules/core/transition_composite.c, src/modules/dv/configure, src/modules/fezzik/configure, src/modules/gtk2/configure, src/modules/inigo/configure, src/modules/normalize/configure, src/modules/resample/configure, src/modules/sdl/configure, src/modules/sdl/consumer_sdl.c, src/modules/sox/configure, src/modules/vorbis/configure, src/modules/westley/configure, src/modules/xine/configure: Portability modifications to scripts * src/modules/plus/Makefile, src/modules/plus/configure, src/modules/plus/factory.c, src/modules/plus/transition_affine.c, src/modules/plus/transition_affine.h: Experimental affine transformation 2004-06-11 lilo_booter * src/modules/plus/Makefile, src/modules/plus/configure, src/modules/plus/factory.c, src/modules/plus/filter_charcoal.c, src/modules/plus/filter_charcoal.h, src/modules/plus/filter_invert.c, src/modules/plus/filter_invert.h: More silliness :-) 2004-06-07 lilo_booter * src/framework/mlt_consumer.c, src/modules/core/producer_colour.c, src/modules/core/producer_noise.c, src/modules/fezzik.ini, src/modules/gtk2/producer_pixbuf.c, src/tests/charlie.c: Minor tweaks 2004-05-25 lilo_booter * src/modules/avformat/Makefile, src/modules/avformat/configure: Yet another way to configure ffmpeg * src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: Sync with current ffmpeg CVS and minor clean up 2004-05-22 lilo_booter * src/framework/configure, src/framework/mlt_consumer.c, src/framework/mlt_factory.c, src/framework/mlt_pool.c, src/framework/mlt_pool.h, src/framework/mlt_repository.c: slight mods to factory (for future module reporting); pool purge function; consumer drop frame rework * src/modules/avformat/configure, src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c: fix for avformat seek < gop; fix for avformat consumer qscale; additional avformat consumer properties 2004-05-03 lilo_booter * src/modules/avformat/consumer_avformat.c, src/modules/fezzik.ini, src/modules/sox/Makefile: sox fix; remove consumer avformat diagnostic * src/framework/Makefile, src/framework/mlt_consumer.c, src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/consumer_null.c, src/modules/core/consumer_null.h, src/modules/core/factory.c, src/modules/core/producer_noise.c, src/modules/fezzik/producer_hold.c, src/modules/sdl/consumer_sdl.c, src/modules/vorbis/producer_vorbis.c: minor clean ups; added a null consumer for easier valgrind testing 2004-05-01 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_frame.c, src/modules/sdl/consumer_sdl.c: Audio read ahead and fine tuning * src/framework/mlt_consumer.c, src/modules/avformat/producer_avformat.c, src/modules/sdl/consumer_sdl.c: Clean up and border preservation 2004-04-30 lilo_booter * src/albino/Makefile, src/framework/mlt_consumer.c, src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c, src/modules/core/filter_mirror.c, src/modules/fezzik.ini, src/modules/sdl/consumer_sdl.c: Sundry consumer modifications; albino compile fix; minor mods to avformat producer 2004-04-27 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_deque.h, src/framework/mlt_field.h, src/framework/mlt_filter.h, src/framework/mlt_frame.h, src/framework/mlt_manager.h, src/framework/mlt_multitrack.h, src/framework/mlt_playlist.h, src/framework/mlt_producer.h, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.h, src/framework/mlt_repository.h, src/framework/mlt_service.c, src/framework/mlt_service.h, src/framework/mlt_tokeniser.h, src/framework/mlt_tractor.h, src/framework/mlt_transition.h: C++ compatability 2004-04-19 lilo_booter * README, configure, docs/install.txt, docs/services.txt, src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/avformat/consumer_avformat.c, src/modules/avformat/factory.c, src/modules/avformat/filter_avdeinterlace.c, src/modules/avformat/filter_avresample.c, src/modules/avformat/producer_avformat.c, src/modules/configure, src/modules/gtk2/producer_pixbuf.c, src/modules/sdl/consumer_sdl.c: config mods; avformat static or shared build; corrections to sdl 2004-04-18 lilo_booter * configure, docs/services.txt, setenv: GPL checking (provisional implementation), mc scaling docs * src/modules/configure, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_rescale.c, src/modules/core/filter_rescale.h, src/modules/fezzik.ini, src/modules/fezzik/Makefile, src/modules/fezzik/producer_fezzik.c, src/modules/gtk2/configure, src/modules/gtk2/factory.c, src/modules/gtk2/filter_rescale.c: Rescaler and fezzik rework (to allow inclusion of mc scaler) 2004-04-17 lilo_booter * src/modules/dv/Makefile, src/modules/normalize/Makefile, src/modules/sox/Makefile: Makefile cleanup in modules * src/modules/sox/Makefile, src/modules/sox/filter_sox.c: switched to mlt_tokeniser and removed libst-config from Makefile * src/framework/Makefile, src/framework/mlt_tokeniser.c, src/framework/mlt_tokeniser.h: added mlt_tokeniser 2004-04-16 ddennedy * src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_volume.c, src/modules/core/filter_volume.h, src/modules/normalize/Makefile, src/modules/normalize/configure, src/modules/normalize/factory.c, src/modules/normalize/filter_volume.c, src/modules/normalize/filter_volume.h, src/modules/sox/Makefile, src/modules/sox/configure, src/modules/sox/factory.c, src/modules/sox/filter_sox.c, src/modules/sox/filter_sox.h: moved filter_volume into a normalize module, added new sox module with filter_sox 2004-04-16 lilo_booter * src/modules/ffmpeg/Makefile, src/modules/ffmpeg/audio.sh, src/modules/ffmpeg/configure, src/modules/ffmpeg/factory.c, src/modules/ffmpeg/producer_ffmpeg.c, src/modules/ffmpeg/producer_ffmpeg.h, src/modules/ffmpeg/video.sh: removed all ffmpeg files * src/modules/ffmpeg/Makefile, src/modules/ffmpeg/configure, src/modules/ffmpeg/consumer_ffmpeg.c, src/modules/ffmpeg/consumer_ffmpeg.h, src/modules/ffmpeg/factory.c, src/modules/ffmpeg/filter_ffmpeg_dub.c, src/modules/ffmpeg/filter_ffmpeg_dub.h: ffmpeg cleanup 2004-04-15 lilo_booter * src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/avformat/factory.c, src/modules/avformat/filter_avdeinterlace.c, src/modules/avformat/filter_avdeinterlace.h, src/modules/avformat/filter_avresample.c, src/modules/avformat/filter_avresample.h, src/modules/avformat/mmx.h: LGPL deinterlace and resampler 2004-04-14 lilo_booter * configure, src/albino/Makefile, src/framework/Makefile, src/framework/mlt_pool.c, src/humperdink/Makefile, src/inigo/Makefile, src/miracle/Makefile, src/miracle/miracle_local.c, src/modules/Makefile, src/modules/avformat/Makefile, src/modules/dv/Makefile, src/modules/gtk2/Makefile, src/modules/resample/Makefile, src/modules/sdl/Makefile, src/modules/vorbis/Makefile, src/modules/westley/Makefile, src/tests/Makefile, src/valerie/Makefile, src/valerie/valerie_socket.c: More configure and build tuning * configure, src/modules/configure: Configure and build tuning * configure, docs/install.txt, src/albino/Makefile, src/framework/Makefile, src/humperdink/Makefile, src/inigo/Makefile, src/miracle/Makefile, src/modules/avformat/Makefile, src/modules/core/Makefile, src/modules/dv/Makefile, src/modules/fezzik/Makefile, src/modules/ffmpeg/Makefile, src/modules/gtk2/Makefile, src/modules/inigo/Makefile, src/modules/resample/Makefile, src/modules/sdl/Makefile, src/modules/vorbis/Makefile, src/modules/westley/Makefile, src/modules/xine/Makefile, src/tests/Makefile, src/valerie/Makefile: Configure and build tuning 2004-04-13 lilo_booter * Makefile, src/framework/mlt_frame.c, src/modules/Makefile, src/modules/avformat/consumer_avformat.c: Makefile error handling and consumer avformat cleanup 2004-04-13 ddennedy * src/modules/avformat/producer_avformat.c, src/modules/core/filter_resize.c, src/modules/fezzik.dict, src/modules/westley/producer_westley.c: field order normalisation fix, add .vob to fezzik, field order detection for avformat 2004-04-09 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_filter.c, src/framework/mlt_playlist.c, src/framework/mlt_properties.c, src/framework/mlt_repository.c, src/inigo/inigo.c, src/modules/dv/consumer_libdv.c, src/modules/resample/filter_resample.c, src/modules/sdl/consumer_sdl.c: Memory leaks and resample rework 2004-04-07 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_frame.c, src/framework/mlt_properties.c: aspect ratio and test card woes 2004-04-06 lilo_booter * demo/mlt_news, docs/framework.txt, src/framework/mlt_consumer.c, src/framework/mlt_factory.c, src/framework/mlt_frame.c, src/framework/mlt_properties.c, src/modules/fezzik/producer_hold.c, src/modules/gtk2/filter_rescale.c, src/modules/sdl/consumer_sdl.c: hold modifications and test card env var 2004-04-02 lilo_booter * setenv_mc, src/modules/sdl/consumer_sdl.c: added setenv_mc * demo/demo.ini, demo/mlt_squeeze, demo/mlt_squeeze_box, docs/framework.txt, docs/services.txt, src/modules/core/transition_composite.c: minor mods 2004-03-30 lilo_booter * docs/services.txt, src/albino/Makefile, src/framework/Makefile, src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_frame.c, src/humperdink/Makefile, src/inigo/Makefile, src/miracle/Makefile, src/miracle/miracle_unit.c, src/modules/avformat/Makefile, src/modules/avformat/consumer_avformat.c, src/modules/avformat/producer_avformat.c, src/modules/core/Makefile, src/modules/dv/Makefile, src/modules/fezzik/Makefile, src/modules/ffmpeg/Makefile, src/modules/gtk2/Makefile, src/modules/inigo/Makefile, src/modules/resample/Makefile, src/modules/sdl/Makefile, src/modules/vorbis/Makefile, src/modules/westley/Makefile, src/modules/xine/Makefile, src/tests/Makefile, src/valerie/Makefile: Minor optimisations, consumer avformat experimentation 2004-03-30 ddennedy * src/framework/mlt_consumer.c, src/modules/avformat/consumer_avformat.c, src/modules/dv/consumer_libdv.c, src/modules/sdl/consumer_sdl.c: inherit scheduling priority on any created thread 2004-03-29 ddennedy * src/modules/core/transition_luma.c, src/modules/gtk2/filter_rescale.c: bugfix limits in transition luma * demo/consumers.ini, src/modules/gtk2/filter_rescale.c, src/modules/gtk2/producer_pixbuf.c, src/modules/sdl/consumer_sdl.c: aspect fixes for rescale=none 2004-03-29 lilo_booter * README, src/framework/configure, src/framework/mlt.h, src/framework/mlt_consumer.c, src/framework/mlt_factory.c, src/framework/mlt_pool.c, src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/avformat/consumer_avformat.c, src/modules/avformat/consumer_avformat.h, src/modules/avformat/factory.c, src/modules/avformat/producer_avformat.c, src/modules/dv/consumer_libdv.c, src/modules/dv/producer_libdv.c, src/modules/sdl/consumer_sdl.c: consumer avformat added, various cleanups and consumer realtime switching 2004-03-28 ddennedy * Makefile, README, configure, mlt-framework.pc.in, mlt-miracle.pc.in, mlt-valerie.pc.in: added pkgconfig files. fixed broken dist-clean make target. 2004-03-27 lilo_booter * demo/mlt_fade_black, demo/mlt_push, demo/mlt_squeeze, docs/TODO, docs/dvcp.txt, docs/framework.txt, docs/inigo.txt, docs/install.txt, docs/services.txt, docs/testing.txt, docs/valerie.txt, docs/westley.txt: Doc formating 2004-03-26 ddennedy * demo/entity.westley, demo/new.westley, docs/westley.txt, src/modules/westley/Makefile, src/modules/westley/producer_westley.c, src/modules/westley/westley.dtd: added westley.dtd 2004-03-26 lilo_booter * Makefile, configure, mlt-config-template, src/framework/configure, src/miracle/configure, src/valerie/configure: make install part 2 - building configs 2004-03-26 ddennedy * demo/entity.westley, docs/westley.txt, src/modules/westley/producer_westley.c: fix westley for mixed element text and entity references 2004-03-26 lilo_booter * Makefile, src/modules/Makefile: make install part 1 * Makefile, README, configure, src/albino/Makefile, src/framework/Makefile, src/framework/config.h, src/humperdink/Makefile, src/inigo/Makefile, src/miracle/Makefile, src/modules/Makefile, src/modules/avformat/Makefile, src/modules/core/Makefile, src/modules/dv/Makefile, src/modules/fezzik/Makefile, src/modules/ffmpeg/Makefile, src/modules/gtk2/Makefile, src/modules/inigo/Makefile, src/modules/resample/Makefile, src/modules/sdl/Makefile, src/modules/vorbis/Makefile, src/modules/westley/Makefile, src/modules/xine/Makefile, src/tests/Makefile, src/valerie/Makefile: make install part 1 * src/framework/mlt_factory.c, src/framework/mlt_factory.h, src/framework/mlt_pool.c, src/framework/mlt_properties.c, src/modules/dv/producer_libdv.c, src/modules/fezzik.dict, src/modules/fezzik/producer_fezzik.c, src/modules/sdl/consumer_sdl.c: pooling and properties checks; dv decoder stack; factory cleanup registering 2004-03-26 ddennedy * demo/README, demo/entity.westley, docs/services.txt, docs/westley.txt, src/miracle/miracle_unit_commands.c, src/modules/westley/producer_westley.c: enhance miracle LOAD command to accept a service: prefix. enhance producer_westley to apply parameters on url as entities. bugfix producer_westley memory leak. * demo/README, demo/pango.westley, src/modules/fezzik/producer_hold.c, src/modules/westley/producer_westley.c: fixed westley/fezzik integration when both service and resource supplied. 2004-03-25 ddennedy * demo/mlt_push, demo/new.westley, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: reorganized consumer_westley. added branch tracking and other bugfixes to producer_westley. 2004-03-24 ddennedy * demo/mlt_fade_black, demo/mlt_push, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: added track hiding to westley 2004-03-24 lilo_booter * demo/mlt_fade_black, demo/mlt_title_over_gfx, demo/mlt_titleshadow_watermark: couple of fixes to hidden tracks * demo/consumers.ini, demo/luma1.pgm, demo/mlt_clock_in_and_out, demo/mlt_fade_black, demo/mlt_my_name_is, demo/mlt_news, demo/mlt_squeeze, demo/mlt_title_over_gfx, demo/mlt_voiceover: demo mods for reversed tracks * src/framework/mlt_frame.c, src/framework/mlt_multitrack.c, src/framework/mlt_producer.c, src/framework/mlt_tractor.c, src/framework/mlt_transition.c, src/modules/inigo/producer_inigo.c: track reversal and hidden tracks * demo/demo, demo/demo.ini, demo/mlt_news, demo/mlt_squeeze: news and squeeze added * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_tractor.c, src/modules/core/transition_composite.c, src/modules/resample/filter_resample.c: Tractor frame handling reworked; fix to composite for key diffs of 1; added mlt_consumer_new for consistency 2004-03-24 ddennedy * demo/README, demo/consumers.ini, demo/demo.ini, demo/mlt_fade_black, demo/mlt_jcut, demo/mlt_jcut2, demo/mlt_lcut, demo/mlt_push, demo/mlt_ticker, docs/services.txt, src/modules/core/producer_colour.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c: remove some progressive flag handling in field renderers bugfix compositing images wider than the frame added more demos 2004-03-23 ddennedy * demo/demo.ini, demo/mlt_jcut, demo/mlt_jcut2: added J Cut demos 2004-03-23 lilo_booter * src/miracle/miracle_local.c, src/miracle/miracle_unit.c, src/miracle/miracle_unit.h, src/miracle/miracle_unit_commands.c, src/miracle/miracle_unit_commands.h, src/valerie/valerie.c, src/valerie/valerie.h: added clear to the miracle command set and valerie api 2004-03-23 ddennedy * README, demo/consumers.ini, docs/framework.txt, docs/install.txt, docs/services.txt, docs/westley.txt, src/albino/albino.c, src/humperdink/client.c, src/modules/gtk2/producer_pango.c, src/modules/westley/producer_westley.c: documentation updates change some references to dv1394d in the example clients to Miracle. more bugfixes for producer_westley iconv for pango 2004-03-22 lilo_booter * src/framework/mlt_frame.c, src/miracle/miracle_commands.c, src/miracle/miracle_unit_commands.c: root corrections to miracle * src/modules/avformat/producer_avformat.c, src/modules/core/producer_colour.c, src/modules/dv/consumer_libdv.c, src/modules/fezzik/Makefile, src/modules/fezzik/configure, src/modules/fezzik/factory.c, src/modules/fezzik/producer_hold.c, src/modules/fezzik/producer_hold.h, src/modules/resample/filter_resample.c, src/tests/dan.c, src/tests/pango.c, src/tests/pixbuf.c: producer hold, experimental ac3 audio support 2004-03-22 ddennedy * demo/circle.svg, demo/demo.kino, demo/new.westley, demo/svg.westley, src/framework/mlt_filter.c, src/framework/mlt_playlist.c, src/modules/fezzik.dict, src/modules/fezzik/producer_fezzik.c, src/modules/westley/producer_westley.c: smarter and harder producer_westley 2004-03-21 lilo_booter * src/framework/mlt_producer.c, src/framework/mlt_properties.c, src/modules/fezzik.dict, src/modules/fezzik/producer_fezzik.c, src/modules/sdl/consumer_sdl.c, src/tests/hello.c: in point fix, low latency sdl, minor fixes 2004-03-19 lilo_booter * docs/framework.txt, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/modules/Makefile, src/modules/configure, src/modules/core/producer_noise.c, src/modules/fezzik.dict, src/modules/fezzik/producer_fezzik.c: fezzik gets a rhyming dictionary * docs/framework.txt, docs/services.txt, src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/framework/mlt_properties.c, src/modules/avformat/producer_avformat.c, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_mirror.c, src/modules/core/filter_mirror.h, src/modules/core/filter_watermark.c, src/modules/core/producer_colour.c, src/modules/core/producer_noise.c, src/modules/core/producer_noise.h, src/modules/fezzik/producer_fezzik.c, src/tests/hello.c: Noise and mirrors 2004-03-18 ddennedy * docs/services.txt, src/modules/avformat/producer_avformat.c: revert avformat pts offset change and note bug in docs 2004-03-18 lilo_booter * docs/framework.txt, docs/westley.txt, src/framework/config.h, src/framework/mlt_factory.c, src/framework/mlt_frame.h, src/framework/mlt_producer.c, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_service.c, src/framework/mlt_service.h, src/framework/mlt_types.h, src/modules/core/transition_composite.c, src/modules/sdl/consumer_sdl.c, src/tests/Makefile, src/tests/hello.c: provisional framework docs and corrections 2004-03-17 ddennedy * docs/services.txt, src/modules/avformat/producer_avformat.c, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_channelcopy.c, src/modules/core/filter_channelcopy.h, src/modules/resample/filter_resample.c: added filter_channelcopy. enhance filter_resample to reproduce channels when producer does not create as many as consumer requested. * docs/services.txt, src/modules/avformat/producer_avformat.c, src/modules/fezzik/producer_fezzik.c, src/modules/inigo/producer_inigo.c: fezzik now accepts service:resource and strips \'avformat:\' before fallback avformat construction. avformat now accepts urls with a format and format parameters designation. updated services.txt for above changes. added a video pts offset to avformat. 2004-03-16 ddennedy * demo/luma1.pgm, demo/mlt_obscure, docs/services.txt, src/modules/core/composite_line_yuv_mmx.S, src/modules/core/filter_luma.c, src/modules/core/transition_luma.c, src/modules/fezzik/producer_fezzik.c: updated services docs plus minor fixes discovered during 2004-03-12 ddennedy * demo/README, demo/consumers.ini, demo/demo, demo/mlt_clock_in_and_out, demo/mlt_voiceover: notes for the demo * demo/circle.png, demo/circle.svg, demo/consumers.ini, demo/luma1.pgm, demo/mlt_bouncy_ball, demo/mlt_composite_transition, demo/mlt_fade_in_and_out, demo/mlt_obscure, demo/mlt_title_over_gfx, demo/mlt_titleshadow_watermark, demo/mlt_voiceover: some demo updates 2004-03-12 lilo_booter * demo/consumers.ini, demo/demo, src/framework/mlt_consumer.c, src/modules/core/transition_luma.c, src/modules/sdl/consumer_sdl.c: more sdl/consumer tuning and demo updates 2004-03-11 lilo_booter * demo/mlt_voiceover, src/framework/mlt_deque.c, src/framework/mlt_properties.c, src/framework/mlt_property.c, src/framework/mlt_property.h, src/modules/sdl/consumer_sdl.c: more small optimisations * demo/demo, demo/demo.ini, demo/luma1.pgm, demo/mlt_all, demo/mlt_audio_stuff, demo/mlt_avantika_title, demo/mlt_bouncy, demo/mlt_bouncy_ball, demo/mlt_clock_in_and_out, demo/mlt_composite_transition, demo/mlt_effect_in_middle, demo/mlt_fade_in_and_out, demo/mlt_intro, demo/mlt_levels, demo/mlt_my_name_is, demo/mlt_obscure, demo/mlt_slideshow, demo/mlt_title_over_gfx, demo/mlt_titleshadow_watermark, demo/mlt_voiceover, demo/mlt_watermark, demo/pango.westley, demo/watermark1.png, docs/westley.txt, setenv, src/inigo/io.c, src/modules/dv/producer_libdv.c, src/modules/sdl/consumer_sdl.c: demo framework added 2004-03-11 ddennedy * src/modules/core/Makefile, src/modules/core/composite_line_yuv_mmx.S, src/modules/core/filter_resize.c, src/modules/core/transition_composite.c, src/modules/gtk2/filter_rescale.c: added very preliminary mmx for composite. bugfixes to -x and too small rescaling. 2004-03-10 lilo_booter * src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/core/transition_mix.c, src/modules/core/transition_region.c: RPN clean up for frames * docs/inigo.txt, docs/westley.txt, src/framework/mlt_consumer.c, src/modules/westley/producer_westley.c: Minor fixes to westley and mlt_consumer; first draft westley docs 2004-03-10 ddennedy * src/modules/core/transition_composite.c, src/modules/core/transition_luma.c: pgm scaling in transition_composite. optimisations for luma producer. 2004-03-09 ddennedy * src/framework/mlt_consumer.c, src/framework/mlt_frame.c, src/framework/mlt_producer.c, src/modules/avformat/producer_avformat.c, src/modules/core/filter_resize.c, src/modules/core/producer_ppm.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/dv/producer_libdv.c, src/modules/gtk2/filter_rescale.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/sdl/consumer_sdl.c, src/modules/westley/producer_westley.c: add luma to composite. rework aspect handling to use sample aspect. workaround westley segfault when another instance of libxml2 is used. improved inline xml handling in westley - pango and svg. 2004-03-04 lilo_booter * src/framework/mlt_consumer.c, src/modules/dv/consumer_libdv.c: experimental tuning 2004-03-04 ddennedy * src/modules/xine/attributes.h, src/modules/xine/xineutils.h: add missing header 2004-03-04 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/modules/core/transition_luma.c, src/modules/dv/consumer_libdv.c, src/modules/sdl/consumer_sdl.c: tunable read ahead buffer and fix for luma * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/humperdink/client.c, src/miracle/miracle_unit.c, src/miracle/miracle_unit.h, src/miracle/miracle_unit_commands.c, src/modules/dv/consumer_libdv.c, src/modules/sdl/consumer_sdl.c, src/valerie/valerie.c, src/valerie/valerie.h, src/valerie/valerie_status.c, src/valerie/valerie_status.h: consumer read ahead and int32_t migration 2004-03-04 ddennedy * src/modules/Makefile, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_deinterlace.c, src/modules/core/filter_deinterlace.h, src/modules/core/producer_colour.c, src/modules/xine/Makefile, src/modules/xine/configure, src/modules/xine/cpu_accel.c, src/modules/xine/deinterlace.c, src/modules/xine/deinterlace.h, src/modules/xine/factory.c, src/modules/xine/filter_deinterlace.c, src/modules/xine/filter_deinterlace.h, src/modules/xine/xineutils.h: added xine-based accellerated deinterlace 2004-03-03 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_frame.h, src/framework/mlt_properties.c, src/framework/mlt_service.h, src/framework/mlt_types.h, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_region.c, src/modules/core/transition_region.c, src/modules/core/transition_region.h: transition region 2004-03-03 ddennedy * src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/producer_colour.c, src/modules/core/producer_colour.h: producer_colour 2004-03-03 lilo_booter * src/framework/mlt_multitrack.c, src/framework/mlt_pool.c, src/framework/mlt_pool.h, src/framework/mlt_properties.c, src/framework/mlt_property.c, src/framework/mlt_service.c, src/framework/mlt_service.h, src/framework/mlt_types.h, src/inigo/inigo.c, src/modules/avformat/producer_avformat.c, src/modules/core/filter_region.c, src/modules/core/transition_composite.c, src/modules/core/transition_composite.h, src/modules/gtk2/producer_pixbuf.c, src/modules/sdl/consumer_sdl.c, src/modules/westley/consumer_westley.c: Yet more sdl hacking, region memory leak fix, mlt_position changed to int32_t, experimental hash in properties 2004-03-03 ddennedy * src/framework/mlt_frame.c, src/modules/core/filter_region.c, src/modules/core/transition_composite.c, src/modules/fezzik/producer_fezzik.c, src/modules/gtk2/producer_pixbuf.c, src/modules/westley/producer_westley.c: some bugfixes, filter_shape producer, pixbuf takes svg xml, fezzik can take a service name 2004-03-01 ddennedy * src/modules/avformat/producer_avformat.c, src/modules/dv/producer_libdv.c, src/modules/gtk2/scale_line_22_yuv_mmx.S: much improved mmx yuv scaler added producer_libdv quality property improve avformat aspect_ratio and frame_rate reporting 2004-03-01 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_factory.c, src/framework/mlt_factory.h, src/framework/mlt_frame.c, src/framework/mlt_producer.c, src/modules/gtk2/filter_rescale.c, src/modules/sdl/consumer_sdl.c: sdl hacks 2004-02-29 lilo_booter * src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_region.c, src/modules/core/filter_region.h, src/modules/core/filter_watermark.c, src/modules/core/transition_composite.c, src/modules/core/transition_composite.h: regionalised fx part 1 * src/framework/mlt_factory.c, src/modules/core/filter_watermark.c, src/modules/dv/producer_libdv.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c: unique ids 2004-02-27 lilo_booter * src/framework/mlt_frame.c, src/modules/core/filter_resize.c, src/modules/dv/consumer_libdv.c: Scaling experimentation 2004-02-27 ddennedy * src/modules/gtk2/Makefile, src/modules/gtk2/pixops.c, src/modules/gtk2/scale_line_22_33_mmx.S, src/modules/gtk2/scale_line_22_yuv_mmx.S: mmx version of non-nearest, 2x2 rescaling 2004-02-26 ddennedy * src/modules/gtk2/Makefile, src/modules/gtk2/pixops.c, src/modules/gtk2/scale_line_22_33_mmx.S: updated mmx yuv scaling 2004-02-26 lilo_booter * src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/modules/avformat/producer_avformat.c, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_luma.c, src/modules/core/filter_luma.h, src/modules/core/filter_watermark.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c: composite aspect ratio fix (again ;-)), added fill compositing test case, filter luma, mlt_properties_pass and sundry fixes 2004-02-25 lilo_booter * docs/TODO, src/framework/mlt_consumer.c, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/modules/avformat/producer_avformat.c, src/modules/core/filter_deinterlace.c, src/modules/core/filter_obscure.c, src/modules/core/filter_watermark.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/sdl/consumer_sdl.c: service stack, various fixes 2004-02-24 lilo_booter * docs/services.txt, src/framework/mlt_frame.c, src/framework/mlt_producer.h, src/framework/mlt_transition.c, src/framework/mlt_transition.h, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_obscure.c, src/modules/core/filter_resize.c, src/modules/core/filter_watermark.c, src/modules/core/filter_watermark.h, src/modules/ffmpeg/filter_ffmpeg_dub.c, src/modules/gtk2/filter_rescale.c, src/modules/resample/filter_resample.c: watermark added, minor mods to mlt framework required * src/framework/mlt_consumer.c, src/framework/mlt_filter.c, src/framework/mlt_filter.h, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/modules/core/filter_brightness.c, src/modules/core/filter_deinterlace.c, src/modules/core/filter_gamma.c, src/modules/core/filter_greyscale.c, src/modules/core/filter_obscure.c, src/modules/core/filter_resize.c, src/modules/core/transition_composite.c, src/modules/fezzik/producer_fezzik.c, src/modules/gtk2/producer_pixbuf.c, src/modules/sdl/consumer_sdl.c: Filter optimisations and cleanup part 1 2004-02-23 lilo_booter * src/framework/mlt_frame.c, src/framework/mlt_producer.c, src/modules/avformat/producer_avformat.c, src/modules/fezzik/producer_fezzik.c: Minor fixes * src/modules/core/transition_luma.c, src/modules/sdl/consumer_sdl.c: sdl rework (prepatory read-ahead implementation) and luma work around * src/framework/mlt_pool.c, src/framework/mlt_pool.h, src/modules/core/transition_luma.c: Big luma optimisations, minor pooling optimisations 2004-02-22 ddennedy * src/modules/core/filter_obscure.c, src/modules/core/transition_composite.c: composite alpha operations, make obscure alpha aware 2004-02-21 ddennedy * src/modules/avformat/producer_avformat.c, src/modules/core/filter_resize.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/tests/Makefile, src/tests/dan.c: fix broken aspect handling again 2004-02-21 lilo_booter * src/framework/mlt_pool.c, src/modules/avformat/producer_avformat.c, src/modules/dv/producer_libdv.c: avformat whoops, pooling claridication and removal of dv leak 2004-02-20 lilo_booter * src/albino/Makefile, src/framework/Makefile, src/framework/mlt_frame.c, src/framework/mlt_multitrack.c, src/framework/mlt_pool.c, src/framework/mlt_pool.h, src/framework/mlt_properties.c, src/humperdink/Makefile, src/inigo/Makefile, src/miracle/Makefile, src/modules/avformat/producer_avformat.c, src/modules/core/producer_ppm.c, src/modules/core/transition_luma.c, src/modules/dv/producer_libdv.c, src/modules/ffmpeg/producer_ffmpeg.c, src/modules/gtk2/filter_rescale.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/resample/filter_resample.c, src/modules/sdl/consumer_sdl.c, src/modules/vorbis/producer_vorbis.c, src/tests/Makefile, src/valerie/Makefile: Memory pooling part 2 and other optimisations 2004-02-19 lilo_booter * docs/services.txt, src/framework/Makefile, src/framework/mlt_factory.c, src/framework/mlt_frame.c, src/framework/mlt_pool.c, src/framework/mlt_pool.h, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_types.h, src/modules/avformat/producer_avformat.c, src/modules/core/filter_resize.c, src/modules/core/producer_ppm.c, src/modules/core/transition_luma.c, src/modules/dv/producer_libdv.c, src/modules/ffmpeg/producer_ffmpeg.c, src/modules/gtk2/filter_rescale.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/gtk2/producer_pixbuf.h, src/modules/resample/filter_resample.c, src/modules/vorbis/producer_vorbis.c: Memory pooling 2004-02-19 ddennedy * src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c: field rendering and alignment for composite, bugfixes for luma, pixbuf and pango 2004-02-18 ddennedy * src/modules/core/filter_deinterlace.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c: split getting of b_frame image and composite 2004-02-18 lilo_booter * src/albino/Makefile, src/framework/Makefile, src/framework/mlt_consumer.c, src/framework/mlt_filter.c, src/framework/mlt_filter.h, src/framework/mlt_frame.c, src/framework/mlt_properties.c, src/humperdink/Makefile, src/inigo/Makefile, src/miracle/Makefile, src/miracle/miracle_local.c, src/miracle/miracle_unit.c, src/miracle/miracle_unit_commands.c, src/modules/avformat/Makefile, src/modules/avformat/producer_avformat.c, src/modules/core/Makefile, src/modules/core/filter_obscure.c, src/modules/core/filter_resize.c, src/modules/core/transition_composite.c, src/modules/dv/Makefile, src/modules/fezzik/Makefile, src/modules/ffmpeg/Makefile, src/modules/gtk2/filter_rescale.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/inigo/Makefile, src/modules/resample/Makefile, src/modules/sdl/Makefile, src/modules/sdl/consumer_sdl.c, src/modules/vorbis/Makefile, src/modules/westley/Makefile, src/modules/westley/producer_westley.c, src/tests/Makefile, src/valerie/Makefile: Optimisations (part 0), pixel v percentage, reworked aspect ratio calcs, ante/post properties for dv consumers, avformat rework, westley root 2004-02-16 ddennedy * src/modules/core/transition_composite.c, src/modules/gtk2/filter_rescale.c, src/modules/sdl/consumer_sdl.c: bug fixes * src/framework/mlt_consumer.c, src/framework/mlt_frame.c, src/framework/mlt_producer.c, src/modules/avformat/producer_avformat.c, src/modules/core/filter_resize.c, src/modules/core/producer_ppm.c, src/modules/core/producer_ppm.h, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/dv/producer_libdv.c, src/modules/ffmpeg/producer_ffmpeg.c, src/modules/gtk2/filter_rescale.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/sdl/consumer_sdl.c, src/modules/westley/consumer_westley.c: westley serialises with entry in/out; full field, aspect, and colour space normalisation; scaling overlays to consumer size; tagged frame mallocs with //IRRIGATE ME 2004-02-13 lilo_booter * src/framework/mlt_consumer.c, src/framework/mlt_properties.c, src/framework/mlt_properties.h: Properties rename and dump function * docs/testing-20040110.txt, src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_frame.c, src/framework/mlt_producer.c, src/modules/avformat/producer_avformat.c, src/modules/dv/consumer_libdv.c, src/modules/dv/producer_libdv.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/sdl/consumer_sdl.c, src/modules/westley/consumer_westley.c: Defaults for PAL/NTSC on producers and consumers 2004-02-13 ddennedy * docs/services.txt, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_brightness.c, src/modules/core/filter_brightness.h, src/modules/core/filter_volume.c, src/modules/core/transition_mix.c, src/modules/gtk2/filter_rescale.c: added brightness filter, added smooth ramping to audio processing, added start/end interpolation points to filter_mix and filter_volume 2004-02-12 ddennedy * mlt/Makefile, mlt/README, mlt/configure, mlt/docs/dvcp.txt, mlt/docs/inigo.txt, mlt/docs/services.txt, mlt/docs/testing-20040110.txt, mlt/docs/testing.txt, mlt/docs/valerie.txt, mlt/setenv, mlt/src/albino/Makefile, mlt/src/albino/albino.c, mlt/src/framework/Makefile, mlt/src/framework/config.h, mlt/src/framework/configure, mlt/src/framework/mlt.h, mlt/src/framework/mlt_consumer.c, mlt/src/framework/mlt_consumer.h, mlt/src/framework/mlt_factory.c, mlt/src/framework/mlt_factory.h, mlt/src/framework/mlt_field.c, mlt/src/framework/mlt_field.h, mlt/src/framework/mlt_filter.c, mlt/src/framework/mlt_filter.h, mlt/src/framework/mlt_frame.c, mlt/src/framework/mlt_frame.h, mlt/src/framework/mlt_manager.h, mlt/src/framework/mlt_multitrack.c, mlt/src/framework/mlt_multitrack.h, mlt/src/framework/mlt_playlist.c, mlt/src/framework/mlt_playlist.h, mlt/src/framework/mlt_producer.c, mlt/src/framework/mlt_producer.h, mlt/src/framework/mlt_properties.c, mlt/src/framework/mlt_properties.h, mlt/src/framework/mlt_property.c, mlt/src/framework/mlt_property.h, mlt/src/framework/mlt_repository.c, mlt/src/framework/mlt_repository.h, mlt/src/framework/mlt_service.c, mlt/src/framework/mlt_service.h, mlt/src/framework/mlt_tractor.c, mlt/src/framework/mlt_tractor.h, mlt/src/framework/mlt_transition.c, mlt/src/framework/mlt_transition.h, mlt/src/framework/mlt_types.h, mlt/src/humperdink/Makefile, mlt/src/humperdink/client.c, mlt/src/humperdink/client.h, mlt/src/humperdink/io.c, mlt/src/humperdink/io.h, mlt/src/humperdink/remote.c, mlt/src/inigo/Makefile, mlt/src/inigo/inigo.c, mlt/src/inigo/io.c, mlt/src/inigo/io.h, mlt/src/miracle/Makefile, mlt/src/miracle/configure, mlt/src/miracle/miracle.c, mlt/src/miracle/miracle_commands.c, mlt/src/miracle/miracle_commands.h, mlt/src/miracle/miracle_connection.c, mlt/src/miracle/miracle_connection.h, mlt/src/miracle/miracle_local.c, mlt/src/miracle/miracle_local.h, mlt/src/miracle/miracle_log.c, mlt/src/miracle/miracle_log.h, mlt/src/miracle/miracle_server.c, mlt/src/miracle/miracle_server.h, mlt/src/miracle/miracle_unit.c, mlt/src/miracle/miracle_unit.h, mlt/src/miracle/miracle_unit_commands.c, mlt/src/miracle/miracle_unit_commands.h, mlt/src/modules/Makefile, mlt/src/modules/configure, mlt/src/modules/core/Makefile, mlt/src/modules/core/configure, mlt/src/modules/core/factory.c, mlt/src/modules/core/filter_deinterlace.c, mlt/src/modules/core/filter_deinterlace.h, mlt/src/modules/core/filter_gamma.c, mlt/src/modules/core/filter_gamma.h, mlt/src/modules/core/filter_greyscale.c, mlt/src/modules/core/filter_greyscale.h, mlt/src/modules/core/filter_resize.c, mlt/src/modules/core/filter_resize.h, mlt/src/modules/core/filter_volume.c, mlt/src/modules/core/filter_volume.h, mlt/src/modules/core/producer_ppm.c, mlt/src/modules/core/producer_ppm.h, mlt/src/modules/core/transition_composite.c, mlt/src/modules/core/transition_composite.h, mlt/src/modules/core/transition_luma.c, mlt/src/modules/core/transition_luma.h, mlt/src/modules/core/transition_mix.c, mlt/src/modules/core/transition_mix.h, mlt/src/modules/dv/Makefile, mlt/src/modules/dv/configure, mlt/src/modules/dv/consumer_libdv.c, mlt/src/modules/dv/consumer_libdv.h, mlt/src/modules/dv/factory.c, mlt/src/modules/dv/producer_libdv.c, mlt/src/modules/dv/producer_libdv.h, mlt/src/modules/ffmpeg/Makefile, mlt/src/modules/ffmpeg/audio.sh, mlt/src/modules/ffmpeg/configure, mlt/src/modules/ffmpeg/consumer_ffmpeg.c, mlt/src/modules/ffmpeg/consumer_ffmpeg.h, mlt/src/modules/ffmpeg/factory.c, mlt/src/modules/ffmpeg/filter_ffmpeg_dub.c, mlt/src/modules/ffmpeg/filter_ffmpeg_dub.h, mlt/src/modules/ffmpeg/producer_ffmpeg.c, mlt/src/modules/ffmpeg/producer_ffmpeg.h, mlt/src/modules/ffmpeg/video.sh, mlt/src/modules/gtk2/Makefile, mlt/src/modules/gtk2/configure, mlt/src/modules/gtk2/factory.c, mlt/src/modules/gtk2/producer_pango.c, mlt/src/modules/gtk2/producer_pango.h, mlt/src/modules/gtk2/producer_pixbuf.c, mlt/src/modules/gtk2/producer_pixbuf.h, mlt/src/modules/inigo/Makefile, mlt/src/modules/inigo/configure, mlt/src/modules/inigo/factory.c, mlt/src/modules/inigo/producer_inigo.c, mlt/src/modules/inigo/producer_inigo.h, mlt/src/modules/resample/Makefile, mlt/src/modules/resample/configure, mlt/src/modules/resample/factory.c, mlt/src/modules/resample/filter_resample.c, mlt/src/modules/resample/filter_resample.h, mlt/src/modules/sdl/Makefile, mlt/src/modules/sdl/configure, mlt/src/modules/sdl/consumer_sdl.c, mlt/src/modules/sdl/consumer_sdl.h, mlt/src/modules/sdl/factory.c, mlt/src/modules/westley/Makefile, mlt/src/modules/westley/configure, mlt/src/modules/westley/consumer_westley.c, mlt/src/modules/westley/consumer_westley.h, mlt/src/modules/westley/factory.c, mlt/src/modules/westley/producer_westley.c, mlt/src/modules/westley/producer_westley.h, mlt/src/tests/Makefile, mlt/src/tests/charlie.c, mlt/src/tests/clock16ntsc.pgm, mlt/src/tests/clock16pal.pgm, mlt/src/tests/dan.c, mlt/src/tests/dissolve.c, mlt/src/tests/io.c, mlt/src/tests/io.h, mlt/src/tests/luma.c, mlt/src/tests/pango.c, mlt/src/tests/pixbuf.c, mlt/src/tests/setenv, mlt/src/tests/test.png, mlt/src/valerie/Makefile, mlt/src/valerie/configure, mlt/src/valerie/valerie.c, mlt/src/valerie/valerie.h, mlt/src/valerie/valerie_notifier.c, mlt/src/valerie/valerie_notifier.h, mlt/src/valerie/valerie_parser.c, mlt/src/valerie/valerie_parser.h, mlt/src/valerie/valerie_remote.c, mlt/src/valerie/valerie_remote.h, mlt/src/valerie/valerie_response.c, mlt/src/valerie/valerie_response.h, mlt/src/valerie/valerie_socket.c, mlt/src/valerie/valerie_socket.h, mlt/src/valerie/valerie_status.c, mlt/src/valerie/valerie_status.h, mlt/src/valerie/valerie_tokeniser.c, mlt/src/valerie/valerie_tokeniser.h, mlt/src/valerie/valerie_util.c, mlt/src/valerie/valerie_util.h: remove child mlt dir * docs/TODO, src/miracle/miracle_local.c: add TODO 2004-02-11 ddennedy * src/framework/mlt_frame.c, src/framework/mlt_playlist.c, src/miracle/miracle_local.c, src/valerie/valerie_notifier.c: segv handler, playlist_move bugfix, resize_yuv422 optimisation 2004-02-11 lilo_booter * docs/testing-20040110.txt, src/framework/mlt_frame.c, src/miracle/miracle_unit.c, src/miracle/miracle_unit_commands.c, src/modules/dv/consumer_libdv.c, src/valerie/valerie_notifier.c, src/valerie/valerie_notifier.h: Miracle mods - clean working, test card fix, silence dv when not playing 2004-02-10 lilo_booter * docs/testing-20040110.txt, src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/framework/mlt_properties.c, src/miracle/miracle_unit.c, src/valerie/valerie_notifier.c, src/valerie/valerie_status.h: Miracle mods 2004-02-10 ddennedy * setenv, src/framework/mlt_producer.c, src/modules/fezzik/producer_fezzik.c, src/modules/resample/filter_resample.c, src/modules/westley/producer_westley.c: bugfixes 2004-02-09 lilo_booter * src/framework/mlt_filter.c, src/framework/mlt_frame.c: filter fixes * src/miracle/miracle_unit.c, src/modules/dv/consumer_libdv.c: brought by a resizable bunny * docs/services.txt, src/modules/gtk2/producer_pango.c: pango colour handling 2004-02-08 lilo_booter * src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/modules/core/transition_luma.c: luma funkiness * src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/modules/core/transition_composite.c, src/modules/fezzik/producer_fezzik.c, src/modules/gtk2/filter_rescale.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c: pixbuf, composite and fezzik mirrors 2004-02-07 lilo_booter * src/modules/avformat/producer_avformat.c, src/modules/sdl/consumer_sdl.c, src/modules/westley/producer_westley.c: Minor corrections, rescale=nearest for sdl 2004-02-07 ddennedy * src/modules/avformat/producer_avformat.c, src/modules/gtk2/filter_rescale.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c: fixup and disable rescale changes 2004-02-06 ddennedy * src/framework/mlt_frame.c, src/modules/core/filter_volume.c, src/modules/dv/producer_libdv.c, src/modules/fezzik/producer_fezzik.c, src/modules/gtk2/filter_rescale.c, src/modules/resample/filter_resample.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: some bugfixes, westley property handling reorg, make rescale respect the aspect ratio, make resize update the aspect ratio, add resize to fezzik 2004-02-06 lilo_booter * docs/services.txt, src/modules/core/filter_obscure.c, src/modules/core/transition_composite.c: composite * src/framework/mlt_factory.c, src/framework/mlt_tractor.c, src/miracle/miracle_unit.c, src/modules/Makefile, src/modules/fezzik/Makefile, src/modules/fezzik/configure, src/modules/fezzik/factory.c, src/modules/fezzik/producer_fezzik.c, src/modules/fezzik/producer_fezzik.h, src/modules/inigo/producer_inigo.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: adding the rock thrower... 2004-02-05 lilo_booter * docs/services.txt, setenv, src/framework/mlt_frame.c, src/framework/mlt_multitrack.c, src/framework/mlt_producer.c, src/framework/mlt_transition.c, src/miracle/miracle_unit.c, src/modules/dv/producer_libdv.c, src/modules/ffmpeg/consumer_ffmpeg.c, src/modules/ffmpeg/producer_ffmpeg.c, src/modules/resample/filter_resample.c, src/modules/sdl/consumer_sdl.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: westley/libxml2 mods, mcdv/mpeg release integration 2004-02-05 ddennedy * docs/inigo.txt, src/framework/mlt_frame.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: bugfixes to westley 2004-02-04 ddennedy * src/modules/gtk2/pixops.c, src/modules/gtk2/pixops.h: interim rescale improvements 2004-02-04 lilo_booter * src/framework/mlt_factory.c, src/framework/mlt_field.c, src/framework/mlt_repository.c, src/framework/mlt_tractor.c, src/inigo/inigo.c, src/miracle/miracle_unit.c, src/modules/Makefile, src/modules/core/filter_obscure.c, src/modules/inigo/configure, src/modules/inigo/factory.c, src/modules/inigo/producer_inigo.c, src/modules/inigo/producer_inigo.h, src/modules/westley/producer_westley.c: pre-beta cleanup part 1 2004-02-02 lilo_booter * src/inigo/inigo.c, src/modules/avformat/producer_avformat.c, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_obscure.c, src/modules/core/filter_obscure.h, src/modules/inigo/Makefile, src/modules/inigo/configure, src/modules/inigo/producer_inigo.c, src/modules/vorbis/Makefile: obscurer filter, consistency mods and bug fixes * src/framework/Makefile, src/framework/mlt.h, src/framework/mlt_deque.c, src/framework/mlt_deque.h, src/framework/mlt_factory.c, src/framework/mlt_field.c, src/framework/mlt_frame.c, src/framework/mlt_manager.h, src/framework/mlt_repository.c, src/framework/mlt_types.h: added deque, api design for manager, minor affine tweaks, experimental destructor work 2004-01-30 ddennedy * src/framework/mlt_frame.c, src/modules/avformat/producer_avformat.c, src/modules/gtk2/Makefile, src/modules/gtk2/configure, src/modules/gtk2/factory.c, src/modules/gtk2/filter_rescale.c, src/modules/gtk2/filter_rescale.h, src/modules/gtk2/have_mmx.S, src/modules/gtk2/pixops.c, src/modules/gtk2/pixops.h, src/modules/gtk2/producer_pango.c, src/modules/gtk2/scale_line_22_33_mmx.S, src/modules/vorbis/Makefile: some bugfixes and rescale filter 2004-01-28 ddennedy * docs/services.txt, src/modules/core/filter_volume.c: doc updates; property changes, and tweaks for volume filter normalisation 2004-01-27 ddennedy * src/modules/core/filter_volume.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: westley bugfixes and audio normalisation 2004-01-27 lilo_booter * README, docs/services.txt, src/framework/mlt_multitrack.c, src/miracle/miracle_unit.c, src/modules/Makefile, src/modules/avformat/producer_avformat.c, src/modules/inigo/producer_inigo.c, src/modules/vorbis/Makefile, src/modules/vorbis/configure, src/modules/vorbis/factory.c, src/modules/vorbis/producer_vorbis.c, src/modules/vorbis/producer_vorbis.h: vorbis producer added, clean up on clip handling in multitrack 2004-01-26 ddennedy * src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: westley updates for non-inline serialisation and code cleanup 2004-01-26 lilo_booter * src/framework/mlt_properties.c, src/miracle/miracle_unit.c, src/modules/avformat/producer_avformat.c: mutex protection of avformat, miracle avformat usage, and destrector reversal * README, docs/services.txt, src/modules/avformat/producer_avformat.c: Added avformat * README, docs/inigo.txt, src/framework/mlt_producer.c, src/inigo/inigo.c, src/modules/Makefile, src/modules/avformat/Makefile, src/modules/avformat/configure, src/modules/avformat/factory.c, src/modules/avformat/producer_avformat.c, src/modules/avformat/producer_avformat.h, src/modules/inigo/producer_inigo.c, src/modules/sdl/consumer_sdl.c: Added avformat 2004-01-25 ddennedy * src/framework/mlt_filter.c, src/framework/mlt_transition.c, src/modules/core/transition_luma.c, src/modules/inigo/producer_inigo.c, src/modules/westley/consumer_westley.c, src/modules/westley/producer_westley.c: updated westley 2004-01-22 ddennedy * mlt/src/modules/westley/consumer_westley.c, src/modules/westley/consumer_westley.c: xml based westley serialisation * mlt/src/framework/mlt_playlist.c, mlt/src/framework/mlt_tractor.c, mlt/src/framework/mlt_types.h, mlt/src/modules/westley/consumer_westley.c, src/framework/mlt_playlist.c, src/framework/mlt_tractor.c, src/framework/mlt_types.h, src/modules/westley/consumer_westley.c: xml based westley serialisation 2004-01-21 ddennedy * docs/services.txt, mlt/docs/services.txt, mlt/src/framework/mlt_multitrack.c, mlt/src/framework/mlt_multitrack.h, mlt/src/framework/mlt_repository.c, mlt/src/framework/mlt_service.c, mlt/src/framework/mlt_service.h, mlt/src/framework/mlt_tractor.c, mlt/src/framework/mlt_types.h, mlt/src/modules/Makefile, mlt/src/modules/westley/Makefile, mlt/src/modules/westley/configure, mlt/src/modules/westley/consumer_westley.c, mlt/src/modules/westley/consumer_westley.h, mlt/src/modules/westley/factory.c, mlt/src/modules/westley/producer_westley.c, mlt/src/modules/westley/producer_westley.h, mlt/src/tests/dan.c, src/framework/mlt_multitrack.c, src/framework/mlt_multitrack.h, src/framework/mlt_repository.c, src/framework/mlt_service.c, src/framework/mlt_service.h, src/framework/mlt_tractor.c, src/framework/mlt_types.h, src/modules/Makefile, src/modules/westley/Makefile, src/modules/westley/configure, src/modules/westley/consumer_westley.c, src/modules/westley/consumer_westley.h, src/modules/westley/factory.c, src/modules/westley/producer_westley.c, src/modules/westley/producer_westley.h, src/tests/dan.c: added modules/westley 2004-01-20 lilo_booter * docs/inigo.txt, mlt/docs/inigo.txt, mlt/src/modules/dv/consumer_libdv.c, src/modules/dv/consumer_libdv.c: updated libdv consumer 2004-01-19 lilo_booter * docs/inigo.txt, docs/testing-20040110.txt, mlt/docs/inigo.txt, mlt/docs/testing-20040110.txt, mlt/src/framework/mlt_consumer.c, mlt/src/framework/mlt_consumer.h, mlt/src/framework/mlt_frame.c, mlt/src/framework/mlt_tractor.c, mlt/src/inigo/inigo.c, mlt/src/miracle/miracle_unit.c, mlt/src/miracle/miracle_unit_commands.c, mlt/src/modules/core/transition_luma.c, mlt/src/modules/core/transition_mix.c, mlt/src/modules/sdl/consumer_sdl.c, src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_frame.c, src/framework/mlt_tractor.c, src/inigo/inigo.c, src/miracle/miracle_unit.c, src/miracle/miracle_unit_commands.c, src/modules/core/transition_luma.c, src/modules/core/transition_mix.c, src/modules/sdl/consumer_sdl.c: inigo docs load/stop corrections 2004-01-17 lilo_booter * docs/services.txt, mlt/docs/services.txt, mlt/src/framework/mlt_playlist.c, mlt/src/framework/mlt_playlist.h, mlt/src/framework/mlt_producer.c, mlt/src/modules/Makefile, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_producer.c, src/modules/Makefile: insert/move/remove dvcp operations 2004-01-17 ddennedy * mlt/src/modules/core/transition_mix.c, src/modules/core/transition_mix.c: default mix to 0.5 * docs/services.txt, mlt/docs/services.txt, mlt/src/miracle/miracle_log.c, mlt/src/miracle/miracle_unit.c, mlt/src/modules/Makefile, mlt/src/modules/core/Makefile, mlt/src/modules/core/configure, mlt/src/modules/core/factory.c, mlt/src/modules/core/filter_volume.c, mlt/src/modules/core/filter_volume.h, mlt/src/modules/core/transition_composite.c, mlt/src/modules/core/transition_composite.h, mlt/src/modules/core/transition_luma.c, mlt/src/modules/core/transition_mix.c, mlt/src/modules/core/transition_mix.h, mlt/src/modules/gtk2/producer_pango.c, mlt/src/modules/gtk2/producer_pixbuf.c, mlt/src/modules/resample/Makefile, mlt/src/modules/resample/configure, mlt/src/modules/resample/factory.c, mlt/src/modules/resample/filter_resample.c, mlt/src/modules/resample/filter_resample.h, mlt/src/tests/luma.c, mlt/src/tests/pango.c, src/miracle/miracle_log.c, src/miracle/miracle_unit.c, src/modules/Makefile, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_volume.c, src/modules/core/filter_volume.h, src/modules/core/transition_composite.c, src/modules/core/transition_composite.h, src/modules/core/transition_luma.c, src/modules/core/transition_mix.c, src/modules/core/transition_mix.h, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/resample/Makefile, src/modules/resample/configure, src/modules/resample/factory.c, src/modules/resample/filter_resample.c, src/modules/resample/filter_resample.h, src/tests/luma.c, src/tests/pango.c: new volume, mix, and resample filters and transitions 2004-01-15 lilo_booter * mlt/src/inigo/inigo.c, src/inigo/inigo.c: inigo usage message * mlt/src/framework/mlt_frame.c, mlt/src/framework/mlt_tractor.c, mlt/src/modules/inigo/producer_inigo.c, src/framework/mlt_frame.c, src/framework/mlt_tractor.c, src/modules/inigo/producer_inigo.c: finally - multitrack inigo serialisation * mlt/src/framework/mlt_producer.c, mlt/src/framework/mlt_tractor.c, src/framework/mlt_producer.c, src/framework/mlt_tractor.c: in/out specification on .inigo serialisations * mlt/src/framework/mlt_frame.c, mlt/src/framework/mlt_multitrack.c, mlt/src/framework/mlt_playlist.c, mlt/src/framework/mlt_producer.c, mlt/src/framework/mlt_properties.c, mlt/src/framework/mlt_tractor.c, mlt/src/framework/mlt_transition.c, mlt/src/framework/mlt_transition.h, mlt/src/inigo/inigo.c, mlt/src/modules/core/transition_composite.c, mlt/src/modules/core/transition_luma.c, mlt/src/modules/inigo/producer_inigo.c, mlt/src/tests/charlie.c, src/framework/mlt_frame.c, src/framework/mlt_multitrack.c, src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/framework/mlt_properties.c, src/framework/mlt_tractor.c, src/framework/mlt_transition.c, src/framework/mlt_transition.h, src/inigo/inigo.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/inigo/producer_inigo.c, src/tests/charlie.c: partial corrections to serialisation 2004-01-14 lilo_booter * mlt/src/framework/mlt_frame.c, mlt/src/framework/mlt_frame.h, mlt/src/framework/mlt_tractor.c, mlt/src/modules/core/transition_luma.c, mlt/src/modules/dv/consumer_libdv.c, mlt/src/modules/ffmpeg/producer_ffmpeg.c, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/framework/mlt_tractor.c, src/modules/core/transition_luma.c, src/modules/dv/consumer_libdv.c, src/modules/ffmpeg/producer_ffmpeg.c: some temporary fixes * mlt/src/modules/dv/consumer_libdv.c, src/modules/dv/consumer_libdv.c: Minor mods * mlt/src/framework/mlt_multitrack.c, mlt/src/framework/mlt_playlist.c, mlt/src/framework/mlt_producer.c, mlt/src/modules/ffmpeg/producer_ffmpeg.c, src/framework/mlt_multitrack.c, src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/modules/ffmpeg/producer_ffmpeg.c: Minor mods * mlt/src/framework/mlt_frame.c, src/framework/mlt_frame.c: Minor mods * docs/testing-20040110.txt, mlt/docs/testing-20040110.txt, mlt/src/framework/mlt_consumer.c, mlt/src/framework/mlt_factory.c, mlt/src/framework/mlt_field.c, mlt/src/framework/mlt_field.h, mlt/src/framework/mlt_filter.c, mlt/src/framework/mlt_filter.h, mlt/src/framework/mlt_frame.c, mlt/src/framework/mlt_frame.h, mlt/src/framework/mlt_multitrack.c, mlt/src/framework/mlt_multitrack.h, mlt/src/framework/mlt_playlist.c, mlt/src/framework/mlt_playlist.h, mlt/src/framework/mlt_producer.c, mlt/src/framework/mlt_producer.h, mlt/src/framework/mlt_properties.c, mlt/src/framework/mlt_properties.h, mlt/src/framework/mlt_property.c, mlt/src/framework/mlt_property.h, mlt/src/framework/mlt_tractor.c, mlt/src/framework/mlt_tractor.h, mlt/src/framework/mlt_transition.c, mlt/src/framework/mlt_transition.h, mlt/src/framework/mlt_types.h, mlt/src/inigo/inigo.c, mlt/src/miracle/miracle_unit.c, mlt/src/modules/core/producer_ppm.c, mlt/src/modules/core/transition_composite.c, mlt/src/modules/core/transition_luma.c, mlt/src/modules/dv/Makefile, mlt/src/modules/dv/configure, mlt/src/modules/dv/consumer_libdv.c, mlt/src/modules/dv/consumer_libdv.h, mlt/src/modules/dv/factory.c, mlt/src/modules/dv/producer_libdv.c, mlt/src/modules/ffmpeg/filter_ffmpeg_dub.c, mlt/src/modules/ffmpeg/producer_ffmpeg.c, mlt/src/modules/gtk2/producer_pango.c, mlt/src/modules/gtk2/producer_pixbuf.c, mlt/src/modules/inigo/producer_inigo.c, mlt/src/modules/sdl/consumer_sdl.c, src/framework/mlt_consumer.c, src/framework/mlt_factory.c, src/framework/mlt_field.c, src/framework/mlt_field.h, src/framework/mlt_filter.c, src/framework/mlt_filter.h, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/framework/mlt_multitrack.c, src/framework/mlt_multitrack.h, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/framework/mlt_tractor.c, src/framework/mlt_tractor.h, src/framework/mlt_transition.c, src/framework/mlt_transition.h, src/framework/mlt_types.h, src/inigo/inigo.c, src/miracle/miracle_unit.c, src/modules/core/producer_ppm.c, src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, src/modules/dv/Makefile, src/modules/dv/configure, src/modules/dv/consumer_libdv.c, src/modules/dv/consumer_libdv.h, src/modules/dv/factory.c, src/modules/dv/producer_libdv.c, src/modules/ffmpeg/filter_ffmpeg_dub.c, src/modules/ffmpeg/producer_ffmpeg.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/inigo/producer_inigo.c, src/modules/sdl/consumer_sdl.c: Removal of timecodes, consumer libdv, serialisation of inigo 2004-01-13 lilo_booter * README, docs/testing-20040110.txt, mlt/README, mlt/docs/testing-20040110.txt, mlt/setenv, setenv: minor doc updates 2004-01-12 lilo_booter * docs/testing-20040110.txt, mlt/docs/testing-20040110.txt, mlt/src/albino/Makefile, mlt/src/modules/configure, src/albino/Makefile, src/modules/configure: minor testing update 2004-01-12 ddennedy * docs/testing-20040110.txt, docs/testing.txt, mlt/docs/testing-20040110.txt, mlt/docs/testing.txt: update testing.txt for miracle and complete initial testing.txt results * docs/services.txt, mlt/docs/services.txt: change bluefish arg * docs/testing-20040110.txt, mlt/docs/testing-20040110.txt: updated with user acceptance test results 2004-01-12 lilo_booter * mlt/src/inigo/inigo.c, mlt/src/modules/inigo/producer_inigo.c, src/inigo/inigo.c, src/modules/inigo/producer_inigo.c: minor corrections * mlt/src/inigo/inigo.c, src/inigo/inigo.c: minor corrections * mlt/src/framework/mlt_playlist.c, src/framework/mlt_playlist.c: minor corrections * mlt/src/albino/albino.c, mlt/src/miracle/miracle_commands.c, mlt/src/miracle/miracle_connection.c, src/albino/albino.c, src/miracle/miracle_commands.c, src/miracle/miracle_connection.c: minor corrections * mlt/src/inigo/inigo.c, mlt/src/modules/inigo/producer_inigo.c, src/inigo/inigo.c, src/modules/inigo/producer_inigo.c: inigo rewrite, producer, serialise and deserialise * docs/services.txt, docs/testing-20040110.txt, mlt/docs/services.txt, mlt/docs/testing-20040110.txt, mlt/src/framework/mlt_frame.c, mlt/src/framework/mlt_playlist.c, mlt/src/inigo/inigo.c, mlt/src/miracle/miracle_unit.c, mlt/src/modules/Makefile, mlt/src/modules/ffmpeg/producer_ffmpeg.c, mlt/src/modules/inigo/Makefile, mlt/src/modules/inigo/configure, mlt/src/modules/inigo/factory.c, mlt/src/modules/inigo/producer_inigo.c, mlt/src/modules/inigo/producer_inigo.h, mlt/src/modules/sdl/consumer_sdl.c, src/framework/mlt_frame.c, src/framework/mlt_playlist.c, src/inigo/inigo.c, src/miracle/miracle_unit.c, src/modules/Makefile, src/modules/ffmpeg/producer_ffmpeg.c, src/modules/inigo/Makefile, src/modules/inigo/configure, src/modules/inigo/factory.c, src/modules/inigo/producer_inigo.c, src/modules/inigo/producer_inigo.h, src/modules/sdl/consumer_sdl.c: inigo rewrite, producer, serialise and deserialise 2004-01-12 ddennedy * docs/testing-20040110.txt, docs/testing.txt, mlt/docs/testing-20040110.txt, mlt/docs/testing.txt: adding testing.txt and initial test results * docs/services.txt, mlt/docs/services.txt: pango markup encoding * docs/services.txt, mlt/docs/services.txt, mlt/src/modules/gtk2/producer_pixbuf.c, src/modules/gtk2/producer_pixbuf.c: doc updates and better control of pixbuf composite property propogation * mlt/src/inigo/inigo.c, mlt/src/modules/core/transition_composite.c, mlt/src/modules/gtk2/producer_pango.c, mlt/src/modules/gtk2/producer_pango.h, src/inigo/inigo.c, src/modules/core/transition_composite.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pango.h: better propogating of producer and transition properties to the frame in pango and composite; add pango support to inigo 2004-01-11 ddennedy * mlt/src/framework/mlt_frame.c, src/framework/mlt_frame.c: small change to prevent segfault in some transitions time specifications 2004-01-11 lilo_booter * mlt/src/framework/mlt_multitrack.c, src/framework/mlt_multitrack.c: multitrack eof handling * docs/dvcp.txt, docs/valerie.txt, mlt/docs/dvcp.txt, mlt/docs/valerie.txt, mlt/src/framework/mlt_playlist.c, mlt/src/miracle/miracle_unit.c, mlt/src/miracle/miracle_unit.h, mlt/src/miracle/miracle_unit_commands.c, src/framework/mlt_playlist.c, src/miracle/miracle_unit.c, src/miracle/miracle_unit.h, src/miracle/miracle_unit_commands.c: uset and doco 2004-01-11 ddennedy * mlt/src/tests/dissolve.c, mlt/src/tests/luma.c, src/tests/dissolve.c, src/tests/luma.c: remove no longer necessary blanks * mlt/src/framework/mlt_frame.c, mlt/src/modules/core/transition_luma.c, mlt/src/modules/gtk2/producer_pango.c, mlt/src/modules/gtk2/producer_pixbuf.c, mlt/src/tests/Makefile, mlt/src/tests/clock16ntsc.pgm, mlt/src/tests/clock16pal.pgm, mlt/src/tests/dan.c, mlt/src/tests/dissolve.c, mlt/src/tests/luma.c, mlt/src/tests/pango.c, mlt/src/tests/pixbuf.c, src/framework/mlt_frame.c, src/modules/core/transition_luma.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/tests/Makefile, src/tests/clock16ntsc.pgm, src/tests/clock16pal.pgm, src/tests/dan.c, src/tests/dissolve.c, src/tests/luma.c, src/tests/pango.c, src/tests/pixbuf.c: 4 new tests, bugfixes in pango, pixbuf, transition_luma, and mlt_frame_audio_mix 2004-01-11 lilo_booter * mlt/src/framework/mlt_multitrack.c, mlt/src/framework/mlt_playlist.c, src/framework/mlt_multitrack.c, src/framework/mlt_playlist.c: eof=continue and eof=pause * mlt/src/framework/mlt_playlist.c, src/framework/mlt_playlist.c: end of playlist position fix 2004-01-10 ddennedy * mlt/src/framework/mlt_frame.c, mlt/src/modules/core/transition_luma.c, mlt/src/modules/sdl/consumer_sdl.c, mlt/src/tests/dan.c, src/framework/mlt_frame.c, src/modules/core/transition_luma.c, src/modules/sdl/consumer_sdl.c, src/tests/dan.c: attempt to retain samples in mlt_frame_mix_audio, make consumers request the number of samples to get_audio 2004-01-10 lilo_booter * mlt/src/framework/mlt_playlist.c, src/framework/mlt_playlist.c: in/out fix * mlt/src/inigo/inigo.c, src/inigo/inigo.c: inigo gets transitions * mlt/src/framework/mlt_playlist.c, mlt/src/framework/mlt_playlist.h, mlt/src/framework/mlt_producer.c, mlt/src/framework/mlt_producer.h, mlt/src/miracle/miracle_unit.c, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/miracle/miracle_unit.c: more int64 frame addressing in playlist 2004-01-09 lilo_booter * mlt/src/framework/mlt_playlist.c, mlt/src/framework/mlt_playlist.h, mlt/src/framework/mlt_producer.c, mlt/src/framework/mlt_producer.h, mlt/src/framework/mlt_property.c, mlt/src/framework/mlt_property.h, mlt/src/humperdink/client.c, mlt/src/humperdink/remote.c, mlt/src/miracle/miracle_local.c, mlt/src/miracle/miracle_unit.c, mlt/src/miracle/miracle_unit.h, mlt/src/miracle/miracle_unit_commands.c, mlt/src/modules/dv/producer_libdv.c, mlt/src/valerie/valerie.c, mlt/src/valerie/valerie.h, mlt/src/valerie/valerie_status.c, mlt/src/valerie/valerie_status.h, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/humperdink/client.c, src/humperdink/remote.c, src/miracle/miracle_local.c, src/miracle/miracle_unit.c, src/miracle/miracle_unit.h, src/miracle/miracle_unit_commands.c, src/modules/dv/producer_libdv.c, src/valerie/valerie.c, src/valerie/valerie.h, src/valerie/valerie_status.c, src/valerie/valerie_status.h: int64 based comms and more unit functionality * mlt/src/miracle/miracle.c, mlt/src/miracle/miracle_local.c, src/miracle/miracle.c, src/miracle/miracle_local.c: albino * Makefile, mlt/Makefile, mlt/setenv, mlt/src/albino/Makefile, mlt/src/albino/albino.c, mlt/src/framework/mlt_transition.c, mlt/src/framework/mlt_transition.h, mlt/src/miracle/Makefile, setenv, src/albino/Makefile, src/albino/albino.c, src/framework/mlt_transition.c, src/framework/mlt_transition.h, src/miracle/Makefile: albino 2004-01-08 lilo_booter * mlt/src/inigo/inigo.c, src/inigo/inigo.c: inigo track test * docs/services.txt, mlt/docs/services.txt, mlt/src/framework/mlt_playlist.c, mlt/src/framework/mlt_playlist.h, mlt/src/framework/mlt_properties.c, mlt/src/miracle/miracle_unit.c, mlt/src/miracle/miracle_unit.h, mlt/src/miracle/miracle_unit_commands.c, mlt/src/modules/dv/producer_libdv.c, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_properties.c, src/miracle/miracle_unit.c, src/miracle/miracle_unit.h, src/miracle/miracle_unit_commands.c, src/modules/dv/producer_libdv.c: More miracle mods 2004-01-08 ddennedy * mlt/src/modules/dv/producer_libdv.c, src/modules/dv/producer_libdv.c: some fixes to the fixes * docs/services.txt, mlt/docs/services.txt, mlt/src/framework/mlt_frame.c, mlt/src/framework/mlt_frame.h, mlt/src/modules/core/transition_luma.c, mlt/src/modules/dv/producer_libdv.c, mlt/src/modules/ffmpeg/producer_ffmpeg.c, mlt/src/modules/sdl/consumer_sdl.c, mlt/src/tests/dan.c, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/modules/core/transition_luma.c, src/modules/dv/producer_libdv.c, src/modules/ffmpeg/producer_ffmpeg.c, src/modules/sdl/consumer_sdl.c, src/tests/dan.c: move audio sample calculator to mlt_frame and use from ffmpeg and mcmpeg, add mlt_frame_audio_mix, add audio_crossfade to transition_luma, add to docs 2004-01-07 lilo_booter * Makefile, docs/services.txt, mlt/Makefile, mlt/docs/services.txt, mlt/setenv, mlt/src/framework/Makefile, mlt/src/framework/mlt_frame.c, mlt/src/framework/mlt_playlist.c, mlt/src/framework/mlt_playlist.h, mlt/src/framework/mlt_producer.c, mlt/src/humperdink/Makefile, mlt/src/humperdink/client.c, mlt/src/humperdink/client.h, mlt/src/humperdink/io.c, mlt/src/humperdink/io.h, mlt/src/humperdink/remote.c, mlt/src/inigo/inigo.c, mlt/src/miracle/Makefile, mlt/src/miracle/miracle.c, mlt/src/miracle/miracle_commands.c, mlt/src/miracle/miracle_commands.h, mlt/src/miracle/miracle_connection.c, mlt/src/miracle/miracle_connection.h, mlt/src/miracle/miracle_local.c, mlt/src/miracle/miracle_local.h, mlt/src/miracle/miracle_log.c, mlt/src/miracle/miracle_log.h, mlt/src/miracle/miracle_server.c, mlt/src/miracle/miracle_server.h, mlt/src/miracle/miracle_unit.c, mlt/src/miracle/miracle_unit.h, mlt/src/miracle/miracle_unit_commands.c, mlt/src/miracle/miracle_unit_commands.h, mlt/src/modules/core/producer_ppm.c, mlt/src/modules/dv/producer_libdv.c, mlt/src/modules/ffmpeg/audio.sh, mlt/src/modules/ffmpeg/producer_ffmpeg.c, mlt/src/modules/ffmpeg/video.sh, mlt/src/modules/gtk2/producer_pango.c, mlt/src/modules/gtk2/producer_pixbuf.c, mlt/src/modules/gtk2/producer_pixbuf.h, mlt/src/modules/sdl/consumer_sdl.c, mlt/src/valerie/Makefile, mlt/src/valerie/valerie.c, mlt/src/valerie/valerie.h, setenv, src/framework/Makefile, src/framework/mlt_frame.c, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_producer.c, src/humperdink/Makefile, src/humperdink/client.c, src/humperdink/client.h, src/humperdink/io.c, src/humperdink/io.h, src/humperdink/remote.c, src/inigo/inigo.c, src/miracle/Makefile, src/miracle/miracle.c, src/miracle/miracle_commands.c, src/miracle/miracle_commands.h, src/miracle/miracle_connection.c, src/miracle/miracle_connection.h, src/miracle/miracle_local.c, src/miracle/miracle_local.h, src/miracle/miracle_log.c, src/miracle/miracle_log.h, src/miracle/miracle_server.c, src/miracle/miracle_server.h, src/miracle/miracle_unit.c, src/miracle/miracle_unit.h, src/miracle/miracle_unit_commands.c, src/miracle/miracle_unit_commands.h, src/modules/core/producer_ppm.c, src/modules/dv/producer_libdv.c, src/modules/ffmpeg/audio.sh, src/modules/ffmpeg/producer_ffmpeg.c, src/modules/ffmpeg/video.sh, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, src/modules/gtk2/producer_pixbuf.h, src/modules/sdl/consumer_sdl.c, src/valerie/Makefile, src/valerie/valerie.c, src/valerie/valerie.h: miracle part 1 2004-01-06 ddennedy * mlt/src/modules/core/transition_luma.c, mlt/src/modules/core/transition_luma.h, src/modules/core/transition_luma.c, src/modules/core/transition_luma.h: add forgotten files * mlt/src/framework/mlt_transition.c, mlt/src/framework/mlt_transition.h, mlt/src/modules/core/Makefile, mlt/src/modules/core/configure, mlt/src/modules/core/factory.c, mlt/src/modules/dv/producer_libdv.c, mlt/src/tests/dan.c, src/framework/mlt_transition.c, src/framework/mlt_transition.h, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/dv/producer_libdv.c, src/tests/dan.c: added luma transition and new frame properties 2004-01-03 lilo_booter * mlt/src/framework/mlt_multitrack.c, mlt/src/framework/mlt_playlist.c, mlt/src/framework/mlt_producer.c, mlt/src/inigo/inigo.c, mlt/src/modules/ffmpeg/producer_ffmpeg.c, src/framework/mlt_multitrack.c, src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/inigo/inigo.c, src/modules/ffmpeg/producer_ffmpeg.c: more complete next/prev clip behaviour 2004-01-02 ddennedy * mlt/src/framework/mlt_frame.c, mlt/src/modules/core/transition_composite.c, mlt/src/modules/gtk2/producer_pango.c, mlt/src/modules/gtk2/producer_pango.h, mlt/src/tests/dan.c, src/framework/mlt_frame.c, src/modules/core/transition_composite.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pango.h, src/tests/dan.c: fixup and optimize edge conditions of composite; updated property handling of producer_pango 2004-01-02 lilo_booter * docs/services.txt, mlt/docs/services.txt, mlt/src/framework/mlt_multitrack.c, mlt/src/framework/mlt_multitrack.h, mlt/src/framework/mlt_playlist.c, mlt/src/framework/mlt_playlist.h, mlt/src/framework/mlt_producer.c, mlt/src/framework/mlt_properties.c, mlt/src/framework/mlt_properties.h, mlt/src/framework/mlt_types.h, mlt/src/inigo/inigo.c, mlt/src/modules/dv/producer_libdv.c, mlt/src/modules/ffmpeg/Makefile, mlt/src/modules/ffmpeg/configure, mlt/src/modules/ffmpeg/consumer_ffmpeg.c, mlt/src/modules/ffmpeg/consumer_ffmpeg.h, mlt/src/modules/ffmpeg/factory.c, mlt/src/modules/ffmpeg/producer_ffmpeg.c, mlt/src/modules/gtk2/producer_pixbuf.c, mlt/src/modules/sdl/consumer_sdl.c, src/framework/mlt_multitrack.c, src/framework/mlt_multitrack.h, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_producer.c, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_types.h, src/inigo/inigo.c, src/modules/dv/producer_libdv.c, src/modules/ffmpeg/Makefile, src/modules/ffmpeg/configure, src/modules/ffmpeg/consumer_ffmpeg.c, src/modules/ffmpeg/consumer_ffmpeg.h, src/modules/ffmpeg/factory.c, src/modules/ffmpeg/producer_ffmpeg.c, src/modules/gtk2/producer_pixbuf.c, src/modules/sdl/consumer_sdl.c: incomplete next/prev clip behaviour 2004-01-01 lilo_booter * docs/services.txt, mlt/docs/services.txt, mlt/src/framework/mlt_factory.c, mlt/src/framework/mlt_factory.h, mlt/src/framework/mlt_multitrack.c, mlt/src/framework/mlt_producer.c, mlt/src/modules/ffmpeg/audio.sh, mlt/src/modules/ffmpeg/filter_ffmpeg_dub.c, mlt/src/modules/ffmpeg/producer_ffmpeg.c, mlt/src/modules/ffmpeg/producer_ffmpeg.h, mlt/src/modules/ffmpeg/video.sh, src/framework/mlt_factory.c, src/framework/mlt_factory.h, src/framework/mlt_multitrack.c, src/framework/mlt_producer.c, src/modules/ffmpeg/audio.sh, src/modules/ffmpeg/filter_ffmpeg_dub.c, src/modules/ffmpeg/producer_ffmpeg.c, src/modules/ffmpeg/producer_ffmpeg.h, src/modules/ffmpeg/video.sh: ntsc fixes and service doco for discussion 2003-12-31 lilo_booter * mlt/src/modules/ffmpeg/Makefile, mlt/src/modules/ffmpeg/configure, mlt/src/modules/ffmpeg/factory.c, mlt/src/modules/ffmpeg/filter_ffmpeg_dub.c, mlt/src/modules/ffmpeg/filter_ffmpeg_dub.h, mlt/src/modules/ffmpeg/producer_ffmpeg.c, mlt/src/modules/gtk2/producer_pixbuf.c, src/modules/ffmpeg/Makefile, src/modules/ffmpeg/configure, src/modules/ffmpeg/factory.c, src/modules/ffmpeg/filter_ffmpeg_dub.c, src/modules/ffmpeg/filter_ffmpeg_dub.h, src/modules/ffmpeg/producer_ffmpeg.c, src/modules/gtk2/producer_pixbuf.c: ffmpeg audio dub 2003-12-30 lilo_booter * mlt/src/modules/ffmpeg/producer_ffmpeg.c, mlt/src/modules/sdl/consumer_sdl.c, src/modules/ffmpeg/producer_ffmpeg.c, src/modules/sdl/consumer_sdl.c: correction on playlist ffmpeg sizing issue and additional sdl tweaks * mlt/src/framework/mlt_frame.c, mlt/src/framework/mlt_multitrack.c, mlt/src/inigo/inigo.c, mlt/src/modules/ffmpeg/producer_ffmpeg.c, mlt/src/modules/gtk2/producer_pixbuf.c, mlt/src/modules/sdl/consumer_sdl.c, src/framework/mlt_frame.c, src/framework/mlt_multitrack.c, src/inigo/inigo.c, src/modules/ffmpeg/producer_ffmpeg.c, src/modules/gtk2/producer_pixbuf.c, src/modules/sdl/consumer_sdl.c: More sdl experimental mods, pixbuf writable work around and minor fixes 2003-12-29 lilo_booter * mlt/src/framework/mlt_multitrack.c, mlt/src/framework/mlt_playlist.c, mlt/src/framework/mlt_producer.c, mlt/src/modules/ffmpeg/producer_ffmpeg.c, mlt/src/modules/sdl/consumer_sdl.c, src/framework/mlt_multitrack.c, src/framework/mlt_playlist.c, src/framework/mlt_producer.c, src/modules/ffmpeg/producer_ffmpeg.c, src/modules/sdl/consumer_sdl.c: Many ffmpeg and sdl mods 2003-12-28 lilo_booter * mlt/src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl.c: SDL a/v sync issues [incomplete] * mlt/src/framework/mlt_frame.c, mlt/src/framework/mlt_frame.h, mlt/src/inigo/inigo.c, mlt/src/modules/Makefile, mlt/src/modules/core/factory.c, mlt/src/modules/core/producer_ppm.c, mlt/src/modules/core/producer_ppm.h, mlt/src/modules/ffmpeg/Makefile, mlt/src/modules/ffmpeg/configure, mlt/src/modules/ffmpeg/factory.c, mlt/src/modules/ffmpeg/producer_ffmpeg.c, mlt/src/modules/ffmpeg/producer_ffmpeg.h, mlt/src/modules/sdl/consumer_sdl.c, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/inigo/inigo.c, src/modules/Makefile, src/modules/core/factory.c, src/modules/core/producer_ppm.c, src/modules/core/producer_ppm.h, src/modules/ffmpeg/Makefile, src/modules/ffmpeg/configure, src/modules/ffmpeg/factory.c, src/modules/ffmpeg/producer_ffmpeg.c, src/modules/ffmpeg/producer_ffmpeg.h, src/modules/sdl/consumer_sdl.c: Added ffmpeg producer 2003-12-27 lilo_booter * Makefile, README, configure, mlt/Makefile, mlt/README, mlt/configure, mlt/setenv, mlt/src/framework/mlt_frame.c, mlt/src/framework/mlt_playlist.c, mlt/src/inigo/Makefile, mlt/src/inigo/inigo.c, mlt/src/inigo/io.c, mlt/src/inigo/io.h, mlt/src/modules/core/filter_resize.c, mlt/src/modules/core/filter_resize.h, mlt/src/modules/core/producer_ppm.c, mlt/src/modules/core/producer_ppm.h, mlt/src/modules/sdl/consumer_sdl.c, mlt/src/tests/charlie.c, setenv, src/framework/mlt_frame.c, src/framework/mlt_playlist.c, src/inigo/Makefile, src/inigo/inigo.c, src/inigo/io.c, src/inigo/io.h, src/modules/core/filter_resize.c, src/modules/core/filter_resize.h, src/modules/core/producer_ppm.c, src/modules/core/producer_ppm.h, src/modules/sdl/consumer_sdl.c, src/tests/charlie.c: ppm ffmpeg 2003-12-26 lilo_booter * mlt/src/modules/core/Makefile, mlt/src/modules/core/configure, mlt/src/modules/core/factory.c, mlt/src/modules/core/filter_gamma.c, mlt/src/modules/core/filter_gamma.h, mlt/src/modules/core/filter_resize.h, mlt/src/tests/io.c, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_gamma.c, src/modules/core/filter_gamma.h, src/modules/core/filter_resize.h, src/tests/io.c: Gamma filter * mlt/src/tests/charlie.c, src/tests/charlie.c: quit fix for SDL * mlt/src/framework/mlt_playlist.c, src/framework/mlt_playlist.c: playlist fps fix * mlt/src/tests/io.c, mlt/src/tests/io.h, src/tests/io.c, src/tests/io.h: added io files * mlt/src/tests/charlie.c, src/tests/charlie.c: SDL transport callback * mlt/src/framework/mlt_property.c, mlt/src/modules/sdl/consumer_sdl.c, mlt/src/tests/Makefile, mlt/src/tests/charlie.c, src/framework/mlt_property.c, src/modules/sdl/consumer_sdl.c, src/tests/Makefile, src/tests/charlie.c: SDL transport callback * mlt/src/framework/mlt_frame.c, mlt/src/framework/mlt_frame.h, mlt/src/modules/sdl/consumer_sdl.c, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/modules/sdl/consumer_sdl.c: More SDL tweaks * mlt/src/framework/mlt_frame.c, mlt/src/modules/sdl/consumer_sdl.c, mlt/src/modules/sdl/consumer_sdl.h, mlt/src/tests/charlie.c, src/framework/mlt_frame.c, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl.h, src/tests/charlie.c: More SDL updates * mlt/src/modules/core/filter_resize.c, mlt/src/modules/sdl/consumer_sdl.c, src/modules/core/filter_resize.c, src/modules/sdl/consumer_sdl.c: SDL updates and resizing fix 2003-12-25 lilo_booter * mlt/src/framework/mlt_field.c, mlt/src/framework/mlt_field.h, mlt/src/framework/mlt_filter.c, mlt/src/framework/mlt_filter.h, mlt/src/framework/mlt_playlist.c, mlt/src/modules/core/Makefile, mlt/src/modules/core/configure, mlt/src/modules/core/factory.c, mlt/src/modules/core/filter_resize.c, mlt/src/modules/core/filter_resize.h, mlt/src/modules/gtk2/producer_pixbuf.c, mlt/src/modules/gtk2/producer_pixbuf.h, mlt/src/modules/sdl/consumer_sdl.c, mlt/src/tests/charlie.c, src/framework/mlt_field.c, src/framework/mlt_field.h, src/framework/mlt_filter.c, src/framework/mlt_filter.h, src/framework/mlt_playlist.c, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_resize.c, src/modules/core/filter_resize.h, src/modules/gtk2/producer_pixbuf.c, src/modules/gtk2/producer_pixbuf.h, src/modules/sdl/consumer_sdl.c, src/tests/charlie.c: field and playlist enhancements, producer pixbuf reorg 2003-12-24 lilo_booter * mlt/src/framework/Makefile, mlt/src/framework/mlt.h, mlt/src/framework/mlt_field.c, mlt/src/framework/mlt_field.h, mlt/src/framework/mlt_filter.c, mlt/src/framework/mlt_filter.h, mlt/src/framework/mlt_playlist.c, mlt/src/framework/mlt_playlist.h, mlt/src/framework/mlt_types.h, mlt/src/tests/charlie.c, mlt/src/tests/setenv, src/framework/Makefile, src/framework/mlt.h, src/framework/mlt_field.c, src/framework/mlt_field.h, src/framework/mlt_filter.c, src/framework/mlt_filter.h, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_types.h, src/tests/charlie.c, src/tests/setenv: field and playlist provisional implementations 2003-12-23 lilo_booter * mlt/src/modules/sdl/consumer_sdl.c, mlt/src/tests/charlie.c, mlt/src/tests/dan.c, src/modules/sdl/consumer_sdl.c, src/tests/charlie.c, src/tests/dan.c: SDL fixes on close * mlt/src/framework/mlt_frame.c, mlt/src/framework/mlt_frame.h, mlt/src/modules/Makefile, mlt/src/tests/charlie.c, mlt/src/tests/setenv, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/modules/Makefile, src/tests/charlie.c, src/tests/setenv: test frame services 2003-12-23 ddennedy * mlt/src/framework/mlt_consumer.c, mlt/src/framework/mlt_consumer.h, mlt/src/framework/mlt_frame.h, mlt/src/modules/gtk2/producer_pango.c, mlt/src/modules/gtk2/producer_pango.h, mlt/src/modules/gtk2/producer_pixbuf.c, mlt/src/modules/gtk2/producer_pixbuf.h, mlt/src/tests/dan.c, src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_frame.h, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pango.h, src/modules/gtk2/producer_pixbuf.c, src/modules/gtk2/producer_pixbuf.h, src/tests/dan.c: add video_standard enum to mlt_frame, add mlt_consumer_properties, add properties to gtk2 producers and bluefish consumer 2003-12-22 lilo_booter * mlt/src/modules/Makefile, mlt/src/modules/dv/producer_libdv.c, mlt/src/tests/charlie.c, src/modules/Makefile, src/modules/dv/producer_libdv.c, src/tests/charlie.c: minor tidy up 2003-12-22 ddennedy * mlt/src/modules/Makefile, mlt/src/modules/gtk2/configure, mlt/src/tests/dan.c, src/modules/Makefile, src/modules/gtk2/configure, src/tests/dan.c: allow for building mainconcept and bluefish plugins outside cvs * mlt/src/framework/mlt_frame.c, mlt/src/modules/gtk2/Makefile, mlt/src/modules/gtk2/factory.c, mlt/src/modules/gtk2/producer_pango.c, mlt/src/modules/gtk2/producer_pango.h, mlt/src/modules/gtk2/producer_pixbuf.c, mlt/src/modules/gtk2/producer_pixbuf.h, mlt/src/tests/dan.c, src/framework/mlt_frame.c, src/modules/gtk2/Makefile, src/modules/gtk2/factory.c, src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pango.h, src/modules/gtk2/producer_pixbuf.c, src/modules/gtk2/producer_pixbuf.h, src/tests/dan.c: add sample aspect ratio scaling output to producer_pixbuf, fix a bug in rgb to yuv conversions, add producer_pango 2003-12-22 lilo_booter * mlt/src/framework/mlt.h, mlt/src/framework/mlt_repository.c, src/framework/mlt.h, src/framework/mlt_repository.c: c++ compatability * README, mlt/README, mlt/src/framework/Makefile, mlt/src/framework/mlt.h, mlt/src/framework/mlt_factory.c, mlt/src/framework/mlt_factory.h, mlt/src/framework/mlt_multitrack.c, mlt/src/framework/mlt_playlist.h, mlt/src/framework/mlt_repository.c, mlt/src/framework/mlt_repository.h, mlt/src/modules/core/Makefile, mlt/src/modules/dv/Makefile, mlt/src/modules/gtk2/Makefile, mlt/src/modules/sdl/Makefile, mlt/src/tests/Makefile, mlt/src/tests/charlie.c, mlt/src/tests/dan.c, src/framework/Makefile, src/framework/mlt.h, src/framework/mlt_factory.c, src/framework/mlt_factory.h, src/framework/mlt_multitrack.c, src/framework/mlt_playlist.h, src/framework/mlt_repository.c, src/framework/mlt_repository.h, src/modules/core/Makefile, src/modules/dv/Makefile, src/modules/gtk2/Makefile, src/modules/sdl/Makefile, src/tests/Makefile, src/tests/charlie.c, src/tests/dan.c: Factory implementation 2003-12-19 lilo_booter * mlt/src/modules/core/Makefile, mlt/src/modules/core/configure, mlt/src/modules/core/factory.c, mlt/src/modules/core/filter_deinterlace.c, mlt/src/modules/core/filter_deinterlace.h, mlt/src/modules/core/filter_greyscale.c, mlt/src/modules/core/filter_greyscale.h, mlt/src/modules/core/producer_ppm.c, mlt/src/modules/core/producer_ppm.h, mlt/src/modules/core/transition_composite.c, mlt/src/modules/core/transition_composite.h, src/modules/core/Makefile, src/modules/core/configure, src/modules/core/factory.c, src/modules/core/filter_deinterlace.c, src/modules/core/filter_deinterlace.h, src/modules/core/filter_greyscale.c, src/modules/core/filter_greyscale.h, src/modules/core/producer_ppm.c, src/modules/core/producer_ppm.h, src/modules/core/transition_composite.c, src/modules/core/transition_composite.h: Added files rejected by import * Makefile, README, configure, mlt/Makefile, mlt/README, mlt/configure, mlt/src/framework/Makefile, mlt/src/framework/config.h, mlt/src/framework/configure, mlt/src/framework/mlt_consumer.c, mlt/src/framework/mlt_consumer.h, mlt/src/framework/mlt_factory.c, mlt/src/framework/mlt_factory.h, mlt/src/framework/mlt_filter.c, mlt/src/framework/mlt_filter.h, mlt/src/framework/mlt_frame.c, mlt/src/framework/mlt_frame.h, mlt/src/framework/mlt_manager.h, mlt/src/framework/mlt_multitrack.c, mlt/src/framework/mlt_multitrack.h, mlt/src/framework/mlt_playlist.c, mlt/src/framework/mlt_playlist.h, mlt/src/framework/mlt_producer.c, mlt/src/framework/mlt_producer.h, mlt/src/framework/mlt_properties.c, mlt/src/framework/mlt_properties.h, mlt/src/framework/mlt_property.c, mlt/src/framework/mlt_property.h, mlt/src/framework/mlt_repository.c, mlt/src/framework/mlt_repository.h, mlt/src/framework/mlt_service.c, mlt/src/framework/mlt_service.h, mlt/src/framework/mlt_tractor.c, mlt/src/framework/mlt_tractor.h, mlt/src/framework/mlt_transition.c, mlt/src/framework/mlt_transition.h, mlt/src/framework/mlt_types.h, mlt/src/miracle/configure, mlt/src/miracle/miracle.c, mlt/src/miracle/miracle_commands.c, mlt/src/miracle/miracle_commands.h, mlt/src/miracle/miracle_connection.c, mlt/src/miracle/miracle_connection.h, mlt/src/miracle/miracle_local.c, mlt/src/miracle/miracle_local.h, mlt/src/miracle/miracle_log.c, mlt/src/miracle/miracle_log.h, mlt/src/miracle/miracle_server.c, mlt/src/miracle/miracle_server.h, mlt/src/miracle/miracle_unit.c, mlt/src/miracle/miracle_unit.h, mlt/src/miracle/miracle_unit_commands.c, mlt/src/miracle/miracle_unit_commands.h, mlt/src/modules/Makefile, mlt/src/modules/configure, mlt/src/modules/dv/Makefile, mlt/src/modules/dv/configure, mlt/src/modules/dv/factory.c, mlt/src/modules/dv/producer_libdv.c, mlt/src/modules/dv/producer_libdv.h, mlt/src/modules/gtk2/Makefile, mlt/src/modules/gtk2/configure, mlt/src/modules/gtk2/factory.c, mlt/src/modules/gtk2/producer_pixbuf.c, mlt/src/modules/gtk2/producer_pixbuf.h, mlt/src/modules/sdl/Makefile, mlt/src/modules/sdl/configure, mlt/src/modules/sdl/consumer_sdl.c, mlt/src/modules/sdl/consumer_sdl.h, mlt/src/modules/sdl/factory.c, mlt/src/tests/charlie.c, mlt/src/tests/dan.c, mlt/src/tests/test.png, mlt/src/valerie/Makefile, mlt/src/valerie/configure, mlt/src/valerie/valerie.c, mlt/src/valerie/valerie.h, mlt/src/valerie/valerie_notifier.c, mlt/src/valerie/valerie_notifier.h, mlt/src/valerie/valerie_parser.c, mlt/src/valerie/valerie_parser.h, mlt/src/valerie/valerie_remote.c, mlt/src/valerie/valerie_remote.h, mlt/src/valerie/valerie_response.c, mlt/src/valerie/valerie_response.h, mlt/src/valerie/valerie_socket.c, mlt/src/valerie/valerie_socket.h, mlt/src/valerie/valerie_status.c, mlt/src/valerie/valerie_status.h, mlt/src/valerie/valerie_tokeniser.c, mlt/src/valerie/valerie_tokeniser.h, mlt/src/valerie/valerie_util.c, mlt/src/valerie/valerie_util.h, src/framework/Makefile, src/framework/config.h, src/framework/configure, src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, src/framework/mlt_factory.c, src/framework/mlt_factory.h, src/framework/mlt_filter.c, src/framework/mlt_filter.h, src/framework/mlt_frame.c, src/framework/mlt_frame.h, src/framework/mlt_manager.h, src/framework/mlt_multitrack.c, src/framework/mlt_multitrack.h, src/framework/mlt_playlist.c, src/framework/mlt_playlist.h, src/framework/mlt_producer.c, src/framework/mlt_producer.h, src/framework/mlt_properties.c, src/framework/mlt_properties.h, src/framework/mlt_property.c, src/framework/mlt_property.h, src/framework/mlt_repository.c, src/framework/mlt_repository.h, src/framework/mlt_service.c, src/framework/mlt_service.h, src/framework/mlt_tractor.c, src/framework/mlt_tractor.h, src/framework/mlt_transition.c, src/framework/mlt_transition.h, src/framework/mlt_types.h, src/miracle/configure, src/miracle/miracle.c, src/miracle/miracle_commands.c, src/miracle/miracle_commands.h, src/miracle/miracle_connection.c, src/miracle/miracle_connection.h, src/miracle/miracle_local.c, src/miracle/miracle_local.h, src/miracle/miracle_log.c, src/miracle/miracle_log.h, src/miracle/miracle_server.c, src/miracle/miracle_server.h, src/miracle/miracle_unit.c, src/miracle/miracle_unit.h, src/miracle/miracle_unit_commands.c, src/miracle/miracle_unit_commands.h, src/modules/Makefile, src/modules/configure, src/modules/dv/Makefile, src/modules/dv/configure, src/modules/dv/factory.c, src/modules/dv/producer_libdv.c, src/modules/dv/producer_libdv.h, src/modules/gtk2/Makefile, src/modules/gtk2/configure, src/modules/gtk2/factory.c, src/modules/gtk2/producer_pixbuf.c, src/modules/gtk2/producer_pixbuf.h, src/modules/sdl/Makefile, src/modules/sdl/configure, src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl.h, src/modules/sdl/factory.c, src/tests/charlie.c, src/tests/dan.c, src/tests/test.png, src/valerie/Makefile, src/valerie/configure, src/valerie/valerie.c, src/valerie/valerie.h, src/valerie/valerie_notifier.c, src/valerie/valerie_notifier.h, src/valerie/valerie_parser.c, src/valerie/valerie_parser.h, src/valerie/valerie_remote.c, src/valerie/valerie_remote.h, src/valerie/valerie_response.c, src/valerie/valerie_response.h, src/valerie/valerie_socket.c, src/valerie/valerie_socket.h, src/valerie/valerie_status.c, src/valerie/valerie_status.h, src/valerie/valerie_tokeniser.c, src/valerie/valerie_tokeniser.h, src/valerie/valerie_util.c, src/valerie/valerie_util.h: Initial revision mlt-0.9.0/Doxyfile000066400000000000000000001661361215300731300140320ustar00rootroot00000000000000# Doxyfile 1.5.7 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = MLT # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = 0.9.0 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = docs # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, # Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, # Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, # Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = src/framework/ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = YES # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = "properties=\xrefitem properties \"Property\" \"Properties Dictionary\"" "event=\xrefitem event \"Event\" \"Events Dictionary\"" # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penality. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will rougly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = YES # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST = YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by # doxygen. The layout file controls the global structure of the generated output files # in an output format independent way. The create the layout file that represents # doxygen's defaults, run doxygen with the -l option. You can optionally specify a # file name after the option, if omitted DoxygenLayout.xml will be used as the name # of the layout file. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = src/framework # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER # are set, an additional index file will be generated that can be used as input for # Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated # HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # Qt Help Project / Namespace. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # Qt Help Project / Virtual Folders. QHP_VIRTUAL_FOLDER = doc # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file . QHG_LOCATION = # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to FRAME, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. Other possible values # for this tag are: HIERARCHIES, which will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list; # ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which # disables this behavior completely. For backwards compatibility with previous # releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE # respectively. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = FreeSans # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = YES # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO mlt-0.9.0/GPL000066400000000000000000000431101215300731300126530ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. mlt-0.9.0/GPLv3000066400000000000000000001045131215300731300131310ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . mlt-0.9.0/Makefile000066400000000000000000000034011215300731300137450ustar00rootroot00000000000000SUBDIRS = src/framework \ src/mlt++ \ src/melt \ src/modules \ src/swig \ profiles all clean: list='$(SUBDIRS)'; \ for subdir in $$list; do \ $(MAKE) -s -C $$subdir depend || exit 1; \ $(MAKE) -C $$subdir $@ || exit 1; \ done distclean: rm mlt-config packages.dat; \ list='$(SUBDIRS)'; \ for subdir in $$list; do \ $(MAKE) -C $$subdir $@ || exit 1; \ done; \ rm config.mak; dist-clean: distclean include config.mak install: install -d "$(DESTDIR)$(prefix)/bin" install -d "$(DESTDIR)$(prefix)/include" install -d "$(DESTDIR)$(libdir)" install -d "$(DESTDIR)$(moduledir)" ifeq ($(extra_versioning), true) ln -s "$(moduledir)" "$(DESTDIR)$(unversionedmoduledir)" endif install -d "$(DESTDIR)$(libdir)/pkgconfig" install -d "$(DESTDIR)$(mltdatadir)" ifeq ($(extra_versioning), true) ln -s "$(mltdatadir)" "$(DESTDIR)$(unversionedmltdatadir)" endif install -c -m 644 *.pc "$(DESTDIR)$(libdir)/pkgconfig" list='$(SUBDIRS)'; \ for subdir in $$list; do \ $(MAKE) DESTDIR=$(DESTDIR) -C $$subdir $@ || exit 1; \ done cp -R presets "$(DESTDIR)$(mltdatadir)" uninstall: rm -f "$(DESTDIR)$(bindir)"/mlt-config rm -f "$(DESTDIR)$(libdir)"/pkgconfig/mlt-framework.pc rm -f "$(DESTDIR)$(libdir)"/pkgconfig/mlt++.pc list='$(SUBDIRS)'; \ for subdir in $$list; do \ $(MAKE) DESTDIR=$(DESTDIR) -C $$subdir $@ || exit 1; \ done rm -rf "$(DESTDIR)$(prefix)/include/mlt" rm -rf "$(DESTDIR)$(mltdatadir)" ifeq ($(compat_dirs), true) rm -rf "$(DESTDIR)$(prefix)/share/mlt" endif dist: git archive --format=tar --prefix=mlt-$(version)/ v$(version) | gzip >mlt-$(version).tar.gz validate-yml: for file in `find src/modules -type f -name \*.yml`; do \ echo "validate: $$file"; \ kwalify -f src/framework/metaschema.yaml $$file || exit 1; \ done mlt-0.9.0/NEWS000066400000000000000000000566071215300731300130240ustar00rootroot00000000000000MLT Release Notes ----------------- Version 0.9.0 - June 2, 2013 This is a significant enhancement release. Build (especially interesting for Linux packagers) * Added --rename-melt and --enable-extra-versioning configure options. * Added symbol versioning on Linux. Framework * Improved pause behavior when using buffered rendering in mlt_consumer. * Added mlt_animation API (exposed via Mlt::Properties in C++). * Added mlt_rect and mlt_color types. * Deprecated mlt_geometry API. Modules * Support for the latest versions of FFmpeg and Libav (but dropping support for 0.5 and 0.6 versions). * Added alpha channel output to avformat consumer. * Added reconnect and exit_on_disconnect properties to avformat producer. * Added opengl module that uses Movit for GLSL image processing. * Added qglsl consumer to use opengl with avformat, sdi, and decklink. * Added avsync module with blipflash producer and consumer for testing. * Added new "count" producer to gtk2 module. * Changed frei0r to use index-based property names making it impervious to param name changes (param name still accepted for compatibility). * Added default parameter values to frei0r metadata. Other * Added more python example web services. * Added the beginnings of unit test suite. Version 0.8.8 - January 20, 2013 This is purely a bugfix release. See the ChangeLog or git log. Version 0.8.6 - November 14, 2012 This is a re-issue of the 0.8.4 release with a fix for a performance regression on videos that use full-range colorspaces such as yuv420p. Version 0.8.4 - November 13, 2012 This is a bugfix and minor enhancement release. * Added playlist-next event and PlaylistNextListener to Ruby binding * FFmpeg 1.0 and libAV master compatibility * Improvements to motion_est filter to generate keyframes for apps * Added audiolevel (measurement) filter Version 0.8.2 - August 28, 2012 This is a bugfix and minor enhancement release. * Overhaul of A/V sync with libavformat-based inputs. * Fix a major memory leak introduced in previous release. * Fixes to problems revealed by Coverity Scan static analysis. * Improved encoding presets. * melt can now be built without SDL with define MELT_NOSDL, which is handy for running it as a child process on Windows and OS X. * melt can now be signaled to quit, which also makes it more useful as a child process. Special thanks to Mikko Rapeli who provided many of the Coverity fixes. Version 0.8.0 - June 1, 2012 The minor version is increased due to the addition of time properties! The soname version increased in the process because some mlt_property functions changed; however, very few if any apps actually directly use mlt_property preferring to use mlt_properties instead. In addition: * improve seek speed on AVCHD when using FFmpeg v0.9.1+ (NOT Libav!) * composite and dissolve speed improvements on x86-64 * improve performance of caching in image producers * add device enumeration to decklink producer and consumer Special thanks go to contributors Maksym Veremeyenko and Ed Rogalsky. Version 0.7.8 - February 13, 2012 This is a bugfix and minor enhancement release. * Improved support for v53 of libavcodec/libavformat * Added "multi" consumer - multiple, simultanous outputs * Added framerate adaption to "consumer" producer and "multi" consumer * Can now use YADIF deinterlacer with decklink producer * Added "rtaudio" consumer for native audio support on multiple platforms * Added ability to request image format closest to source (mlt_image_none) * Added more audio formats * Added vqm (video quality measurement) transition Version 0.7.6 - October 31, 2011 This is a bugfix and minor enhancement release. * Improved support for v53 of libavcodec/libavformat (0.7 and 0.8 releases) * Major DeckLink consumer improvements * Much more metadata * Added audio-only JACK consumer * Added video stabilization filters * Added dual pass audio normalization to sox filter * Added VITC and VANC capture to DeckLink producer * Added support for writing timecode tracks * Added MLT, frei0r, and SoX version to xml serialization * Added D-10, XDCAM, DNxHD, and Sony-PSP encoding presets * Can now use rotoscoping for masking filters * Added dynamictext filter makes burned-in timecode and similar easier * Added support for consumer element in MLT XML * Added outlining, padding, and alignment to pango filter Special thanks go to contributors Maksym Veremeyenko, Brian Matherly, and Marco Gittler. Version 0.7.4 - July 16, 2011 This is a bugfix and minor enhancement release. Framework * Important: change consumer property profile to mlt_profile. * Improve frame-dropping and drop_max property to mlt_consumer. * Added support for presets for any service through special property named "properties" * Added mlt_profile_from_producer() for auto-profile. * Added mlt_properties_set_lcnumeric() and mlt_properties_get_lcnumeric(). * Added LC_NUMERIC to YAML Tiny metadata schema and parser. Modules * Added support for more than 2 channels of greater than 16-bit audio. * Added discrete filters for each SoX effect. * Added discrete filters for each LADSPA audio plugin. * Added automatic service metadata for SoX and LADSPA plugins. * Added at least basic metadata for nearly every service. * Added support for decklink on Windows (tested) and Mac OS X (untested). * Added support for JACK transport synchronization. * Added blacklist.txt to jackrack plugin (contains dssi-vst). * Rewrite of decklink consumer. * Added support for live network, multi-stream device, and pipe/fifo sources in avformat producer. * Added LC_NUMERIC attribute to root XML element. Melt * Added '-query presets' option. * Added -jack option for transport synchronization. * Send -help and -query output to stdout to make it convenient for pagers. Other * Added mlt.Frame.get_image() for Python. * Removed configure option --avformat-svn. * Fixes for locales that use comma for decimal point. * Added presets for DVD, DV, x264, and WebM encoding. Since FFmpeg forked and there were a few releases, there is no recommended version at this time. With that said, there were changes to accomodate the API changes with some moderate testing of the 0.6, 0.7, and 0.8 series releases of both FFmpeg and Libav. Version 0.7.2 - May 1, 2011 This is a minor release to fix a few things between the 0.7.0 release and the release of Kdenlive 0.8. I recommend Kdenlive v0.8 users to upgrade to this version of Mlt. Beyond that there are some exciting additions to the Blackmagic Design DeckLink plugin! Framework * Added mlt_profile_list(). Modules * Added decklink producer (i.e. capture, live encoding). * Added keyer output for decklink consumer. * Added AVOptions to the avformat service metadata. * Added support for new major API versions (53) of FFmpeg. Melt * Added '-query profile' option. * Added '-query formats', '-query audio_codecs' and '-query video_codecs'. The recommended version of FFmpeg for use with this release is 0.6.1. Version 0.7.0 - March 27, 2011 This is a major new release due to signficant additions to API, framework, and build. Build * Added support for Windows via MinGW. * Enabled linsys module by default. * Disabled VDPAU by default and added --avformat-vdpau to enable it. * Added support for swfdec 0.7. Framework: * Added parallelism to mlt_consumer when 'real_time' > 1 or < -1. * Added mlt_deque_insert() and mlt_deque_peek(). * Added mlt_profile parameter to mlt_producer_new(). * Let transitions with no out point run forever. * Added mlt_frame_unique_properties(). * Added mlt_frame_set_image() and mlt_frame_set_alpha(). * Added mlt_image_format_size() and mlt_audio_format_size(). * Added mlt_filter_get_length() and mlt_transition_get_length(). * Added mlt_filter_get_progress(), mlt_transition_get_progress(), and mlt_transition_get_progress_delta(). * Added mlt_filter_get_position() and mlt_transition_get_position(). * Added mlt_properties_lock() and mlt_properties_unlock(). Modules * Added rotoscoping filter. * Improve libavdevice support (V4L2, ALSA, libdc1394). * Added support for new FFmpeg metadata API. * Various fixes, refactoring, and improvements. The recommended version of FFmpeg for use with this release is 0.6.1. Version 0.6.2 - January 23, 2011 This is just a minor release to address a few things prior to introducing major changes from other branches. * Added force_aspect_ratio property to pixbuf and qimage producers. * Added opacity handling in geometry property of the affine filter and transition. * Added use_normalised property to affine filter. * Added always_active property to affine transition. * Fix building on NetBSD. The recommended version of FFmpeg for use with this release is 0.6.1. Version 0.6.0 - January 1, 2011 The recommended version of FFmpeg for use with this release is 0.6.1. There were quite a few enhancements and changes including a minor interface change. Therefore, this release gets a jump in the versioning. Framework * mlt_profile - Added (Y'CbCr) colorspace attribute. - Added mlt_profile_clone(). * Added mlt_consumer_position() and Mlt::Consumer::position(). * Added Mlt::Properties::wait_for(string). * Added a version API: mlt_version_get_int() and others. * Added Mlt::Producer::pause(). * Added mlt_frame_write_ppm() for debugging. Melt * Added automatic detection of profile from first input when profile not specified. * Now exits with error result when consumer fails fatally. Modules * Added swfdec producer for Flash files including variables support. (Does not support audio.) * Added consumer for Blackmagic Design DeckLink SDI and Intensity HDMI. * Added Y'CbCr colorspace conversion and option to use full luma range. * Added (de)serialization of profile to XML. * Added support for #frame# variable to the data_show filter. * Added support for frei0r string parameters. * Make FFmpeg formats and codecs available as properties (not just stderr). * Try to load .xml file as MLT XML. * Added a consumer-sdl-paused event to sdl_preview. * Added a consumer-fatal-error event to avformat. * Change composite transition to default to progressive rendering; field- based rendering available only explicitly. Version 0.5.10 - September 13, 2010 This is a quick followup to the 0.5.8 release to address an issue I want to address immediately. I noticed an extra unconditional colorspace conversion to and from RGB was added for all YCbCr (YUV) video sources. In addition, I have enabled the avcolor_space filter on OS X since it works now. Version 0.5.8 - September 12, 2010 The recommended version of FFmpeg for use with this release is 0.6. This is a maintenance release to address some bugs that appeared thus far in the 0.5.x series. Beyond that is a few enhancements: * Added EXIF-based auto-rotation of images to pixbuf and qimage producers. * Improved quality of libswscale-based image conversion and scaling. * Added channelswap and panner audio filters; panner also does balance. * Improve audio waveform and add audiowave video filter. * Enhanced luma filter to work with animated filters such as affine. * Automatically crop 8 bottom lines of 1088 source in a 16:9 project (common in Canon EOS digital cameras). * Added support for inline images in kdenlivetitler. Version 0.5.6 - June 20, 2010 The recommended version of FFmpeg for use with this release is 0.6. This is a maintenance release to address some bugs that appeared this far in the 0.5.x series. Beyond that it a few enhancements: * Added interpolation to the affine transition and filter. * Added multi-track audio encoding to avformat consumer. * Added interlaced field rendering to kdenlivetitle producer. Version 0.5.4 - April 19, 2010 The recommended version of FFmpeg for use with this release is SVN r21322. This is another maintenance release to address some bugs that appeared this far in the 0.5.x series. Beyond that it adds two things that only very specific users will see: * Added C# (ECMA CLR) binding (not enabled by default). * Linsys SDI consumer now configures itself from MLT profile. Version 0.5.2 - March 10, 2010 The recommended version of FFmpeg for use with this release is SVN r21322. This is a minor maintenance release, but it is interesting because it now enables usage of libswscale as the default choice for image scaling, image format conversion, and color space conversion. That gives better quality and performance. In addition, there are some improvements in the sdl_preview consumer to make it suitable for use in OpenShot 1.1. Other things: * Fixed mlt++/MltFilteredProducer * Fixed playing to the end in Kdenlive (mantis bug 1207) * Fixed crash load uncompressed video * Fixed compiling yadif for non-sse2 builds Version 0.5.0 - February 15, 2010 The recommended version of FFmpeg for use with this release is SVN r21322. This is an enhancement release, confined mainly to the modules rather than the framework. In particular, this adds support for VDPAU, YADIF, and HD-SDI technologies! configure: added --disable-sse2 framework: * mlt_cache: added mlt_cache_set_size() * mlt_filter: added data property "service" - set when attached * mlt_frame: - added Doxygen docs - added "previous frame" and "next frame" data properties - available when its producer has _need_previous_next=1 * mlt_playlist: added support for negative out point same as length-1 * mlt_service: - added mlt_service_cache_purge() - added "_need_previous_next" handling in mlt_service_get_frame() - added firing event "service-changed" in mlt_service_attach() modules: * avformat producer: - added decoding H.264 with NVIDIA VDPAU Requires FFmpeg built with vdpau. This is automatically detected and enabled. You can disable this by setting environment variable MLT_NO_VDPAU=1 or property novdpau=1. - added caching of FFmpeg contexts and decoded images This allows large numbers of clips in a project avoiding limitations with number of threads and file descriptors permitted per process. You can disable image caching with property noimagecache=1. - added variant of producer named avformat-novalidate - restored support for video4linux(2) * avformat consumer: added apre, fpre, and vpre preset properties * crop filter: added center_bias integer property * deinterlace filter: added the excellent YADIF as a method * kdenlivetitle producer: added text outlining * linsys/sdi consumer: - added support for HD-SDI - changed name from "linsys_sdi" to just "sdi" * oldfilm filter: added "uneven development" effect * xml producer: add support for unspecified out points profiles: * added several missing ATSC (HD) profiles * change descriptions from using Hz to fps Version 0.4.10 - December 8, 2009 The recommended version of FFmpeg for use with this release is SVN r19873. This is "hotfix" for the 0.4.8 release that fixes a couple of regression bugs introduced just before the release. Version 0.4.8 - December 7, 2009 The recommended version of FFmpeg for use with this release is SVN r19873. This is mainly a maintenance release. Besides bug fixes here are other notable changes. modules: * avformat producer: - refactored producer to use much less properties - added support for audio_index=all for linsys_sdi consumer - added force_fps property (does yet not adjust duration) * core/crop: added "center" property to crop filter * linsys_sdi: - added support for >2 audio channels - added property meta.map.audio..channels= - added property meta.map.audio..start= * qimage/kdenlivetitle: add typewriter effect Version 0.4.6 - October 7, 2009 The recommended version of FFmpeg for use with this release is SVN r19873. This release is an enhancement release along with numerous build, A/V synch, concurrency, and other bug fixes. configure: new option --avformat-svn-version modules: * avformat: much improved seeking on H.264/MPEG2-TS (AVCHD) (Ivan Schreter) * core: new imageconvert and audioconvert filters (framework refactorization) * linsys: new SDI consumer (Broadcast Centre Europe) * qimage: new kdenlivetitle producer (J.B. Mardelle and Marco Gittler) * sdl: new audio_only consumer for OS X mlt++ and swig: update bindings framework: * refactored image format conversion mlt_frame.h: - added convert_image() virtual function - added mlt_image_format_name() - removed many mlt_convert_ and scaling/padding functions * refactored audio format conversion mlt_frame.h: - mlt_get_audio() virtual function parameters changed - added convert_audio() virtual function - mlt_frame_get_audio() parameters changed - added mlt_frame_set_audio() - added mlt_audio_format_name() mlt_types.h: - deprecated mlt_audio_pcm - added mlt_audio_s16 - added mlt_audio_s32 - added mlt_audio_float Version 0.4.4 - June 30, 2009 The recommended version of FFmpeg for use with this release is 0.5.0. This release is a minor maintenance update to the 0.4.2 - just build and bug fixes. * new configure script options: --swig-languages --rename-melt --mandir --datadir * added man page for melt (not installed) * added invert property to composite transition * added frei0r plugin blacklist, currently only contains facedetect * added Lua binding via SWIG Version 0.4.2 - May 30, 2009 The recommended version of FFmpeg for use with this release is 0.5.0. This release is a minor maintenance update to the 0.4.0 - just build and bug fixes. Version 0.4.0 - May 17, 2009 The recommended version of FFmpeg for use with this release is 0.5.0. This release is primarily a reorganization of the mlt and mlt++ projects. In brief: * "inigo" was renamed "melt" * "westley" is no longer the XML file extension and root element - they are simply "mlt" now * mlt++ is included with mlt and no longer a separate project * miracle, valerie, and humperdink were moved to a new, separate project For details: http://www.mltframework.org/twiki/bin/view/MLT/ExtremeMakeover avformat producer improvements: * improve audio synchronization * improve reliability of video playback with FFmpeg newer than v0.5.0 * improve seeking performance of DNxHD and HuffYUV Version 0.3.8 - April 15, 2009 The recommended version of FFmpeg for use with this release is SVN r17923. This almost entirely a bugfix release to coincide with the Kdenlive 0.7.3 release. See the ChangeLog (SVN log) for details. framework: * added mlt_cache API * improved doxygen documentation comments * added some 15 fps profiles * improved color property handling (support web-style '#' color value) * add const qualifier to many string parameters modules: * core: improved brightness filter * core: added image crop filter * frei0r: added support for producer/source plugins * frei0r: added support for color parameters * sdl: added window_background color property Version 0.3.6 - February 2, 2009 The recommended version of FFmpeg for use with this release is SVN r16849. This almost entirely a bugfix release to coincide with the Kdenlive 0.7.2 release. See the ChangeLog (SVN log) for details. framework: * added mlt_log logging API * improved doxygen documentation comments avformat module: * consumer: report list of muxers when f=list and codecs when acodec=list or vcodec=list * consumer: added support for an=1 or acodec=none and vn=1 or vcodec=none * producer: list available demuxers and decoders when constructor arg is like f-list[[,]acodec-list][[,]vcodec-list] Version 0.3.4 - December 29, 2008 The recommended version of FFmpeg for use with this release is SVN r16313. This almost entirely a bugfix release. See the ChangeLog (SVN log) for details. There are a few notes: framework: * improved doxygen documentation comments (work in progress) published docs are at http://mltframework.org/doxygen/ avformat module: * added support for AVOption parsing to producer * added filter_swscale as alternative rescaler * added recommended FFmpeg revision to configure option --help * use recommended FFmpeg revision with --avformat-svn on release versions * added configure option --avformat-no-codecs * added configure option --avformat-no-filters misc: * new profile atsc_1080i_50 * added --disable-sse option to configure script * improved build for OS X and x86-64 and improved handling of mmx/sse Version 0.3.2 - November 10, 2008 In addition to bug fixes detailed in the ChangeLog, here is a list of enhancements. framework: * deprecated mlt-config; use pkg-config instead * added more HD profiles modules: * sdl: added fullscreen property * sox: sox v14.1.0 compatibility * gtk: added force_reload property to producer_pixbuf * frei0r: added support for YAML Tiny metadata * frei0r: added keyframe support on double and boolean parameters * oldfilm: added keyframe support for filter_vignette * kdenlive: added filter_freeze inigo: * added -version, -silent, and -progress options * improved output of usage information * removed realtime process scheduling Version 0.3.0 - August 5, 2008 framework: * fix bugs with introduction of mlt_profile in v0.2.4 * added versioning to libs * remove module registry and add dynamic module loading: added mlt_repository_register, mlt_repository_consumers, mlt_repository_filters, mlt_repository_producers, mlt_repository_transitions * new module metadata system based on YAML Tiny: added mlt_repository_register_metadata, mlt_repository_metadata, mlt_repository_languages, mlt_properties_is_sequence, mlt_properties_parse_yaml, mlt_properties_serialise_yaml, and added metaschema.yaml Kwalify schema file * mlt_consumer: added threaded, non-lossy processing when real_time=-1 * added autoclose property to mlt_playlist for sequential processing of very large playlists (prevents resource exhaustion) * mlt_factory_init now returns the global mlt_repository * change mlt_repository_fetch to mlt_repository_create * change mlt_factory_prefix to mlt_factory_directory * added mlt_field_disconnect_service modules: * move all modules from $datadir to $libdir * new oldfilm module by Marco Gittler * new frei0r module by Marco Gittler * new dgraft module by Dan Dennedy for inverse telecine (not ready yet) * avformat: added support for multi-threaded encoding and decoding * consumer_avformat: added support for AVOption to support all ffmpeg options using ffmpeg-style property names * consumer_avformat: added support for dual pass encoding * qimage: added support for Qt4 * sox: added support for sox v14.0.0 * transition_composite: added animatable geometry-type "pan" property to crop and pan instead of automatic down-scale inigo: * added -query option to lookup module metadata * added -profile option and support for progress=1 for kdenlive Version 0.2.4 - August 4, 2007 * framework: new extensible profiles system to replace MLT_NORMALISATION * module avformat: interlaced coding support for ffmpeg/libavcodec * module avformat: build improvements for --avformat-svn * new effectv module with BurningTV video filter * module qimage: added support for psd, xcf and exr images * numerous bugfixes Version 0.2.3 - April 9, 2007 * Addition of kdenlive module * Support for ffmpeg from subversion * Support for ffmpeg libswscale * Copyright and license cleanup Version 0.2.2 - May 27, 2006 * Prepared specifically for the kdenlive 0.3 release. * Contains some patches to support rgb24a output for the gdk-pixbuf and qimage producers as well as some minor bugfixes. Version 0.2.1 - December 5, 2005 * Many improvements since initial releases due to development of Shotcut and Jahshaka editing interfaces. Version 0.1.1 - June 9, 2004 * Minor modifications and bug fixes from the previous release. Better ffmpeg/avformat integration and more reliable playback. Version 0.1.0 - May 6, 2004 * First official release mlt-0.9.0/README000066400000000000000000000030131215300731300131640ustar00rootroot00000000000000MLT FRAMEWORK README -------------------- Sponsored by Ushodaya Enterprises Limited Written by Charles Yates and Dan Dennedy MLT is a LGPL multimedia framework designed for television broadcasting, and melted is a GPL multi-unit video playout server with realtime effects. This document provides a quick reference for the minimal configuration, build and installation of MLT. See the docs directory for usage details. See the website for development details: http://www.mltframework.org/twiki/bin/view/MLT/Documentation http://www.mltframework.org/twiki/bin/view/MLT/Contributing http://www.mltframework.org/twiki/bin/view/MLT/ToDo Configuration ------------- Configuration is triggered by running: ./configure More information on usage is found by running: ./configure --help NB: This script must be run to register new services after a CVS checkout or subsequent update. Compilation ----------- Once configured, it should be sufficient to run: make to compile the system. Testing ------- To execute the mlt tools without installation, or to test a new version on a system with an already installed mlt version, you should run: . setenv NB: This applies to your current shell only and it assumes a bash or regular bourne shell is in use. Installation ------------ The install is triggered by running: make install More Information ---------------- For more detailed information, please refer to docs/install.txt. mlt-0.9.0/configure000077500000000000000000000237221215300731300142240ustar00rootroot00000000000000#!/bin/sh export version=0.9.0 export soversion=6 show_help() { cat << EOF Non-autotool config script for MLT. Help options: --help - this information General build options: --prefix=directory - install prefix for path (default: $prefix) --libdir=directory - lib directory (default: $prefix/lib) --datadir=directory - data directory (default: $prefix/share) --mandir=directory - man documentation directory (default: $prefix/share/man) --rename-melt - Give melt executable a different name (it will not be versioned) --enable-extra-versioning - Version melt and the data and modules directories --enable-gpl - Enable GPLv2 components --enable-gpl3 - Enable GPLv3 components --enable-debug - Compile without optimizations support (default: off) --disable-debug - Compile without debug support (default: on) --disable-mmx - Compile without MMX support (default: on) --disable-sse - Compile without SSE support (default: on) --disable-sse2 - Compile without SSE2 support (default: on) --arch='arch' - Compile for a specific architecture (default: none) --cpu='cpu' - Compile for a specific CPU (default: none) --target-os='os' - Cross-compile to a specific OS (default: $(uname -s)) --target-arch='arch' - Cross-compile to a specific CPU architecture Module disable options: EOF for i in src/modules/* do [ -d $i ] && [ "`basename $i`" != "CVS" ] && echo `basename $i` `[ -f $i/gpl ] && echo [GPL]` done | awk '{ printf( " --disable-%-14.14s- Disable the %s module %s\n", $1, $1, $2 ); }' echo echo " NOTE: libraries marked [GPL] will not be built unless --enable-gpl is stipulated." echo } build_config() { ( echo "version=$version" echo "soversion=$soversion" echo "prefix=$prefix" echo "libdir=$libdir" echo "bindir=$prefix/bin" echo "datadir=$datadir" echo "mandir=$mandir" echo "extra_versioning=$extra_versioning" echo "melt_noversion=$melt_noversion" echo "targetos=$targetos" [ "$mmx" = "true" ] && echo "MMX_FLAGS=-DUSE_MMX" [ "$sse" = "true" ] && echo "SSE_FLAGS=-DUSE_SSE" [ "$sse2" = "true" ] && echo "SSE2_FLAGS=-DUSE_SSE2" [ "$debug" = "true" ] && echo "DEBUG_FLAGS=-g" echo "LARGE_FILE=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE" [ "$amd64" = "true" ] && echo "ARCH_X86_64=1" && echo "CFLAGS+=-DARCH_X86_64" [ "$arch" != "" ] && echo "TARGETARCH=-march=$arch" [ "$cpu" != "" ] && echo "TARGETCPU=-mcpu=$cpu" if [ "$optimisations" = "true" ] then echo "OPTIMISATIONS=-O2 -pipe" # Since gcc 4.6, this optimization enabled with -O1 causes filter_line_sse2 to crash. echo "OPTIMISATIONS+=-fno-tree-dominator-opts" # Since gcc 4.6, this optimization enabled with -O2 causes filter_line_sse2 to crash. echo "OPTIMISATIONS+=-fno-tree-pre" fi echo "CFLAGS+=-Wall -DPIC \$(TARGETARCH) \$(TARGETCPU) \$(OPTIMISATIONS) \$(MMX_FLAGS) \$(SSE_FLAGS) \$(SSE2_FLAGS) \$(DEBUG_FLAGS) \$(LARGE_FILE)" case $targetos in Darwin) echo "CFLAGS+=-fPIC -D__DARWIN__ `sdl-config --cflags`" echo "SHFLAGS=-dynamiclib" echo "LDFLAGS+=`sdl-config --libs`" ;; Linux|GNU/kFreeBSD|GNU) [ "$optimisations" = "true" ] && echo "OPTIMISATIONS+=-ffast-math" echo "CFLAGS+=-fPIC -pthread" echo "SHFLAGS=-shared" echo "LIBDL=-ldl" echo "RDYNAMIC=-rdynamic" echo "LDFLAGS+=-Wl,--no-undefined -Wl,--as-needed" ;; FreeBSD) [ "$optimisations" = "true" ] && echo "OPTIMISATIONS+=-ffast-math" echo "CFLAGS+=-fPIC -pthread" echo "SHFLAGS=-shared" echo "RDYNAMIC=-rdynamic" echo "LDFLAGS+=-Wl,--no-undefined -Wl,--as-needed" ;; NetBSD) [ "$optimisations" = "true" ] && echo "OPTIMISATIONS+=-ffast-math" echo "CFLAGS+=-fPIC -pthread" echo "SHFLAGS=-shared" echo "RDYNAMIC=-rdynamic" echo "LDFLAGS+=-Wl,--no-undefined -Wl,--as-needed" ;; MinGW) [ "$optimisations" = "true" ] && echo "OPTIMISATIONS+=-ffast-math" echo "SHFLAGS=-shared" echo "LIBDL=-ldl" echo "RDYNAMIC=" echo "LDFLAGS+=-Wl,--no-undefined -Wl,--as-needed" ;; *) ;; esac echo "LIBSUF=$LIBSUF" echo "moduledir=${moduledir}" echo "mltdatadir=${mltdatadir}" echo "unversionedmoduledir=${unversionedmoduledir}" echo "unversionedmltdatadir=${unversionedmltdatadir}" echo "meltname=${meltname}" ) > config.mak echo "#!/bin/sh" > mlt-config ( echo export version=$version echo export prefix=$prefix echo export libdir=$libdir echo export bindir=$prefix/bin ) >> mlt-config cat < mlt-config-template >> mlt-config echo -n > packages.dat } build_pkgconfig() { echo prefix="$prefix" > mlt-framework.pc ( echo exec_prefix=$prefix echo libdir=$libdir echo includedir=$prefix/include echo datadir=$datadir echo mandir=$mandir echo version=$version echo cflags=`grep ^framework packages.dat | cut -f 2` echo libs=`grep ^framework packages.dat | cut -f 3` echo moduledir=${moduledir} echo mltdatadir=${mltdatadir} echo meltbin=${prefix}/bin/${meltname} ) >> mlt-framework.pc cat mlt-framework.pc.in >>mlt-framework.pc echo prefix="$prefix" > mlt++.pc ( echo exec_prefix=$prefix echo libdir=$libdir echo includedir=$prefix/include echo datadir=$datadir echo mandir=$mandir echo version=$version echo cflags=`grep ^mlt++ packages.dat | cut -f 2` echo libs=`grep ^mlt++ packages.dat | cut -f 3` ) >> mlt++.pc cat mlt++.pc.in >>mlt++.pc } # Debug mode set +x # Define build directory for scripts called export build_dir=`dirname $0` export prefix=/usr/local export libdir="" export datadir="" export mandir="" export help=0 export optimisations=true export debug=true export mmx=true export sse=true export sse2=true export gpl=false export gpl3=false export arch= export cpu= export targetos=$(uname -s) export targetarch= export amd64=false export extra_versioning=false export melt_noversion=false # Define the compiler used in tests (gcc is not installed everywhere) : ${CC:=gcc} # Iterate through arguments for i in "$@" do case $i in --help ) help=1 ;; --prefix=* ) prefix="${i#--prefix=}" ;; --libdir=* ) libdir="${i#--libdir=}" ;; --datadir=* ) datadir="${i#--datadir=}" ;; --mandir=* ) mandir="${i#--mandir=}" ;; --rename-melt=* ) meltname="${i#--rename-melt=}"; melt_noversion=true ;; --enable-extra-versioning ) extra_versioning=true ;; --enable-debug ) optimisations=false ;; --disable-debug ) debug=false ;; --disable-mmx ) mmx=false; sse=false; sse2=false ;; --disable-sse ) sse=false; sse2=false ;; --disable-sse2 ) sse2=false ;; --enable-gpl ) gpl=true ;; --enable-gpl3 ) gpl3=true ;; --arch=* ) arch="${i#--arch=}" ;; --cpu=* ) cpu="${i#--cpu=}" ;; --target-os=* ) targetos="${i#--target-os=}" ;; --target-arch=* ) targetarch="${i#--target-arch=}" ;; esac done if [ -z "${meltname}" ] then if [ "$extra_versioning" = "false" ] then meltname=melt else meltname=melt${soversion} fi fi # Chose appropriate suffix for libraries case $targetos in Darwin) LIBSUF=".dylib" if [ "$targetarch" = "" ] then sysctl -a hw | grep "x86_64: 1" > /dev/null [ "$?" = "0" ] && targetarch="amd64" fi ;; Linux|FreeBSD|NetBSD) LIBSUF=".so" ;; MINGW32_NT-*|MinGW|mingw) targetos="MinGW" LIBSUF=".dll" ;; *) LIBSUF=".so" ;; esac export LIBSUF # Determine if we are compiling for 64-bit Intel architecture [ "$targetarch" = "" ] && targetarch=$(uname -m) [ "$targetarch" = "amd64" -o "$targetarch" = "x86_64" ] && amd64=true # Determine the libdir if it's not specified in the args [ "$libdir" = "" ] && libdir=$prefix/lib [ "$datadir" = "" ] && datadir=$prefix/share [ "$mandir" = "" ] && mandir=$prefix/share/man export unversionedmoduledir=${libdir}/mlt export unversionedmltdatadir=${datadir}/mlt if [ "$extra_versioning" = "false" ] then export moduledir=${libdir}/mlt export mltdatadir=${datadir}/mlt else export moduledir=${libdir}/mlt-${soversion} export mltdatadir=${datadir}/mlt-${soversion} fi # Double check MMX (Darwin, Linux and FreeBSD supported, may end up disabling MMX on other platforms incorrectly) if [ "$mmx" = "true" ] then case $targetos in Darwin) sysctl -a hw | grep "mmx: 1" > /dev/null || mmx=false ;; Linux) grep mmx /proc/cpuinfo > /dev/null 2>&1 || mmx=false ;; FreeBSD) [ "$(make -V MACHINE_CPU:Mmmx)" ] || mmx=false ;; *) grep mmx /proc/cpuinfo > /dev/null 2>&1 || mmx=false ;; esac fi # Double check SSE (Darwin, Linux and FreeBSD supported, may end up disabling SSE on other platforms incorrectly) if [ "$sse" = "true" ] then case $targetos in Darwin) sysctl -a hw | grep "sse: 1" > /dev/null || sse=false ;; Linux) grep sse /proc/cpuinfo > /dev/null 2>&1 || sse=false ;; FreeBSD) [ "$(make -V MACHINE_CPU:Msse)" ] || sse=false ;; *) grep sse /proc/cpuinfo > /dev/null 2>&1 || sse=false ;; esac fi # Double check SSE2 (Darwin, Linux and FreeBSD supported, may end up disabling SSE2 on other platforms incorrectly) if [ "$sse2" = "true" ] then case $targetos in Darwin) sysctl -a hw | grep "sse2: 1" > /dev/null || sse2=false ;; Linux) grep sse2 /proc/cpuinfo > /dev/null 2>&1 || sse2=false ;; FreeBSD) [ "$(make -V MACHINE_CPU:Msse2)" ] || sse2=false ;; *) grep sse2 /proc/cpuinfo > /dev/null 2>&1 || sse2=false ;; esac fi # Show help if requested if [ $help = 1 ] then show_help else # Log the configuration history date >> config.log echo "$0 $@" >> config.log build_config fi # Iterate through each of the components for i in framework modules melt mlt++ swig do if [ -x src/$i/configure ] then [ $help = 0 ] && echo "Configuring `basename $i`:" olddir=`pwd` cd src/$i CC="$CC" ./configure "$@" [ $? != 0 ] && exit 1 cd $olddir fi done # Build the pkg-config files build_pkgconfig # Report license Usage if [ $help != 1 ] then if [ "$gpl" = "false" ] then echo "LGPLv2.1 license used; GPL components disabled" elif [ "$gpl3" = "false" ] then echo "GPLv2 license used; GPLv3 components disabled" else echo "GPLv3 license used" fi fi mlt-0.9.0/demo/000077500000000000000000000000001215300731300132335ustar00rootroot00000000000000mlt-0.9.0/demo/README000066400000000000000000000230261215300731300141160ustar00rootroot00000000000000MLT Demo Notes Before running the demo script, make sure you '. setenv' from the parent directory. Also, please create clips clip1.dv, clip2.dv, clip3.dv, clip1.mpeg, clip2.mpeg, clip3.mpeg, and music1.ogg. Please make sure clips are at least 500 frames duration. These notes explain the the concepts presented in each demonstration and what details to look for. First, a note on consumers. When you start the script, the main menu asks you to choose a consumer. A consumer is like a viewer, but it could also write to a stream/file. The "SDL" consumer is the popular Simple DirectMedia Layer audio and video output. The "xml" consumer generates an XML representation of the service network. That can be played directly due to the XML producer plugin. See docs/mlt-xml.txt for more information. "/dev/dv1394/0" refers to a device file for transmitting DV over FireWire using the Linux dv1394 kernel module. These examples assume the numeric locale LC_NUMERIC decimal separator is a period. Therefore, the demo script sets LC_NUMERIC=C for you, but if you are running these manually or learning from them, remember to use the appropriate separator for your locale. And now the demos... All clips Simply builds a playlist containing each video clip, and you can transport between them using j and k keys. Filter in/out A video filter can be applied to a portion of a producer (clip, playlist, or multitrack). This examples shows the greyscale filter. Watermark A graphic can overlay video in realtime with support for alpha channel. This example uses a PNG file with an alpha channel. Distortion is explicitly enabled here so the otherwise circular graphic is scaled to fill the compositing region. By default, compositing honours the aspect ratio of the overlay. My name is... Titles are very easy to composite in realtime. The titler uses Pango with the FreeType2 rendering backend. This means it supports high quality scalable font rendering with anti-aliasing, unicode (UTF-8), and Pango markup capabilities. The compsiting here respects the aspect ratio of the rendered title in the first two title pieces but distorts the final one. This demo also shows the motion and scaling capabilities of the compositor in conjunction with honouring aspect. The compositor is doing field-based rendering. So, when displayed non-progressively with SDL, you can see motion artifacts during animation. A composite transition The compositor also handles video over video as demonstrated in this usage of the compositor to create a special transition. This demonstration also crossfades the audio during the transition! Progressive rendering is explicitly enabled on the compositor due to the poor results that would otherwise occur due to scaling an interleaved video frame and moving the video in a reverse direction horizontally. Fade in and out A simple series of transitions betwen 3 clips using dissolves and audio crossfades. This is easy :-). Clock in and out Wipe transitions are very easy and highly extensible as they are generated using a very convenient lookup table based upon the luma of an image. This image can be a 16 bit PGM (grayscale bitmap) or the luma channel of any video producer. A number of high quality wipes can be downloaded from http://mlt.sf.net/. It also performs field rendering. The second wipe demonstrates the ability to control the direction of the wipe as well. Obscure A popular requirement in news production is to obscure a face, obscenity, or trademarked logo. This demonstrates using a simple rectangular obscure filter applied to a region of the image. The second example is more advanced and shows using the "region" filter to select the image area and a property of the region filter to "shape" the region using the alpha channel of another image (circle.png) and another property to "filter" the region using the obscure filter. Audio Stuff A music bed sound track can be mixed with a video. The sound track of the video clip has a "floating" amplitude normalisation filter applied. Typically, audio normalisation applies a constant gain factor across the entire duration of an audio segment from a single source where the gain factor is automatically determined by anaylsing the maximum "power" or peak levels. However, in news production, a popular requirement is to to dynamically boost the amplitude in soft areas and reduce the amplitude in louder areas. Thus, the gain analysis is performed using a "sliding window" approach. This example also applies a constant gain factor of 0.5 (50%) to the normalised audio of the video clip (to get a nicer mix level). Audio and Video Levels Audio can be normalised by setting a target amplitude level in decibels. A gamma curve can be applied to the luma channel of video. Shadowed Title and Watermark Two instances of the titler are used to create a shadow effect. The aspect ratio of the watermark in this example is not distorted. Since the original image is a circle with square pixels--a computer-generated image--and ITU BT.601 video is not composed of square samples. Therefore, the compositor normalises the pixel aspect ratio of the overlay to the destination image, and the circular image remains circular on the analog video output. Finally, a greyscale filter is applied to the watermark while its opacity is set at 30%. Station Promo into Story? Here is fun demo that might show using a still graphic with some music to introduce a show. A luma wipe with an audio crossfade transitions from the show title or station promotional material. Voiceover 2 clips with title A common news production requirement to have a "voiceover" audio track to a clip or even multiple clips as demonstrated here. Likewise, it is common to place a title caption on the video at the same time! This demo has a little fun with the titler at the sake of practicality :-) The foreground of the title is transparent while the opacity of the background is reduced to blend with the video. Meanwhile, the compositor stretches the image to fill the bottom slice of the video--not suitable for overscan displays ;-) Also, pay close attention to the mixing levels of the audio tracks. The audio of the video fades out as the voiceover track (just music in this demo) fades in. Then, the voiceover remains mixed with the ambient audio at a 60% level. Finally, the voiceover fades out smoothly from the 60% level to nothing. GJ-TTAvantika title This demo requires a special TrueType font called Avantika. If you have the font, register it with fontconfig using the fc-cache utility. This demonstrates i18n capabilities of the titler and the alignment capabilities of both the titler and the compositor. The titler centre aligns the two lines of text, and the compositor centre aligns the title horizontally on the frame. Title over graphic You can superimpose a title over a graphic over video! Also, you can apply a luma wipe to the compositor! Slideshow This demo requires any number of JPEG images with the extension ".jpg" in a subdirectory named "photos." Bouncy, Bouncy The "watermark" filter encapsulates the compositor, and you have full control over the compositor properties. Who says a watermark can not also be a video?! Bouncy, Bouncy Ball A variation on the above Bouncy, Bouncy demo that applies a shape, or alpha producer, to the the compositing region. Breaking News This demonstrates layout capabilities of the compositor. Squeeze Transitions This demonstrates a distorting barndoor-like wipe. J Cut A J cut is an edit where the audio cuts before the video. It gets its name from the way it looks on a NLE timeline user interface. When the audio cuts over, it does an audio crossfade over the duration of one frame. This makes the audio cut slightly less abrupt and avoids any "click" due to mismatched sample levels at the edit point. The video edit is a hard cut. L Cut An L cut is an edit where the video cuts before the audio. It gets its name from the way it looks on a NLE timeline user interface. This demo shows a very quick dissolve over 5 frames for a soft video cut. Like the J Cut demo, an audio crossfade for the duration of one frame makes an audio edit nearly instantaneous while being slightly softened and avoiding aberrations. Fade from/to black/silence Of course, it is possible using MLT to fade from black on video and silence on audio as well fade to black and silence. Push wipe A push wipe is a somewhat fancier transition than most standard wipes because it involves motion. The new video clip "pushes" the old video clip off one edge. If you can preview on an analog monitor you will notice how smooth the motion is due to field-based rendering. Ticker tape A very minimal reverse crawling title neard the bottom of the screen. The goal of the demo is show fluid motion of the field-based rendering of the compositor when viewed on an analog monitor using a DV or BlueFish444 consumer. The demo also shows the potientional for using and extending the existing set of services for a full blown news ticker implementation. Pango Keyframed Markup You can create timed text and subtitles using a .mpl file, which is a properties format file. A properties file contains key=value pairs on separate lines. For .mpl the key is a frame number and the value is Pango Markup Language. A tilde is interpreted as a new line. This example also demonstrates using the watermark and the alignment properties of its encapsulated composite transition where halign is the horizontal, valign is the vertical, c is for center, and m is for middle. mlt-0.9.0/demo/circle.png000066400000000000000000000121671215300731300152110ustar00rootroot00000000000000‰PNG  IHDR,,y}ŽusBIT|dˆ.IDATxœíÝa°\eyÀñÿ½×$0BbÃ$”(HDef ¥¥kÇi;¥N?8µ¢V«vô›ŽÎtª3N¿´ú¡VeTÀ©Ž #&à@'VˆB 4$&!q’÷Þ~xö&››Ý½gwÏ9ï9gÿ¿™göÆ{÷œGö=ϼï»ïyÏÒéÎÖ‹%­/™õó"à `0¿ Ú^Ç£ÀËÀñÖëÌÏÇ€CÀ~àÅÖkûÏ€­K'Œ¥N@IŒ—«Z¯«3S%6ËQàIài`wëuð8ð0*1¥aÁj¾¥ÀeÀ[Ú^×R¢4¨£ÀvàQà‘¶×R&¥bY°šgð.`#p-p~ÒlÊ÷ p/° ø ð\Òl”+ Vý-6´b#1÷¤“vÅks+ö¥MGð`ÕÏbàN¨µø9f5M #g Ø}Ä¿j†^}cÀ DqÚ¬#¾Ó𦀭DñÚÜùÒ@Ö_ö‘Q|ìmý7_—áó‘FÞJàSÀc¤¿xG=k}+{~bÒˆ9 ¸ø10Iú Õ85&[ŸÍ-­ÏJ9ÀõÀ׀ä¿(lq¸õ™]ßú ¥F»øÎK5!ö¶>Ë‹‘fp;ùš“­ÏÖ‰zÕÞzà‡Ä×ç©/,£Ø˜j}Öë‘jæ:bmOê‹ÈH›‰6 UÖp°…ôŒQØB´ h«2&€ÛHÕŒmDñ›E%3ø °ƒô„QØA´™yH%ÚHl$—ú0껈6$ê<àÒ7x£qѦ¤\Í#î+;BúFn4+ŽmËa¢rq-±‡Rê†m4;¶mMÈràë¸èÓ(/¦ˆ6·)£ à£ÀAÒ7`c4ã Ñ]¡ž®"v LÝ` cšh‹W!Í2ø,ÿŒêÅÑ6”Wpò¡œ†QÕx‚h«a&È™º1F–8J´Y˜…À·Hß cøцGÎ(ÞE¾ŽøÀW§NDÂ“Ä Õ[S'R¦QûÚôV¢X-Kˆ4¤ß!n¤>üOÚT”·EÀwHß•7Œ"â;Do¼Q^Iôª.LˆT §ˆ!⃩)R“‡„cÀÇ€Û€¥‰s‘жø à% |²äsJ*ÆZ`%.u(sHx1oåÞVRs#æ³.ãde¬…Dö¦f©yv À ŸÏ*kHøeàú’Î%©\Kˆ§ï|¿è•ÑÃºŠØŒ/õ"UIÅ™"6ýÛRäIŠ.XÀωù+IÍö0ðv`²¨=$¼øË‚Ï!©Î^¤ÀUðEö°– ò!Òè8¼x¾ˆƒ9¯ôÏX¬¤Q³ˆ¸ö QTëZ`SÇ—T]ÓÀFàÞ¼\DA™ü‚¸«[Òhú%ðVà•<ZĤûßRÀq%ÕÇRà·Ä’¦ÜäÝÃ:¨¬¯Íù¸’êç·ÄHëÙ¼˜÷¤û±XI ¯%jBnòìa½‡xð¢$µ»øQÊ«`7@º?»¤Ùž"6>˜ö@y oÁb%©³ ‰1´ÃCtÁ$© ž%özN-XK™µæA’*`qoó)CÂËÒä"I=¨Míë- ‘¤¹œ¨Mö°$U=,Iµq¢6ÍLºO‡3“¤#IÝÎ&gzX«±XIª¦3‰ubHø¦t¹HÒœÞ' Öª„‰HÒ\VÁÉ‚uAº<$iN€=,Iõ`KRm\'—5¼D|m(IUtX8œCëÆBIª°¥ã´mÝ Ivþ8ðúÔYHR¯–¤ÎB’2X2NÌaIRÕcKR],±`Iª ‡„’jÃ!¡¤ÚX2¼.u’”ÁëÆ©³¤ X°$ÕÅ‚q`~ê,$)ƒù,Iu1ß!¡¤ºpH(©6æ¯Ï%”¤*›Ÿûo$©Æã©“¤ Ž/§ÎB’2xÙ–¤º°‡%©6^¶`Iª ‡„’jã¸KR]¦ÎB’288ìO…$e°x1u’”Á‹ö°$ÕÅ~ –¤ºpH(©6JªýãÀÞÔYHR{Lj'?¿:IšÃÒ±Ö/g§ÌD’z8 ,œÙqô鄉HÒ\ž†ØqôÄ?$©¢ž†“kwº<$iN»Á–¤zxìaIª‡SzX¿J˜ˆ$ÍåW3Ë&ˆ¯ ÏL–Ž$uv”XvuâAª“ÀötùHRWÛ‰Eû“ŸM“‹$õt¢6µ¬G$"Is9Q›ìaIªºµi¬í\ ì+?Iêi­ Ú{X/Ï&IG’:{–¶ÝdÆgýrs¹¹HRO§Ô¤ÙkS‰‰HÒ\N©Ic³~ùJªŽó€_Ïücvë×ÀÎRÓ‘¤ÎvÒV¬àô‚ %UÃiµ¨SÁrâ]RœV‹fÏaA¬yx¾Ëï$© ÓÀrf­ íÔÃÚ‡7BKJk;²w*Xà<–¤´:Ö nËy,I)u¬AÝæ©Ëá' KG’:›$îm>0ûÝzX€‡‹ÌH’ºx˜Å º,pX()®µ§WÁº§€D$i.]kO¯µV¯ž#ÖeIRö+€W;ý²WëUà¶"2’¤.n£K±‚Þ àkùæ"I=õ¬9Yn¿y X›O.’ÔÕvàͽþ`®Àæ“‹$õ4g­ÉÒÃZ ÇÅ òYü9AlIÇ’ÔL³É|ß`'yìÓ> |>‡ãHj®Ï3d±‚ün¯'nо0§ãIjާˆ›œ§†=P^O™nÍéX’šåVr(V~„;9H:ÕDmÈEÞ;.œüxmÎÇ•T?¿.žÍë€y¨å1±v]ÎÇ•T?Ÿ~˜ç‹ØÓj±˜ôÒŽ-©~I,}%σñøùW€0ä1Iµ5MÔ€\‹S° ¶øfAÇ–Tmߤ í§ŠÜæx9°XTà9$UË!àÀóE<ïI÷vGˆo ÞSà9$UË'ME¼èIL?®(ø<’Ò{x;9Ü‚ÓMQsX3&¿&§U®’*kŠ¸Ö +VP|Á‚Ø•ô«%œGR:_%®õB•õlÁ…ij ×”t>IåÙI¼Bªƒ§€uÄ ÎI¤˜Ãjw糤:˜™·JV¬ ÝV»ÿ%&ïÜÕAª®ßMDê!a»;€÷¥NBÒiîþ(uP­‚5ø>ÀBª’{ˆ»S^NT«`œ l&¤IJë!`p8u"3ªV°–÷ãÎRJ;«}©iWÅ‚° x87u"ÒÚ¬v§Nd¶Ô˺ÙM|k˜ô+Ti"®½Ê+¨nÁØü!î¡%•åqÍmKH7U.X÷JÁûDKb’¸ÖîKH/UX8:—Äæ7¥NDj°ßHÄ\êP° ¾^"¾b•”¯Ï_LDu)X?–ïHˆÔ ÿ üCê$²ªSÁ¸ XAÜ1.i8_>L§N$«º¬ibÃ{‡‡Òp>|‚+¨_ÁšñSbqÛTÿ›N©J&‰ öZÌYÍVÕ•îYÝ |8#u"R #–.$ß&fPu/X×ûK/JˆTa‡ˆE¡•^g5—&,€Ë὇R'{ˆÛm*»‚=«¦,ˆ¦ïÆ]¤v;¨è½ýjÒ„õnb;Œ‡R'"UÄCÄ5шbÍ*X{÷l vI”FÙ=ĵP©ý¬†Õ´‚±;âÀ÷R'"%ò=â¨ÌN¡yibÁxx/ð7ø1ŽãD›/q 4N“&Ý»¹ø>¬UÍöñÜÀS'R¤¦ö°Ú=HÜ{x{êD¤‚ÜN´ñF«Qt+±ÚwÚ0Lj6=2FaH8Û:bˆ¸:u"Òž$†€[S'R¦Qζ•xîá·S'" èÛD©b¥¸ký(é»ö†‘%ŽmV#ì à Ò7FÃèOmUbðYbcÀÔ Ó0ÚcŠh›óf¹Š˜HÝH cšh‹W!õ0|8HúkŒf$Ú`]wV˯ã0Ñ(/¦ˆ6·i@×ÛIߘfÇv¢­IC›| 8Bú†m4+ŽmËIuåî<àÒ7r£qѦ¤Bmv‘¾ÁõŒ]D’J3ø °ƒô€QØA´‡Jf‚¸ ué/£š±h#.SPeŒ7[HÕˆ-D›Å]QT#×›IÁib3ѤZYüŸŽBLµ>ëõH57³Eó$é/,#ߘääÅR£\ |ØKú Í.ö¶>Ë‹‘n¸øñì¸ÔŸ‘-·>³ëñ?¨³€[€㱊1Ùúlni}V’ZV÷•=Fú uÔã±Ög±²ç'& ˆIÜ/á|W™±·õßÜ ôŠrA[õ7÷žm .¦Q|ÚQ¦ˆ]=7›€»‰Â¥Š²`ÕÏbà¢xmÖâç˜Õ4±ïÔ&¢HÝHš‘úbC¯¿eDñš)`kÒ¦S9;9Y 6ûÒ¦£aX°šgð.¢x] œŸ4›ò=ÜK©ŸÏ%ÍF¹²`5ßRà2à-m¯k3S&•ƒ£ÄðîQà‘¶×R&¥bY°FÓ±Bûà"à`Uëu5Õ)fG'§Ý­×]Àãœ|ø­FˆKœCÌ…-–´þ½dÖÏ‹€3€ÀüV,h{' ÎËÀñÖëÌÏÇ€CÀ~àÅÖkûψ¹§‹þ?ªzùK¸„¡8eÇIEND®B`‚mlt-0.9.0/demo/circle.svg000066400000000000000000000001251215300731300152130ustar00rootroot00000000000000 mlt-0.9.0/demo/consumers.ini000066400000000000000000000004741215300731300157570ustar00rootroot00000000000000SDL Default sdl SDL Half D1 sdl:360x288 rescale=nearest resize=1 SDL High Latency sdl buffer=12 rescale=none SDL Progressive sdl progressive=1 XML to Terminal xml XML to File xml: libdv to /dev/dv1394/0 libdv:/dev/dv1394/0 rescale=nearest buffer=25 DeckLink decklink DeckLink Prog LL decklink progressive=1 buffer=1 mlt-0.9.0/demo/demo000077500000000000000000000040171215300731300141070ustar00rootroot00000000000000#!/bin/bash export MLT_PROFILE=dv_pal export LC_NUMERIC=C function show_consumers( ) { awk -F '\t' '{ printf( "%d. %s\n", ++ i, $1 ); }' < consumers.ini } function get_consumer( ) { option=$1 [ "$option" != "" ] && [ $option -gt 0 ] && sed 's/\t\+/\t/g' < consumers.ini | cut -f 2 | head -n $option | tail -n -1 } function show_menu( ) { sed 's/\t\+/\t/g' < demo.ini | awk -F '\t' '{ printf( "%2d. %-30.30s", ++ i, $2 ); if ( i % 2 == 0 ) printf( "\n" ); } END { if ( i % 2 == 1 ) printf( "\n" ); }' } function check_dependencies( ) { option=$1 if [ $option -gt 0 ] then deps=`sed 's/\t\+/\t/g' < demo.ini | cut -f 3 | head -n $option | tail -n -1` if [ "$deps" != "" ] then echo "$deps" | tr ',' '\n' | while read dep do ls $dep > /dev/null 2>&1 val=$? [ $val != 0 ] && echo Failed to find $dep >&2 && echo $val done fi echo 0 fi } function get_demo( ) { option=$1 if [ $option -gt 0 ] then cut -f 1 demo.ini | head -n $option | tail -n -1 fi } while [ 1 ] do echo Select Consumer echo show_consumers echo echo 0. Exit echo echo -n "Option: " read option echo [ "$option" == "0" ] && break export MLT_CONSUMER=`get_consumer $option` while [ "$option" != "0" -a "$MLT_CONSUMER" != "" ] do echo Choose Demo echo show_menu echo echo -n "Option: " read option echo [ "$option" == "" ] && break demo=`get_demo $option` usable=`check_dependencies $option` if [ "$usable" = "0" -a "$demo" != "" ] then if [ "$MLT_CONSUMER" == "xml:" ] then export XML_CONSUMER="xml:$demo.mlt" bash $demo -consumer $XML_CONSUMER melt +$demo.txt out=100 $demo.mlt $demo.mlt -filter watermark:watermark1.png composite.fill=1 composite.geometry=85%/5%:10%x10% elif [ "$MLT_CONSUMER" == "xml" ] then bash $demo -consumer $MLT_CONSUMER | less else bash $demo -consumer $MLT_CONSUMER fi elif [ "$usable" != "" ] then echo echo Unable to locate suitable files for the demo - please provide them. read pause fi stty sane done done mlt-0.9.0/demo/demo.ini000066400000000000000000000027221215300731300146630ustar00rootroot00000000000000mlt_all All clips clip* mlt_effect_in_middle Filter in/out clip1.mpeg mlt_watermark Watermark clip2.dv,watermark1.png mlt_my_name_is My name is... clip3.dv mlt_composite_transition A composite transition clip1.dv,clip2.mpeg mlt_fade_in_and_out Fade in and out clip1.dv,clip2.mpeg,clip3.dv mlt_clock_in_and_out Clock in and out clip2.dv,clip1.dv,clip3.mpeg mlt_obscure Obscure clip2.mpeg,circle.png mlt_audio_stuff Audio Stuff clip*.dv,music1.ogg mlt_levels Audio and Video Levels clip*.dv mlt_titleshadow_watermark Shadowed Title and Watermark clip3.dv mlt_intro Station Promo into Story? watermark1.png,clip3.mpeg,music1.ogg mlt_voiceover Voiceover 2 clips with title clip1.dv,clip2.mpeg,music1.ogg mlt_avantika_title GJ-TTAvantika title pango.mlt mlt_title_over_gfx Title over graphic watermark1.png,clip1.dv mlt_slideshow Slideshow photos mlt_bouncy Bouncy, Bouncy clip1.dv,clip3.dv mlt_bouncy_ball Bouncy, Bouncy Ball clip1.mpeg,clip3.mpeg,circle.png mlt_news Breaking News clip1.dv,clip2.dv mlt_squeeze Squeeze Transitions clip1.dv,clip2.dv,clip3.dv mlt_squeeze_box Squeeze Box clip1.dv,clip2.dv,clip3.dv mlt_jcut J Cut clip1.dv,clip2.dv mlt_lcut L Cut clip1.dv,clip2.dv mlt_fade_black Fade from/to black/silence clip3.mpeg mlt_push Push wipe clip1.mpeg, clip2.mpeg mlt_ticker Ticker tape clip1.dv mlt_attributes Attributes clip1.dv mlt_slideshow_black Composite slideshow photos mlt_slideshow2 Ken Burns slideshow photos mlt_pango_keyframes Pango Keyframed Markup pango_keyframes.mpl mlt-0.9.0/demo/demo.kino000066400000000000000000000006611215300731300150440ustar00rootroot00000000000000 mlt-0.9.0/demo/entity.mlt000066400000000000000000000004321215300731300152640ustar00rootroot00000000000000 ]> pango Hello &name;, My name is Inigo Montoya. mlt-0.9.0/demo/luma1.pgm000066400000000000000000014520171215300731300147710ustar00rootroot00000000000000P5 720 576 255 ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßàààààààááááááâââââââããããããääääääååååååææææææççççççèèèèèééééééêêêêêëëëëëììììììíííííîîîîîïïïïïðððððñññññòòòòòóóóóôôôôôõõõõõööööö÷÷÷÷øøøøøùùùùúúúúúûûûûüüüüüýýýýþþþþþÿÿÿÿ  !!!!!!!!"""""""########$$$$$$$$%%%%%%%%%&&&&&&&&''''''''''((((((((()))))))))))***********++++++++++,,,,,,,,,,,,,--------------.............///////////////00000000000000001111111111111111ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØØÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßßàààààààáááááááââââââããããããäääääääååååååææææææçççççèèèèèèéééééêêêêêêëëëëëìììììíííííîîîîîïïïïïðððððñññññòòòòòóóóóóôôôôõõõõõööööö÷÷÷÷øøøøøùùùùúúúúúûûûûüüüüüýýýýþþþþþÿÿÿÿ  !!!!!!!""""""""#######$$$$$$$$$%%%%%%%&&&&&&&&&&'''''''''(((((((((())))))))))**********++++++++++++,,,,,,,,,,,,-------------..............////////////////00000000000000001111111111111111ÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßßàààààààáááááááââââââããããããääääääååååååææææææççççççèèèèèééééééêêêêêëëëëëìììììíííííîîîîîîïïïïðððððñññññòòòòòóóóóóôôôôõõõõõööööö÷÷÷÷øøøøøùùùùúúúúúûûûûûüüüüýýýýýþþþþÿÿÿÿ  !!!!!!!""""""""########$$$$$$$%%%%%%%%%&&&&&&&&'''''''''''(((((((()))))))))))***********+++++++++++,,,,,,,,,,,,,------------.............///////////////00000000000000000111111111111111112ÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßààààààààááááááââââââããããããäääääääåååååææææææççççççèèèèèèéééééêêêêêëëëëëììììììíííííîîîîîïïïïïðððððññññòòòòòóóóóóôôôôôõõõõööööö÷÷÷÷øøøøøùùùùùúúúúûûûûûüüüüýýýýýþþþþÿÿÿÿ  !!!!!!!!"""""""########$$$$$$$$%%%%%%%%&&&&&&&&&'''''''''(((((((((())))))))))***********+++++++++++,,,,,,,,,,,--------------..............///////////////00000000000000011111111111111111122ÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßßàààààààáááááááââââââããããããääääääååååååææææææçççççèèèèèèéééééêêêêêêëëëëëìììììíííííîîîîîïïïïïðððððñññññòòòòóóóóóôôôôôõõõõööööö÷÷÷÷÷øøøøùùùùùúúúúûûûûûüüüüýýýýýþþþþÿÿÿÿ  !!!!!!!"""""""########$$$$$$$$%%%%%%%%%&&&&&&&&''''''''''((((((((()))))))))))**********+++++++++++,,,,,,,,,,,,------------..............////////////////000000000000000011111111111111111122ÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ×××××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßààààààààááááááââââââãããããããäääääåååååååæææææççççççèèèèèééééééêêêêêëëëëëìììììííííííîîîîïïïïïðððððñññññòòòòòóóóóôôôôôõõõõõöööö÷÷÷÷÷øøøøùùùùùúúúúûûûûûüüüüýýýýýþþþþÿÿÿÿ  !!!!!!!""""""""#######$$$$$$$$$%%%%%%%%&&&&&&&&&''''''''((((((((((()))))))))***********+++++++++++,,,,,,,,,,,,-------------.............///////////////00000000000000001111111111111111122222ÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßßàààààààááááááâââââââããããããääääääååååååææææææçççççèèèèèèéééééêêêêêëëëëëëìììììíííííîîîîîïïïïðððððñññññòòòòòóóóóôôôôôõõõõõöööö÷÷÷÷÷øøøøùùùùùúúúúûûûûûüüüüýýýýýþþþþÿÿÿÿ  !!!!!!""""""""########$$$$$$$$%%%%%%%%%&&&&&&&''''''''''((((((((()))))))))))*********+++++++++++++,,,,,,,,,,,------------...............///////////////00000000000000011111111111111111222222ÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØØÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßßàààààààááááááââââââãããããããäääääååååååææææææçççççèèèèèèéééééêêêêêêëëëëëìììììíííííîîîîîïïïïïðððððññññòòòòòóóóóóôôôôõõõõõööööö÷÷÷÷øøøøøùùùùúúúúûûûûûüüüüýýýýýþþþþÿÿÿÿ  !!!!!!!"""""""########$$$$$$$$%%%%%%%%&&&&&&&&&'''''''''(((((((((()))))))))***********+++++++++++,,,,,,,,,,,,-------------.............///////////////0000000000000000011111111111111111222222ÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßßàààààààááááááâââââââããããããääääääååååååæææææççççççèèèèèééééééêêêêêëëëëëìììììíííííîîîîîïïïïïðððððññññòòòòòóóóóóôôôôõõõõõööööö÷÷÷÷øøøøøùùùùúúúúúûûûûüüüüýýýýýþþþþÿÿÿÿ  !!!!!!""""""""#######$$$$$$$$%%%%%%%%%&&&&&&&&''''''''''(((((((()))))))))))**********++++++++++++,,,,,,,,,,,-------------..............//////////////00000000000000011111111111111111122222222ÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßßààààààáááááááââââââããããããäääääääåååååææææææçççççèèèèèèéééééêêêêêëëëëëëììììííííííîîîîïïïïïðððððñññññòòòòòóóóóôôôôôõõõõööööö÷÷÷÷øøøøøùùùùúúúúúûûûûüüüüýýýýýþþþþÿÿÿÿ  !!!!!!!"""""""########$$$$$$$$%%%%%%%%&&&&&&&&&''''''''(((((((((()))))))))***********+++++++++++,,,,,,,,,,,,,-----------..............////////////////00000000000000011111111111111111222222222ÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßàààààààáááááááââââââããããããääääääååååååæææææççççççèèèèèéééééêêêêêêëëëëëìììììíííííîîîîîïïïïðððððñññññòòòòòóóóóôôôôôõõõõööööö÷÷÷÷øøøøøùùùùúúúúúûûûûüüüüýýýýýþþþþÿÿÿÿ  !!!!!!!""""""""#######$$$$$$$$%%%%%%%%%&&&&&&&''''''''''((((((((())))))))))**********++++++++++++,,,,,,,,,,,-------------.............//////////////00000000000000000111111111111111112222222222ÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßßàààààààááááááâââââââãããããääääääååååååææææææçççççèèèèèèéééééêêêêêëëëëëìììììíííííîîîîîïïïïïðððððññññòòòòòóóóóôôôôôõõõõõöööö÷÷÷÷øøøøøùùùùúúúúúûûûûüüüüýýýýýþþþþÿÿÿÿ  !!!!!!!"""""""########$$$$$$$%%%%%%%%&&&&&&&&&''''''''(((((((((())))))))))**********+++++++++++,,,,,,,,,,,,------------...............//////////////00000000000000011111111111111111222222222222ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßàààààààáááááááââââââããããããääääääåååååææææææççççççèèèèèéééééêêêêêëëëëëëììììíííííîîîîîïïïïïðððððñññññòòòòóóóóóôôôôõõõõõöööö÷÷÷÷÷øøøøùùùùúúúúúûûûûüüüüýýýýýþþþþÿÿÿÿ  !!!!!!!""""""""######$$$$$$$$%%%%%%%%%&&&&&&&&'''''''''((((((((())))))))))***********++++++++++,,,,,,,,,,,,-------------............////////////////000000000000000011111111111111112222222222222ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßßàààààààááááááââââââãããããããäääääååååååææææææçççççèèèèèééééééêêêêêëëëëëìììììíííííîîîîîïïïïðððððñññññòòòòóóóóóôôôôõõõõõöööö÷÷÷÷÷øøøøùùùùùúúúúûûûûüüüüüýýýýþþþþÿÿÿÿ  !!!!!!"""""""########$$$$$$$$%%%%%%%%&&&&&&&&&''''''''((((((((()))))))))))*********++++++++++++,,,,,,,,,,,-------------.............//////////////00000000000000001111111111111111122222222222222ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßßààààààáááááááââââââããããããääääääååååååæææææçççççèèèèèèéééééêêêêêëëëëëìììììíííííîîîîîïïïïðððððñññññòòòòòóóóóôôôôôõõõõööööö÷÷÷÷øøøøùùùùùúúúúûûûûüüüüüýýýýþþþþÿÿÿÿ  !!!!!!!"""""""#######$$$$$$$$%%%%%%%%%&&&&&&&''''''''''((((((((()))))))))***********++++++++++,,,,,,,,,,,,,-----------..............///////////////00000000000000111111111111111112222222222222222ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßàààààààááááááââââââããããããääääääååååååæææææççççççèèèèèéééééêêêêêëëëëëììììììííííîîîîîïïïïïðððððññññòòòòòóóóóôôôôôõõõõööööö÷÷÷÷øøøøùùùùùúúúúûûûûüüüüüýýýýþþþþÿÿÿÿ  !!!!!!!"""""""########$$$$$$$%%%%%%%%&&&&&&&&&''''''''(((((((((())))))))))*********++++++++++++,,,,,,,,,,,-------------............///////////////0000000000000000111111111111111122222222222222222ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßààààààáááááááââââââããããããäääääååååååææææææçççççèèèèèèéééééêêêêêëëëëëìììììíííííîîîîïïïïïðððððññññòòòòòóóóóóôôôôõõõõööööö÷÷÷÷øøøøøùùùùúúúúûûûûüüüüüýýýýþþþþÿÿÿÿ  !!!!!!!!"""""""#######$$$$$$$$%%%%%%%%&&&&&&&&'''''''''((((((((()))))))))***********++++++++++,,,,,,,,,,,,,-----------..............//////////////00000000000000011111111111111111222222222222222222ÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßàààààààáááááááâââââããããããääääääååååååæææææççççççèèèèèéééééêêêêêëëëëëìììììíííííîîîîîïïïïðððððñññññòòòòóóóóóôôôôõõõõõöööö÷÷÷÷øøøøøùùùùúúúúûûûûüüüüüýýýýþþþþÿÿÿÿ  !!!!!!!"""""""########$$$$$$$%%%%%%%%&&&&&&&&&''''''''((((((((())))))))))**********+++++++++++,,,,,,,,,,,-------------............////////////////00000000000000111111111111111122222222222222222223ÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßàààààààááááááââââââããããããääääääåååååææææææçççççèèèèèéééééêêêêêêëëëëìììììíííííîîîîîïïïïïððððñññññòòòòóóóóóôôôôõõõõõöööö÷÷÷÷øøøøøùùùùúúúúûûûûûüüüüýýýýþþþþÿÿÿÿ  !!!!!!!!""""""#######$$$$$$$$%%%%%%%%%&&&&&&&'''''''''(((((((((())))))))***********+++++++++++,,,,,,,,,,,------------............../////////////00000000000000001111111111111111122222222222222222233ÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßßààààààáááááááââââââãããããääääääååååååæææææçççççèèèèèèéééééêêêêêëëëëëìììììííííîîîîîïïïïïðððððññññòòòòòóóóóôôôôõõõõõöööö÷÷÷÷øøøøøùùùùúúúúûûûûûüüüüýýýýþþþþÿÿÿÿ  !!!!!!""""""""#######$$$$$$$%%%%%%%%&&&&&&&&&''''''''((((((((())))))))))**********+++++++++++,,,,,,,,,,,,-----------..............//////////////00000000000000111111111111111112222222222222222222233ÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßàààààààááááááââââââããããããääääääåååååæææææççççççèèèèèéééééêêêêêëëëëëìììììíííííîîîîïïïïïðððððññññòòòòòóóóóôôôôôõõõõöööö÷÷÷÷÷øøøøùùùùúúúúûûûûûüüüüýýýýþþþþÿÿÿÿ  !!!!!!!"""""""#######$$$$$$$$%%%%%%%%&&&&&&&&'''''''''((((((((()))))))))**********+++++++++++,,,,,,,,,,,-------------............///////////////000000000000000111111111111111222222222222222222233333ÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßààààààááááááâââââââããããããäääääåååååææææææçççççèèèèèééééééêêêêêëëëëìììììíííííîîîîîïïïïðððððñññññòòòòóóóóôôôôôõõõõööööö÷÷÷÷øøøøùùùùúúúúúûûûûüüüüýýýýþþþþÿÿÿÿ  !!!!!!!""""""""#######$$$$$$$%%%%%%%%&&&&&&&&'''''''''(((((((())))))))))***********++++++++++,,,,,,,,,,,,-----------............../////////////00000000000000011111111111111111222222222222222222333333ÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßàààààààááááááââââââããããããäääääååååååæææææçççççèèèèèèéééééêêêêêëëëëëìììììííííîîîîîïïïïïððððñññññòòòòóóóóóôôôôõõõõööööö÷÷÷÷øøøøùùùùúúúúúûûûûüüüüýýýýþþþþÿÿÿÿ  !!!!!!!""""""########$$$$$$$$%%%%%%%%&&&&&&&'''''''''((((((((()))))))))**********++++++++++++,,,,,,,,,,-------------............///////////////00000000000001111111111111111122222222222222222222333333ÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßààààààááááááââââââããããããääääääåååååææææææçççççèèèèèéééééêêêêêëëëëëìììììíííííîîîîïïïïïððððñññññòòòòóóóóóôôôôõõõõööööö÷÷÷÷øøøøùùùùúúúúúûûûûüüüüýýýýþþþþÿÿÿÿ  !!!!!!!"""""""#######$$$$$$$%%%%%%%%&&&&&&&&&''''''''((((((((())))))))))**********++++++++++,,,,,,,,,,,------------.............//////////////0000000000000001111111111111111222222222222222222333333333ÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßàààààààááááááââââââããããããäääääååååååæææææççççççèèèèééééééêêêêêëëëëëììììíííííîîîîîïïïïðððððññññòòòòòóóóóôôôôõõõõõöööö÷÷÷÷øøøøùùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿÿ  !!!!!!"""""""########$$$$$$$%%%%%%%%&&&&&&&&''''''''(((((((((()))))))))*********+++++++++++,,,,,,,,,,,------------.............//////////////00000000000000011111111111111111222222222222222223333333333ÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßàààààààááááááâââââããããããääääääåååååææææææçççççèèèèèéééééêêêêêëëëëëìììììííííîîîîîïïïïðððððññññòòòòòóóóóôôôôôõõõõöööö÷÷÷÷øøøøùùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿÿ  !!!!!!!"""""""#######$$$$$$$%%%%%%%%&&&&&&&&'''''''''(((((((())))))))))**********++++++++++,,,,,,,,,,,-------------...........///////////////000000000000001111111111111111222222222222222222223333333333ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßààààààááááááââââââããããããäääääååååååæææææçççççèèèèèéééééêêêêêëëëëëìììììííííîîîîîïïïïïððððñññññòòòòóóóóôôôôôõõõõöööö÷÷÷÷øøøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿÿ  !!!!!!!"""""""#######$$$$$$$$%%%%%%%%&&&&&&&'''''''''((((((((()))))))))*********+++++++++++,,,,,,,,,,,,----------............../////////////00000000000000001111111111111112222222222222222223333333333333ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßàààààààááááááââââââãããããääääääåååååææææææçççççèèèèèéééééêêêêêëëëëëììììíííííîîîîïïïïïððððñññññòòòòóóóóóôôôôõõõõöööö÷÷÷÷øøøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿÿ  !!!!!!!"""""""######$$$$$$$$%%%%%%%&&&&&&&&&''''''''((((((((()))))))))**********+++++++++++,,,,,,,,,,------------............///////////////00000000000000111111111111111112222222222222222233333333333333ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßààààààááááááââââââããããããäääääååååååæææææçççççèèèèèéééééêêêêêëëëëëììììíííííîîîîîïïïïðððððññññòòòòóóóóóôôôôõõõõöööö÷÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿÿ  !!!!!!!"""""""#######$$$$$$$$%%%%%%%&&&&&&&&''''''''((((((((())))))))))*********++++++++++,,,,,,,,,,,,-----------............./////////////0000000000000001111111111111112222222222222222222233333333333333ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßàààààààááááááââââââãããããääääääåååååæææææçççççèèèèèèéééééêêêêëëëëëìììììíííííîîîîïïïïðððððññññòòòòòóóóóôôôôõõõõööööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿÿ  !!!!!!!""""""#######$$$$$$$%%%%%%%%&&&&&&&&'''''''''(((((((()))))))))**********+++++++++++,,,,,,,,,,------------............./////////////00000000000000011111111111111112222222222222222233333333333333333ËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßàààààààáááááââââââãããããääääääååååååæææææçççççèèèèèéééééêêêêêëëëëìììììíííííîîîîïïïïïððððñññññòòòòóóóóôôôôõõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿÿ  !!!!!!!""""""########$$$$$$$%%%%%%%%&&&&&&&''''''''((((((((())))))))))*********++++++++++,,,,,,,,,,,-------------...........///////////////00000000000001111111111111111122222222222222222333333333333333333ËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßàààààààááááááââââââãããããääääääåååååæææææçççççèèèèèéééééêêêêêëëëëëììììíííííîîîîîïïïïððððñññññòòòòóóóóôôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿÿ  !!!!!!"""""""######$$$$$$$$%%%%%%%%&&&&&&&&''''''''((((((((())))))))**********+++++++++++,,,,,,,,,,,----------..............////////////00000000000000001111111111111122222222222222222222333333333333333333ËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßàààààààááááááâââââããããããäääääåååååæææææççççççèèèèèéééééêêêêëëëëëìììììííííîîîîîïïïïðððððññññòòòòóóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿÿ  !!!!!!"""""""#######$$$$$$$$%%%%%%%&&&&&&&&''''''''(((((((())))))))))**********+++++++++,,,,,,,,,,,------------............//////////////00000000000000111111111111111122222222222222222333333333333333333334ËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßààààààááááááâââââããããããääääääåååååæææææçççççèèèèèéééééêêêêêëëëëìììììíííííîîîîïïïïðððððññññòòòòóóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿÿ  !!!!!!!""""""#######$$$$$$$%%%%%%%%&&&&&&&&'''''''''(((((((()))))))))*********+++++++++++,,,,,,,,,,,-----------............//////////////000000000000011111111111111111222222222222222223333333333333333334444ËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßàààààààáááááââââââããããããäääääåååååæææææçççççèèèèèéééééêêêêêëëëëëììììíííííîîîîïïïïïððððññññòòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúúûûûûüüüüýýýýþþþÿÿÿÿ  !!!!!!"""""""#######$$$$$$$%%%%%%%%&&&&&&&''''''''((((((((()))))))))**********++++++++++,,,,,,,,,,------------.............////////////00000000000000011111111111111222222222222222222223333333333333333334444ËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââââãããããäääääååååååæææææçççççèèèèèéééééêêêêêëëëëìììììííííîîîîîïïïïððððñññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿ  !!!!!!"""""""#######$$$$$$$%%%%%%%%&&&&&&&&''''''''((((((((())))))))*********++++++++++,,,,,,,,,,,,-----------...........///////////////00000000000001111111111111111222222222222222223333333333333333333344444ËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââââããããããäääääåååååæææææçççççèèèèèéééééêêêêêëëëëìììììíííííîîîîïïïïðððððññññòòòòóóóóôôôôõõõõööööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿ  !!!!!!"""""""#######$$$$$$$%%%%%%%&&&&&&&&'''''''((((((((()))))))))**********++++++++++,,,,,,,,,,-----------............./////////////0000000000000011111111111111112222222222222222233333333333333333344444444ËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââââãããããääääääåååååæææææçççççèèèèéééééêêêêêëëëëëììììíííííîîîîïïïïðððððññññòòòòóóóóôôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿ  !!!!!!"""""""#######$$$$$$$%%%%%%%&&&&&&&&''''''''((((((((()))))))))*********+++++++++,,,,,,,,,,,------------............/////////////00000000000000011111111111111222222222222222222233333333333333333344444444ËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââââãããããääääääåååååæææææçççççèèèèèéééééêêêêêëëëëìììììííííîîîîïïïïïððððññññòòòòóóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿ  !!!!!!""""""#######$$$$$$$%%%%%%%%&&&&&&&''''''''(((((((()))))))))**********++++++++++,,,,,,,,,,,----------.............//////////////00000000000011111111111111111222222222222222233333333333333333333444444444ËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââââãããããäääääååååååæææææçççççèèèèèééééêêêêêëëëëìììììííííîîîîîïïïïððððññññòòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿ  !!!!!!""""""#######$$$$$$$%%%%%%%%&&&&&&&'''''''''(((((((()))))))))*********++++++++++,,,,,,,,,,------------.............///////////00000000000000011111111111111122222222222222222333333333333333333444444444444ËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááâââââããããããäääääåååååæææææçççççèèèèèééééêêêêêëëëëëììììíííííîîîîïïïïððððñññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿ  !!!!!!"""""""#######$$$$$$$%%%%%%%&&&&&&&&'''''''((((((((())))))))**********++++++++++,,,,,,,,,,,-----------...........//////////////00000000000000111111111111112222222222222222222333333333333333334444444444444ËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââââãããããäääääåååååæææææçççççèèèèèéééééêêêêêëëëëìììììííííîîîîïïïïðððððññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿ  !!!!!!""""""#######$$$$$$$%%%%%%%&&&&&&&&''''''''(((((((()))))))))**********+++++++++,,,,,,,,,,-----------............./////////////000000000000011111111111111112222222222222222333333333333333333334444444444444ËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááâââââããããããäääääåååååæææææçççççèèèèèééééêêêêêëëëëëììììííííîîîîïïïïïððððññññòòòòóóóóôôôôôõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿ  !!!!!!"""""""######$$$$$$$%%%%%%%%&&&&&&&''''''''(((((((()))))))))*********++++++++++,,,,,,,,,,------------............////////////00000000000000011111111111111222222222222222223333333333333333334444444444444444ËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááâââââããããããäääääåååååæææææçççççèèèèèééééêêêêêëëëëëììììííííîîîîîïïïïððððññññòòòòóóóóóôôôôõõõõöööö÷÷÷÷øøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿÿ  !!!!!!!""""""#######$$$$$$$%%%%%%%&&&&&&&''''''''((((((((())))))))**********++++++++++,,,,,,,,,,----------............//////////////00000000000001111111111111112222222222222222223333333333333333344444444444444444ËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßààààààááááááâââââãããããääääääåååååæææææççççèèèèèéééééêêêêëëëëëììììíííííîîîîïïïïððððñññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùúúúúûûûûüüüüýýýýþþþþÿÿÿ  !!!!!!!""""""#######$$$$$$$%%%%%%%&&&&&&&&'''''''((((((((())))))))*********++++++++++,,,,,,,,,,------------............////////////0000000000000111111111111111112222222222222223333333333333333333344444444444444444ËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßààààààáááááââââââãããããäääääåååååæææææçççççèèèèèééééêêêêêëëëëìììììííííîîîîïïïïðððððññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúûûûûüüüüýýýýþþþþÿÿÿ  !!!!!!!""""""######$$$$$$$%%%%%%%&&&&&&&&''''''''(((((((())))))))**********++++++++++,,,,,,,,,,-----------.........../////////////00000000000000111111111111112222222222222222233333333333333333344444444444444444444ÊÊËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßààààààááááááâââââãããããäääääåååååæææææçççççèèèèèéééééêêêêëëëëëììììííííîîîîîïïïïððððññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúûûûûüüüüýýýýþþþþÿÿÿ  !!!!!!"""""""######$$$$$$$%%%%%%%%&&&&&&&''''''''(((((((()))))))))*********+++++++++,,,,,,,,,,-----------............//////////////00000000000011111111111111122222222222222222233333333333333333444444444444444444445ÊÊÊÊËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááâââââãããããäääääåååååæææææçççççèèèèéééééêêêêëëëëëììììíííííîîîîïïïïððððññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûüüüüýýýýþþþþÿÿÿ  !!!!!!"""""""######$$$$$$$%%%%%%%&&&&&&&''''''''(((((((()))))))))*********+++++++++,,,,,,,,,,,-----------...........////////////00000000000000111111111111111122222222222222233333333333333333333444444444444444444555ÊÊÊÊËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßààààààááááááâââââãããããääääääåååååæææææççççèèèèèééééêêêêêëëëëìììììííííîîîîïïïïðððððñññòòòòòóóóóôôôôõõõõööö÷÷÷÷øøøøùùùùúúúúûûûüüüüýýýýþþþþÿÿÿ  !!!!!!""""""#######$$$$$$$%%%%%%%&&&&&&&&'''''''((((((((())))))))*********++++++++++,,,,,,,,,,----------...........//////////////00000000000000111111111111122222222222222222333333333333333333444444444444444444444555ÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààáááááââââââãããããäääääåååååæææææçççççèèèèéééééêêêêëëëëëììììííííîîîîîïïïïððððññññòòòòóóóóôôôôõõõõööö÷÷÷÷øøøøùùùùúúúúûûûüüüüýýýýþþþþÿÿÿ  !!!!!!""""""#######$$$$$$%%%%%%%&&&&&&&&'''''''(((((((()))))))))*********+++++++++,,,,,,,,,,-----------............/////////////000000000000111111111111111122222222222222222333333333333333344444444444444444444455555ÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßààààààááááááâââââããããããäääääååååæææææçççççèèèèéééééêêêêëëëëëììììííííîîîîîïïïïððððññññòòòòóóóóôôôôõõõõöööö÷÷÷øøøøùùùùúúúúûûûûüüüýýýýþþþþÿÿÿ  !!!!!!""""""#######$$$$$$%%%%%%%%&&&&&&&''''''''(((((((()))))))))*********+++++++++,,,,,,,,,,-----------...........////////////00000000000000111111111111111222222222222222333333333333333333344444444444444444455555555ÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ×××××××ØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßààààààáááááâââââããããããäääääåååååæææææççççèèèèèéééééêêêêëëëëìììììííííîîîîïïïïððððññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøùùùùúúúúûûûûüüüýýýýþþþþÿÿÿ  !!!!!!"""""""#######$$$$$$%%%%%%%&&&&&&&''''''''((((((()))))))))*********+++++++++,,,,,,,,,,-----------............/////////////00000000000001111111111111222222222222222223333333333333333334444444444444444444455555555ÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààáááááâââââãããããäääääåååååæææææçççççèèèèèééééêêêêëëëëëììììííííîîîîïïïïðððððññññòòòóóóóôôôôõõõõöööö÷÷÷÷øøøùùùùúúúúûûûûüüüýýýýþþþþÿÿÿ  !!!!!!""""""######$$$$$$$%%%%%%%&&&&&&&&'''''''(((((((()))))))))*********+++++++++,,,,,,,,,,-----------...........////////////0000000000000111111111111111222222222222222223333333333333333444444444444444444444555555555ÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××ØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßààààààáááááââââââãããããäääääåååååææææçççççèèèèèééééêêêêêëëëëììììíííííîîîîïïïïððððññññòòòòóóóôôôôõõõõöööö÷÷÷÷øøøøùùùúúúúûûûûüüüýýýýþþþþÿÿÿ  !!!!!!""""""#######$$$$$$$%%%%%%&&&&&&&''''''''(((((((())))))))*********+++++++++,,,,,,,,,,-----------.........../////////////00000000000000111111111111112222222222222223333333333333333333444444444444444444555555555555ÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààáááááâââââãããããäääääåååååæææææçççççèèèèéééééêêêêëëëëììììíííííîîîîïïïïððððññññòòòòóóóóôôôôõõõöööö÷÷÷÷øøøøùùùúúúúûûûûüüüýýýýþþþþÿÿÿ  !!!!!!""""""######$$$$$$%%%%%%%%&&&&&&&''''''''(((((((())))))))********++++++++++,,,,,,,,,,----------............/////////////00000000000011111111111112222222222222222223333333333333333344444444444444444444555555555555ÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßààààààááááááâââââãããããäääääååååæææææçççççèèèèèééééêêêêëëëëëììììííííîîîîïïïïððððññññòòòòóóóóôôôôõõõõööö÷÷÷÷øøøøùùùúúúúûûûûüüüüýýýþþþþÿÿÿ  !!!!!!""""""#######$$$$$$%%%%%%%&&&&&&&'''''''(((((((()))))))))*********+++++++++,,,,,,,,,,----------...........////////////00000000000001111111111111112222222222222222233333333333333334444444444444444444445555555555555ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××ØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßààààààáááááâââââãããããäääääåååååæææææççççèèèèèééééêêêêêëëëëììììííííîîîîïïïïððððññññòòòòóóóóôôôôõõõõööö÷÷÷÷øøøøùùùùúúúûûûûüüüüýýýþþþþÿÿÿ  !!!!!!!""""""######$$$$$$%%%%%%%&&&&&&&&'''''''(((((((())))))))********++++++++++,,,,,,,,,-----------.........../////////////00000000000001111111111111122222222222222233333333333333333334444444444444444445555555555555555ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞÞßßßßßààààààááááááâââââãããããääääååååååææææçççççèèèèéééééêêêêëëëëìììììííííîîîîïïïïððððññññòòòòóóóôôôôõõõõöööö÷÷÷øøøøùùùùúúúûûûûüüüüýýýþþþþÿÿÿ  !!!!!!"""""#######$$$$$$$%%%%%%%&&&&&&''''''''(((((((())))))))*********++++++++++,,,,,,,,,-----------...........////////////000000000000111111111111112222222222222222233333333333333333444444444444444444455555555555555555ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ×××××××ØØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßààààààáááááâââââãããããäääääåååååææææçççççèèèèèééééêêêêëëëëëììììííííîîîîïïïïððððññññòòòòóóóôôôôõõõõöööö÷÷÷øøøøùùùùúúúûûûûüüüüýýýþþþþÿÿÿ  !!!!!!""""""######$$$$$$$%%%%%%%&&&&&&&''''''''((((((())))))))********+++++++++,,,,,,,,,,----------.........../////////////00000000000001111111111111112222222222222222333333333333333444444444444444444444455555555555555555ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞßßßßßßààààààáááááâââââãããããäääääåååååææææççççèèèèèéééééêêêêëëëëììììííííîîîîïïïïððððññññòòòòóóóóôôôõõõõöööö÷÷÷÷øøøùùùùúúúúûûûüüüüýýýþþþþÿÿÿ  !!!!!""""""#######$$$$$$$%%%%%%&&&&&&&'''''''(((((((()))))))))********+++++++++,,,,,,,,,,----------.........../////////////00000000000001111111111111222222222222222333333333333333333444444444444444444455555555555555555555ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ×××××××ØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßààààààáááááâââââãããããäääääåååååæææææççççèèèèéééééêêêêëëëëìììììííííîîîîïïïððððññññòòòòóóóóôôôôõõõöööö÷÷÷÷øøøùùùùúúúúûûûüüüüýýýþþþþÿÿÿ  !!!!!!""""""######$$$$$$%%%%%%%&&&&&&&&'''''''((((((())))))))********++++++++++,,,,,,,,,,----------...........////////////0000000000001111111111111122222222222222222333333333333333334444444444444444445555555555555555555555ÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ×××××××××ØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞßßßßßßààààààáááááâââââãããããäääääååååæææææçççççèèèèééééêêêêëëëëìììììííííîîîîïïïïððððññññòòòóóóóôôôôõõõõööö÷÷÷÷øøøùùùùúúúúûûûüüüüýýýþþþþÿÿÿ  !!!!!""""""######$$$$$$$%%%%%%%&&&&&&'''''''((((((((())))))))********+++++++++,,,,,,,,,,----------...........////////////00000000000001111111111111122222222222222223333333333333334444444444444444444445555555555555555555566ÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ××××××××ØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞßßßßßààààààáááááâââââãããããäääääåååååææææçççççèèèèéééééêêêêëëëëììììííííîîîîïïïïððððññññòòòòóóóôôôôõõõõööö÷÷÷÷øøøøùùùúúúúûûûüüüüýýýþþþþÿÿÿ  !!!!!"""""""######$$$$$$%%%%%%%&&&&&&&'''''''((((((())))))))*********+++++++++,,,,,,,,,,-----------...........///////////000000000000011111111111112222222222222223333333333333333334444444444444444444555555555555555555555666ÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××ØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßààààààááááââââââãããããääääåååååæææææççççèèèèèééééêêêêëëëëììììííííîîîîïïïïððððññññòòòòóóóôôôôõõõõööö÷÷÷÷øøøøùùùúúúúûûûüüüüýýýþþþþÿÿÿ  !!!!!!""""""######$$$$$$$%%%%%%&&&&&&&'''''''(((((((())))))))********+++++++++,,,,,,,,,----------...........////////////00000000000011111111111111122222222222222223333333333333333344444444444444444555555555555555555555555666ÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ×××××××ØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞßßßßßßàààààáááááâââââãããããäääääåååååææææçççççèèèèééééêêêêëëëëëììììííííîîîîïïïððððññññòòòòóóóóôôôõõõõöööö÷÷÷øøøøùùùúúúúûûûüüüüýýýþþþþÿÿÿ  !!!!!""""""#######$$$$$%%%%%%%&&&&&&&&'''''''((((((()))))))*********++++++++++,,,,,,,,,----------...........////////////00000000000011111111111111122222222222222233333333333333344444444444444444444555555555555555555555666666ÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ×××××××××ØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßàààààááááááâââââãããããääääåååååæææææççççèèèèéééééêêêêëëëëììììííííîîîîïïïïððððñññòòòòóóóóôôôõõõõöööö÷÷÷øøøøùùùúúúúûûûüüüüýýýþþþþÿÿÿ  !!!!!!""""""#####$$$$$$$%%%%%%%&&&&&&'''''''((((((((()))))))********+++++++++,,,,,,,,,-----------...........////////////000000000000111111111111122222222222222233333333333333333344444444444444444445555555555555555555566666666ÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ×××××××ØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞßßßßßßàààààáááááâââââãããããäääääååååæææææççççèèèèèééééêêêêëëëëììììííííîîîîïïïïððððññññòòòóóóóôôôôõõõöööö÷÷÷øøøøùùùùúúúûûûûüüüýýýýþþþÿÿÿ  !!!!!""""""######$$$$$$%%%%%%%&&&&&&&'''''''((((((())))))))*********+++++++++,,,,,,,,,----------..........////////////00000000000011111111111111222222222222222233333333333333333444444444444444445555555555555555555555566666666ÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ××××××××ØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞÞßßßßßààààààáááááâââââãããããäääääååååææææçççççèèèèééééêêêêëëëëëììììííííîîîïïïïððððññññòòòòóóóôôôôõõõöööö÷÷÷÷øøøùùùùúúúûûûûüüüýýýýþþþÿÿÿ  !!!!!!"""""######$$$$$$$%%%%%%&&&&&&&'''''''(((((((()))))))********+++++++++,,,,,,,,,,----------...........////////////00000000000011111111111111222222222222222333333333333333444444444444444444455555555555555555555556666666666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ×××××××ØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßßßàààààáááááââââââããããäääääåååååææææççççèèèèèééééêêêêëëëëììììííííîîîîïïïððððññññòòòòóóóôôôôõõõõööö÷÷÷÷øøøùùùùúúúûûûûüüüýýýýþþþÿÿÿ  !!!!!"""""#######$$$$$$%%%%%%&&&&&&&&''''''((((((()))))))))********+++++++++,,,,,,,,----------...........////////////0000000000001111111111111222222222222222333333333333333334444444444444444444455555555555555555556666666666666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ××××××××ØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞßßßßßààààààáááááâââââãããããääääåååååæææææççççèèèèééééêêêêëëëëììììííííîîîîïïïïððððñññòòòòóóóóôôôõõõõööö÷÷÷÷øøøùùùùúúúûûûûüüüýýýýþþþÿÿÿ  !!!!!""""""######$$$$$$%%%%%%%&&&&&&'''''''(((((((()))))))********++++++++++,,,,,,,,,----------..........////////////00000000000011111111111111222222222222222333333333333333334444444444444444455555555555555555555566666666666666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ××××××ØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞÞßßßßßàààààááááááââââãããããäääääååååæææææççççèèèèééééêêêêêëëëëìììííííîîîîïïïïððððñññòòòòóóóóôôôõõõõööö÷÷÷÷øøøùùùùúúúûûûûüüüýýýýþþþÿÿÿ  !!!!!!"""""#######$$$$$%%%%%%%&&&&&&&'''''''(((((()))))))))********++++++++,,,,,,,,,-----------...........///////////000000000000011111111111112222222222222223333333333333334444444444444444445555555555555555555555566666666666666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ×××××××ØØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßàààààáááááâââââãããããääääåååååææææççççèèèèèééééêêêêëëëëììììííííîîîïïïïððððññññòòòóóóóôôôõõõõöööö÷÷÷øøøøùùùúúúûûûûüüüýýýýþþþÿÿÿ  !!!!!!""""""#####$$$$$$$%%%%%%&&&&&&''''''''((((((())))))))********+++++++++,,,,,,,,,---------...........///////////00000000000011111111111112222222222222223333333333333333344444444444444444445555555555555555555566666666666666666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ×××××××ØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞÞßßßßßàààààááááááââââãããããäääääååååæææææççççèèèèééééêêêêëëëëììììííííîîîîïïïððððññññòòòòóóóôôôôõõõöööö÷÷÷øøøøùùùúúúúûûûüüüýýýýþþþÿÿÿ  !!!!!!"""""######$$$$$$%%%%%%&&&&&&&'''''''((((((()))))))))*******++++++++,,,,,,,,,,----------...........///////////00000000000011111111111112222222222222223333333333333333344444444444444444555555555555555555556666666666666666666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ××××××××ØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞßßßßßàààààáááááâââââããããäääääåååååææææççççèèèèééééêêêêêëëëëìììííííîîîîïïïïðððññññòòòòóóóôôôôõõõöööö÷÷÷øøøøùùùúúúúûûûüüüýýýýþþþÿÿÿ  !!!!!"""""""#####$$$$$$%%%%%%%&&&&&&'''''''(((((((()))))))********+++++++++,,,,,,,,,---------...........///////////0000000000000111111111111122222222222222233333333333333344444444444444444455555555555555555555556666666666666666666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ×××××××ØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßààààààáááááââââãããããääääåååååææææççççèèèèèééééêêêêëëëëììììíííîîîîîïïïððððñññòòòòóóóóôôôõõõõööö÷÷÷øøøøùùùúúúúûûûüüüýýýýþþþÿÿÿ  !!!!!!""""""######$$$$$$%%%%%%&&&&&&&''''''((((((()))))))))*******++++++++,,,,,,,,,,----------..........///////////00000000000111111111111122222222222222233333333333333333444444444444444444455555555555555555555666666666666666666666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ×××××××ØØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞßßßßßàààààáááááâââââããããäääääååååæææææççççèèèèééééêêêêëëëëììììííííîîîîïïïððððññññòòòóóóóôôôõõõõööö÷÷÷÷øøøùùùúúúúûûûüüüýýýýþþþÿÿÿ  !!!!!""""""######$$$$$$%%%%%%&&&&&&''''''''((((((()))))))*********++++++++,,,,,,,,----------...........////////////00000000000111111111111122222222222222233333333333333333444444444444444445555555555555555556666666666666666666666666ÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ×××××××ØØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞÞßßßßààààààáááááâââââããããäääääååååææææçççççèèèèééééêêêêëëëììììííííîîîîïïïððððññññòòòóóóóôôôõõõõööö÷÷÷÷øøøùùùùúúúûûûüüüüýýýþþþÿÿÿ  !!!!!!"""""######$$$$$$%%%%%%&&&&&&&'''''''((((((())))))))*******+++++++++,,,,,,,,,---------..........///////////00000000000001111111111111222222222222222333333333333333444444444444444445555555555555555555556666666666666666666666667ÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ×××××××ØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞßßßßßàààààáááááâââââãããããääääåååååææææççççèèèèééééêêêêëëëëììììííííîîîïïïïðððññññòòòòóóóôôôôõõõööö÷÷÷÷øøøùùùùúúúûûûüüüüýýýþþþÿÿÿ  !!!!!""""""######$$$$$%%%%%%%&&&&&&'''''''((((((()))))))*********++++++++,,,,,,,,-----------..........///////////00000000000111111111111122222222222222333333333333333344444444444444444445555555555555555555556666666666666666666677777ÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖÖ××××××××ØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞÞßßßßßàààààááááââââââããããäääääååååææææççççèèèèééééêêêêëëëëììììííííîîîîïïïððððñññòòòòóóóôôôôõõõöööö÷÷÷øøøùùùùúúúûûûüüüüýýýþþþÿÿÿ  !!!!!!"""""######$$$$$$%%%%%%&&&&&&&''''''(((((((()))))))*******++++++++++,,,,,,,,---------..........////////////000000000000111111111111122222222222222333333333333333344444444444444444455555555555555555566666666666666666666666677777ÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××ØØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßßàààààáááááâââââãããããääääååååææææçççççèèèèééééêêêêëëëììììííííîîîîïïïððððñññòòòòóóóóôôôõõõöööö÷÷÷øøøùùùùúúúûûûüüüüýýýþþþÿÿÿ  !!!!!"""""######$$$$$$%%%%%%&&&&&&''''''''(((((())))))))********++++++++,,,,,,,,,----------.........///////////00000000000011111111111112222222222222223333333333333334444444444444444455555555555555555555666666666666666666666666677777ÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ××××××××ØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞßßßßßàààààáááááââââãããããääääåååååææææççççèèèèééééêêêêëëëëììììíííîîîîïïïïðððññññòòòóóóóôôôõõõõööö÷÷÷øøøøùùùúúúûûûüüüüýýýþþþÿÿÿ  !!!!!""""""#####$$$$$$$%%%%%&&&&&&&''''''(((((((()))))))********+++++++++,,,,,,,,---------...........///////////00000000000111111111111222222222222223333333333333333444444444444444444555555555555555555555666666666666666666666677777777ÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××ØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞÞßßßßààààààááááâââââããããäääääååååæææææçççèèèèèééééêêêëëëëììììííííîîîïïïïððððñññòòòóóóóôôôõõõõööö÷÷÷øøøøùùùúúúûûûüüüüýýýþþþÿÿÿ  !!!!!!"""""######$$$$$%%%%%%%&&&&&&'''''''(((((())))))))********++++++++,,,,,,,,,,--------..........///////////0000000000000111111111111222222222222223333333333333333444444444444444444555555555555555555566666666666666666666677777777777ÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ×××××××ØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞßßßßßàààààáááááââââãããããääääåååååææææççççèèèèééééêêêêëëëëìììííííîîîîïïïððððñññòòòòóóóôôôõõõõööö÷÷÷øøøøùùùúúúûûûûüüüýýýþþþÿÿÿ  !!!!!""""""#####$$$$$$%%%%%%&&&&&&&''''''((((((()))))))********++++++++,,,,,,,,-----------.........///////////00000000000111111111111122222222222222233333333333333344444444444444444555555555555555555566666666666666666666666677777777777ÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××ØØØØØØØØÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞÞßßßßààààààááááâââââããããäääääååååææææççççèèèèééééêêêêëëëëììììíííîîîîïïïððððñññòòòòóóóôôôôõõõööö÷÷÷÷øøøùùùúúúûûûûüüüýýýþþþÿÿÿ  !!!!!!""""#######$$$$$%%%%%%%&&&&&''''''''(((((())))))))*******++++++++,,,,,,,,,---------..........////////////00000000000111111111111222222222222233333333333333334444444444444444455555555555555555555566666666666666666666666777777777777ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖ××××××××ØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÛÛÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞßßßßßàààààáááááâââââããããääääååååæææææççççèèèèééééêêêëëëëììììííííîîîïïïïðððññññòòòóóóôôôôõõõööö÷÷÷÷øøøùùùúúúûûûûüüüýýýþþþÿÿÿ  !!!!!"""""#####$$$$$$$%%%%%&&&&&&&''''''(((((((())))))*********+++++++,,,,,,,,,----------.........//////////00000000000001111111111111222222222222233333333333333334444444444444444455555555555555555555666666666666666666667777777777777777ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××ØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßßàààààáááááââââãããããääääååååææææççççèèèèééééêêêêëëëëìììííííîîîïïïïðððññññòòòóóóóôôôõõõöööö÷÷÷øøøùùùúúúúûûûüüüýýýþþþÿÿÿ  !!!!!"""""######$$$$$%%%%%%%&&&&&&'''''''(((((())))))))*******+++++++++,,,,,,,,---------...........//////////00000000001111111111111222222222222222333333333333333444444444444444445555555555555555556666666666666666666666677777777777777777ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖ××××××××ØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞßßßßààààààááááâââââããããääääååååæææææçççèèèèééééêêêêëëëëììììíííîîîîïïïððððñññòòòóóóóôôôõõõöööö÷÷÷øøøùùùúúúúûûûüüüýýýþþþÿÿÿ  !!!!!""""""#####$$$$$$%%%%%%&&&&&&&'''''(((((((())))))*********+++++++,,,,,,,,,---------.........////////////000000000001111111111112222222222222333333333333333444444444444444445555555555555555555566666666666666666666666677777777777777777ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××ØØØØØØØÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßßàààààáááááââââããããäääääååååææææççççèèèèééééêêêêëëëììììíííîîîîïïïððððñññòòòòóóóôôôõõõõööö÷÷÷øøøùùùùúúúûûûüüüýýýþþþÿÿÿ  !!!!!"""""######$$$$$%%%%%%%&&&&&'''''''(((((())))))))*******+++++++++,,,,,,,----------..........//////////00000000000011111111111112222222222222333333333333333444444444444444445555555555555555555566666666666666666666677777777777777777777ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ×××××××ØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞßßßßààààààááááâââââããããääääåååååæææççççèèèèééééêêêêëëëëìììííííîîîïïïïðððñññòòòòóóóôôôõõõõööö÷÷÷øøøùùùùúúúûûûüüüýýýþþþÿÿÿ  !!!!!""""""#####$$$$$$%%%%%&&&&&&&''''''((((((()))))))********+++++++,,,,,,,,,---------..........///////////00000000001111111111112222222222222223333333333333334444444444444444455555555555555555566666666666666666666677777777777777777777777ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ××××××ØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßßàààààáááááââââããããäääääååååææææççççèèèèééééêêêëëëëìììííííîîîïïïïðððññññòòòóóóôôôôõõõööö÷÷÷øøøøùùùúúúûûûüüüýýýþþþÿÿÿ  !!!!!"""""######$$$$$%%%%%%&&&&&&'''''''(((((()))))))********++++++++,,,,,,,,----------........///////////0000000000001111111111112222222222223333333333333334444444444444444455555555555555555556666666666666666666666677777777777777777777777ÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ×××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßßàààààááááââââãããããääääååååææææççççèèèèééééêêêêëëëììììíííîîîîïïïððððñññòòòóóóóôôôõõõööö÷÷÷øøøøùùùúúúûûûüüüýýýþþþÿÿÿ  !!!!!"""""######$$$$$$%%%%%&&&&&&''''''((((((()))))))********++++++++,,,,,,,,---------..........//////////00000000000111111111111122222222222223333333333333334444444444444444455555555555555555556666666666666666666666677777777777777777777778ÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ××××××ØØØØØØØÙÙÙÙÙÚÚÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞßßßßßàààààááááâââââããããäääääååååæææçççççèèèééééêêêêëëëììììííííîîîïïïððððñññòòòóóóóôôôõõõöööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿÿ  !!!!""""""#####$$$$$%%%%%%%&&&&&'''''''(((((()))))))********++++++++,,,,,,,,---------.........////////////00000000001111111111122222222222222233333333333333344444444444444444555555555555555555666666666666666666666777777777777777777777777788ÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖÖ×××××××ØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßßààààáááááââââãããããääääååååææææççççèèèèééééêêêëëëëìììííííîîîïïïïðððññññòòòóóóôôôõõõöööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿÿ  !!!!!"""""#####$$$$$$%%%%%&&&&&&&''''''((((((()))))))*******++++++++,,,,,,,,---------.........//////////00000000000001111111111122222222222223333333333333344444444444444444555555555555555555666666666666666666666677777777777777777777777777788ÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖ×××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßàààààááááâââââãããããäääåååååææææçççèèèèééééêêêêëëëììììíííîîîîïïïðððññññòòòóóóôôôõõõõööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿÿ  !!!!!"""""######$$$$$%%%%%%&&&&&&''''''((((((())))))*********++++++,,,,,,,,,,-------...........//////////00000000001111111111111222222222222223333333333333344444444444444445555555555555555556666666666666666666666677777777777777777777777778888ÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖÖ×××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÞÞÞÞÞßßßßßààààáááááâââââããããääääååååææææççççèèèèéééêêêêëëëììììíííîîîîïïïððððñññòòòóóóôôôôõõõööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿÿ  !!!!!""""######$$$$$$%%%%%&&&&&&''''''((((((()))))))*******++++++++,,,,,,,----------.........///////////000000000011111111111222222222222222333333333333333444444444444444445555555555555555556666666666666666666667777777777777777777777788888888ÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ××××××ØØØØØØØÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßàààààáááááââââããããäääääåååææææççççèèèèééééêêêëëëëìììííííîîîïïïððððñññòòòóóóóôôôõõõööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿÿ  !!!!!"""""#####$$$$$$%%%%%%&&&&&'''''''(((((()))))))********++++++,,,,,,,,,--------.........../////////00000000000011111111111222222222222233333333333333444444444444444445555555555555555556666666666666666666677777777777777777777777777888888888ÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞßßßßßàààààááááâââââããããääääååååææææçççèèèèééééêêêêëëëììììíííîîîïïïïðððñññòòòóóóóôôôõõõööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿÿ  !!!!"""""######$$$$$%%%%%&&&&&&&''''''(((((())))))))******++++++++,,,,,,,,---------.........///////////00000000011111111111112222222222222233333333333334444444444444444555555555555555555666666666666666666666677777777777777777777777777888888888ÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖ×××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßßààààáááááââââããããääääååååææææççççèèèèéééêêêêëëëììììíííîîîîïïïðððññññòòòóóóôôôõõõööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿÿ  !!!!!!"""""#####$$$$$%%%%%%&&&&&&''''''((((((())))))********+++++++,,,,,,,,---------.........//////////0000000000011111111111222222222222223333333333333334444444444444444555555555555555555666666666666666666666677777777777777777777777888888888888ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÞÞÞÞßßßßßàààààááááâââââããããääääååååææææçççèèèèééééêêêëëëëìììííííîîîïïïððððñññòòòóóóôôôõõõööö÷÷÷øøøùùùùúúúûûûüüüýýýþþþÿÿ  !!!!!"""""#####$$$$$$%%%%%&&&&&&''''''(((((())))))))******++++++++,,,,,,,,--------..........//////////00000000000111111111111222222222222333333333333334444444444444444455555555555555555566666666666666666666677777777777777777777778888888888888888ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖ×××××××ØØØØØØÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÝÝÝÝÝÞÞÞÞÞÞßßßßààààáááááââââããããääääååååææææççççèèèèéééêêêêëëëììììíííîîîïïïððððñññòòòóóóôôôõõõöööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿ  !!!!!!"""""####$$$$$$%%%%%%&&&&&''''''((((((())))))********++++++++,,,,,,,---------........////////////00000000011111111111122222222222222333333333333344444444444444455555555555555555566666666666666666666777777777777777777777777778888888888888888ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ×××××ØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞßßßßàààààáááááâââãããããääääååååæææççççèèèèéééêêêêëëëëìììíííîîîïïïïðððñññòòòóóóôôôôõõõööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿ  !!!!""""""#####$$$$$%%%%%&&&&&&&''''''((((())))))))*******+++++++,,,,,,,,,-------........../////////00000000000011111111112222222222222233333333333333344444444444444455555555555555555566666666666666666666777777777777777777777777778888888888888888ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßàààààááááââââããããääääååååææææççççèèèééééêêêêëëëìììííííîîîïïïðððñññòòòóóóóôôôõõõööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿ  !!!!!"""""#####$$$$$%%%%%%&&&&&&''''''(((((()))))))******+++++++++,,,,,,,---------.........//////////00000000001111111111112222222222223333333333333344444444444444444555555555555555555666666666666666666666777777777777777777777778888888888888888888ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞßßßßàààààáááááââââãããäääääååååæææççççèèèèéééêêêêëëëììììíííîîîïïïðððññññòòòóóóôôôõõõööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿ  !!!!"""""######$$$$$%%%%%&&&&&&''''''(((((()))))))*******+++++++,,,,,,,,---------........///////////000000000011111111111222222222222223333333333333444444444444445555555555555555555666666666666666666667777777777777777777777788888888888888888888888ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ×××××××ØØØØØØÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßàààààááááââââããããääääååååææææçççèèèèéééêêêêëëëëìììíííîîîïïïððððñññòòòóóóôôôõõõööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿ  !!!!!"""""#####$$$$$%%%%%%&&&&&''''''((((((())))))******+++++++++,,,,,,,--------........../////////00000000000111111111112222222222222333333333333333444444444444445555555555555555566666666666666666666777777777777777777777777788888888888888888888888ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖÖ×××××ØØØØØØÙÙÙÙÙÙÙÚÚÚÚÚÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßààààáááááââââããããäääååååææææççççèèèééééêêêëëëëìììíííîîîîïïïðððñññòòòóóóôôôõõõööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿ  !!!!!"""""######$$$$%%%%%&&&&&&'''''''((((()))))))*******+++++++,,,,,,,,---------........///////////00000000011111111111112222222222233333333333333444444444444444445555555555555555566666666666666666666777777777777777777777777788888888888888888888888ÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖÖ×××××××ØØØØØÙÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÝÝÝÝÞÞÞÞÞßßßßàààààááááââââããããääääååååææææçççèèèèéééêêêêëëëìììííííîîîïïïðððñññòòòòóóôôôôõõööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿ  !!!!!""""#####$$$$$$%%%%%&&&&&&'''''((((((()))))))******+++++++,,,,,,,,,-------........../////////0000000000111111111112222222222222233333333333344444444444444445555555555555555556666666666666666666677777777777777777777777888888888888888888888888889ÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßààààááááâââââããããääääåååææææççççèèèééééêêêëëëììììíííîîîïïïðððññññòòòóóóôôôõõõööö÷÷øøøùùùúúúûûûüüüýýýþþþÿÿ  !!!!!"""""#####$$$$$%%%%%&&&&&&''''''(((((())))))*******++++++++,,,,,,,---------........//////////00000000001111111111122222222222223333333333333344444444444444555555555555555556666666666666666666677777777777777777777777888888888888888888888888888889ÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÞÞÞÞßßßßàààààááááââââããããääääååååææææçççèèèééééêêêëëëëìììíííîîîîïïððððñññòòòóóóôôôõõõööö÷÷÷øøùùùúúúûûûüüüýýýþþþÿÿ  !!!!"""""#####$$$$$%%%%%%&&&&&''''''(((((()))))))******+++++++,,,,,,,,,-------.........//////////000000000111111111111122222222222333333333333334444444444444444555555555555555556666666666666666666777777777777777777777777888888888888888888888888888889ÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖ×××××ØØØØØØØÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßàààààáááââââãããããääääåååææææçççèèèèéééêêêêëëëìììííííîîîïïïðððñññòòòóóóôôôõõõööö÷÷÷øøøùùùúúûûûüüüýýýþþþÿÿ  !!!!!"""""#####$$$$%%%%%%&&&&&'''''''((((())))))*******++++++++,,,,,,,--------..........////////00000000000111111111122222222222222333333333333444444444444444455555555555555555566666666666666666666777777777777777777777777888888888888888888888888889999ÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖÖ××××××ØØØØØÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÞÞÞÞßßßßàààààááááââââããããääääåååææææççççèèèééééêêêëëëììììíííîîîïïïðððñññòòòóóóôôôõõõööö÷÷÷øøøùùùúúûûûüüüýýýþþþÿÿ  !!!!"""""#####$$$$$%%%%%%&&&&&'''''(((((()))))))*******++++++,,,,,,,,---------.......///////////00000000011111111111122222222222233333333333333444444444444445555555555555555566666666666666666666777777777777777777777778888888888888888888888888899999999ÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßàààààááááââââãããääääååååææææçççèèèèéééêêêëëëëìììíííîîîïïïðððñññòòòòóóôôôõõõööö÷÷÷øøøùùùúúúûûüüüýýýþþþÿÿ  !!!!!"""""####$$$$$%%%%%&&&&&&''''''(((((())))))******++++++++,,,,,,,,-------........./////////0000000000111111111111222222222223333333333333344444444444444445555555555555556666666666666666666777777777777777777777778888888888888888888888888888999999999ÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖ×××××××ØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÝÝÝÝÞÞÞÞÞßßßßààààááááââââããããääääååååæææçççèèèèééééêêêëëëìììíííîîîîïïïðððñññòòòóóóôôôõõööö÷÷÷øøøùùùúúúûûüüüýýýþþþÿÿ  !!!!!""""#####$$$$$$%%%%%&&&&&'''''(((((()))))))*******+++++++,,,,,,,---------......../////////00000000000111111111222222222222223333333333334444444444444444555555555555555556666666666666666666777777777777777777777778888888888888888888888888888999999999ÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÜÜÜÜÜÝÝÝÝÞÞÞÞÞßßßßàààààááááââââããããäääååååæææççççèèèèéééêêêëëëììììíííîîîïïïðððñññòòòóóóôôôõõõöö÷÷÷øøøùùùúúúûûüüüýýýþþþÿÿ  !!!!!""""#####$$$$%%%%%%&&&&&''''''(((((())))))******++++++++,,,,,,,,-------........///////////00000000011111111111222222222222333333333333334444444444444555555555555555555666666666666666666667777777777777777777777788888888888888888888888888999999999999ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÞÞÞÞßßßßààààááááââââããããääääåååææææççççèèèéééêêêëëëëìììíííîîîïïïðððñññòòòóóóôôôõõõööö÷÷øøøùùùúúúûûüüüýýýþþþÿÿ  !!!!"""""#####$$$$$%%%%%%&&&&&'''''(((((())))))*******+++++++,,,,,,,--------........./////////0000000000111111111112222222222233333333333333444444444444444555555555555555666666666666666666667777777777777777777777888888888888888888888888889999999999999999ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÝÝÝÝÝÞÞÞÞßßßßàààààááááââââããããäääååååæææççççèèèééééêêêëëëìììíííîîîïïïððððññòòòóóóôôôõõõööö÷÷øøøùùùúúúûûûüüýýýþþþÿÿ  !!!!"""""####$$$$$%%%%%&&&&&&''''''(((((())))))******+++++++,,,,,,,---------.......//////////00000000001111111112222222222222233333333333444444444444444445555555555555555666666666666666666777777777777777777777788888888888888888888888888899999999999999999ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÞÞÞÞßßßßàààààááááâââããããäääååååææææçççèèèèéééêêêëëëìììííííîîîïïïðððñññòòòóóôôôõõõööö÷÷÷øøùùùúúúûûûüüýýýþþþÿÿ  !!!!"""""#####$$$$$%%%%%&&&&&'''''(((((())))))*******++++++++,,,,,,-------........../////////000000000111111111112222222222223333333333333444444444444455555555555555555556666666666666666666777777777777777777777788888888888888888888888888899999999999999999ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÝÝÝÝÞÞÞÞÞßßßßààààááááââââãããääääååååæææççççèèèéééêêêëëëëìììíííîîîïïïðððñññòòòóóôôôõõõööö÷÷÷øøùùùúúúûûûüüýýýþþþÿÿ  !!!!!""""#####$$$$%%%%%%&&&&&''''''(((((())))))******++++++,,,,,,,,--------.........////////00000000001111111111122222222222333333333333334444444444444455555555555555566666666666666666666677777777777777777777777888888888888888888888888889999999999999999999ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖ×××××ØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÞÞÞÞßßßßàààààááááâââããããääääåååææææçççèèèééééêêêëëëìììíííîîîïïïðððñññòòòóóóôôôõõööö÷÷÷øøøùùúúúûûûüüýýýþþþÿÿ  !!!!"""""#####$$$$%%%%%%&&&&&'''''((((())))))*******+++++++,,,,,,,,-------........//////////00000000011111111112222222222222333333333334444444444444444455555555555555566666666666666666777777777777777777777778888888888888888888888888899999999999999999999999ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØÙÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÝÝÝÝÝÞÞÞÞßßßßààààááááââââãããääääååååæææçççèèèèéééêêêëëëëììíííîîîïïïðððñññòòòóóóôôôõõööö÷÷÷øøøùùúúúûûûüüýýýþþþÿÿ  !!!!"""""####$$$$$%%%%%&&&&&&'''''(((((())))))*******++++++,,,,,,,--------.........////////0000000001111111111112222222222233333333333334444444444444555555555555555555566666666666666666777777777777777777777888888888888888888888888889999999999999999999999999ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÝÝÝÝÝÞÞÞÞßßßßàààààáááââââããããääääåååææææçççèèèéééêêêëëëëìììíííîîîïïïðððññòòòóóóôôôõõõöö÷÷÷øøøùùùúúûûûüüüýýþþþÿÿ  !!!!"""""####$$$$$%%%%%&&&&&'''''(((((())))))******+++++++,,,,,,,,--------......./////////00000000001111111111222222222223333333333333344444444444445555555555555555666666666666666666666777777777777777777777888888888888888888888888889999999999999999999999999ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖÖ×××××ØØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÝÝÝÝÞÞÞÞßßßßààààááááââââããããäääååååæææçççèèèééééêêêëëëìììíííîîîïïïðððñññòòòóóôôôõõõööö÷÷øøøùùùúúûûûüüüýýþþþÿÿ  !!!!""""#####$$$$$%%%%%&&&&&''''''((((()))))))******+++++++,,,,,,-------.........//////////00000000111111111122222222222223333333333344444444444444445555555555555566666666666666666667777777777777777777777788888888888888888888888888999999999999999999999999999ÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ×××××ØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÝÝÝÝÞÞÞÞßßßßààààááááââââããããäääååååæææççççèèèéééêêêëëëììììííîîîïïïðððñññòòòóóôôôõõõööö÷÷øøøùùùúúûûûüüüýýþþþÿÿ  !!!!""""#####$$$$$%%%%%&&&&&'''''((((())))))******+++++++,,,,,,,--------.........///////0000000000111111111112222222222233333333333334444444444444555555555555555556666666666666666677777777777777777777788888888888888888888888888999999999999999999999999999999:ÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÜÜÜÜÜÝÝÝÝÞÞÞÞßßßßààààááááââââããããäääååååæææçççèèèèéééêêêëëëìììíííîîîïïðððñññòòòóóóôôõõõööö÷÷øøøùùùúúûûûüüüýýþþþÿÿ  !!!!""""#####$$$$%%%%%&&&&&''''''(((((())))))******+++++++,,,,,,,-------.......//////////000000000011111111122222222222333333333333334444444444445555555555555555556666666666666666667777777777777777777788888888888888888888888899999999999999999999999999999999::ÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞÞßßßßààààáááââââããããäääååååæææçççèèèèéééêêêëëëìììíííîîîïïïðððññòòòóóóôôôõõööö÷÷÷øøùùùúúúûûüüüýýþþþÿÿ  !!!!!""""####$$$$$%%%%%&&&&&'''''(((((())))))*****+++++++,,,,,,,--------......../////////0000000011111111111222222222222333333333334444444444444445555555555555566666666666666666666677777777777777777777788888888888888888888888899999999999999999999999999999999::ÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞßßßßààààááááââââãããääääåååææææçççèèèéééêêêëëëìììíííîîîïïïðððñññòòóóóôôôõõööö÷÷÷øøùùùúúúûûüüüýýþþþÿÿ  !!!!""""####$$$$$%%%%%&&&&&'''''(((((())))))******+++++++,,,,,,,-------........////////0000000000111111111112222222222333333333333444444444444445555555555555555666666666666666667777777777777777777777788888888888888888888888888999999999999999999999999999999::::ÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ×××××ØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÝÝÝÝÞÞÞÞßßßßààààááááââââãããääääåååæææçççèèèèéééêêêëëëìììíííîîïïïðððñññòòòóóôôôõõõöö÷÷÷øøøùùúúúûûüüüýýþþþÿÿ  !!!!""""#####$$$$$%%%%%&&&&&'''''((((())))))******++++++,,,,,,,-------........//////////000000000111111111222222222223333333333333344444444444555555555555555555566666666666666667777777777777777777788888888888888888888888888999999999999999999999999999999::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ×××××ØØØØØØÙÙÙÙÙÚÚÚÚÛÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞÞßßßààààááááââââãããääääåååæææççççèèèéééêêêëëëìììíííîîîïïðððñññòòòóóóôôõõõöö÷÷÷øøøùùúúúûûüüüýýþþþÿÿ  !!!!!""""####$$$$$%%%%&&&&&''''''((((())))))******+++++++,,,,,,,-------........////////00000000111111111112222222222223333333333344444444444444555555555555555666666666666666666667777777777777777777888888888888888888888889999999999999999999999999999999:::::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞÞßßßààààááááâââããããäääååååæææçççèèèéééêêêëëëìììíííîîîïïïðððññòòòóóóôôõõõööö÷÷øøøùùúúúûûüüüýýþþþÿÿ  !!!!!""""####$$$$$%%%%%&&&&&'''''(((((())))))******++++++,,,,,,-------......../////////000000000111111111112222222222333333333333444444444444444555555555555566666666666666666667777777777777777777777888888888888888888888889999999999999999999999999999999:::::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ×××××ØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÝÞÞÞÞßßßààààááááââââãããääääåååææææçççèèèéééêêêëëëìììíííîîïïïðððññòòòóóóôôõõõööö÷÷øøøùùúúúûûüüüýýþþþÿÿ  !!!!"""""####$$$$%%%%%&&&&&'''''((((())))))******++++++,,,,,,,--------......../////////000000001111111112222222222233333333333333444444444445555555555555555566666666666666667777777777777777777777888888888888888888888888889999999999999999999999999999999:::::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ×××××ØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÜÝÝÝÝÞÞÞÞßßßààààááááâââããããäääåååææææçççèèèéééêêêëëëìììíííîîîïïðððñññòòóóóôôôõõööö÷÷øøøùùúúúûûüüüýýþþþÿÿ  !!!!""""#####$$$$$%%%%%&&&&&'''''((((())))))******++++++,,,,,,,-------.......////////0000000001111111111122222222222333333333334444444444444455555555555555566666666666666666677777777777777777788888888888888888888888888999999999999999999999999999999::::::::::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ×××××ØØØØØÙÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÜÜÝÝÝÝÞÞÞÞßßßßààààááááâââãããääääåååæææçççèèèéééêêêëëëìììíííîîîïïðððñññòòòóóôôôõõööö÷÷øøøùùùúúûûûüüýýýþþÿÿ  !!!!""""#####$$$$%%%%&&&&&'''''((((())))))******++++++,,,,,,,-------......../////////000000000111111111122222222223333333333334444444444444445555555555556666666666666666666677777777777777777778888888888888888888888999999999999999999999999999999::::::::::::::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ×××××ØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞßßßààààááááâââããããäääååååæææçççèèèéééêêêëëëìììííîîîïïïðððññòòòóóôôôõõõöö÷÷÷øøùùùúúûûûüüýýýþþÿÿ  !!!!""""####$$$$$%%%%%&&&&&'''''((((())))))******++++++,,,,,,,-------........////////000000001111111112222222222233333333333333444444444445555555555555555666666666666666667777777777777777777777888888888888888888888899999999999999999999999999999:::::::::::::::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖ×××××ØØØØØÙÙÙÙÙÚÚÚÚÛÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞßßßßààààááááâââãããääääåååæææçççèèèéééêêêëëëìììíííîîïïïðððññòòòóóóôôõõõöö÷÷÷øøùùùúúûûûüüýýýþþÿÿ  !!!!""""####$$$$$%%%%&&&&&'''''((((()))))******+++++++,,,,,,-------......./////////00000000011111111112222222222233333333333444444444444455555555555555556666666666666667777777777777777777777888888888888888888888888899999999999999999999999999999:::::::::::::::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖ×××××ØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞßßßààààááááââââãããäääåååæææçççèèèéééêêêëëëìììíííîîîïïðððñññòòóóóôôõõõöö÷÷÷øøùùùúúûûûüüýýýþþÿÿ  !!!!""""####$$$$$%%%%%&&&&&'''''((((()))))******++++++,,,,,,--------......./////////000000000111111111222222222233333333333444444444444444555555555555566666666666666666677777777777777777788888888888888888888888888999999999999999999999999999999:::::::::::::::::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ×××××ØØØØØÙÙÙÙÚÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞÞßßßààààáááââââãããäääååååæææçççèèèéééêêêëëëììíííîîîïïðððñññòòóóóôôôõõööö÷÷øøøùùúúûûûüüýýýþþÿÿ  !!!!!""""####$$$$%%%%%&&&&'''''((((())))))******++++++,,,,,,,-------.......////////000000001111111112222222222223333333333334444444444445555555555555556666666666666666667777777777777777777888888888888888888888999999999999999999999999999999::::::::::::::::::::::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖ×××××ØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞßßßààààááááââââãããäääåååæææçççèèèèééêêêëëëìììííîîîïïïððñññòòòóóôôôõõööö÷÷øøøùùúúûûûüüýýýþþÿÿ  !!!!""""####$$$$%%%%%&&&&&'''''((((()))))******++++++,,,,,,-------......./////////0000000011111111112222222222223333333333444444444444555555555555555556666666666666677777777777777777777777888888888888888888888999999999999999999999999999:::::::::::::::::::::::::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖ××××××ØØØØÙÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÜÜÝÝÝÝÞÞÞÞßßßààààáááââââãããääääåååæææçççèèèéééêêêëëìììíííîîîïïðððññòòòóóôôôõõööö÷÷øøøùùúúúûûüüýýýþþÿÿ  !!!!""""#####$$$$%%%%&&&&&''''(((((()))))******+++++++,,,,,,-------......./////////0000000011111111122222222223333333333344444444444444555555555555556666666666666666777777777777777777778888888888888888888888888999999999999999999999999999:::::::::::::::::::::::::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖ×××××ØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÛÜÜÜÝÝÝÝÞÞÞÞßßßßààààáááâââããããäääåååæææçççèèèéééêêêëëìììíííîîîïïðððñññòòóóóôôõõõöö÷÷øøøùùúúúûûüüýýýþþÿÿ  !!!!"""####$$$$$%%%%%&&&&&''''((((()))))******++++++,,,,,,-------.......////////0000000011111111112222222222233333333333344444444444455555555555556666666666666666666777777777777777778888888888888888888888888999999999999999999999999999999:::::::::::::::::::::::::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ×××××ØØØØØÙÙÙÙÚÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞßßßààààáááââââãããäääåååæææççççèèèééêêêëëëìììííîîîïïïððñññòòóóóôôõõõöö÷÷øøøùùúúúûûüüýýýþþÿÿ  !!!!""""####$$$$%%%%%&&&&'''''((((())))))******++++++,,,,,,------........////////000000001111111111222222222223333333333444444444445555555555555555666666666666666677777777777777777777888888888888888888888999999999999999999999999999999:::::::::::::::::::::::::::::::::::ÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖ××××ØØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÞÞÞÞßßßßààààáááâââããããäääåååæææçççèèèéééêêêëëìììíííîîïïïððñññòòóóóôôõõõöö÷÷÷øøùùúúúûûüüýýýþþÿÿ  !!!!"""####$$$$%%%%%&&&&&'''''(((()))))******++++++,,,,,,,-------.......////////00000000111111111222222222233333333333444444444444455555555555555566666666666666777777777777777777777778888888888888888888899999999999999999999999999::::::::::::::::::::::::::::::::::::;;;;ÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖ××××××ØØØØØÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÜÜÝÝÝÝÞÞÞßßßààààááááâââãããäääåååææææççèèèéééêêêëëëììíííîîîïïðððññòòòóóôôôõõöö÷÷÷øøùùùúúûûüüüýýþþÿÿ  !!!""""#####$$$$%%%%&&&&'''''(((((()))))******+++++,,,,,,-------.......////////0000000011111111122222222222333333333333444444444444555555555555566666666666666666777777777777777777788888888888888888888888899999999999999999999999999:::::::::::::::::::::::::::::::::::;;;;;ÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖ×××××ØØØØØÙÙÙÙÚÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞßßßààààáááâââããããäääåååæææçççèèèéééêêëëëììíííîîîïïðððññòòòóóôôôõõööö÷÷øøùùùúúûûüüüýýþþÿÿ  !!!!""""####$$$$%%%%%&&&&'''''((((())))******+++++++,,,,,,-------.......////////0000000011111111122222222222333333333344444444444555555555555555666666666666666666777777777777777788888888888888888888888889999999999999999999999999999:::::::::::::::::::::::::::::::::::;;;;;ÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖ×××××ØØØØØÙÙÙÙÚÚÚÚÛÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞßßßßààààáááâââãããäääåååæææçççèèèéééêêêëëìììííîîîïïïððñññòòóóóôôõõööö÷÷øøùùùúúûûüüüýýþþÿÿ  !!!""""####$$$$$%%%%&&&&'''''((((()))))******+++++,,,,,,-------.......////////0000000011111111122222222223333333333444444444444455555555555555556666666666666677777777777777777777888888888888888888888999999999999999999999999999999::::::::::::::::::::::::::::::::::::;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖ×××××ØØØØÙÙÙÙÙÚÚÚÚÚÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞßßßààààáááââââãããäääåååæææçççèèéééêêêëëëììíííîîïïïððñññòòóóóôôõõõöö÷÷øøøùùúúûûüüüýýþþÿÿ  !!!!""""####$$$%%%%%&&&&&''''((((()))))******++++++,,,,,,------.......////////000000001111111112222222222333333333334444444444444555555555555566666666666666677777777777777777777788888888888888888888999999999999999999999999999::::::::::::::::::::::::::::::::::::;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÕÕÕÕÕÖÖÖÖÖ××××××ØØØØØÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞßßßßààààáááâââãããäääåååæææçççèèèéééêêëëëìììííîîîïïðððññòòóóóôôõõõöö÷÷øøøùùúúûûüüüýýþþÿÿ  !!!""""####$$$$%%%%&&&&'''''(((((()))))*****+++++,,,,,,-------........////////000000001111111112222222222333333333344444444444555555555555566666666666666666677777777777777777888888888888888888888888999999999999999999999999::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖ××××ØØØØØÙÙÙÙÚÚÚÚÚÛÛÛÛÜÜÜÝÝÝÝÝÞÞÞßßßààààááááâââããääääåååæææççèèèéééêêêëëìììííîîîïïðððññòòòóóôôõõõöö÷÷øøøùùúúûûüüüýýþþÿÿ  !!!"""""###$$$$%%%%%&&&&'''''(((()))))******++++++,,,,,,------......////////000000001111111112222222222333333333344444444444445555555555555566666666666666667777777777777777788888888888888888888888899999999999999999999999999:::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÕÕÕÕÕÖÖÖÖÖ×××××ØØØØØÙÙÙÙÚÚÚÚÛÛÛÛÛÜÜÜÜÝÝÝÞÞÞßßßßààààáááâââãããäääåååæææçççèèèééêêêëëëììíííîîïïïððñññòòóóôôôõõöö÷÷øøøùùúúûûûüüýýþþÿÿ  !!!"""####$$$$$%%%%&&&&'''''((((()))))*****+++++,,,,,,,-------......////////000000011111111122222222223333333333344444444444445555555555555666666666666667777777777777777777788888888888888888888999999999999999999999999999999:::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÓÓÓÓÓÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××ØØØØÙÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞßßßààààáááâââããããäääåååææçççèèèéééêêëëëìììííîîïïïððñññòòóóôôôõõöö÷÷÷øøùùúúûûûüüýýþþÿÿ  !!!""""####$$$$%%%%&&&&&''''(((())))))******+++++,,,,,------........////////000000001111111112222222222333333333344444444444555555555555666666666666666667777777777777777777788888888888888888889999999999999999999999999999::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÖÖÖÖÖ×××××ØØØØØÙÙÙÙÚÚÚÛÛÛÛÛÜÜÜÜÝÝÝÞÞÞÞßßßààààáááâââãããäääåååæææççèèèéééêêêëëìììííîîîïïðððññòòóóóôôõõööö÷÷øøùùúúûûûüüýýþþÿÿ  !!!!"""####$$$$$%%%&&&&'''''((((()))))*****++++++,,,,,,------.......///////000000011111111122222222223333333333444444444444555555555555556666666666666666677777777777777778888888888888888888888899999999999999999999999::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖ×××××ØØØØÙÙÙÙÚÚÚÚÚÛÛÛÜÜÜÜÝÝÝÝÞÞÞßßßßàààáááâââããããäääååæææçççèèèééêêêëëëììíííîîïïðððññòòòóóôôõõööö÷÷øøùùúúúûûüüýýþþÿÿ  !!!""""####$$$%%%%%&&&&''''((((()))))*****++++++,,,,,-------.......////////00000001111111112222222223333333333344444444444455555555555555666666666666667777777777777777788888888888888888888888899999999999999999999999::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÖÖÖÖÖ××××ØØØØØÙÙÙÙÚÚÚÚÛÛÛÛÛÜÜÜÝÝÝÞÞÞÞßßßàààááááâââãããäääåååæææçççèèéééêêëëëììíííîîïïïððññòòòóóôôõõõöö÷÷øøùùúúúûûüüýýþþÿÿ  !!!!"""###$$$$$%%%%&&&&'''''(((()))))*****++++++,,,,,,------......////////0000000011111111122222222223333333333444444444445555555555555666666666666667777777777777777777788888888888888888888999999999999999999999999999:::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÓÓÔÔÔÔÔÕÕÕÕÖÖÖÖÖÖ××××ØØØØÙÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÞÞÞßßßßàààáááââââãããääååååææçççèèèééêêêëëìììííîîîïïððñññòòóóôôõõõöö÷÷øøùùùúúûûüüýýþþÿÿ  !!!"""####$$$$%%%%&&&&&''''(((())))))****+++++,,,,,,,-------......///////000000011111111222222222233333333334444444444455555555555555666666666666666677777777777777777788888888888888888899999999999999999999999999999:::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖ×××××ØØØØØÙÙÙÙÚÚÚÛÛÛÛÛÜÜÜÝÝÝÝÞÞÞÞßßààààáááâââãããäääåååæææççèèèéééêêëëìììíííîîïïðððññòòóóôôôõõöö÷÷øøøùùúúûûüüýýþþÿÿ  !!!!""""###$$$$$%%%&&&&'''''((((())))******+++++,,,,,,-----.......////////000000001111111122222222233333333334444444444445555555555555566666666666666677777777777777788888888888888888888889999999999999999999999999::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÖÖÖÖÖ×××××ØØØØÙÙÙÙÚÚÚÚÚÛÛÛÜÜÜÜÝÝÝÞÞÞÞßßßàààáááââââããääääååæææçççèèéééêêêëëììíííîîïïðððññòòóóóôôõõöö÷÷øøøùùúúûûüüýýþþÿÿ  !!!!"""####$$$%%%%%&&&&''''((((()))))****++++++,,,,,,------......///////00000000111111111222222222233333333334444444444455555555555556666666666666777777777777777777888888888888888888888889999999999999999999999::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÏÏÏÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖ××××ØØØØØÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÝÝÝÝÞÞÞÞßßààààáááâââãããäääåååææçççèèèééêêêëëìììííîîïïïððññòòòóóôôõõöö÷÷øøøùùúúûûüüýýþþÿÿ  !!!!""""###$$$$%%%%&&&&'''''(((())))******+++++,,,,,-------.......///////00000001111111222222222233333333334444444444455555555555566666666666666667777777777777777777888888888888888888899999999999999999999999999:::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÖÖÖÖÖ×××××ØØØÙÙÙÙÙÚÚÚÚÛÛÛÜÜÜÜÜÝÝÝÞÞÞßßßàààááááâââããäääåååæææççèèèéééêêëëìììííîîîïïððñññòòóóôôõõööö÷÷øøùùúúûûüüýýþþÿÿ  !!!"""#####$$$%%%%&&&&''''((((()))))****++++++,,,,,,------......///////0000000001111111222222222333333333344444444444555555555555566666666666666667777777777777777788888888888888888999999999999999999999999999999::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÓÔÔÔÔÔÕÕÕÕÕÖÖÖÖÖ××××ØØØØØÙÙÙÙÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞßßßàààáááâââãããäääåååææçççèèéééêêêëëììíííîîïïðððññòòóóôôõõõöö÷÷øøùùúúûûüüýýþþÿÿ  !!!""""####$$$$%%%&&&&'''''(((()))))*****+++++,,,,,-------......///////000000011111111122222222223333333333444444444445555555555555666666666666667777777777777778888888888888888888889999999999999999999999999:::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÓÓÓÓÓÔÔÔÔÔÔÔÕÕÕÕÖÖÖÖ×××××ØØØØÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÞÞÞÞßßààààáááââããããääåååæææççèèèééêêêëëìììííîîïïðððññòòóóôôõõõöö÷÷øøùùúúûûüüýýþþÿÿ  !!!!"""####$$$$%%%%&&&&''''((((())))****+++++++,,,,,-----.......////////00000011111111222222222333333333344444444444555555555555666666666666667777777777777777778888888888888888888888999999999999999999999::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÕÕÕÕÕÖÖÖÖÖ×××ØØØØØÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÝÝÝÝÞÞÞßßßàààáááâââãããäääååæææçççèèéééêêëëëììííîîîïïððññòòóóóôôõõöö÷÷øøùùúúûûüüýýþþÿÿ  !!!""""###$$$$%%%%&&&&'''''((()))))*****+++++,,,,,,------......//////0000000001111111122222222333333333344444444445555555555555666666666666666777777777777777777888888888888888888899999999999999999999999::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<ÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÖÖÖÖ×××××ØØØØÙÙÙÙÚÚÚÚÛÛÛÜÜÜÜÝÝÝÞÞÞÞßßààààáááâââããäääåååææçççèèèééêêêëëììíííîîïïððññòòòóóôôõõöö÷÷øøùùúúûûüüýýþþÿÿ  !!!!"""####$$$%%%%&&&&''''((((())))*****++++++,,,,-------.......//////0000001111111112222222222333333333344444444445555555555555666666666666666777777777777777888888888888888889999999999999999999999999999:::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÕÕÕÕÖÖÖÖÖ××××ØØØØØÙÙÙÚÚÚÚÛÛÛÛÜÜÜÝÝÝÝÞÞÞßßßàààááááââãããäääååæææççèèèééêêêëëììíííîîïïðððññòòóóôôõõöö÷÷øøùùúúûûüüýýþþÿÿ  !!!""""###$$$$%%%%&&&'''''((())))))****+++++,,,,,,-----......////////000000011111112222222223333333333444444444445555555555556666666666666677777777777777788888888888888888888899999999999999999999999999:::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÔÔÔÔÔÕÕÕÕÕÕÖÖÖ××××××ØØØÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÝÝÝÞÞÞÞßßßàààáááâââããäääåååææçççèèéééêêëëëììííîîïïðððññòòóóôôõõöö÷÷øøùùúúûûüüýýþþÿÿ  !!!!"""###$$$$%%%%&&&&'''((((())))******+++++,,,,-------......//////0000000011111111222222223333333334444444444555555555555666666666666667777777777777777778888888888888888888889999999999999999999999:::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÖÖÖÖÖ××××ØØØØÙÙÙÙÚÚÚÚÛÛÛÜÜÜÜÝÝÝÞÞÞßßßàààáááâââãããääåååæææççèèèééêêêëëììííîîîïïððññòòóóôôõõöö÷÷øøøùùúúûûüüýýþþÿ  !!!"""####$$$%%%%&&&&''''(((()))))****++++++,,,,,-----.......///////000000111111112222222222333333333444444444455555555555566666666666666777777777777777777888888888888888888999999999999999999999:::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÑÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÕÕÕÕÕÕÖÖÖ×××××ØØØØÙÙÙÙÚÚÚÛÛÛÛÜÜÜÝÝÝÝÞÞÞßßßàààáááâââããäääåååææççèèèééêêêëëìììííîîïïððññòòóóôôôõõöö÷÷øøùùúúûûüüýýþþÿ  !!!""""###$$$$%%%&&&&''''((((()))******++++,,,,,,------.....///////00000000111111122222222333333333344444444444555555555555566666666666667777777777777777888888888888888889999999999999999999999999::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÖÖÖÖÖ×××ØØØØØÙÙÙÚÚÚÚÛÛÛÛÜÜÜÝÝÝÞÞÞÞßßààààááâââãããäääååæææççèèèééêêëëëììííîîïïððññòòòóóôôõõöö÷÷øøùùúúûûüüýýþþÿ  !!!!"""###$$$$%%%%&&&'''''((()))))****++++++,,,,,-----.......//////000000011111111122222223333333334444444444555555555555666666666666667777777777777778888888888888888888899999999999999999999999999:::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÕÕÕÕÕÖÖÖÖ×××××ØØØÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÝÝÝÞÞÞßßßàààáááâââãããääåååææçççèèééêêêëëììííîîïïðððññòòóóôôõõöö÷÷øøùùúúûûüüýýþþÿ  !!!"""###$$$$%%%%&&&&'''((((())))*****++++,,,,,,-----......////////00000011111112222222222333333333444444444455555555555666666666666677777777777777777888888888888888888889999999999999999999999:::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÒÒÒÒÒÒÒÓÓÓÓÔÔÔÔÔÔÕÕÕÕÖÖÖÖ××××ØØØØÙÙÙÙÚÚÚÚÛÛÛÜÜÜÜÝÝÞÞÞÞßßààààááâââãããäääååæææççèèééêêêëëììííîîîïïððññòòóóôôõõöö÷÷øøùùúúûûüüýýþþÿ  !!!!""####$$$%%%%&&&&''''(((())))****++++++,,,,-------.....//////0000000001111112222222233333333334444444444455555555555566666666666667777777777777777788888888888888888899999999999999999999:::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÕÕÕÕÕÖÖÖÖ××××ØØØØÙÙÙÙÚÚÚÛÛÛÛÜÜÜÝÝÝÝÞÞßßßàààáááâââããäääååæææççèèèééêêëëìììííîîïïððññòòóóôôõõöö÷÷øøùùúúûûüüýýþþÿ  !!""""###$$$$%%%&&&&''''(((())))*****++++,,,,,,-----.......//////000000111111111222222233333333344444444445555555555556666666666666677777777777777788888888888888888999999999999999999999999::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÑÒÒÒÒÒÒÓÓÓÓÓÔÔÔÔÔÕÕÕÕÖÖÖÖÖ××××ØØØØÙÙÙÚÚÚÚÛÛÛÜÜÜÜÝÝÝÞÞÞßßßàààááâââãããääåååææçççèèééêêëëëììííîîïïððññòòòóôôôõöö÷÷øøùùúúûûüüýýþþÿ  !!!"""####$$$%%%%&&&''''(((()))))****+++++,,,,,------....////////0000001111111222222222233333333344444444455555555555666666666666777777777777777788888888888888888889999999999999999999999999:::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÓÓÓÓÓÔÔÔÔÔÕÕÕÕÖÖÖÖÖ××××ØØØÙÙÙÙÚÚÚÚÛÛÛÜÜÜÝÝÝÝÞÞßßßàààáááâââããäääååæææççèèéééêêëëììííîîîïïððññòòóóôôõõö÷÷øøùùúúûûüüýýþþÿ  !!""""###$$$%%%%&&&&'''(((()))))****+++++,,,,,-----......//////0000000011111112222222333333333344444444444555555555556666666666667777777777777777888888888888888888899999999999999999999999::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÓÓÓÓÓÔÔÔÔÔÕÕÕÕÖÖÖÖ××××ØØØØÙÙÙÙÚÚÚÚÛÛÜÜÜÜÝÝÝÞÞÞßßßàààáááââãããääåååææççèèèééêêëëìììííîîïïððññòòóóôôõõöö÷÷øùùúúûûüüýýþþÿ  !!!"""####$$%%%%&&&&''''(((())))****+++++,,,,,-----......///////00000111111111222222233333333444444444445555555555556666666666666677777777777777778888888888888888899999999999999999999:::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÒÒÒÒÒÒÓÓÓÓÓÔÔÔÔÔÕÕÕÕÖÖÖÖ××××ØØØØÙÙÙÙÚÚÚÛÛÛÛÜÜÝÝÝÝÞÞÞßßààààááâââããäääååææçççèèéééêêëëììííîîïïððññòòóóôôõõöö÷÷øøùúúûûüüýýþþÿ  !!!""""##$$$$%%%&&&&''''(((())))****+++++,,,,,------.....//////0000000111111222222222233333333444444444555555555556666666666666777777777777777788888888888888888999999999999999999999::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÎÎÎÎÎÎÎÏÏÏÏÏÏÏÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÓÓÓÓÓÓÔÔÔÔÕÕÕÕÕÖÖÖÖ××××ØØØØÙÙÙÚÚÚÚÛÛÛÜÜÜÝÝÝÞÞÞßßßàààáááââãããääååæææççèèèééêêëëììííîîïïððññòòóóôôõõöö÷÷øøùùúûûüüýýþþÿ  !!!"""###$$$%%%%&&&''''(((())))*****++++,,,,,,----......./////00000001111111222222233333333334444444444555555555566666666666677777777777777788888888888888888899999999999999999999999::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÒÒÒÒÒÒÒÓÓÓÔÔÔÔÔÔÕÕÕÖÖÖÖÖ××××ØØØØÙÙÙÚÚÚÛÛÛÛÜÜÜÝÝÝÞÞÞßßààààááâââããääåååææçççèèééêêëëìììííîîïïððññòòóôôõõöö÷÷øøùùúûûüüýýþþÿ  !!!"""###$$$$%%%&&&''''(((()))))***++++++,,,-------....////////00000111111112222222233333334444444444455555555555566666666666677777777777777788888888888888888899999999999999999999999:::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÓÓÓÓÓÔÔÔÔÕÕÕÕÕÖÖÖ×××××ØØØÙÙÙÙÚÚÚÚÛÛÜÜÜÜÝÝÝÞÞßßßàààáááââããäääåååææççèèéééêêëëììííîîïïððññòòóóôôõöö÷÷øøùùúúûüüýýþþÿ  !!"""####$$%%%%&&&&'''((((()))*****++++,,,,,-----....../////0000000011111222222222233333333444444445555555555556666666666666677777777777777788888888888888888899999999999999999999::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÎÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÓÓÓÓÓÔÔÔÔÔÕÕÕÖÖÖÖÖ×××ØØØØÙÙÙÙÚÚÚÛÛÛÜÜÜÝÝÝÞÞÞßßßàààááââãããäääååææççèèèééêêëëììííîîïïððññòòóóôôõõö÷÷øøùùúúûüüýýþþÿ  !!!"""###$$$%%%&&&&''''((()))))***+++++,,,,,-----......//////00000011111112222222333333333344444444455555555556666666666667777777777777778888888888888888899999999999999999999:::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÑÒÒÒÒÒÓÓÓÓÓÔÔÔÔÕÕÕÕÕÖÖÖ××××ØØØØÙÙÙÚÚÚÚÛÛÛÜÜÜÝÝÝÞÞßßßàààááâââãããääåååææççèèééêêëëëìíííîïïððññòòóóôôõõö÷÷øøùùúúûüüýýþþÿ  !!"""###$$$%%%%&&&''''(((()))*****++++,,,,,-----.....///////00000111111112222222233333334444444444455555555555666666666667777777777777788888888888888889999999999999999999999::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÓÓÓÓÓÔÔÔÔÕÕÕÕÖÖÖÖÖ×××ØØØØÙÙÙÚÚÚÛÛÛÛÜÜÜÝÝÞÞÞßßßààáááâââããäääååææççèèéééêêëëììííîîïïððññòóóôôõõöö÷øøùùúúûüüýýþþÿ  !!!""###$$$$%%%&&&''''((()))))****++++,,,,,-----....../////0000000111111222222222333333334444444455555555555566666666666667777777777777788888888888888889999999999999999999999::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<======ÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÒÒÒÒÒÒÓÓÓÓÔÔÔÔÔÕÕÕÕÖÖÖÖ××××ØØØÙÙÙÙÚÚÚÛÛÛÜÜÜÝÝÝÞÞÞßßàààáááââãããääååæææççèèééêêëëììííîîïïððññòòóôôõõöö÷÷øùùúúûûüýýþþÿ  !!!"""###$$$%%%&&&&'''(((())))****+++++,,,-------....///////000001111111122222233333333334444444455555555556666666666666777777777777777788888888888888888999999999999999999999::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<============ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÒÒÒÒÓÓÓÓÓÓÔÔÔÔÕÕÕÕÖÖÖÖÖ××ØØØØÙÙÙÙÚÚÛÛÛÛÜÜÜÝÝÞÞÞßßßàààááâââããääåååææççèèééêêëëëìííîîïïððññòòóôôõõöö÷÷øùùúúûûüýýþþÿ  !!!""###$$$$%%&&&&''''(()))))****++++,,,,,-----.....//////000000111111122222222333333344444444444555555555666666666667777777777777778888888888888888899999999999999999999::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=============ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÎÎÎÎÎÏÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÒÒÒÒÒÓÓÓÓÔÔÔÔÔÕÕÕÕÖÖÖÖ××××ØØØÙÙÙÚÚÚÚÛÛÛÜÜÝÝÝÞÞÞßßàààáááââãããääååææçççèèééêêëëììííîïïððññòòóóôôõöö÷÷øøùúúûûüýýþþÿ  !!!"""##$$$%%%%&&&'''(((())))****+++++,,,,-----.....//////0000000111112222222223333333444444444555555555555666666666667777777777777888888888888888999999999999999999999:::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=============ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÑÒÒÒÒÒÓÓÓÓÓÔÔÔÕÕÕÕÕÖÖÖÖ×××ØØØØÙÙÙÚÚÚÛÛÛÜÜÜÝÝÝÞÞÞßßàààááâââããääåååææççèèééêêëëììííîîïïðññòòóóôôõöö÷÷øøùúúûûüýýþþÿ  !!!"""###$$$%%%&&&''''((())))*****+++,,,,,-----.....///////0000111111112222223333333333444444445555555555666666666666677777777777777888888888888888999999999999999999999:::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=============ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊËËËËËËËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÏÏÏÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÓÓÓÓÔÔÔÔÔÕÕÕÖÖÖÖ××××ØØØÙÙÙÙÚÚÚÛÛÛÜÜÝÝÝÝÞÞÞßßààáááâââãäääååææççèèèééêëëììííîîïïððññòóóôôõõö÷÷øøùúúûûüýýþþÿ  !!!""""##$$$%%%&&&&'''(((())))***+++++,,,,----.......////0000000111111222222223333333444444444445555555566666666666677777777777777788888888888888888999999999999999999999:::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÒÒÒÒÒÓÓÓÓÔÔÔÔÕÕÕÕÕÖÖÖ×××ØØØØÙÙÙÙÚÚÛÛÛÜÜÜÜÝÝÞÞÞßßàààááâââããäääåæææççèèééêêëëììííîîïððññòòóôôõõö÷÷øøùùúûûüüýþþÿ  !!!""####$$$%%&&&&''''((()))*****++++,,,,-----....///////000000111111222222223333333444444444555555555556666666666777777777777788888888888888888899999999999999999999::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=======================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÓÓÓÓÓÔÔÔÔÔÕÕÕÖÖÖÖ××××ØØØÙÙÙÚÚÚÛÛÛÛÜÜÝÝÝÞÞÞßßààáááââãããääååææççèèééêêëëììííîîïððññòòóóôõõöö÷øøùùúûûüüýþþÿ  !!!"""##$$$$%%%&&&'''(((())))***+++++,,,,,---......//////00000111111112222233333333334444444555555555556666666666667777777777778888888888888899999999999999999999::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=============================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊËËËËËËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÏÏÏÏÏÏÏÐÐÐÐÐÑÑÑÑÑÒÒÒÒÒÒÓÓÓÔÔÔÔÕÕÕÕÕÖÖÖ×××ØØØØÙÙÙÚÚÚÛÛÛÜÜÜÝÝÝÞÞßßàààáááââããääåååæççèèèééêëëììííîîïïððñòòóóôõõöö÷øøùùúûûüüýþþÿ  !!"""###$$$%%%&&&''''((()))*****++++,,,------...../////000000011111222222223333333444444444455555555666666666666677777777777777888888888888889999999999999999999:::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==================================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊËËËËËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÒÒÒÒÒÓÓÓÓÓÔÔÔÕÕÕÕÖÖÖÖ×××רØÙÙÙÚÚÚÚÛÛÛÜÜÝÝÝÞÞÞßßàààááââãããääååææççèèééêêëëììíîîïïððññòóóôôõöö÷÷øùùúûûüüýþþÿ  !!!"""##$$$%%%%&&&''(((())))****+++,,,,,-----....///////000001111112222222233333334444444445555555555666666666777777777777777788888888888888889999999999999999999:::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==================================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÏÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÓÓÓÓÔÔÔÔÕÕÕÕÕÖÖ××××ØØØÙÙÙÙÚÚÛÛÛÜÜÜÝÝÝÞÞÞßßààáááââããääååæææçèèééêêëëììííîîïððññòóóôôõöö÷÷øùùúúûüüýþþÿ  !!!"""###$$$%%&&&&'''(((())*****++++,,,,----....../////000001111111122222333333333344444455555555555566666666667777777777778888888888888888899999999999999999999:::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==================================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊËËËËËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÒÒÒÒÒÓÓÓÓÓÔÔÔÕÕÕÕÖÖÖÖ×××ØØØÙÙÙÚÚÚÛÛÛÜÜÜÝÝÞÞÞßßàààááââããäääååææççèèééêêëììííîîïððññòòóôôõõö÷÷øùùúúûüüýþþÿ  !!!""###$$$%%%&&&'''((())))****+++,,,,,-----....//////000000111112222222233333334444444445555555566666666666666777777777778888888888888899999999999999999999::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==================================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊËËËËËËËËËËÌÌÌÌÌÌÍÍÍÍÍÍÍÎÎÎÎÎÎÎÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÒÒÒÓÓÓÓÓÔÔÔÔÕÕÕÕÖÖÖ×××ØØØØÙÙÙÚÚÚÛÛÜÜÜÝÝÝÞÞÞßßààáááââããääååææççèèééêêëëììíîîïïððñòòóóôõõö÷÷øøùúúûüüýþþÿ  !!!"""###$$%%%&&&''''((()))****++++,,,,,---.....//////000001111111222222233333344444444445555555566666666666677777777777777888888888888899999999999999999::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<========================================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊËËËËËËËÌÌÌÌÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÑÑÑÑÑÒÒÒÒÒÓÓÓÓÔÔÔÕÕÕÕÕÖÖÖ×××רØÙÙÙÚÚÚÚÛÛÛÜÜÝÝÝÞÞßßàààááââããäääååææççèééêêëëììííîïïððñòòóóôõõöö÷øøùúúûüüýþþÿ  !!"""##$$$%%%%&&&''(((()))*****+++,,,,-----.....////00000011111112222233333333344444445555555555566666666677777777777777888888888888888899999999999999999::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<===============================================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÒÒÒÒÓÓÓÓÓÔÔÔÔÕÕÕÕÖÖ××××ØØØØÙÙÙÚÚÛÛÛÜÜÜÝÝÞÞÞßßààááâââããääååææççèèééêêëììííîîïððññòóóôõõöö÷øøùúúûüüýþþÿ  !!!""###$$$%%&&&''''(((())****++++,,,,,----....//////00000111112222222233333334444444455555555556666666666677777777778888888888888888889999999999999999999::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=====================================================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊËËËËËËËËËËÌÌÌÌÌÌÍÍÍÍÍÍÍÎÎÎÎÎÎÎÏÏÏÏÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÓÓÓÓÔÔÔÕÕÕÕÖÖÖÖ×××ØØØÙÙÙÚÚÚÛÛÛÜÜÜÝÝÞÞßßàààááâââããäååææççèèééêêëëììíîîïððññòóóôôõöö÷øøùúúûüüýþþÿ  !!""###$$$%%%&&&'''((())))****+++,,,,----....../////00001111111222222233333344444444445555555666666666666677777777777888888888888899999999999999999999:::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<======================================================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊËËËËËËËÌÌÌÌÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÑÑÑÑÒÒÒÒÒÓÓÓÓÔÔÔÔÕÕÕÖÖÖ××××ØØØÙÙÙÚÚÚÛÛÜÜÜÝÝÞÞÞßßàààááââããääååææççèèéêêëëììíîîïïððñòòóôôõöö÷øøùúúûüüýþþÿ  !!!""###$$%%%&&&'''(((()))***++++,,,,-----..../////000000111111222223333333334444444555555555566666666677777777777777788888888888899999999999999999::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<======================================================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊËËËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÒÒÒÒÓÓÓÔÔÔÔÕÕÕÕÖÖÖÖ××רØÙÙÙÚÚÚÛÛÛÜÜÜÝÝÝÞÞßßààááââãããääååæççèèééêêëëìííîïïððñòòóôôõöö÷÷øùùúûûüýýþÿ  !!"""###$$$%%%&&&''((())))****++++,,,----.....//////00001111122222222333333344444445555555555566666666777777777777778888888888888889999999999999999:::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<======================================================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊËËËËËËËËËÌÌÌÌÌÌÍÍÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÏÐÐÐÐÑÑÑÑÑÒÒÒÒÒÓÓÓÓÔÔÔÔÕÕÕÖÖÖ×××ØØØØÙÙÙÚÚÛÛÛÜÜÝÝÝÞÞßßàààááââããääååææççèèéêêëëìííîîïððñòòóóôõõö÷÷øùùúûûüýýþÿ  !!"""##$$$%%&&&''''((()))***++++,,,,-----.....////0000011111122222223333334444444445555555666666666666777777777788888888888888888999999999999999999:::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==========================================================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊËËËËËËËÌÌÌÌÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÒÒÒÓÓÓÓÔÔÔÔÔÕÕÕÖÖÖÖ××ØØØÙÙÙÚÚÚÛÛÜÜÜÝÝÝÞÞßßààááââããääååææççèèéêêëëììíîîïððññòóóôõõö÷÷øùùúûûüýýþÿ  !!"""###$$%%%&&&'''(())))***+++++,,,,---....//////000000111112222233333333344444445555555566666666666777777777777888888888888899999999999999999999:::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<================================================================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊËËËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÐÐÐÐÐÑÑÑÑÑÒÒÒÒÓÓÓÓÔÔÔÕÕÕÖÖÖÖ×××ØØØÙÙÙÚÚÚÛÛÜÜÝÝÝÞÞßßàààááââããääååæççèèééêêëììííîïïðññòòóôôõöö÷øùùúûûüýýþÿ  !!"""##$$%%%&&&'''((())))***+++,,,,----...../////000011111122222223333333444444555555555556666666677777777777777788888888888999999999999999999::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=======================================================================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊËËËËËËËËËËÌÌÌÌÌÍÍÍÍÍÍÎÎÎÎÎÎÎÏÏÏÏÏÐÐÐÐÑÑÑÑÒÒÒÒÓÓÓÓÓÔÔÔÔÕÕÕÖÖÖ××רØÙÙÙÚÚÚÛÛÛÜÜÝÝÝÞÞßßàààáââããääååææççèèéêêëëìííîîïððñòòóôôõöö÷øøùúûûüýýþÿ  !!"""##$$$%%%&&&''((()))***++++,,,,,----....////0000011111112222223333344444444455555555666666666677777777777788888888888888899999999999999:::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==========================================================================ÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÒÒÒÒÓÓÓÔÔÔÔÕÕÕÖÖÖÖ×××ØØØÙÙÙÚÚÛÛÛÜÜÝÝÞÞßßàààááââããääååææçèèééêëëììíîîïððñòòóôôõöö÷øøùúûûüýýþÿ  !!""##$$$%%&&&'''((())))***++++,,,----....//////0000011111222223333333344444444555555566666666666677777777788888888888888888999999999999999:::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=====================================================================>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊËËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÍÍÎÎÎÎÎÏÏÏÏÏÐÐÐÐÑÑÑÑÒÒÒÒÒÓÓÓÓÔÔÔÔÕÕÕÖÖÖ××ØØØÙÙÙÚÚÛÛÛÜÜÜÝÝÞÞßßàààááââããäååææçèèééêêëììííîïïðññòóóôõöö÷øøùúúûüýýþÿ  !!""###$$$%%&&&'''(()))***++++,,,,-----....////000001111122222223333333444444555555555566666666677777777777788888888888899999999999999999999:::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=============================================================>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊËËËËËËËËËÌÌÌÌÌÍÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÏÐÐÐÐÐÑÑÑÑÒÒÒÓÓÓÓÔÔÔÔÕÕÕÖÖÖ×××ØØØÙÙÙÚÚÚÛÛÜÜÝÝÝÞÞßßààááââããääåææççèèééêëëìííîïïðññòóóôõõö÷øøùúúûüýýþÿ  !!"""##$$%%%&&&'''((()))***++++,,,,---..../////000001111112222223333344444444455555555666666667777777777777778888888888999999999999999999:::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=========================================================>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÏÏÏÏÐÐÐÐÐÑÑÑÑÑÒÒÒÒÓÓÓÓÔÔÔÕÕÕÖÖÖ××רØÙÙÙÚÚÚÛÛÜÜÜÝÝÞÞßßàààááââãääååææççèééêëëìííîîïððñòòóôõõö÷÷øùúúûüýýþÿ  !!""###$$%%%&&&''((()))***+++,,,,----...../////00001111122222333333334444444455555566666666666777777777778888888888888899999999999999::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<================================================================>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÏÐÐÐÐÑÑÑÒÒÒÒÓÓÓÓÔÔÔÔÕÕÕÖÖÖ×××ØØØÙÙÙÚÚÛÛÛÜÜÝÝÞÞßßààááââããääåææççèééêêëììíîîïððñòòóôôõö÷÷øùúúûüýýþÿ  !!""##$$$%%&&&'''((()))***++++,,,,----...////000001111112222223333333444445555555555666666666677777777788888888888888889999999999999:::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<======================================================================>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÏÐÐÐÐÐÑÑÑÑÑÒÒÒÓÓÓÔÔÔÔÕÕÕÖÖÖ××ØØØÙÙÙÚÚÛÛÛÜÜÝÝÞÞßßàààáââããääååææçèèééêëëìííîïïðñòòóôôõöö÷øùùúûüüýþÿ  !!""##$$$%%&&&'''(()))***++++,,,---...../////000001111112222233333444444445555555555666666777777777777788888888888899999999999999999:::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=============================================================================>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÏÏÏÏÐÐÐÐÑÑÑÑÑÒÒÒÒÓÓÓÔÔÔÔÕÕÕÖÖÖ×××ØØØÙÙÚÚÚÛÛÜÜÝÝÞÞßßààááââããääååæççèèéêêëììíîïïðññòóóôõöö÷øùùúûüüýþÿ  !!""##$$%%%&&'''((()))***++++,,,----.....////000011111222223333333344444444555555666666666777777777777788888888899999999999999999999::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<===========================================================================>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÍÎÎÎÎÎÏÏÏÏÏÐÐÐÐÑÑÑÑÒÒÒÒÓÓÓÔÔÔÕÕÕÖÖÖ×××ØØØÙÙÚÚÚÛÛÜÜÝÝÞÞßßààááââããääååæççèèéêêëììíîîïððñòóóôõöö÷øùùúûüüýþÿ  !!""##$$%%%&&'''((()))***+++,,,----....////000001111122222233333334444455555555666666666667777777778888888888888999999999999999:::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<===================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊËËËËËËËÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÏÏÏÏÏÐÐÐÐÐÑÑÑÑÒÒÒÒÓÓÓÔÔÔÔÕÕÕÖÖÖ××ØØØÙÙÙÚÚÛÛÜÜÝÝÞÞÞßààááââããääåææçèèééêëëìííîïððñòòóôõõö÷øøùúûüüýþÿ  !!!""##$$%%&&&'''(()))***++++,,,----..../////000001111122222333334444444555555555666666666777777777888888888888888999999999999:::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<===========================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÊÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÏÏÏÏÐÐÐÐÑÑÑÒÒÒÒÓÓÓÔÔÔÔÕÕÕÖÖÖ××ØØØÙÙÙÚÚÛÛÜÜÜÝÝÞÞßßààááââãääååææçèèéêêëììíîïïðñòòóôõõö÷øøùúûüüýþÿ  !!""###$$%%&&&'''(()))***++++,,,----...////00001111122222333333344444444555555566666667777777777777888888888889999999999999999::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=======================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊËËËËËËÌÌÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÐÐÐÐÐÑÑÑÑÒÒÒÓÓÓÓÔÔÔÕÕÕÖÖÖ××ØØØÙÙÚÚÛÛÜÜÜÝÝÞÞßààááââããäååææçèèéêêëììíîïïðññòóôôõö÷øøùúûüüýþÿ  !!""###$$%%&&'''(()))***+++,,,,---..../////000011111122222333333344444455555566666666667777777777778888888899999999999999999999::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<========================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊËËËËËËÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÏÏÏÏÐÐÐÐÐÑÑÑÑÒÒÒÓÓÓÓÔÔÔÕÕÕÖÖÖ××ØØØÙÙÚÚÛÛÛÜÜÝÝÞÞßßààááââãääååæççèééêëëìíîîïððñòóôôõö÷÷øùúûûüýþÿ  !!""##$$$%%&&'''(()))***+++,,,,---..../////00001111122222333334444445555555556666666666777777778888888888889999999999999999::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<===============================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊËËËËËËËÌÌÌÌÌÌÍÍÍÍÍÍÎÎÎÎÎÏÏÏÏÐÐÐÐÑÑÑÒÒÒÒÓÓÓÔÔÔÕÕÕÖÖÖ××רØÙÙÚÚÚÛÛÜÜÝÝÞÞßààááââããäååææçèèéêêëìííîïððñòóóôõöö÷øùúûûüýþÿ  !!""##$$%%%&&''((()))***+++,,,----...////000011111222222333333444444455555555666666677777777778888888888888899999999999:::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÊÊÊÊÊÊËËËËËËÌÌÌÌÌÌÍÍÍÍÍÍÎÎÎÎÎÏÏÏÏÐÐÐÐÐÑÑÑÒÒÒÒÓÓÓÔÔÔÕÕÕÖÖ××רØÙÙÚÚÚÛÛÜÜÜÝÝÞÞßààááââãääåææçèèééêëììíîîïðñòòóôõöö÷øùúûûüýþÿ  !!""###$$%%%&&''((())***+++,,,----.../////00001111122222233333344444455555566666666777777777777888888888889999999999999:::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊËËËËËÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÏÏÏÏÐÐÐÐÑÑÑÑÒÒÒÓÓÓÓÔÔÔÕÕÕÖÖÖ××ØØØÙÙÚÚÛÛÜÜÝÝÞÞßßààáââããäååæççèééêëììíîîïðññòóôõõö÷øùúúûüýþÿ  !!""##$$%%&&'''(()))***+++,,,,---....////000011111222223333344444555555556666666666777777777788888888899999999999999999::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊËËËËËËÌÌÌÌÌÌÍÍÍÍÍÍÎÎÎÎÏÏÏÏÐÐÐÐÑÑÑÑÒÒÒÓÓÓÔÔÔÕÕÕÖÖ××ØØØÙÙÚÚÛÛÛÜÜÝÝÞÞßààááâããääåææçèèéêêëìííîïðññòóôõõö÷øùúúûüýþÿ  !!""##$$$%%&&'''(())***+++,,,---....////0000111122222233333344444455555555666666667777777788888888888899999999999999999::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<========================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÊÊÊÊÊÊËËËËËËÌÌÌÌÌÌÍÍÍÍÍÍÎÎÎÎÏÏÏÏÐÐÐÐÑÑÑÑÒÒÒÓÓÓÔÔÔÕÕÕÖÖÖ××רØÙÙÚÚÛÛÜÜÝÝÞÞßßààááâããäååæççèééêëììíîïððñòóôôõö÷øùùúûüýþÿ  !!""##$$%%&&''((()))***+++,,,---....////00001111222222333333444444555555666666677777777778888888888888999999999999:::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=======================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊËËËËËÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÏÏÏÏÐÐÐÐÑÑÑÑÒÒÒÓÓÓÔÔÔÕÕÖÖÖ×רØÙÙÚÚÚÛÛÜÜÝÝÞÞßààááââãääåææçèééêëëìíîîïðñòóóôõö÷øøùúûüýþÿ  !!""##$$%%%&&''(()))**+++,,,---....////000011111222223333344444555555566666666677777777777888888888899999999999:::::::::::::::::::::::;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=====================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊËËËËËËËÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÏÏÏÐÐÐÐÑÑÑÒÒÒÓÓÓÔÔÔÕÕÕÖÖÖ××ØØØÙÙÚÚÛÛÜÝÝÞÞßßààááâãääååæççèéêêëìíîîïðññòóôõö÷øøùúûüýþÿ  !!""#$$%%&&'''(()))***+++,,,---...////0001111122222333334444444555555566666666677777777788888888999999999999999:::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<========================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÊÊÊÊÊÊËËËËËËËÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÏÏÏÐÐÐÐÑÑÑÑÒÒÒÒÓÓÓÔÔÔÕÕÖÖÖ×רØÙÙÚÚÛÛÛÜÜÝÞÞßààááââãääåæççèééêëììíîïðññòóôõöö÷øùúûüýþÿ  !!"##$$$%%&&''(()))**+++,,,----....////0001111122222333334444444555555666666677777777888888888889999999999999999::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<========================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÊÊÊÊÊÊÊËËËËËÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÏÏÏÏÐÐÐÐÑÑÑÒÒÒÓÓÔÔÔÕÕÖÖÖ××רØÙÙÚÚÛÛÜÜÝÝÞÞßààáââããäååæçèèéêëëìíîïððñòóôõõö÷øùúûüýþÿ  !!""##$$%%&&''((()))**+++,,---...////0000111112222233333444445555555666666677777777778888888888889999999999999::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<========================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊËËËËËËÌÌÌÌÌÍÍÍÍÍÎÎÎÎÏÏÏÐÐÐÐÑÑÑÒÒÒÓÓÓÔÔÔÕÕÕÖÖ×רØÙÙÚÚÚÛÛÜÜÝÞÞßßààáââãäååææçèéêêëìííîïðñòóôõõö÷øùúûüýþÿ  !!"##$$%%%&&''(())***+++,,,---...////00011112222233333444444555555566666666777777777788888888889999999999:::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<========================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÊÊÊÊÊÊÊËËËËËËÌÌÌÌÌÍÍÍÍÍÎÎÎÎÏÏÏÏÐÐÐÐÑÑÑÑÒÒÒÓÓÓÔÔÕÕÖÖÖ××ØØØÙÙÚÚÛÜÜÝÝÞÞßààáââããäåææçèèéêëìííîïðñòóóôõö÷øùúûüýþÿ  !!""##$%%&&'''(()))**++,,,---....////00001111222223333344444455555556666666777777778888888889999999999999::::::::::::::::::::;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=========================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÉÉÉÉÉÉÉÊÊÊÊÊÊÊËËËËËÌÌÌÌÌÍÍÍÍÍÎÎÎÎÎÏÏÏÐÐÐÐÑÑÒÒÒÓÓÓÔÔÔÕÕÕÖÖ×רØÙÙÚÚÛÛÜÜÝÝÞßßààáââãääåæçèèéêêëìíîïððñòóôõö÷øùúûüýþÿ  !""##$$%%&&''(())***+++,,,---..////0001111122222333334444455555556666666777777788888888888999999999999999::::::::::::::::;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<========================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÊÊÊÊÊÊËËËËËÌÌÌÌÌÍÍÍÍÎÎÎÎÏÏÏÐÐÐÐÑÑÑÒÒÒÒÓÓÓÔÔÕÕÖÖ××רØÙÙÚÚÛÜÜÜÝÝÞßààááâããäåææçèéêêëìíîïððñòóôõö÷øùúûüýþÿ  !""###$%%&&''((())**++,,,----...////00011112222333334444455555566666666777777777888888888889999999999999:::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<======================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÊÊÊÊÊÊËËËËËÌÌÌÌÌÍÍÍÍÎÎÎÎÎÏÏÏÏÐÐÐÐÑÑÑÒÒÒÓÓÔÔÕÕÕÖÖÖ×רØÙÚÚÚÛÛÜÝÝÞÞßààáâããääåæçèèéêëìííîïðñòóôõö÷øùúûüýþÿ  !!""#$$%%%&''(()))***++,,---...////000011111222233333444445555556666666677777777788888888889999999999::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<=================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÊÊÊÊÊÊÊËËËËËÌÌÌÌÌÍÍÍÍÍÎÎÎÎÏÏÏÐÐÐÑÑÑÒÒÒÓÓÓÔÔÔÕÕÖÖ××ØØØÙÙÚÛÛÜÜÝÝÞßààááâãääåææçèéêêëìíîïðñòóôõö÷øùúûüýþÿ  !""##$$%&&'''(())**+++,,,---...///000111122222333334444455555556666666777777778888888899999999999::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=============================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÊÊÊÊÊÊËËËËËÌÌÌÌÍÍÍÍÎÎÎÏÏÏÐÐÐÐÑÑÑÑÒÒÒÓÓÔÔÕÕÕÖÖÖרØÙÙÚÚÛÛÜÝÝÞÞßààáââãäåææçèéêêëìíîïðñòóôôõö÷øùúûüýþ  !!""#$$%%&&''()))***++,,---....////000111222233334444455555566666667777777788888888889999999999999::::::::::::::::::;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=============================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÊÊÊÊÊÊËËËËËÌÌÌÌÍÍÍÍÎÎÎÎÎÏÏÏÏÐÐÐÑÑÑÒÒÓÓÓÔÔÔÕÕÖÖ×רØÙÙÚÚÛÜÜÜÝÞßßààáâããäåæççèéêëìíîïððñòóôõö÷øùúûüýþ  !"###$%%&&''(())**+++,,,--...///000011111222233334444455555566666677777777788888888889999999999999::::::::::::::;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==============================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÊÊÊÊÊÊËËËËËËÌÌÌÌÌÍÍÍÍÍÎÎÎÎÏÏÐÐÐÑÑÑÒÒÒÒÓÓÔÔÕÕÖÖÖ×רØÙÚÚÚÛÜÜÝÞÞßààáââãäååæçèéêëììíîïðñòóôõö÷øùúûüýþ  !!"##$%%%&''(()))**++,,----...///00111122222333334444445555556666667777777778888888889999999999:::::::::::::;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=====================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÊÊÊÊÊÊËËËËËÌÌÌÌÍÍÍÎÎÎÎÏÏÏÐÐÐÐÑÑÑÒÒÓÓÔÔÔÔÕÕÖÖ×ØØØÙÙÚÛÛÜÜÝÞßßààáâããäåæçèééêëìíîïðñòóôõö÷øùúûüýþ  !"##$$%&&'''())**++++,,--...////00011112223333444445555556666666777777778888888889999999999::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<=========================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÉÉÉÊÊÊÊÊËËËËÌÌÌÌÍÍÍÍÎÎÎÎÎÏÏÏÐÐÐÑÑÒÒÒÓÓÓÔÔÕÕÖÖÖ×רÙÙÚÚÛÛÜÝÝÞßààááâãäåæççèéêëìíîïðñòóôõö÷øùúûüýþ  !""#$$%%&&'(()))**++,,,---..///00011111222233334444555556666667777777788888888899999999999::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<=====================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÉÉÉÊÊÊÊÊËËËËËÌÌÌÌÌÍÍÍÍÍÎÎÎÏÏÐÐÐÐÑÑÑÒÒÒÓÔÔÔÕÕÕÖ×רØÙÙÚÛÛÜÜÝÞÞßààáâãäååæçèééëììíîïðñòôôö÷øùúûüýþ  !!"##$$%&&''(()***+++,---...////00111222223333344444555556666667777777788888888899999999999::::::::::::::::;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<=============================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÊÊÊÊÊÊÊËËËËËÌÌÌÌÍÍÍÎÎÎÏÏÏÏÐÐÐÐÑÑÒÒÓÓÓÔÔÕÕÖÖ×רØÙÚÚÚÛÜÝÝÞßààáâããäåææçèéêëìíîïðñòóôõ÷øùúûüýþ  !""#$%%%&''(())**++,,,--..////000011122233334444455555556666666777777778888888889999999999:::::::::::::;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=====================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>???????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÊÊÊÊÊËËËÌÌÌÌÍÍÍÍÎÎÎÎÎÏÏÐÐÐÑÑÑÒÒÒÓÓÔÕÕÕÖÖ×ØØØÙÙÚÛÛÜÝÞÞßàááâãääåæçèéêëìíîïðñòóôõöøùúûüýþ  !!"#$$%&&'''())***+,,---...///001111122223333444555556666666777777778888888899999999999::::::::::::;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>???????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÈÈÈÈÈÈÈÉÉÉÉÉÊÊÊÊÊËËËËÌÌÌÌÌÍÍÍÍÍÎÎÏÏÏÐÐÐÐÑÑÒÒÓÓÓÔÔÕÕÖÖ×רÙÙÚÚÛÜÜÝÞßßàáââãäåæçèèéëëìîïðñòóôõö÷ùúûüýþ  !"##$%%&&'(())**++,,,--..////000112222233333444455555666667777777888888899999999999:::::::::::::;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<=======================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>???????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÈÈÈÈÈÈÈÉÉÉÉÉÊÊÊÊÊÊÊËËËËËÌÌÌÌÍÍÍÎÎÎÏÏÏÏÐÐÑÑÒÒÒÒÓÓÔÕÕÕÖÖרØÙÙÚÛÛÜÝÝÞÞààáâãääåæçèéêëìíîïðòóôõö÷øúûüýþ !!""#$$%&&''())***+,,----..//00001112223333444445555555666667777777888888899999999999:::::::::::::;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<==============================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>???????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÊÊÊÊÊËËËËÌÌÌÍÍÍÍÎÎÎÎÏÏÐÐÐÑÑÑÑÒÓÓÔÔÔÕÕÖ××רÙÚÚÛÜÜÝÝÞßàáââãäåæçèéêëìíîïðñòóõö÷øùûüýþ  !""##$%%&'((()**+++,,-....///00111122223334444555556666666777777778888888899999999999:::::::::::::;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<====================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>???????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÉÊÊÊÊËËËËÌÌÌÌÌÍÍÍÍÎÎÏÏÏÏÐÐÐÑÑÒÒÓÓÓÔÕÕÖÖÖרØÙÚÛÛÛÜÝÞÞààáâããååæèèéëëíîïðñòóôö÷øùûüýþ !!"#$$$%&''()))**+,,,--..///000011222233333444455556666777777778888888889999999999:::::::::::::;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<===================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>???????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÈÈÈÈÈÈÉÉÉÉÊÊÊÊÊÊËËËËËÌÌÌÌÍÍÎÎÎÎÏÏÏÐÐÑÑÑÒÒÒÓÔÔÔÕÕÖ×רÙÙÚÚÛÜÜÝÞßàááâãäåæçèéêëìíîðñòóôõ÷øùúüýþ  !"##$%%&&'(()**+++,---...//000111122333344444555555666677777788888889999999999::::::::::::;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<===========================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÈÈÈÈÈÈÉÉÉÉÉÉÉÊÊÊÊÊÊËËËÌÌÌÍÍÍÍÎÎÎÎÏÐÐÐÐÑÑÒÒÓÓÓÔÕÕÖÖרØÙÙÚÛÛÜÝÝÞßàáâãäååççéêëìíîïðòóôõ÷øùúüýþ  !""#$$%&&''())**+,,,--..////0111122223334445555556666666777777888888999999999::::::::::::;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<===================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÊÊÊËËËÌÌÌÌÌÍÍÍÍÎÎÏÏÏÐÐÐÑÒÒÒÒÓÔÔÕÕÖ××רÙÚÚÛÜÜÝÞßàááâãäåæçèéêëíîïðñóôõöøùúüýþ  !"##$%%&'((()**++,----.///000112222333334445556666666777777778888888999999999::::::::::::;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<============================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÉÉÉÉÊÊÊÊËËËËËÌÌÌÌÍÍÎÎÎÎÏÏÐÐÑÑÑÑÒÓÓÔÔÕÖÖÖרØÙÚÛÛÜÝÝÞßàáâãääæçèéêëìîïðñòôõöøùúüýþ  !""#$$%&''()))*++,,-....//001111223333444445555666677777778888888899999999999:::::::::::::;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÈÈÈÈÈÉÉÉÉÉÊÊÊÊÊÊËËËÌÌÌÍÍÍÍÎÎÎÏÏÐÐÐÐÑÒÒÓÓÔÔÕÕÖ×רØÙÚÚÜÜÝÞÞààáâãäåæçèêëìíîðñòóõö÷ùúûýþ !!"##%%&''(()**++,,--.////00111222233344455555566666777778888889999999999:::::::::::::;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<=======================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÇÇÇÇÇÈÈÈÈÈÈÉÉÉÉÉÉÉÊÊÊÊËËÌÌÌÌÌÍÍÍÎÎÏÏÏÏÐÐÑÑÒÒÓÓÔÔÔÖÖÖרÙÙÚÛÛÝÝÞßàáâãäåæçèéêìíîïñòóôö÷ùúûýþ  !""$$%&&'()))+++,,--..//000011222333334455556666666777777888889999999::::::::::::;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<============================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>???????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÉÊÊÊËËËËËÌÌÌÌÍÎÎÎÎÎÏÐÐÐÑÑÒÒÓÓÓÔÕÕÖ×רÙÚÚÛÜÜÞÞààáâãäåæèéêëìíïðòóôö÷øúûýþ !!##$%%&'(()**+,,,--..///011111233334444455566667777777788888889999999::::::::::;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<============================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>???????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÈÈÈÈÈÉÉÉÊÊÊÊÊÊËËËËÌÌÍÍÍÍÎÎÏÏÏÐÐÑÑÒÒÒÓÔÔÕÖÖרØÙÚÛÛÜÝÞßàááãäåæçèéëìíîðñòôõ÷øúûýþ  !"#$$%&''())*++,---..//00011222233444455555566677777888888888999999999::::::::::;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<========================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>???????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÈÈÈÈÉÉÉÉÉÉÊÊÊÊÊËËÌÌÌÌÍÍÍÎÎÏÏÏÐÑÑÑÑÒÓÓÔÔÕÕÖרØÙÚÛÜÜÝÞßàáâãäææèéêìíîðñòôõ÷øúûýþ  !"##$%&''()**++,,-..../000112223333445555566666677778888889999999999:::::::::::::;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<===============================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>???????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÇÇÇÇÈÈÈÈÈÈÈÉÉÉÉÉÉÊÊËËËËÌÌÌÌÍÎÎÎÎÏÐÐÐÐÑÒÒÒÓÔÔÕÖÖרÙÙÚÛÜÝÞßàáâãäåæçéêëíîïñòóõöøùûüþ  !"#$%&&'())*++,---.////0111123333444455666666777777788889999999:::::::::::::;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<============================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>???????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÊÊÊÊËËËËÌÌÍÍÍÍÎÏÏÏÏÐÑÑÒÒÓÓÔÔÕÖÖרÙÚÚÛÜÝÞßàáâãäåçèéëìíïðòóõöøùûüþ  !"#$%%&'())*++,,--../000012222334444555566677777777888888999999:::::::::;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<===========================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>???????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÈÈÈÈÉÉÉÉÊÊÊÊÊÊËÌÌÌÌÍÍÎÎÎÏÏÐÐÑÑÑÒÓÓÔÕÕÖ×רÙÚÛÜÜÝÞààââäåæèéêìíîðñóôöøùûüþ !"##$%&'(()**+,,-...//001112233334555555666677778888888889999999:::::::;;;;;;;;;;;<<<<<<<<<<<<<<<<<<================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>???????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÈÈÈÉÉÉÉÉÉÉÊÊÊËËËÌÌÌÍÍÎÎÎÎÏÐÐÐÑÒÒÒÔÔÔÕÖרØÙÚÛÜÝÝßàáâãåæçèêëìîðñòôö÷ùûüþ  ""#$%&''()*+++---.///011112233344455566666667778888899999999999::::::::;;;;;;;;;;;<<<<<<<<<<<<<<<<<=================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÇÇÇÈÈÈÈÈÈÈÉÉÉÉÊÊÊËËËËÌÍÍÍÍÍÎÏÏÏÐÑÑÑÒÓÓÔÕÕÖרÙÙÚÛÜÝÞààâãäåçèéëìíïñòôõ÷ùúüþ !"#$%&&'()**+,,-.../000122222344445556666777777788899999999:::::::::::::;;;;;;;;;;;<<<<<<<<<<<<<<<<<=================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÇÇÇÇÇÇÈÈÈÈÈÈÉÉÊÊÊÊÊÊËÌÌÌÌÍÍÎÎÎÏÐÐÐÑÒÒÒÔÔÔÖÖרÙÚÛÛÝÝßàáâãäæèéêëíïðòóõ÷ùúüþ  ""$$%&'())+++---.///01112233334555555667777778888889999::::::::::::;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<=================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÆÆÆÆÆÇÇÇÇÇÇÇÇÇÈÈÉÉÉÉÉÊÊÊËËËÌÌÌÍÍÎÎÎÏÏÐÐÑÑÒÓÓÔÕÕ×רÙÚÛÜÜÞßàáãäåçèêëìîðñóõ÷øúüþ  !##$%&'((**+,,-..//0011122333444555666667788888888899999:::::::;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<===============================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÆÆÆÆÆÆÆÆÆÇÇÇÇÇÈÈÈÈÉÉÉÉÉÊÊËËËËËÍÍÍÍÍÏÏÏÐÐÑÑÒÓÔÔÕÖÖØØÙÚÛÜÝÞààâäåæçéëìîðñóõöøúüþ !"#$%&''))*++,-..//00022222444445566666777788888999999999:::::;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<=============================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÇÇÈÈÈÈÈÈÈÉÉÊÊÊÊÊËËÌÌÌÍÍÎÎÎÐÐÐÐÒÒÓÓÔÕÕ××ÙÙÚÜÜÞßàáãäæçèêëíïðòôöøúüþ  !##%&&((**+,,--////11122333445555566777777788999999999::::::::;;;;;;;;<<<<<<<<<<<<<<<<============================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÇÇÇÇÇÈÈÈÈÈÉÉÉÊÊÊÊËËÌÌÌÍÍÎÎÏÏÏÐÑÑÒÓÓÔÕÖÖØØÚÛÛÝÞààâãåæèêëíïðòôöøúüþ !"$$%''))*+,,-../000112233344555566677777888889999:::::::::::::;;;;;;;;<<<<<<<<<<<=========================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÆÆÇÇÇÇÇÇÇÇÇÈÉÉÉÉÉÉÉËËËËËÍÍÍÍÎÏÏÐÐÑÒÒÒÔÔÕÖרÙÚÛÜÝßàáâäæçéêìîðòôöøúüþ  "#$%&'()*++---.//0012222444446666666788888888899::::::::::;;;;;;;;;;;;;<<<<<<<<<<<=======================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÆÆÆÆÆÆÆÇÇÇÇÈÈÈÈÉÉÉÉÊÊÊËËÌÌÌÍÎÎÎÎÐÐÑÑÒÓÓÕÕÖØØÙÚÛÝÞßàâãåæèêìîðñóõ÷ùûý  !"$%&'')**,,-..//11112333445556666777788889999999:::::;;;;;;;;;;;;;;;<<<<<<<<<<<<<<=======================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÅÅÅÆÆÆÆÆÆÆÆÆÆÇÈÈÈÈÈÈÈÈÊÊÊÊÊËÌÌÌÍÍÎÎÏÏÐÑÑÒÓÔÔÕÖ×ÙÙÚÜÝßàáâäæèêëíïñóõ÷ùûý  "#%&&()*++,-../0011223334555557777777789999999999:::;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<=======================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÅÅÅÅÅÅÅÅÆÆÆÆÆÇÇÇÇÇÈÈÈÈÉÉÉÊÊËËËËÍÍÍÍÎÏÐÐÐÒÒÓÓÕÕÖØØÚÛÜÞßàâäåçéêìîðòô÷ùûý  !#$%'')**,,--///01222244445566677778888899999::::::::;;;;;<<<<<<<<<<<<<<<<<<<<<============================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÆÇÇÇÇÇÇÇÇÈÉÉÉÉÉÊÊËËÌÌÌÍÎÎÎÏÐÑÑÒÓÔÔÖ××ÙÚÜÝÞàáãäæèéìîðòôöùûý !"#%&(()++,-../011123334455666667888888889::::::::::::;;;;;<<<<<<<<<<<<<<===============================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÆÆÆÆÆÇÇÇÇÈÈÈÈÈÉÊÊÊÊÊÌÌÌÍÍÎÏÏÐÐÒÒÓÔÕÕרÙÛÜÞÞáâäåçéëíïñôöøûý !!#$&'(**+,--//0012233355555677777888899999:::::::;;;;;;;;;;<<<<<<<=============================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÆÆÆÆÆÆÆÆÆÈÈÈÈÈÈÈÉÊÊÊËËËÍÍÍÎÎÐÐÐÑÓÓÔÔÖ×ÙÚÚÜÝàáãäæèêíîñóöøûý "#%%&()++,,.///1122244455567777777999999999::;;;;;;;;;;;;;;;<<<<<<=====================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÆÆÆÆÆÆÆÇÇÇÈÈÈÉÉÉÉÉËËËÌÌÎÎÎÏÏÑÑÒÒÔÕÖØØÚÛÜÞàâãåèéìîðóõøúý !#$%'')*+--..0011133444666667778889999999::::;;;;;;;;;;;<<<<<<<<<<<=============>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÅÅÅÅÅÅÅÅÅÆÆÇÇÇÇÇÇÈÉÉÉÉÊÊÊÌÌÌÍÍÏÏÐÐÐÒÓÔÖÖ×ÙÚÜÝÞáâäçèëîðòõøúý !"#%&())+,-///00223335556666788888899:::::::::;;;;;<<<<<<<<<<<<<<<<<============>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÅÅÅÅÅÅÅÅÅÅÆÆÆÇÇÇÈÈÈÈÈÊÊÊÊËËÍÍÍÎÎÐÐÑÒÔÔÕרÙÛÜÞàâãæèêíïòô÷úý !#$&'(*++-.//1122244555577777888999::::::::::;;<<<<<<<<<<<<<<<<<<<==============>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÅÅÅÅÅÆÆÆÆÆÆÆÈÈÈÈÈÉÉÉËËËÌÌÎÎÏÏÐÒÒÓÕÖÖÙÚÛÝÞáâåæéìîñô÷úý !"$%&))*,--/001133444666777779999999:::::;;;;;;;<<<<<<<<<<<<=====================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÆÆÆÆÆÆÆÆÇÇÇÈÉÉÉÉÊÊÌÌÌÍÍÏÐÐÑÓÓÔÕרÛÜÝàáäåèëíðóöùü "#$'(*+,,.//022333556666788899999999;;;;;;;;;;;;<<<<<============================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÆÆÆÇÇÇÇÇÈÈÉÊÊÊÊËÍÍÎÎÎÑÑÒÒÕÖ×ÙÚÝÞàâåçêìðóöùü !"%&()*--..111224555567788888999::::;;;;;;;;;;;<<<============================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÄÄÄÄÄÅÅÅÅÅÅÅÅÅÇÇÇÈÈÈÈÈÉÊËËÌÌÎÎÏÐÐÒÓÔרÙÛÝàáäæéëïòõùü "$&'(+,-//01133445677777888:::::::::;;;;;<<<<<<<<<===================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÅÅÅÅÅÅÅÅÆÆÆÆÈÈÈÈÉÉÉÊÌÌÌÍÍÐÐÑÑÔÕÖÙÚÛÞàãåèëîñõøü !$%&)*+..//22333566677779999::::::::<<<<<<<<<<<<<<<==========>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÅÅÅÆÆÆÆÆÆÇÇÉÉÉÊÊÊËÍÍÎÎÏÑÒÓÔרÛÜÞáãçêíðôøü !#$'(+,-.01122455566688999999:::;;;;<<<<<<<<<<<<<<<<==>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÆÆÆÆÇÇÇÇÈÈÊÊËËËÌÎÏÐÐÑÔÕÖÙÚÞàãåéìðôøü !%&)*+.//013444557788889999;;;;;;;;;<<<<<<<<<<=======>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÄÄÄÄÄÄÄÄÄÄÅÅÅÅÇÇÇÈÈÈÈÉÉËÌÌÍÍÐÑÒÓÖרÜÞáäèêîó÷û !#'(),-./22334667777888::::;;;;;;;;;;<<<==============>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÄÄÄÄÄÄÅÅÅÅÅÅÆÆÆÈÈÉÉÉÊÊÍÍÎÏÐÓÔÕØÚÜàâæéíòöû #%'*+,/01225566677999::::::;;;;;;=====================>>>>>>>>>>>>>>>>>>>>>>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÅÅÅÅÅÅÆÆÆÆÆÇÇÉÊÊËËÌÏÐÐÑÒÖØÜÝàäéìñöû "#')-.//03445568899999::::::<<<<<======================>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÄÆÆÆÆÆÇÇÇÈÈÈËÌÌÍÎÑÒÔÕÙÛàâçêðõú $&*+-.1233477788899999;<<<<<<<<<<====================>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÇÇÇÈÈÈÉÉÊÍÎÏÐÑÕÖØÝàåèîôú "')*./012566777888;;;;;;<<<<<<<<<<=========>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÅÅÅÅÈÉÉÊÊËÌÐÑÒÓØÚÝâæìóù "%',-./3455667::::;;;;;;;<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÃÄÄÄÄÄÄÄÅÅÅÅÆÆÆÇÊËÌÌÍÎÓÕ×Ýàãêñø"(*,1233458999::::;;;;;;;<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÄÅÅÅÅÆÆÆÇÇÈÈÉÍÎÐÑÓÙÜãèðø#&,./1267788999::::;=======>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÃÃÃÆÇÇÈÈÉÉÊËÑÓÕØàäíö '*,.456677889<<<===========>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÄÄÄÉÉÊËÌÎÐØÛàêõ $'/134566;;;<<<<<===========>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÄÄÄÄÅÅÆÇÎÐÒÕàæó *-/189::;;;;<<<<<===========>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÄÄÄÄÅÅÆÇÈÉÊÕÙàð&*56789::;;;;<<<<<===========>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÄÄÄÄÅÅÆÇÈÉÊÌÐÕê*/356789::;;;;<<<<<===========>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÄÄÄÄÅÅÆÇÈÉÊÌÐÕà*/356789::;;;;<<<<<===========>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½¼¼¼¼¼»»»»ºº¹¸·¶µ³¯ªŸ`UPLJIHGFEEDDDDCCCCCBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½¼¼¼¼¼»»»»ºº¹¸·¶µ³¯ªŸ`UPLJIHGFEEDDDDCCCCCBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½¼¼¼¼¼»»»»ºº¹¸·¶µ³¯ª•jUPLJIHGFEEDDDDCCCCCBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½¼¼¼¼¼»»»»ºº¹¸·¶µª¦Ÿp`YUJIHGFEEDDDDCCCCCBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½¼¼¼¼¼»»»»ºº¹¸±¯­ªŸ™Œsf`URPNGFEEDDDDCCCCCBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½¼¼¼¼¼»»»¶¶µ´³±¯§¤Ÿ•Šuj`[XPNLKJIIDDDCCCCCBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½¼¼¼¹¸¸··¶¶µ´®¬ª§Ÿ›’‰vmd`XUSQKJIIHHGGFCCCBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½»ºººº¹¹¹¸¸··¶²±¯®¬¦£œ—‡xphc\YSQPNMIHHGGFFFEEEEDBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¼»»»»»»»ºººº¹¹¹¸µ´³³²±¬ª¨¢Ÿœ•އxqjc`]WUSNMLLKJGFFFEEEEDDDDDDDCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¼¼¼¼¼¼¼¼¼¼»»»»»»»ºººº·¶¶µµ´³¯®­¬§¥¢™“Œ†yslfb]ZXSRQPLKJJIIHEEEEDDDDDDDCCCCCCCCCCAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½¼¼¼¼¼¼¼¼¼¼»»»»»»¸¸¸···¶¶µ²±°¯®ª©§¢Ÿš—‘‹…ztnhe`]XVUQPONMJIIHHHGGGDDDDDDCCCCCCCCCCBBBBBBBBBAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼»¹¹¹¹¹¸¸¸···´³³²±®­«ª¦¤Ÿ˜•Š…zupjgb`[YUTRQNMLLKHHHGGGFFFFFDCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼ºººººº¹¹¹¹¹¸¸¶µµ´´³°¯¯®­©§£¢Ÿ›–“މ„{vqlid`]\XVRQPPOLKKJJIGGFFFFFEEEEEECCCCCBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½»»»»»»ºººººº¹¹¹··¶¶¶µµ²²±°¯¬«ª§¥£Ÿ™–’‰„{vrmifb`\ZXUTSPONMMJJIIIHHFFFEEEEEEDDDDDDBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½¼¼¼»»»»»»»»»»ºººº¸¸¸····¶¶´³³²²¯®­¬©¨§£¡ž›—•‘Œˆ„{wsnjhda^\XWVSRQPMMLLKIIHHHHGGGEEEEDDDDDDDDDDCCCBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½¼¼¼¼¼¼¼¼¼¼»»»»»»»»»¹¹¹¹¸¸¸¸··µµ´´´³±°¯¯®«ª©¦¥¡Ÿœš–“‹‡ƒ|xtpliec`^ZYVUTQPPONLKKKJJHHGGGGFFFFDDDDDDDDDCCCCCCCCCCBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»ººº¹¹¹¹¹¹¸¸¶¶¶µµµ´²²±±°®­¬«¨§¤£¡žœ˜•’‹‡ƒ|xtpmjgca^\[XWTSRQONNMMKJJJIIIGGFFFFFFEEEDDDDCCCCCCCCCCCCCCCCBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼ºººººººº¹¹¹¹····¶¶¶µ³³³²²¯¯®®«ª©¦¥¤¡Ÿœš—”‘ŽŠ‡ƒ|xuqnkhec`^[ZYVUTQQPPMMLLLJIIIHHHHFFFFEEEEEEEECCCCCCCCCCCCCCCBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼»»»»»ººººººººº¸¸¸·····¶µ´´³³±±°¯¯­¬«¨§¦¤¢Ÿž›™–”Іƒ|yurokifda`][YXWTSRPPONNLLKKJIHHHHHGGGEEEEEEEEEDDDDDCCCCCCCCCBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼»»»»»»»»»»»ºººº¹¹¹¸¸¸¸¸··¶µµµµ´²²±±±®®­­ª©¨¦¥¢¡Ÿš˜•“Œ‰†ƒ|yvspljgeb`^]ZYWVURRQQNNNMMKJJJJIHHGGGGGFFFEEEEDDDDDDDDDDDCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼»»»»»»»»»»»»¹¹¹¹¹¹¹¹¸¸¸·¶¶¶¶µµ³³³²²°¯¯®¬¬«ª¨§¤£¢Ÿž›š—”’Œ‰†ƒ|yvspmkheda`]\[XWUTSSQPPOMMLLLJJIIIIHGGGFFFFFFFFDDDDDDDDDDDDCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»ººººº¹¹¹¹¹¹¹·····¶¶¶´´´³³±±°°¯­­¬ª©©¦¥¤¢¡žš™–“‘Ž‹ˆ…‚}zwtqnlifeba^][ZYVVUSRRPOONNLLKKKIIIHHHHHFFFFFFFEEEEEDDDDDDDCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»ºººººººººº¹¹¹¸¸¸·····µµµµ´´²²²±±¯¯®­««ª¨§¦¤£¡Ÿœ™—•’‹ˆ…‚}zwtromjhfcb`^\[YXWUTTRQPPNNMMMKKJJJJHHHHHGGGFFFEEEEEEEEEEDDCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»ººººººººº¹¹¸¸¸¸¸¸·¶¶¶¶µµµ³³³²²°°¯¯¯­¬«©©¨¦¥£¢¡ž›˜—”‘Ї…‚}zxurpnkhgdba^]\ZYWVVTSRPPPOOMMLLLJJJIIIIHGGGGGGFFEEEEEEEEEDDDDDCCCCCCCCCCCCCCCCCBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»ºººº¹¹¹¹¹¹¹¸¸¸···¶¶¶¶¶´´´³³±±±°°®®­­«ª©§§¥¤£¡Ÿœš—–“‘ŒŠ‡…‚}zxuspnlihecb`^\[ZXXVUTRRQQOONNNLLKKKIIIIIHHHGGGFFFFFFFEEEEDDDDDDDDDDDCCCCCCCCCCCBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼»»»»»»»»»»»»»»»ºº¹¹¹¹¹¹¹¹¹·······¶µµµ´´´²²²±±¯¯¯®¬¬««©¨¦¥¥£¢Ÿžœ›™—•’‘ŽŒ‰‡„‚}{xvsqnmjhfdca`]\ZZYWVTTSSQPPPNNMMMKKKJJJIHHHHHHHFFFFFFFFFEEDDDDDDDDDDDDDDDCCCCCCBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼»»»»»»»»»»ººººººº¹¹¹¹¹¸¸¸¸·····¶µµµµµ³³³²²±°°¯¯­­¬«ªª¨§¦¤£¡¡ž›š˜–”’Ž‹‰‡„‚}{xvtqomkigedba^^\[YXWUUTSRRPPOONMMLLLJJJJJIHHHHHGGGGFFFFFEEEEEEEDDDDDDDDDDCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»ºººººººººººº¹¸¸¸¸¸¸¸¸·¶¶¶¶¶µµ´´³³³²±±±°¯®®­¬««©¨¨¦¥£¢¡Ÿžœ›™—–“‘‹‰†„‚}{yvtrpnlihfdca`^]\ZYWWVTTSRQQPONNNMLLLKKJJIIIIIHGGGGGGGGFEEEEEEEEEEEEDDDDDCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»ºººººººº¹¹¹¹¹¸¸¸¸¸····¶¶¶µµ´´´´²²²²±°¯¯¯­­¬¬ªª©§§¥¤£¡ Ÿ›š˜–•“‘‹ˆ†„‚}{ywtrpnljigedb`_^\[ZXXVUUSSRRPPPONMMMMKKKKJJIIIHHHHGGGGGFFFFFEEEEEEEEDDDDDCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»ººº¹¹¹¹¹¹¹¹¹¹¸········µµµµµ´³³³²²±±°°¯®®­¬««ª©¨¦¦¥£¢ Ÿž›™—•”’ŽŒŠˆ†„‚}{ywusqomkjhfdba`_]\ZYYWVUTTSRQQPOONNMMLLLKJJJJJHHHHHHHHGFFFFFFFFFFEEEDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»ººººº¹¹¹¹¹¹¹¸¸¸¸····¶¶¶¶µµµ´´³³³²±±±±¯¯®®­¬¬ªª©§§¦¥¤¢¡ Ÿœš™—•“‘ŽŒŠˆ†„‚}{ywusqpnljhfecb`_^][ZYXXVUUSSRQQPPNNNNMLLLKKJJJIIIIHHHHGGGGFFFFFFFEEEEEDDDDDDDDDDDDDDDCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»ºººººººººº¹¹¸¸¸¸¸¸¸¸¸·¶¶¶¶¶¶¶´´´´´²²²²±°°¯¯®­­­««ª©¨§¦¥¤£¢ Ÿž›™˜–•“‘‹‰‡…ƒ~|zxvtrpnljigfdba`_]\[ZYXWVUTTRRRQPPOONMMMMKKKKKIIIIIIIHGGGGGGGGGFFEEEEEEEEEEDDDDDDDDDDDDDCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»ººººººººººººº¹¹¹¹¸¸¸¸¸·····¶¶¶µµµµ´´³³³²²±±°°°¯®®­¬¬«ª©©§§¥¤¤¢¡ŸŸœš™—•”’‹‰‡…ƒ~|zxvtrpomkjhfecb``^][[ZXXVVUTSSRQQPOOONNMMLLLKKJJJJIIIHHHHHGGGGGFFFFEEEEEEEEEEEEEDDDDDDDDCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»ºººººººº¹¹¹¹¹¹¹¹¹¸¸·······¶¶µµµµµ´´³³³²²±±±¯¯¯¯­­¬¬«ªª¨¨¦¦¥££¡ Ÿžœ›™˜—•”’‹‰‡…ƒ~|zxvtrpomkjhgfdca`_^\\ZYYWWUUTSSRRPPPPNNNMMLLLKKJJJJJIIHHHHHHHGGFFFFFFFFFEEEEEEEEDDDDDDDDCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»ººººº¹¹¹¹¹¹¹¹¹¸¸¸¸¸····¶¶¶¶¶µµ´´´´´²²²²²°°°¯¯®®­¬««ª©©§§¦¥¤£¢¡ŸŸ›š™˜–”“‘ŽŒŠ‰‡…ƒ~|zxvusqpnlkigfedb``^]\[ZYXXVVUTTSRQQPPOOOMMMMMKKKKKJJIIIIIHHHHGGGGGFFFFFFFFFEEEEEDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»ººººººº¹¹¹¹¹¸¸¸¸¸¸¸¸¸··¶¶¶¶¶µµµ´´´³³³²²±±±°°¯¯®®­¬¬«ªª¨¨§¦¥¤££¡ Ÿžœ›š˜—•”“‘ŽŒŠˆ‡…ƒ~|zxwusqpnlkjhgedca`_^\\[ZYXWWUUTSSRQQPPOONNNMMLLLKKKJJJIIIIIHHGGGGGGGGGFFFFFEEEEEEEDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»ºººººººººººº¹¹¹¹¸¸¸¸¸¸······¶¶µµµµµµ´³³³³²²±±±°¯¯¯®­­­«««©©¨§¦¥¤¤¢¢ Ÿžœ›™—–•”’ŒŠˆ†…ƒ~|zywusrpomkjihfdcba`_]][[ZYXWVVTTTRRRQPPPONNNMMLLLLKJJJJJJIIHHHHHHGGGGGGFFFFEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»ººººººººººººº¹¹¹¹¹¹¹¹¸¸¸·······¶¶¶¶µµµ´´´´³²²²²²±°°°¯®®®­¬¬«ªª©¨§¦¦¥¤£¢¡ŸŸœ›š˜—–”“’Ž‹Šˆ†…ƒ~|zywutrqomlkihgedcb``^]\[ZYYXWVUUTSSRQQQPOOONMMMMMLKKKKJJJIIIIHHHHHHHGGGFFFFFFFFEEEEEEEEEEEEEDDDDDDDDDDDCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»ºººººººº¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸···¶¶¶¶¶¶¶µµµ´´´³³³²²±±±±°¯¯¯®­­­«««ª©¨§§¦¥¤£¢¢ Ÿžœš™˜—•”“‘Ž‹‰ˆ†„ƒ~|{ywvtrqpnlkjhgfecba`_]]\[ZYXXWVUTTTRRRQPPPONNNNMMLLLKKKJJJIIIIIIIHHHGGGGGFFFFFFFFFFFEEEEEEEEDDDDDDDDDDDCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»ººººººº¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸····¶¶¶¶µµµµµµ´³³³³²²±±±°°¯¯®®®­¬¬«ªª©¨¨§¦¥¤££¢¡ŸŸ›š™—–•“’‘ŽŒ‹‰‡†„ƒ~|{yxvtsqpnmljihfedbb``^]\\[ZYXWWVUUTSSRQQQPPOONNNMMLLLLKJJJJJJIIIIHHHHGGGGGGGGGFFFFFFFEEEEEEEDDDDDDDDDDDCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»ººººººººº¹¹¹¹¹¹¸¸¸¸¸¸········¶¶¶µµµµ´´´´³³²²²²±°°°°¯®®­­¬¬««ª©©¨§¦¥¥¤£¢¡ Ÿžœ›š˜—–”“’ŒŠ‰‡†„ƒ~|{yxvusrpomlkihgedcba`_^]\[ZZYXWVVUTTSSRRQQPOOOONMMMMLLKKKKJJJJIIIHHHHHHHHGGGGGGFFFFFFEEEEEEEEEDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»ººººººººººººº¹¹¹¹¹¹¹¸¸¸¸·······¶¶¶¶¶¶µµ´´´´³³³³²±±±±°¯¯¯¯®­­­¬««ª©©¨§¦¦¥¤£¢¡ Ÿžœ›š™˜–•”’‘ŽŒŠ‰‡†„ƒ~|{yxvusrqonmkjigfedcba`_^]\[ZYYXWVVUTTSRRRQPPPPONNNNMLLLLKKKKJJIIIIIIHHHHHHHGGGGFFFFFFFEEEEEEEEEEEEEDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»ººººººººººººº¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸····¶¶¶¶¶¶µµµµµ´´³³³³²²²±±°°°¯®®®®­¬¬««ªª©¨§§¦¥¤££¢¡ Ÿžœ›™™—–•“’‘Ž‹Šˆ‡…„‚~}{zxwutrqpnmljihffdcba`_^]\\[ZYXXWVUUTTSSRQQQQPOOONNMMMLLLLKKJJJJJIIIIIIHHHHGGGGGGFFFFFFFFFFEEEEEEEEEEEEEDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»ºººººººººº¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸·····¶¶¶µµµµµµ´´´´³³²²²²±±°°°¯¯®®­­­¬««ª©©¨§§¦¥¤¤£¢¡ Ÿžžœ›š™˜—–”“’‘Ž‹Šˆ‡…„‚~}{zxwutrqpnmlkihgfedcaa`_^]\[[ZYXXWVVUTTSRRRQQPPOOONNMMMMLLKKKKJJJJJJIIIHHHHHGGGGGGGGGFFFFFFFFFEEEEEEEEEEDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»ºººººººººº¹¹¹¹¹¹¹¸¸¸¸¸¸¸········¶¶¶¶µµµ´´´´´³³³³²±±±±±°¯¯¯®®­­¬¬¬«ªª©¨¨§¦¥¥¤££¡¡ŸŸžœ›š™—–•”“’Œ‹‰ˆ‡…„‚~}{zxwvtsrpomlkjihfedcba``^^\\[ZZYXWWVUUTSSSRRQQPPPONNNNNMLLLLKKKKKJJJIIIIHHHHHHHHGGGGGGGFFFFFFFEEEEEEEEEEDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»ºººººººººººº¹¹¹¹¹¹¹¸¸¸¸¸······¶¶¶¶¶¶¶µµµµ´´³³³³³²²²±±°°°°¯¯®®­­¬¬«««©©©¨§¦¦¥¤¤¢¢¡ Ÿžœ›š™˜—–•“’‘ŽŒ‹‰ˆ†…„‚~}{zywvtsrqonmljihgfedcba`_^]][[ZYYXWVVVTTTSSRRQQPPOOOONNMMMLLLLLKKJJJJIIIIIIIHHHHHHGGGGGFFFFFFFEEEEEEEEEEEEDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»ººººººººººººº¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸·····¶¶¶¶¶µµµµµµ´´´³³³²²²²±±±°°¯¯¯¯®­­¬¬««ªª©¨¨§§¦¥¥££¢¡¡ŸŸžœ›š™˜—•”“’‘ŽŒŠ‰ˆ†…„‚~}{zywvusrqpnmlkjhgfedcba``^^]\\ZZYXXWWVUUTTSSRRQPPPPOONNNMMMMLLLKKKJJJJJJIIIIIHHHHHGGGGGGFFFFFFFFFFEEEEEEEEEEEEEDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»ººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸·······¶¶¶¶µµµµ´´´´´³³³³²²±±±±°°¯¯®®®®­¬¬««ª©©©¨§§¦¥¤¤£¢¢¡ Ÿžœ››™˜—–•”“‘ދЉ‡†…ƒ‚~}|zyxvutrqponlkjihgfddcba`_^]]\[[ZYXXWVVVUTTSSRQQQQPPOONNNNMMLLLLKKKKKJJJJIIIIHHHHHHHGGGGGGGGFFFFFFFFFFFEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»ºººººººººººº¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸········¶¶¶¶¶¶¶µµµ´´´³³³³³²²²²±±°°°¯¯¯®­­­­¬««ªª©¨¨¨§¦¥¥¤££¢¡ Ÿžžœ›š™˜—–•”’‘ŽŒ‹Š‰‡†…ƒ‚~}|zyxvutsqponmkjihgfedcbaa`_^]\\[ZZYXWWWVUUTTSRRRRQPPPOOONNMMMMLLLLLKKKJJJIIIIIIIHHHHHHHHGGGGGGGFFFFFFFFFEEEEEEEEEEEEDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»ºººººººººººº¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸······¶¶¶¶¶¶¶µµµµµµ´´´³³³²²²²±±±±°¯¯¯¯®®­­¬¬¬«ªª©©¨§§¦¦¥¤¤£¢¢¡ Ÿžœ›šš˜˜–•”“’‘Œ‹Šˆ‡†…ƒ‚~}|zyxwutsrponmlkjiggeedcba`_^]]\[[ZYYXXWVVUUTSSSRRQQPPPPONNNNMMMMLLLKKKJJJJJJIIIIIIIHHHHHHGGGGGGFFFFFFFFFEEEEEEEEEEEEDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»ºººººººººººº¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸······¶¶¶¶µµµµµµ´´´´´³³³³²²±±±±°°°¯¯®®®­­­¬«««ªª©¨¨§¦¦¥¥¤££¢¡ Ÿžžœ›š™˜—–•”“’‘ŽŒ‹Šˆ‡†…ƒ‚~}|zyxwutsrqpnmlkjihgfedcbaa`_^]\\[ZZYYXWWVUUTTTSRRRQQQPPOOONNNNMMLLLLKKKKKJJJJJJIIIIHHHHHHGGGGGGGFFFFFFFFFFEEEEEEEEEEEEDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»ººººººººººººº¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸········¶¶¶¶µµµµ´´´´³³³³³²²²²±±°°°°¯¯¯®®­­¬¬¬«ªª©©©¨§§¦¥¤¤¤£¢¡¡ŸŸžœœšš™——–””’‘ŽŒ‹‰ˆ‡†„ƒ‚~}|{yxwvtsrqponmkkihhfeeccba``^^]\[[[ZYXXWVVVUUTSSSRRQQPPPOOOONNMMMMLLLLLKKKKJJJJIIIIHHHHHHHHGGGGGGGGGFFFFFFFFFFEEEEEEEEEEEEEDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»ºººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸········¶¶¶¶¶¶¶µµµµµ´´´´³³³²²²²±±±±°°¯¯¯®®®®­¬¬«««ªª©¨¨¨§¦¥¥¤££¢¢¡ Ÿžœ›š™˜—–•”“’‘ŽŒŠ‰ˆ‡†„ƒ‚~}|{yxwvusrqponmlkjihgfedcbba`_^]]\\[ZZYXWWWVUUTTTSSRQQQQPPPOONNNNMMMMLLLKKKKJJJJJIIIIIIIHHHHHHHHGGGGGGGGFFFFFFFFFFFEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»ºººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸·······¶¶¶¶¶µµµµµµµ´´´´´³³³³²²²±±±°°°°¯¯®®­­­­¬¬«ªªª©©¨§§¦¦¥¤¤£¢¢¡¡ŸŸžœ››š™˜—–•”“’‘Œ‹Š‰ˆ‡…„ƒ‚~}|{zxwvutsrponmlkjihgfeddcba``^^]]\[[ZYYXXWVVUUUTSSRRRRQQPPOOOONNNMMMLLLLKKKKKJJJJJJJIIIIIHHHHHHHGGGGGGGFFFFFFFFFFFEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»ºººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸·······¶¶¶¶¶µµµµµ´´´´³³³³³²²²²²±±°°°¯¯¯¯®®­­¬¬¬««ªª©©¨¨§¦¦¥¥¤££¢¡  Ÿžœ›š™˜——–””“‘ŽŒ‹Š‰ˆ†…„ƒ‚~}|{zywvutsrqponlkkihhgfedcbba`__^]\\[ZZYYXWWVVUUTTSSSRRQQPPPPOOONNMMMMMLLLLLKKKKJJJJJIIIIIHHHHHHHGGGGGGGFFFFFFFFFFFEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»ºººººººººººº¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸········¶¶¶¶¶¶¶µµµµµ´´´³³³³²²²²±±±±±°°¯¯¯®®®­­­¬¬«ªªª©©¨§§§¦¦¥¤¤£¢¡¡ Ÿžžœ››š™˜—–•”“’‘ŽŒ‹Š‰‡†…„ƒ‚~}|{zyxvutsrqponmlkjihgfeddcbaa`_^^]\[[ZYYXXXWVVUUUTSSRRRQQQPPPOONNNNNMMMMLLLLKKKJJJJJIIIIIIIHHHHHHHHGGGGGGGGFFFFFFFFFFFEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»ººººººººººººº¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸········¶¶¶¶¶¶¶µµµµµµµ´´´´´³³³³²²²±±±°°°°¯¯¯¯®®­­¬¬¬««ªª©©¨¨§§¦¥¥¥¤£¢¢¡ ŸŸžœœ›š™™˜—–•”“’‘ŽŒ‹Šˆ‡†…„ƒ‚~}|{zyxwutsrqponmlkjihgffedccba``_^]]\[ZZZYXXWWVVUUTTSSSRRQQPPPPOOOONNNMMMLLLLKKKKKJJJJJJJIIIIIIIHHHHHHHHGGGGGGGGGFFFFFFFFFFEEEEEEEEEEEEEDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»ºººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸········¶¶¶¶¶¶µµµµµ´´´´´³³³³³²²²²²±±±°°¯¯¯¯®®®­­­¬«««ªªª©¨¨§§¦¦¥¤¤££¢¡¡ ŸŸžœ›šš™˜—––”““’‘Ž‹‹‰ˆ‡†…„ƒ‚~}|{zyxwvttrqponmllkiihgfeedcba``_^^]\\[[ZYYXXWWVUUUTTTSRRRQQQPPPPOONNNMMMMMLLLLLKKKKKJJJJJIIIIIIHHHHHHHHGGGGGGGGGFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸········¶¶¶¶¶¶µµµµµ´´´´³³³³²²²²±±±±±°°°¯¯¯®®­­­¬¬¬««ªª©©©¨¨§¦¦¥¥¤¤£¢¢¡ ŸŸžžœ›š™˜˜—–•”“’‘ŽŒ‹Š‰ˆ‡†…„ƒ‚~}|{zyxwvutsrqponmlkjihggfedcbaa``_^]]\[[ZZYYXWWVVVUUTTSSSRRRQQPPPOOONNNNNMMMMLLLLKKKKJJJJJIIIIIIHHHHHHHHGGGGGGGGGFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººº¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸········¶¶¶¶¶¶¶µµµµµµ´´´´´³³³³²²²±±±±°°°¯¯¯¯®®®­­¬¬««««ªª©©¨§§§¦¦¥¤¤££¢¡  ŸŸžœœ›š™˜—––•”“’‘ŽŒ‹Š‰ˆ‡†…„ƒ‚~}|{zyxwvutsrqponmlkjiihgfedccba``__^]\\[[ZYYXXXWVVUUTTTTSSRRQQQPPPPOOONNNNMMMLLLLKKKKKJJJJJJIIIIIIIHHHHHHHHGGGGGGGGGFFFFFFFFFFEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»ººººººººººººº¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸·········¶¶¶¶¶¶µµµµµµ´´´´´´³³³³³²²²²²±±±±°°¯¯¯®®®­­­­¬¬««ªª©©©¨¨§§¦¥¥¥¤££¢¡¡ ŸŸžœ›šš™˜—–•”““’‘ŽŒ‹Š‰ˆ‡†…„ƒ‚~}|{zyxwvutsrqponmllkjihgfeedcbba``_^^]\\[ZZZYXXWWVVVUUTTSSRRRRQQQPPPOONNNNMMMMMLLLLLKKKKKKJJJJJJIIIIIIHHHHHHHHHGGGGGGGGGFFFFFFFFFFEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»ºººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸·········¶¶¶¶¶¶µµµµµµ´´´´´³³³³²²²²±±±±±°°°°¯¯¯®®®­­¬¬¬«««ªª©©¨¨§§¦¦¥¥¤£££¢¡  ŸŸžœœ›š™˜˜—–•”“’‘ŽŒ‹Š‰ˆ‡†…„ƒ‚~}|{zyxwvutsrqpponmlkjihggfedccba``__^]\\\[ZZYYXXWWVVUUTTTSSSRRQQQPPPOOOONNNNNMMMMLLLLKKKKKJJJJJJIIIIIIHHHHHHHHHGGGGGGGGGGFFFFFFFFFFFFFEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»ºººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸········¶¶¶¶¶¶¶µµµµµµ´´´´´³³³³²²²²±±±°°°¯¯¯¯®®®®­­­¬¬««ªªª©©©¨§§¦¦¥¥¤¤£¢¢¡¡ ŸŸžœ›š™™˜—–••”“’‘ŽŒ‹‹Š‰ˆ‡†…„ƒ‚~}|{zyxwvuttsrqponmlkjjihgffedcbba``_^^]]\[[ZZYYXXWVVVUUUTTSSRRRQQQQPPPPOOONNNMMMMLLLLKKKKKJJJJJJIIIIIIIHHHHHHHHGGGGGGGGGGFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸········¶¶¶¶¶¶¶µµµµµµµ´´´´´³³³³³²²²²²±±±±°°°¯¯¯®®®­­­¬¬¬«««ªª©©¨¨§§§¦¦¥¤¤££¢¢¡ ŸŸžžœ››š™™˜—–••”“’‘ŽŒ‹Š‰ˆ‡†…„ƒ‚€~}|{zyxwvutsrqponmlkjjihgffeddcbaa``_^]]\\[[ZYYXXXWWVVUUTTTSSSRRRQQQPPPOOONNNNMMMMMLLLLLKKKKKJJJJJJJIIIIIIIHHHHHHHHGGGGGGGGFFFFFFFFFFFEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººº¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸·········¶¶¶¶¶¶¶¶µµµµµµ´´´´´³³³³³²²²²±±±±±°°°°¯¯¯¯®®®­­­¬¬««ªªª©©©¨¨§§¦¥¥¥¤¤£¢¢¡¡ ŸŸžœœ››š™˜——–•”“’’‘ŽŒ‹Š‰ˆ‡†…„ƒ‚€~}|{zyxwvutsrqponmmlkjihhgfeddccba``_^^]]\[[ZZZYXXWWVVVUUUTTSSRRRQQQPPPPOOOONNNNNMMMMLLLLLKKKKKJJJJJJIIIIIIIIHHHHHHHHHGGGGGGGGGGFFFFFFFFFFEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸·········¶¶¶¶¶¶¶¶µµµµµµ´´´´´³³³³³²²²²±±±±°°°¯¯¯¯®®®­­­­¬¬¬««ªª©©¨¨¨§§¦¦¥¥¤£££¢¢¡ ŸŸžžœœ›š™™˜—–••”“’‘ŽŒ‹Š‰ˆ‡†…„ƒ‚€~}|{zyxwvutsrqpponmlkjjihgffedccbaa``_^]]\\\[ZZYYXXWWWVVUUTTSSSRRRRQQQPPPPOOONNNNMMMMLLLLLKKKKKJJJJJJIIIIIIIIHHHHHHHHHGGGGGGGGGGGFFFFFFFFFFFFFEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»ºººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸·······¶¶¶¶¶¶¶µµµµµµµ´´´´´³³³³³²²²²²±±±±±°°°¯¯¯¯®®­­­¬¬¬«««ªªª©©¨¨§§¦¦¥¥¤¤££¢¢¡  ŸŸžœ››š™˜——–••”“’‘ŽŒ‹Š‰ˆ‡†…„ƒ‚€~}|{zyxwvutsrqpponmlkjjihhgfeddcbba``__^]]\\[[ZZYYXXWWVVUUUTTTSSSRRRQQPPPPOOONNNNNMMMMMLLLLLKKKKKJJJJJJJIIIIIIIHHHHHHHGGGGGGGGGGGFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»ºººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸········¶¶¶¶¶¶¶µµµµµµµ´´´´´´³³³³³²²²²²±±±±°°°°¯¯¯¯®®®®­­­¬¬¬««ªª©©©¨¨§§§¦¦¥¥¤££¢¢¡¡ ŸŸžœœ›š™™˜——–•”“’’‘ŽŒŒ‹Š‰ˆ‡†…„ƒ‚€~}|{zyxwvutssrqponmmlkjihhgffedccbba``_^^]]\\[ZZYYXXXWWVVVUUTTSSSRRRQQQQPPPPOOOONNNNMMMMMLLLLLKKKKKKJJJJJJJIIIIIIIHHHHHHHHGGGGGGGGGFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸··········¶¶¶¶¶¶¶¶µµµµµµµ´´´´´´³³³³³²²²²²±±±±°°°¯¯¯¯®®®­­­¬¬¬«««ªªª©©¨¨§§¦¦¥¥¥¤¤££¢¡¡  ŸŸžœ›šš™™˜—–••”“’’‘ŽŒ‹ŠŠ‰ˆ‡†…„ƒ‚€~}|{zyxwvuutsrqponmmlkjjihgffeedcbba``__^^]\\[[ZZZYYXXWWVVUUUTTTSSSRRRQQQPPPPOOONNNNMMMMMLLLLLKKKKKKJJJJJJJIIIIIIIIHHHHHHHHHHGGGGGGGGGGFFFFFFFFFFEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸··········¶¶¶¶¶¶¶µµµµµµµ´´´´´³³³³³²²²²²±±±±±°°°°¯¯¯¯®®®­­­¬¬«««ªª©©©¨¨¨§§¦¦¥¥¤¤££¢¢¡¡ ŸŸžœœ›šš™˜——–•””“’‘ŽŒ‹ŠŠ‰ˆ‡†…„ƒ‚€~}|{zyxwvuutsrqpponmlkkjihhgfeedccbba``_^^]]\\[[ZZYYXXWWWVVVUUTTTSSRRRQQQPPPPOOOONNNNNMMMMMLLLLLKKKKKJJJJJJJIIIIIIIHHHHHHHHHHGGGGGGGGGGGGFFFFFFFFFFFFFEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸········¶¶¶¶¶¶¶µµµµµµ´´´´´´´³³³³³²²²²²±±±±±°°°¯¯¯¯®®®®­­­­¬¬¬«««ªª©©©¨¨§§¦¦¥¥¤¤¤££¢¡¡ ŸŸžžœ››š™˜˜—––•”““’‘ŽŽŒ‹Š‰‰ˆ‡†…„ƒ‚€~}|{zyxwvvutsrqqponmllkjiihggfeddcbbaa``_^^]\\[[[ZZYYXXWWVVVUUTTTSSSRRRRQQQQPPPPOOONNNNNMMMMMLLLLLKKKKKKKJJJJJJIIIIIIIHHHHHHHHGGGGGGGGGGGFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸·········¶¶¶¶¶¶¶¶¶µµµµµµµ´´´´´´´³³³³³²²²²²±±±±±°°°¯¯¯¯®®®­­­¬¬¬«««ªªª©©©¨¨§§§¦¦¥¥¤¤£¢¢¡¡  ŸŸžžœ››šš™˜˜—–••”“’‘‘ŽŽŒ‹Š‰ˆ‡‡†…„ƒ‚€~}|{zyxxwvutsrqqponnmlkjjihggfeeddcbaa``__^^]]\[[ZZYYXXXWWVVVUUUTTTSSSRRRQQQPPPPOOONNNNNMMMMMLLLLLKKKKKKKJJJJJJJIIIIIIIIIHHHHHHHHHGGGGGGGGFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸···········¶¶¶¶¶¶¶¶¶µµµµµµµ´´´´´³³³³³²²²²²±±±±±°°°°¯¯¯¯®®®®­­­¬¬¬«««ªª©©©¨¨§§¦¦¥¥¥¤¤££¢¢¡¡ ŸŸžžœ››š™™˜—––•””“’‘‘ŽŒŒ‹Š‰ˆ‡‡†…„ƒ‚€~}|{zyxxwvutssrqponnmlkkjiihgffeddcbbaa``_^^]]\\[[ZZZYYXXWWVVVUUTTTSSSRRRQQQQPPPPOOOONNNNNMMMMMLLLLLKKKKKJJJJJJJIIIIIIIIIHHHHHHHHHHHGGGGGGGGGGFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸··········¶¶¶¶¶¶¶µµµµµµ´´´´´´³³³³³³²²²²²²±±±±°°°°¯¯¯¯®®®®­­­¬¬¬«««ªªª©©©¨¨¨§§¦¦¥¥¤¤££¢¢¡¡  ŸŸžžœœ›šš™˜˜—––•”““’‘ŽŒ‹‹Š‰ˆ‡††…„ƒ‚€~}|{zyyxwvuttsrqpponmllkjiihggfeedccbaa``__^^]]\\[[ZZYYXXWWWVVVUUUTTTSSSRRRQQQQPPPPOOOONNNNMMMMMMLLLLLLKKKKKKJJJJJJIIIIIIIHHHHHHHHHHGGGGGGGGGGGGGFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸········¶¶¶¶¶¶¶¶µµµµµµµµ´´´´´´³³³³³³²²²²²²±±±±°°°°¯¯¯¯®®®®­­­¬¬¬«««ªªª©©¨¨§§§¦¦¥¥¤¤¤££¢¢¡¡ ŸŸžžœœ››š™™˜——–••”“’’‘ŽŽŒ‹ŠŠ‰ˆ‡†……„ƒ‚€~}|{zzyxwvuutsrqqponmmlkjjihhgffeddccbaa``_^^]]\\[[[ZZYYXXXWWVVUUUTTTSSSRRRQQQQPPPPOOOONNNNMMMMMMLLLLLLKKKKKKJJJJJJJJIIIIIIIIHHHHHHHHGGGGGGGGGGGGFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸··········¶¶¶¶¶¶¶¶¶¶µµµµµµµµ´´´´´³³³³³²²²²²±±±±±°°°°¯¯¯¯®®®®­­­¬¬¬¬«««ªªª©©©¨¨§§§¦¦¥¥¤¤££¢¢¡¡  ŸŸžœœ›šš™˜˜—––•”““’‘‘ŽŽŒ‹ŠŠ‰ˆ‡†……„ƒ‚€~}|{zzyxwvuutsrqqponnmllkjiihggfeedccbba``__^^]]\\[[ZZYYXXXWWVVVUUUTTTSSSSRRRQQQQPPPPOOOONNNNNMMMMMLLLLLKKKKKJJJJJJJJIIIIIIIIIIHHHHHHHHHHGGGGGGGGGFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸············¶¶¶¶¶¶¶¶µµµµµµ´´´´´´³³³³³³²²²²²²±±±±±°°°°¯¯¯¯¯®®®­­­­¬¬¬«««ªªª©©¨¨¨§§¦¦¥¥¥¤¤£££¢¢¡¡ ŸŸžžœ››š™™˜——––•”““’‘‘ŽŒ‹Š‰‰ˆ‡†…„„ƒ‚€~}|{{zyxwvvutsrrqponnmllkjiihhgffeddcbbaa``_^^]]\\\[[ZZZYYXXWWWVVUUUTTTSSSRRRRQQQPPPPPOOOONNNNNMMMMMMLLLLLLKKKKKKJJJJJJIIIIIIIIHHHHHHHHHHHHGGGGGGGGGGGFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸··········¶¶¶¶¶¶¶µµµµµµµµ´´´´´´´³³³³³³²²²²²²±±±±±°°°°¯¯¯¯®®®­­­­¬¬¬«««ªªª©©©¨¨¨§§¦¦¥¥¥¤¤££¢¢¡¡ ŸŸžžœœ›šš™™˜——–••”“’’‘ŽŒŒ‹Š‰‰ˆ‡†…„„ƒ‚€~}|{{zyxwvvutssrqpponmmlkjjihhgffeedccbbaa``_^^]]\\[[ZZZYYXXWWWVVVUUUTTTSSSRRRRQQQPPPPOOOONNNNNMMMMMMLLLLLLKKKKKKKJJJJJJJJIIIIIIIHHHHHHHHHHGGGGGGGGGGGGGGFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸········¶¶¶¶¶¶¶¶¶¶µµµµµµµµµ´´´´´´³³³³³²²²²²±±±±±°°°°¯¯¯¯¯®®®®­­­¬¬¬¬«««ªªª©©©¨¨§§§¦¦¥¥¤¤¤££¢¢¡¡  ŸŸžžœ››šš™˜˜—––•””“’‘‘ŽŒ‹‹Š‰ˆˆ‡†…„„ƒ‚€~}|{{zyxwwvuttsrqpponnmlkkjiihggfeeddcbbaa``__^^]]\\[[[ZZYYXXXWWVVVUUUTTTSSSSRRRQQQQPPPPPOOOONNNNNMMMMMLLLLLKKKKKKJJJJJJJJJIIIIIIIIIIHHHHHHHHGGGGGGGGGGGGFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸············¶¶¶¶¶¶¶¶¶¶µµµµµµ´´´´´´³³³³³³³²²²²²±±±±±±°°°°¯¯¯¯¯®®®®­­­¬¬¬¬«««ªªª©©©¨¨§§§¦¦¥¥¤¤£££¢¢¡¡ ŸŸžžœœ›šš™™˜——–••”““’‘ŽŽŒ‹‹Š‰ˆ‡‡†…„ƒƒ‚€~}||{zyxxwvuttsrqqpoonmllkjjihhgffeedccbbaa``_^^]]\\\[[ZZYYXXXWWVVVUUUTTTSSSSRRRQQQQPPPPPOOOONNNNNNMMMMMLLLLLLLKKKKKKJJJJJJIIIIIIIIIIHHHHHHHHHHHHGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸·············¶¶¶¶¶¶¶µµµµµµµ´´´´´´´´³³³³³³³²²²²²±±±±±°°°°¯¯¯¯®®®­­­­¬¬¬««««ªªª©©©¨¨§§§¦¦¦¥¥¤¤£££¢¢¡¡  ŸŸžžœ››šš™™˜——–••”““’‘ŽŒ‹ŠŠ‰ˆ‡‡†…„ƒƒ‚€~}||{zyxxwvuutsrrqpoonmllkjjihhgffeeddcbbaa``__^^]]\\\[[ZZYYYXXXWWVVVUUUTTTTSSSRRRRQQQPPPPOOOONNNNNMMMMMLLLLLLLKKKKKKKKJJJJJJJIIIIIIIHHHHHHHHHHHHHGGGGGGGGGGGFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·········¶¶¶¶¶¶¶¶¶µµµµµµµµµ´´´´´´´³³³³³²²²²²±±±±±°°°°°¯¯¯¯¯®®®®­­­­¬¬¬««««ªªª©©©¨¨§§§¦¦¦¥¥¤¤££¢¢¡¡¡ ŸŸžžœœ››š™™˜——––•””“’’‘ŽŒ‹ŠŠ‰ˆ‡‡†…„ƒƒ‚€~}||{zyxxwvuutsrrqpponmmlkkjiihhgffeddccbbaa``_^^^]]\\[[ZZYYYXXXWWVVVUUUTTTTSSSRRRRQQQQPPPPPOOOOONNNNNMMMMMLLLLLKKKKKKKJJJJJJJJJIIIIIIIIIHHHHHHHHHGGGGGGGGGGGGGGGFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸·········¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµ´´´´´³³³³³³³²²²²²²±±±±±°°°°°¯¯¯¯®®®®­­­­¬¬¬«««ªªª©©©¨¨¨§§§¦¦¥¥¥¤¤££¢¢¡¡  ŸŸžžœœ››šš™˜˜——–••”““’‘‘ŽŒŒ‹Š‰‰ˆ‡††…„ƒƒ‚€~}||{zyyxwvvutssrqpponnmllkjjihhggfeeddccbbaa``__^^]]\\[[ZZZYYXXXWWWVVVUUUTTTSSSRRRRQQQQPPPPOOOOONNNNNMMMMMMLLLLLLLKKKKKJJJJJJJJIIIIIIIIIIIHHHHHHHHHGGGGGGGGGGGGGFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸·············¶¶¶¶¶¶¶¶¶µµµµµµ´´´´´´´´³³³³³³³³²²²²²±±±±±°°°°¯¯¯¯®®®®®­­­­¬¬¬««««ªªª©©©¨¨¨§§§¦¦¥¥¥¤¤££¢¢¡¡  ŸŸžžœœ››šš™˜˜——–••”““’‘ŽŽŒŒ‹Š‰‰ˆ‡††…„ƒƒ‚€~}||{zyyxwvvutssrqqpoonmllkjjihhggfeeddccbbaa``__^^]]\\[[ZZZYYXXXWWWVVVUUUTTTTSSSRRRRQQQQQPPPPOOOONNNNNMMMMMLLLLLLLLKKKKKKKKJJJJJJIIIIIIIIIHHHHHHHHHHHHHGGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸·············¶¶¶¶¶¶µµµµµµµµµµ´´´´´´´´³³³³³²²²²²±±±±±±°°°°°¯¯¯¯¯®®®®®­­­¬¬¬««««ªªª©©©¨¨§§§¦¦¦¥¥¤¤¤££¢¢¡¡  ŸŸŸžœœ››šš™™˜——––•””“’’‘ŽŒ‹‹Š‰‰ˆ‡††…„ƒƒ‚€~}||{zyyxwvvuttsrrqpoonmmlkkjiihhgffeeddccbba```__^^]]\\[[[ZZYYYXXXWWVVVUUUTTTTSSSRRRQQQQQPPPPPOOOOONNNNNNMMMMMLLLLLKKKKKKKKJJJJJJJJJJIIIIIIHHHHHHHHHHHHHGGGGGGGGGGGGFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·········¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµ´´´´´³³³³³³³²²²²²²±±±±±±°°°°°¯¯¯¯®®®­­­­¬¬¬¬««««ªªª©©©¨¨¨§§§¦¦¦¥¥¤¤¤££¢¢¡¡  ŸŸžžœœ››š™™˜˜—––••”““’‘‘ŽŒ‹‹Š‰ˆˆ‡†……„ƒ‚‚€~}}|{zzyxwwvuttsrrqpponnmllkjjiihggffeddccbbaa``__^^]]\\[[[ZZYYYXXXWWWVVVUUUTTTTSSSSRRRRQQQPPPPOOOOONNNNNNMMMMMMLLLLLLLKKKKKJJJJJJJJJJIIIIIIIIIIHHHHHHHHHGGGGGGGGGGGGGGGGFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸···········¶¶¶¶¶¶¶¶¶¶¶µµµµµµ´´´´´´´´³³³³³³³³²²²²²±±±±±°°°°¯¯¯¯¯®®®®®­­­­¬¬¬¬«««ªªª©©©¨¨¨§§¦¦¦¥¥¥¤¤£££¢¢¡¡  ŸŸŸžžœ››šš™™˜˜—––•””“’’‘‘ŽŒ‹ŠŠ‰ˆˆ‡†……„ƒ‚‚€~}}|{zzyxwwvuutsrrqpponnmmlkkjiihggffeeddcbbaa```__^^]]\\\[[ZZZYYYXXWWWVVVUUUTTTSSSSRRRRQQQQQPPPPPOOOONNNNNMMMMMLLLLLLLLKKKKKKKKJJJJJJIIIIIIIIIIIHHHHHHHHHHHGGGGGGGGGGGGGGFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸···············¶¶¶¶¶¶¶¶µµµµµµµµ´´´´´´´´´³³³³³²²²²²²±±±±±±°°°°°¯¯¯¯¯®®®®­­­¬¬¬¬««««ªªª©©©¨¨¨§§§¦¦¦¥¥¥¤¤££¢¢¢¡¡  ŸŸžžœœ››š™™˜˜——––•””“’’‘ŽŽŒŒ‹ŠŠ‰ˆ‡‡†……„ƒ‚‚€~}}|{zzyxxwvuutssrqqpoonmmlkkjiihhggffeddccbbaa``__^^]]]\\[[ZZZYYYXXXWWWVVVUUUTTTTSSSSRRRQQQQPPPPPOOOOONNNNNNMMMMMMLLLLLKKKKKKKKKJJJJJJJJIIIIIIIIHHHHHHHHHHHHHHHGGGGGGGGGGFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸············¶¶¶¶¶¶¶¶¶µµµµµµµµµµ´´´´´´³³³³³³³²²²²²²²±±±±±°°°°°¯¯¯¯®®®®­­­­­¬¬¬¬««««ªªª©©©¨¨§§§¦¦¦¥¥¤¤¤£££¢¢¡¡  ŸŸŸžžœœ›šš™™˜——––••”““’’‘ŽŽŒŒ‹Š‰‰ˆ‡‡†……„ƒ‚‚€~}}|{zzyxxwvvutssrqqpoonmmllkjjiihhgffeedccbbaa```__^^]]\\\[[[ZZYYYXXXWWVVVUUUTTTTSSSSRRRRRQQQQPPPPOOOOONNNNNMMMMMMMLLLLLLLKKKKKKJJJJJJJJJJIIIIIIIIIHHHHHHHHHHHHGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAA¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·········¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµ´´´´´´´´³³³³³³³³²²²²²±±±±±°°°°°¯¯¯¯¯¯®®®®­­­­¬¬¬««««ªªª©©©©¨¨¨§§§¦¦¦¥¥¤¤¤££¢¢¡¡  ŸŸŸžžœœ››šš™™˜——––•””““’‘‘ŽŒ‹‹Š‰‰ˆ‡‡†…„„ƒ‚‚€~}}|{{zyxxwvvuttsrrqpponnmllkkjiihhgffeeddccbbaa```__^^]]\\[[[ZZYYYXXXWWWVVVVUUUTTTTSSSRRRRQQQQPPPPPPOOOOONNNNNMMMMMLLLLLLLLKKKKKKKKJJJJJJJIIIIIIIIIIIIHHHHHHHHHGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAA½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸············¶¶¶¶¶¶¶¶¶¶µµµµµµµ´´´´´´´´´´³³³³³²²²²²²±±±±±±±°°°°°¯¯¯¯®®®®­­­­¬¬¬¬¬««««ªªª©©©¨¨¨§§¦¦¦¥¥¥¤¤¤££¢¢¢¡¡  ŸŸŸžœœ››šš™™˜˜——–••””“’’‘‘ŽŒ‹‹Š‰‰ˆ‡‡†…„„ƒ‚‚€~}}|{{zyxxwvvuttsrrqpponnmmlkkjjihhggffeeddccbba```__^^]]]\\[[[ZZZYYYXXWWWVVVUUUTTTTSSSSSRRRRQQQQPPPPOOOOONNNNNNNMMMMMMLLLLLKKKKKKKKKJJJJJJJJIIIIIIIIIIHHHHHHHHHHHHGGGGGGGGGGGGGGGFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸···············¶¶¶¶¶¶¶¶µµµµµµµµµµ´´´´´´´³³³³³³³²²²²²²²±±±±±±°°°°¯¯¯¯¯®®®®®­­­­¬¬¬¬«««ªªª©©©©¨¨¨§§§¦¦¦¥¥¥¤¤££¢¢¢¡¡  ŸŸŸžžœœ››šš™˜˜——––••”““’’‘ŽŽŒ‹‹Š‰‰ˆ‡††…„„ƒ‚‚€~}}|{{zyyxwvvuttsrrqqpoonmmllkjjiihhggfeeddccbbaa```__^^]]]\\[[ZZZYYYXXXWWWVVVVUUUTTTSSSSRRRRQQQQQPPPPPOOOONNNNNNMMMMMMMLLLLLLLKKKKKKJJJJJJJJJJJIIIIIIIIHHHHHHHHHHHHHHHGGGGGGGGGGGFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸············¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµ´´´´´´´³³³³³³³³³²²²²²±±±±±°°°°°°¯¯¯¯¯¯®®®®­­­¬¬¬¬«««««ªªª©©©©¨¨§§§¦¦¦¥¥¥¤¤£££¢¢¢¡¡  ŸŸžžœœ››šš™™˜˜——–••””““’‘‘ŽŽŒŒ‹ŠŠ‰ˆˆ‡††…„„ƒ‚‚€~}}|{{zyyxwwvuutssrqqpponnmllkkjjihhggffeeddccbbaa``__^^]]]\\\[[ZZZYYYXXXWWVVVVUUUTTTTTSSSSRRRQQQQPPPPPPOOOOOONNNNNMMMMMLLLLLLLLLKKKKKKKJJJJJJJJIIIIIIIIIIIHHHHHHHHHHHHGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·········¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµ´´´´´´´´´³³³³³³²²²²²²²±±±±±±°°°°°¯¯¯¯®®®®®­­­­­¬¬¬¬««««ªªª©©©¨¨¨§§§§¦¦¦¥¥¤¤¤££¢¢¢¡¡  ŸŸŸžžœœ››šš™™˜˜——–••””“’’‘‘ŽŒŒ‹ŠŠ‰ˆˆ‡††…„„ƒ‚‚€~}}|{{zyyxwwvuutssrrqpponnmmlkkjjihhggffeeddccbbaa```__^^]]]\\[[[ZZYYYXXXXWWWVVVUUUTTTTSSSSRRRRRQQQQQPPPPOOOOONNNNNNMMMMMMMLLLLLLKKKKKKKKKJJJJJJJIIIIIIIIIIIIHHHHHHHHHHGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·············¶¶¶¶¶¶¶¶¶µµµµµµµµµµµ´´´´´´´³³³³³³³²²²²²²²²±±±±±°°°°¯¯¯¯¯¯®®®®®­­­­¬¬¬««««ªªªª©©©©¨¨¨§§¦¦¦¥¥¥¤¤¤£££¢¢¢¡¡  ŸŸžžœœœ››šš™˜˜——––••””“’’‘ŽŒ‹‹Š‰‰ˆˆ‡††…„„ƒ‚‚€~}}|{{zyyxwwvvuttsrrqppoonmmlkkjjiihhggfeeddcccbbaa``__^^]]]\\\[[[ZZZYYYXXWWWVVVVUUUUTTTTSSSRRRRQQQQQPPPPPPOOOONNNNNMMMMMMMMLLLLLLLKKKKKKKJJJJJJJJJJJIIIIIIIIHHHHHHHHHHHHHHGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸···············¶¶¶¶¶¶¶¶¶µµµµµµµµµµ´´´´´´´³³³³³³³³³²²²²²±±±±±±°°°°°°¯¯¯¯¯®®®®­­­­­¬¬¬¬««««ªªª©©©¨¨¨¨§§§¦¦¦¥¥¥¤¤£££¢¢¡¡¡  ŸŸŸžžœœ››šš™™˜˜——–••””““’‘‘ŽŒ‹‹Š‰‰ˆ‡‡†……„ƒƒ‚€~~}||{zzyxxwvvuttsrrqppoonnmllkkjjihhggffeeddccbbaa```__^^^]]\\\[[ZZZYYYXXXWWWWVVVUUUTTTTSSSSRRRRRQQQQPPPPPOOOOOONNNNNNMMMMMLLLLLLLLLKKKKKKKJJJJJJJJJJIIIIIIIIIHHHHHHHHHHHHHHHGGGGGGGGGGGGFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸···········¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµ´´´´´´´´´´³³³³³³²²²²²²²±±±±±±±°°°°¯¯¯¯¯®®®®®®­­­­¬¬¬¬«««ªªªª©©©©¨¨¨§§§¦¦¦¥¥¥¤¤¤£££¢¢¡¡  ŸŸŸžžœœ›šš™™˜˜——––••””““’‘‘ŽŽŒŒ‹‹Š‰‰ˆ‡‡†……„ƒƒ‚€~~}||{zzyxxwvvuttssrqqpponnmllkkjjiihhggffeedccbbbaa```__^^]]\\\[[[ZZZYYYXXXWWWVVVVUUUUTTTSSSSRRRRQQQQQQPPPPPOOOONNNNNNNMMMMMMMLLLLLLKKKKKKKKKKJJJJJJJIIIIIIIIIIIIIHHHHHHHHHHHGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··········¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµ´´´´´´´´³³³³³³³²²²²²²²²±±±±±°°°°°¯¯¯¯¯¯®®®®­­­­¬¬¬¬¬««««ªªªª©©¨¨¨¨§§§§¦¦¦¥¥¤¤¤£££¢¢¡¡¡  ŸŸžžœœ››šš™™˜˜——––••”““’’‘‘ŽŽŒŒ‹ŠŠ‰‰ˆ‡‡†……„ƒƒ‚€~~}||{zzyxxwvvuutssrqqpponnmmllkjjiihhggffeeddccbbbaa``__^^^]]\\\[[[ZZYYYXXXXWWWWVVUUUUTTTTSSSSSRRRRQQQQPPPPPPOOOOONNNNNMMMMMMMMLLLLLLLKKKKKKKKJJJJJJJJJJIIIIIIIIIIIHHHHHHHHHHGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··············¶¶¶¶¶¶¶¶¶µµµµµµµµµµµ´´´´´´´³³³³³³³³³²²²²²±±±±±±±°°°°°°¯¯¯¯®®®®®­­­­­¬¬¬¬«««ªªªªª©©©¨¨¨¨§§¦¦¦¥¥¥¥¤¤¤££¢¢¢¡¡  ŸŸŸžžœœ›››šš™™˜˜—––••””““’’‘ŽŒŒ‹ŠŠ‰‰ˆ‡‡†……„ƒƒ‚€~~}||{zzyxxwvvuutssrrqppoonmmllkkjjiihggffeedddccbbaa```__^^]]]\\[[[ZZZZYYYXXWWWWVVVUUUUUTTTSSSSRRRRRQQQQQPPPPOOOOOONNNNNNNMMMMMLLLLLLLLLKKKKKKKJJJJJJJJJJJIIIIIIIIIHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸··············¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµ´´´´´´´´´´³³³³³³²²²²²²²±±±±±±±°°°°°¯¯¯¯¯¯®®®®®­­­¬¬¬¬¬««««ªªªª©©©¨¨¨§§§§¦¦¦¥¥¥¤¤£££¢¢¢¡¡¡  ŸŸžžžœœ››šš™™˜˜——––••””““’‘‘ŽŒŒ‹ŠŠ‰ˆˆ‡‡†……„ƒƒ‚€~~}||{zzyxxwwvuutssrrqppoonnmllkkjjiihhggffeeddccbbaaa``__^^^]]]\\\[[ZZZYYYXXXXWWWVVVUUUUTTTTSSSSSRRRQQQQQPPPPPPOOOOONNNNNNNMMMMMMMLLLLLLKKKKKKKKKKJJJJJJJJIIIIIIIIIIIIHHHHHHHHHHHHHHGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸···········¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµ´´´´´´´´´³³³³³³³²²²²²²²²±±±±±°°°°°°¯¯¯¯¯¯®®®®­­­­­¬¬¬¬¬«««ªªªª©©©©¨¨¨§§§¦¦¦¥¥¥¤¤¤£££¢¢¡¡¡  ŸŸŸžžœœ›››šš™™˜˜——––••”““’’‘‘ŽŽŒ‹‹ŠŠ‰ˆˆ‡††……„ƒƒ‚€~~}||{zzyyxwwvuuttsrrqqpponnmmllkjjiihhggffeedddccbbaa```__^^^]]\\\[[[ZZZYYYXXXWWWVVVVUUUUTTTSSSSSRRRRRQQQQPPPPPPOOOOOONNNNNMMMMMMMMLLLLLLLKKKKKKKKKJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸············¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´³³³³³³³³³³²²²²²±±±±±±±±°°°°°¯¯¯¯¯®®®®®®­­­­¬¬¬¬««««ªªªªª©©¨¨¨¨§§§¦¦¦¦¥¥¤¤¤£££¢¢¢¡¡¡  ŸŸžžžœœ››šš™™™˜——––••””““’’‘‘ŽŽŒŒ‹‹Š‰‰ˆˆ‡††……„ƒƒ‚€~~}||{zzyyxwwvvuttssrqqpponnmmllkkjjiihhgfffeeddccbbaaa``__^^^]]]\\\[[[ZZYYYYXXXWWWWVVUUUUUTTTTSSSSRRRRQQQQQQPPPPPOOOOONNNNNNNNMMMMMLLLLLLLLLLKKKKKKJJJJJJJJJJJJIIIIIIIIIIHHHHHHHHHHHHGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸················¶¶¶¶¶¶¶¶¶µµµµµµµµµµ´´´´´´´´´³³³³³³³²²²²²²²²±±±±±±°°°°°¯¯¯¯¯¯¯®®®®­­­­­¬¬¬¬¬«««ªªªª©©©©¨¨¨¨§§¦¦¦¥¥¥¥¤¤¤££¢¢¢¡¡¡  ŸŸŸžžœœœ››šš™™˜˜——––••””““’‘‘ŽŽŒŒ‹‹Š‰‰ˆˆ‡††…„„ƒƒ‚€~~}||{{zyyxwwvvuttssrqqppoonnmllkkjjiihhggffeeddcccbbaa```__^^^]]]\\[[[ZZZZYYYXXWWWWVVVVUUUUTTTSSSSSRRRRRQQQQPPPPPPPOOOOONNNNNNMMMMMMMMLLLLLLLKKKKKKKKKJJJJJJJJJJIIIIIIIIIHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸··············¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµ´´´´´´´´´´³³³³³³³²²²²²²²²±±±±±°°°°°°°¯¯¯¯¯®®®®®­­­­­­¬¬¬««««ªªªªª©©©¨¨¨§§§§¦¦¦¥¥¥¤¤¤£££¢¢¢¡¡  ŸŸŸžžžœœ››ššš™˜˜———––•””““’’‘‘ŽŒŒ‹ŠŠ‰‰ˆ‡‡††…„„ƒƒ‚€~~}||{{zyyxxwvvuutssrrqppoonnmmllkkjiihhhggfeeeddccbbaaa```__^^]]]\\\[[[ZZZYYYXXXXWWWVVVUUUUUTTTTSSSRRRRRRQQQQQPPPPPOOOOOOONNNNNMMMMMMMMLLLLLLLKKKKKKKKKKJJJJJJJJIIIIIIIIIIIIIHHHHHHHHHHHHHHGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸············¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµ´´´´´´´³³³³³³³³³³²²²²²±±±±±±±±°°°°°¯¯¯¯¯¯®®®®®®­­­¬¬¬¬¬«««««ªªª©©©©¨¨¨¨§§§¦¦¦¥¥¥¤¤¤¤££¢¢¢¡¡¡  ŸŸžžžœœœ››šš™™˜˜——––••””““’’‘‘ŽŽŒŒ‹ŠŠ‰‰ˆ‡‡††…„„ƒƒ‚€~~}||{{zyyxxwvvuutssrrqqpponnmmllkkjjiihhggffeeddcccbbaaa``__^^^]]]\\[[[[ZZZYYYXXXWWWWVVVVUUUTTTTTSSSSSRRRQQQQQQPPPPPPOOOOONNNNNNNNMMMMMLLLLLLLLLLKKKKKKKJJJJJJJJJJJIIIIIIIIIIIIHHHHHHHHHHHHGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·············¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµ´´´´´´´´´³³³³³³³²²²²²²²²±±±±±±°°°°°°¯¯¯¯¯¯¯®®®®­­­­­¬¬¬¬««««ªªªªª©©©¨¨¨§§§§¦¦¦¦¥¥¤¤¤££££¢¢¡¡¡  ŸŸŸžžœœ›››š™™™˜˜——––••””““’’‘‘ŽŽŒ‹‹ŠŠ‰ˆˆ‡‡††…„„ƒƒ‚€~~}||{{zyyxxwwvuuttsrrqqpponnmmllkkjjiihhggfffedddccbbbaa```__^^^]]\\\\[[[ZZYYYYXXXXWWWVVVUUUUUTTTTSSSSRRRRRQQQQPPPPPPPOOOOOONNNNNNMMMMMMMMLLLLLLLKKKKKKKKKJJJJJJJJJJJIIIIIIIIIIHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···············¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµ´´´´´´´´´´´³³³³³³³²²²²²²²²±±±±±±°°°°°°°¯¯¯¯®®®®®®®­­­­¬¬¬¬«««««ªªª©©©©¨¨¨¨§§§¦¦¦¦¥¥¥¤¤¤££¢¢¢¢¡¡¡  ŸŸžžžœ›››šš™™˜˜———––•””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰ˆˆ‡‡†……„„ƒ‚‚€~~}}|{{zzyxxwwvuuttssrqqppoonnmmllkkjiihhhggffeedddcbbbaaa``__^^^]]]]\\[[[ZZZYYYYXXXWWWWVVVVUUUTTTTTSSSSRRRRQQQQQQQPPPPOOOOOOONNNNNNMMMMMMMMLLLLLLLKKKKKKKKKKKJJJJJJJJIIIIIIIIIIIIHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··············¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµ´´´´´´´´³³³³³³³³³³²²²²²²±±±±±±±±°°°°¯¯¯¯¯¯¯®®®®®­­­­­¬¬¬¬¬«««ªªªªª©©©©¨¨¨§§§§¦¦¦¥¥¥¤¤¤£££¢¢¢¡¡¡  ŸŸŸžžœœ››ššš™™˜˜——––••””““’’‘‘ŽŽŒŒ‹‹Š‰‰ˆˆ‡‡†……„„ƒ‚‚€~~}}|{{zzyxxwwvvuttssrrqqpoonnmmllkkjjiihhggffeeeddccbbbaa```__^^^]]]\\\[[[ZZZYYYXXXXWWWVVVVUUUUUTTTSSSSSRRRRRQQQQQPPPPPPPOOOONNNNNNNNMMMMMMLLLLLLLLLLKKKKKKKKJJJJJJJJJJIIIIIIIIIIIIIHHHHHHHHHHHHHHGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBB½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·············¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´´³³³³³³³²²²²²²²²²±±±±±°°°°°°°¯¯¯¯¯¯®®®®®­­­­­¬¬¬¬«««««ªªªª©©©©¨¨¨¨§§§¦¦¦¥¥¥¥¤¤¤££¢¢¢¡¡¡  ŸŸŸžžžœœœ››šš™™˜˜˜——––••””““’’‘ŽŽŒŒ‹‹Š‰‰ˆˆ‡‡†……„„ƒ‚‚€~~}}|{{zzyxxwwvvuttssrrqqppoonmmllkkjjiihhgggffeeddcccbbaaa```__^^^]]]\\[[[ZZZZYYYXXXWWWWVVVVUUUUTTTTTSSSSRRRRRQQQQQPPPPPPOOOOOOONNNNNMMMMMMMMMLLLLLLLKKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIHHHHHHHHHHHHHGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBB½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···············¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµ´´´´´´´´´´´³³³³³³³²²²²²²²²±±±±±±±°°°°°°¯¯¯¯¯¯®®®®®­­­­¬¬¬¬¬¬««««ªªªª©©©©©¨¨§§§§¦¦¦¦¥¥¤¤¤¤£££¢¢¡¡¡   ŸŸŸžžœœ››ššš™™˜˜——––••”””“’’‘‘ŽŽŒ‹‹ŠŠ‰‰ˆˆ‡††……„„ƒ‚‚€~~}}|{{zzyyxwwvvuuttsrrqqppoonnmmlkkkjjiihhggffeeeddccbbbaa```___^^^]]\\\[[[[ZZYYYYXXXXWWVVVVVUUUUTTTTSSSSSRRRRRQQQQQPPPPPPOOOOOONNNNNNNMMMMMMMMLLLLLLLKKKKKKKKKKKJJJJJJJJJIIIIIIIIIIIHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBB½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸················¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµ´´´´´´´´³³³³³³³³³³²²²²²²±±±±±±±±°°°°°¯¯¯¯¯¯¯®®®®­­­­­­¬¬¬¬«««««ªªªª©©©©¨¨¨¨§§§¦¦¦¦¥¥¥¤¤¤£££¢¢¢¡¡¡  ŸŸŸžžžœœœ››šš™™™˜˜——––••””““’’‘‘ŽŽŒ‹‹ŠŠ‰‰ˆˆ‡††……„„ƒ‚‚€~~}}|{{zzyyxwwvvuuttsrrqqppoonnmmllkkjjiihhggfffeeddcccbbaaa```__^^^]]]\\\[[[ZZZYYYYXXXWWWWVVVVUUUUTTTTTSSSRRRRRRRQQQQPPPPPPPOOOOONNNNNNNNMMMMMMLLLLLLLLLLKKKKKKKKJJJJJJJJJJIIIIIIIIIIIIIHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBB½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··············¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´³³³³³³³³²²²²²²²²²±±±±±°°°°°°°°¯¯¯¯¯®®®®®®­­­­­¬¬¬¬¬««««ªªªª©©©©©¨¨¨§§§§¦¦¦¥¥¥¤¤¤¤£££¢¢¡¡¡   ŸŸžžžœœ›››šš™™˜˜——–––••””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆ‡‡††……„ƒƒ‚‚€~~}}||{zzyyxxwvvuuttssrqqppoonnmmllkkjjiiihhggffeedddccbbbaaa``___^^^]]\\\[[[[ZZZYYYXXXXWWWVVVVVUUUUTTTTSSSSSRRRRRQQQQQQPPPPPOOOOOOONNNNNNMMMMMMMMMLLLLLLLLKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIIIHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBB¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··············¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµ´´´´´´´´´´´³³³³³³³²²²²²²²²±±±±±±±°°°°°°¯¯¯¯¯¯¯®®®®®­­­­­¬¬¬¬¬««««ªªªªª©©©¨¨¨¨§§§§¦¦¦¥¥¥¥¤¤¤£££¢¢¢¡¡   ŸŸŸžžœœœ››ššš™™˜˜——––••”””“’’’‘ŽŽŒŒ‹‹ŠŠ‰ˆˆ‡‡††……„ƒƒ‚‚€~~}}||{zzyyxxwwvuuttssrrqqppoonmmmlkkkjjiihhggffeeeddcccbbbaa```___^^]]]\\\[[[ZZZZYYYXXXXWWWWVVVUUUUUTTTTSSSSSRRRRRQQQQQPPPPPPPOOOOONNNNNNNNMMMMMMMMLLLLLLLKKKKKKKKKKKJJJJJJJJJJJIIIIIIIIIIIHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···············¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµ´´´´´´´´´³³³³³³³³³³²²²²²²²±±±±±±±°°°°°°¯¯¯¯¯¯®®®®®®­­­­­¬¬¬¬¬«««««ªªª©©©©©¨¨¨§§§§¦¦¦¦¥¥¥¤¤¤£££¢¢¢¡¡¡   ŸŸŸžžœœœ›››šš™™˜˜———––••””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰ˆˆ‡‡††……„ƒƒ‚‚€~~}}||{zzyyxxwwvuuttssrrqqppoonnmmllkkjjiihhhggffeedddcccbbaa```___^^^]]]\\\[[[ZZZYYYYXXXXWWWVVVVVUUUTTTTTSSSSSRRRRRQQQQQQPPPPPPOOOOOONNNNNNNMMMMMMMLLLLLLLLLLKKKKKKKKKJJJJJJJJJJIIIIIIIIIIIIHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···············¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´³³³³³³³³²²²²²²²²²²±±±±±°°°°°°°°¯¯¯¯¯®®®®®®­­­­­¬¬¬¬¬««««ªªªªª©©©¨¨¨¨¨§§§¦¦¦¦¥¥¥¥¤¤££££¢¢¢¡¡   ŸŸŸžžžœœ›››ššš™™˜˜——–––••””““’’‘‘ŽŽŒŒ‹‹Š‰‰ˆˆ‡‡††……„ƒƒ‚‚€~~}}||{zzyyxxwwvvuttssrrqqppoonnmmllkkjjiiihhggffeeedddccbbaaa```___^^]]]\\\\[[ZZZZYYYYXXXWWWWWVVVUUUUUTTTTSSSSSRRRRRQQQQQQPPPPPOOOOOOOONNNNNMMMMMMMMMMLLLLLLLLKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···············¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³²²²²²²²²±±±±±±±±°°°°°¯¯¯¯¯¯¯¯®®®®­­­­­­­¬¬¬««««««ªªª©©©©©¨¨¨¨§§§§¦¦¦¥¥¥¤¤¤¤£££¢¢¢¡¡¡  ŸŸŸŸžžœœ››ššš™™˜˜˜——––••””“““’’‘‘ŽŽŒ‹‹ŠŠ‰‰ˆˆ‡‡††…„„ƒƒ‚‚€~~}}||{{zyyxxwwvvuuttsrrqqppoonnmmlllkkjjiihhgggffeeeddccbbbaa````__^^^]]]\\\[[[[ZZZYYYXXXXWWWWVVVVVUUUTTTTTTSSSRRRRRRRQQQQPPPPPPPPOOOOONNNNNNNNMMMMMMMMLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIIHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···············¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµ´´´´´´´´´´³³³³³³³³³³²²²²²²²±±±±±±±°°°°°°°¯¯¯¯¯®®®®®®®­­­­¬¬¬¬¬¬««««ªªªªª©©©©¨¨¨¨§§§§¦¦¦¥¥¥¥¤¤¤£££¢¢¢¡¡¡   ŸŸŸžžžœœœ››šš™™™˜˜———––••””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††…„„ƒƒ‚‚€~~}}||{{zyyxxwwvvuuttssrrqqppoonnmmllkkjjiihhhggfffeeddcccbbaaa```___^^^]]]\\\[[[ZZZZYYYXXXXWWWWVVVVUUUUUTTTTSSSSSSRRRRQQQQQQQPPPPPOOOOOOONNNNNNNMMMMMMMLLLLLLLLLLKKKKKKKKKKJJJJJJJJJJIIIIIIIIIIIIHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸················¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµ´´´´´´´´´³³³³³³³³²²²²²²²²²²±±±±±±°°°°°°°¯¯¯¯¯¯®®®®®­­­­­­¬¬¬¬¬«««««ªªªª©©©©¨¨¨¨§§§§¦¦¦¦¥¥¥¤¤¤¤££¢¢¢¢¡¡¡  ŸŸŸŸžžœœ›››šš™™˜˜˜——–––••””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡†……„„ƒƒ‚‚€~~}}||{{zzyxxwwvvuuttssrrqqppoonnmmllkkjjiiihhgggffeedddccbbbaa````__^^^]]]]\\[[[[ZZZYYYYXXXXWWWWVVVVUUUUTTTTTSSSSSRRRRRRQQQQQPPPPPPOOOOOOONNNNNNMMMMMMMMMMLLLLLLLLKKKKKKKKKJJJJJJJJJJJIIIIIIIIIIIIIHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸················¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³²²²²²²²²±±±±±±±±±°°°°°¯¯¯¯¯¯¯®®®®®®­­­­­¬¬¬¬¬«««««ªªªª©©©©¨¨¨¨§§§§¦¦¦¦¥¥¥¥¤¤££££¢¢¢¡¡¡   ŸŸŸžžžœœœ››ššš™™˜˜———––••””“““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡††……„„ƒƒ‚‚€~~}}||{{zzyyxwwvvuuttssrrqqppoonnmmlllkkjjiihhhggffeeeddcccbbaaa```___^^^]]]\\\\[[ZZZZYYYYXXXXWWWWVVVVUUUUTTTTTSSSSSRRRRRQQQQQQPPPPPPPOOOOONNNNNNNNNMMMMMMMLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸················¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³²²²²²²²±±±±±±±°°°°°°°°¯¯¯¯¯®®®®®®®­­­­­¬¬¬¬¬«««««ªªªª©©©©©¨¨¨¨§§§¦¦¦¦¥¥¥¥¤¤¤£££¢¢¢¢¡¡   ŸŸŸžžžœœ›››šš™™™˜˜——–––••””““’’‘‘‘ŽŽŒŒ‹‹ŠŠ‰ˆˆ‡‡††……„„ƒƒ‚‚€~~}}||{{zzyyxxwwvuuttssrrqqppoonnnmmllkkjjiiihhggfffeedddccbbbaaa```___^^]]]]\\\[[[ZZZZYYYYXXXWWWWVVVVVUUUUTTTTTSSSSSRRRRRQQQQQQPPPPPPOOOOOOOONNNNNNNMMMMMMMLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJIIIIIIIIIIIIHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸················¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµ´´´´´´´´´³³³³³³³³³²²²²²²²²²²±±±±±±±°°°°°°¯¯¯¯¯¯¯®®®®®­­­­­­¬¬¬¬¬«««««ªªªª©©©©©¨¨¨¨§§§§¦¦¦¥¥¥¥¤¤¤££££¢¢¢¡¡¡   ŸŸŸžžœœœ››ššš™™˜˜˜——––••”””““’’‘‘ŽŽŒ‹‹‹Š‰‰ˆˆ‡‡††……„„ƒƒ‚‚€~~}}||{{zzyyxxwwvvutttsrrrqqppoonnmmllkkkjjiihhgggffeeeddcccbbbaa```___^^^]]]\\\\[[[ZZZZYYYXXXXWWWWVVVVVUUUUTTTTTSSSSSRRRRRRQQQQPPPPPPPPOOOOOONNNNNNNMMMMMMMMMMLLLLLLLLLKKKKKKKKKJJJJJJJJJJJIIIIIIIIIIIIHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···············¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´´´³³³³³³³³³²²²²²²²±±±±±±±±±°°°°°°¯¯¯¯¯¯®®®®®®®­­­­­¬¬¬¬¬¬««««ªªªªª©©©©¨¨¨¨§§§§¦¦¦¦¥¥¥¤¤¤¤£££¢¢¢¢¡¡   ŸŸŸžžžœœ›››šš™™™˜˜———––••””“““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€~~}}||{{zzyyxxwwvvuuttssrrqqppoonnmmlllkkjjiihhhggfffeedddccbbbaaa```___^^]]]]\\\[[[[ZZZYYYYXXXXWWWWVVVVUUUUUTTTTSSSSSSRRRRRQQQQQQQPPPPPPOOOOOONNNNNNNNNMMMMMMMLLLLLLLLLKKKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·················¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³²²²²²²²²±±±±±±°°°°°°°°°¯¯¯¯¯¯®®®®®­­­­­­­¬¬¬¬««««««ªªªª©©©©¨¨¨¨§§§§¦¦¦¦¥¥¥¥¤¤¤££££¢¢¡¡¡¡  ŸŸŸŸžžœœœ›››šš™™™˜˜——––•••””““’’‘‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€~~}}||{{zzyyxxwwvvuuttssrrqqppoonnnmmllkkjjjiihhggfffeedddcccbbbaa````__^^^^]]\\\\[[[ZZZZYYYYXXXXWWWWVVVVUUUUTTTTTTSSSSRRRRRRRQQQQQPPPPPPOOOOOOOOONNNNNNMMMMMMMMLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·················¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµ´´´´´´´´´´³³³³³³³³³²²²²²²²²²²±±±±±±±°°°°°°¯¯¯¯¯¯¯¯®®®®®®­­­­­¬¬¬¬¬¬««««ªªªªª©©©©¨¨¨¨¨§§§¦¦¦¦¥¥¥¥¤¤¤¤£££¢¢¢¡¡¡   ŸŸŸžžžœœœ››ššš™™˜˜˜——––•••””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€~~}}||{{zzyyxxwwvvuuttssrrqqpppoonnmmllkkjjjiihhgggffeeeddcccbbbaaa```___^^^]]]\\\[[[[ZZZZYYYYXXXWWWWWVVVVUUUUUTTTTSSSSSSRRRRRQQQQQQPPPPPPPPOOOOOONNNNNNNMMMMMMMMMMLLLLLLLLLKKKKKKKKKKJJJJJJJJJJJIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···············¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´´´³³³³³³³³³²²²²²²²±±±±±±±±±°°°°°°°¯¯¯¯¯¯®®®®®®®­­­­­¬¬¬¬¬««««««ªªªª©©©©©¨¨¨§§§§§¦¦¦¥¥¥¥¤¤¤¤£££¢¢¢¡¡¡¡  ŸŸŸŸžžœœœ›››šš™™™˜˜———––••”””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€~~}}||{{zzyyxxwwvvuuttssrrrqqppoonnmmllkkkjjiihhhggfffeedddcccbbbaa````__^^^^]]]\\\[[[[ZZZZYYYXXXXXWWWVVVVVUUUUTTTTTTSSSSSRRRRRQQQQQQQPPPPPPOOOOOOONNNNNNNNNMMMMMMMLLLLLLLLLKKKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸················¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³²²²²²²²²±±±±±±±°°°°°°°°¯¯¯¯¯¯¯®®®®®­­­­­­¬¬¬¬¬¬««««ªªªªªª©©©¨¨¨¨¨§§§§¦¦¦¦¥¥¥¤¤¤¤£££¢¢¢¢¡¡¡   ŸŸŸžžžœœ›››ššš™™˜˜———––•••””“““’’‘‘ŽŽŒŒ‹‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€~~}}||{{zzyyxxwwvvuutttssrrqqppoonnmmlllkkjjjiihhhggffeeedddccbbbaaa```___^^^]]]]\\\[[[[ZZZYYYYXXXXWWWWWVVVUUUUUUTTTTSSSSSSRRRRRRQQQQQPPPPPPPOOOOOOOONNNNNNNMMMMMMMMLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJJIIIIIIIIIIIIIHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³²²²²²²²²²²±±±±±±±±°°°°°°¯¯¯¯¯¯¯®®®®®®®­­­­­¬¬¬¬¬««««««ªªªª©©©©©¨¨¨¨§§§§¦¦¦¦¥¥¥¥¤¤¤££££¢¢¢¡¡¡   ŸŸŸžžžœœœ››ššš™™™˜˜———––•••””““’’‘‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡‡††……„„ƒƒ‚‚€~~}}||{{zzyyxxxwwvvuuttssrrqqppoonnnmmllkkjjjiihhhggfffeeeddcccbbbaaa```___^^^]]]\\\\[[[ZZZZYYYYXXXXWWWWVVVVVUUUUTTTTTTSSSSSRRRRRQQQQQQQPPPPPPPOOOOOONNNNNNNNMMMMMMMMMMLLLLLLLLLKKKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³²²²²²²²²±±±±±±±±°°°°°°°°¯¯¯¯¯¯®®®®®®­­­­­­­¬¬¬¬«««««ªªªªªª©©©¨¨¨¨¨¨§§§¦¦¦¦¥¥¥¥¤¤¤¤£££¢¢¢¡¡¡¡   ŸŸŸžžžœœ›››ššš™™˜˜˜——–––••”””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyxxwwvvuuttssrrqqpppoonnmmllkkkjjiiihhgggffeeedddccbbbaaa```___^^^^]]]\\\[[[[ZZZZYYYYXXXWWWWWVVVVUUUUUUTTTTTSSSSRRRRRRRQQQQQQPPPPPPOOOOOOOONNNNNNNNMMMMMMMMLLLLLLLLLKKKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···············¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²±±±±±±±°°°°°°°¯¯¯¯¯¯¯¯®®®®®®­­­­­¬¬¬¬¬¬«««««ªªªª©©©©©¨¨¨¨§§§§§¦¦¦¥¥¥¥¤¤¤¤£££¢¢¢¢¡¡¡   ŸŸŸžžžžœœœ›››šš™™™˜˜———––•••””““’’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyxxwwvvuuttssrrqqpppoonnmmmllkkjjjiihhhggfffeedddcccbbaaaa```___^^^]]]]\\\[[[[ZZZZYYYXXXXXWWWVVVVVVUUUUTTTTTSSSSSSRRRRRQQQQQQPPPPPPPPOOOOOOONNNNNNNMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···············¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµ´´´´´´´´´´³³³³³³³³³³²²²²²²²²²²±±±±±±±±±°°°°°°¯¯¯¯¯¯®®®®®®®­­­­­­­¬¬¬¬««««««ªªªªª©©©©¨¨¨¨¨§§§§¦¦¦¦¥¥¥¥¤¤¤££££¢¢¢¡¡¡¡  ŸŸŸŸžžžœœ›››ššš™™˜˜˜———––•••””““’’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyxxwwvvuuttssrrrqqppoonnmmmllkkjjjiihhhgggffeeedddccbbbaaa````__^^^^]]]\\\\[[[ZZZZYYYYXXXXWWWWWVVVVUUUUUTTTTTTSSSSRRRRRRRQQQQQQQPPPPPPOOOOOONNNNNNNNNMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKJJJJJJJJJJJJJIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCC¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµ´´´´´´´´´´³³³³³³³³³³²²²²²²²²±±±±±±±±°°°°°°°°°¯¯¯¯¯¯®®®®®®­­­­­­¬¬¬¬¬¬«««««ªªªªª©©©©©¨¨¨§§§§§¦¦¦¦¥¥¥¥¤¤¤¤£££¢¢¢¢¡¡¡   ŸŸŸžžžœœœ›››šš™™™˜˜˜——–––••”””““’’‘‘‘ŽŽŒŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyxxwwvvuuttsssrrqqppoonnnmmllkkkjjiiihhgggfffeedddcccbbbaaa```___^^^]]]]\\\[[[[ZZZZYYYYXXXXXWWWVVVVVUUUUUTTTTTSSSSSSRRRRRRQQQQQQPPPPPPOOOOOOOOONNNNNNNNMMMMMMMMLLLLLLLLLLKKKKKKKKKKJJJJJJJJJJJJJIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCC»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··················¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²±±±±±±±±°°°°°°¯¯¯¯¯¯¯¯®®®®®®®­­­­­¬¬¬¬¬«««««««ªªªª©©©©¨¨¨¨¨§§§§¦¦¦¦¥¥¥¥¤¤¤¤££££¢¢¢¡¡¡¡  ŸŸŸŸžžžœœœœ››ššš™™™˜˜———––•••””“““’’‘‘ŽŽŒŒ‹‹ŠŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyxxwwvvuuuttssrrqqpppoonnmmlllkkjjjiihhhggfffeeeddccccbbaaa````__^^^^]]]\\\\[[[[ZZZZYYYYXXXXWWWWWVVVVUUUUTTTTTTTSSSSSRRRRRQQQQQQQPPPPPPPPOOOOOONNNNNNNNMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···············¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²²±±±±±±±±±°°°°°°°¯¯¯¯¯¯¯®®®®®®­­­­­­­¬¬¬¬¬«««««ªªªªª©©©©©¨¨¨¨§§§§§¦¦¦¦¥¥¥¤¤¤¤££££¢¢¢¢¡¡¡   ŸŸŸžžžœœœ›››ššš™™˜˜˜——–––•••””““’’’‘‘ŽŽŒŒ‹‹ŠŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyxxwwvvuuuttssrrqqpppoonnmmmllkkjjjiiihhgggffeeedddcccbbbaaa```___^^^]]]]\\\\[[[[ZZZYYYYXXXXXWWWWVVVVVUUUUUTTTTTSSSSSRRRRRRRQQQQQQPPPPPPPOOOOOOONNNNNNNNNMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯®®®®®®­­­­­­¬¬¬¬¬¬««««««ªªªª©©©©©¨¨¨¨¨§§§¦¦¦¦¦¥¥¥¥¤¤¤£££££¢¢¢¡¡¡   ŸŸŸžžžžœœ›››ššš™™™˜˜———–––••””“““’’‘‘‘ŽŽŽŒŒ‹‹ŠŠ‰‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyxxwwvvvuuttssrrqqqppoonnnmmlllkkjjiiihhhggfffeeedddccbbbaaaa```___^^^]]]\\\\\[[[ZZZZYYYYXXXXWWWWWVVVVVUUUUTTTTTTSSSSSSRRRRRRQQQQQQPPPPPPPOOOOOOOOONNNNNNNMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJJIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²²±±±±±±±°°°°°°°¯¯¯¯¯¯¯®®®®®®®­­­­­­­¬¬¬¬¬«««««ªªªªªª©©©©¨¨¨¨§§§§§¦¦¦¦¥¥¥¥¤¤¤¤£££¢¢¢¢¡¡¡¡  ŸŸŸŸžžžœœœ›››ššš™™˜˜˜———––•••””“““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyxxxwwvvuuttssrrrqqppooonnmmlllkkjjjiihhhgggffeeedddcccbbbaaa````__^^^^]]]]\\\[[[[ZZZZYYYYXXXXXWWWWVVVVUUUUUUTTTTTSSSSSRRRRRRRQQQQQQQPPPPPPPOOOOOOONNNNNNNMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··················¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²²±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯®®®®®®­­­­­­¬¬¬¬¬¬««««««ªªªª©©©©©¨¨¨¨¨§§§§¦¦¦¦¥¥¥¥¥¤¤¤££££¢¢¢¡¡¡¡   ŸŸŸžžžœœ››››šš™™™˜˜˜——–––•••””““’’’‘‘ŽŽŒŒŒ‹‹ŠŠ‰‰ˆˆ‡‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyxxxwwvvuuttsssrrqqpppoonnmmmllkkjjjiiihhgggfffeeddddccbbbbaaa```___^^^^]]]\\\\[[[ZZZZZYYYYXXXXWWWWWVVVVVUUUUTTTTTTSSSSSSRRRRRRQQQQQQPPPPPPPOOOOOOOONNNNNNNNNMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJJIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···············¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµ´´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®­­­­­¬¬¬¬¬¬«««««ªªªªªª©©©©¨¨¨¨¨§§§§§¦¦¦¦¥¥¥¤¤¤¤¤£££¢¢¢¢¡¡¡¡  ŸŸŸŸžžžœœœ›››ššš™™™˜˜———–––••””“““’’’‘‘ŽŽŒŒ‹‹‹ŠŠ‰‰ˆˆ‡‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyxxxwwvvuutttssrrqqpppoonnmmmlllkkjjiiihhhggfffeeedddcccbbbaaa````__^^^^]]]]\\\[[[[[ZZZYYYYXXXXXWWWWWVVVVUUUUUUTTTTTSSSSSSRRRRRQQQQQQQPPPPPPPPOOOOOOOONNNNNNNNMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKKJJJJJJJJJJJJJJIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²²±±±±±±±±°°°°°°°¯¯¯¯¯¯¯®®®®®®­­­­­­­¬¬¬¬¬¬¬«««««ªªªª©©©©©©¨¨¨¨§§§§¦¦¦¦¦¥¥¥¥¤¤¤¤££££¢¢¢¡¡¡    ŸŸŸžžžœœœ››šššš™™˜˜˜———––•••””“““’’‘‘‘ŽŽŽŒŒ‹‹ŠŠŠ‰‰ˆˆ‡‡†††……„„ƒƒ‚‚€€~~}}||{{zzyyyxxwwvvuuuttssrrqqqppoonnnmmlllkkjjjiihhhgggffeeeeddcccbbbbaaa```____^^^]]]\\\\[[[[ZZZZYYYYYXXXXWWWWVVVVVVUUUUTTTTTSSSSSSSRRRRRRRQQQQQQPPPPPPPOOOOOOONNNNNNNNMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²²±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®­­­­­­¬¬¬¬¬¬««««««ªªªªª©©©©©¨¨¨¨§§§§§¦¦¦¦¥¥¥¥¤¤¤¤¤£££¢¢¢¡¡¡¡   ŸŸŸžžžžœœœ›››ššš™™™˜˜˜——–––••”””““’’’‘‘ŽŽŒŒ‹‹ŠŠŠ‰‰ˆˆ‡‡††………„„ƒƒ‚‚€€~~}}||{{zzzyyxxwwvvuuuttssrrrqqppooonnmmmllkkkjjiiihhgggfffeeedddcccbbbaaaa```___^^^^]]]\\\[[[[[ZZZZYYYYXXXXXWWWWVVVVVUUUUUTTTTTTSSSSSSRRRRRRQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·················¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµ´´´´´´´´´´´´³³³³³³³³³³³²²²²²²²²²±±±±±±±±±°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®­­­­­­­¬¬¬¬¬«««««ªªªªªª©©©©©¨¨¨¨¨§§§§¦¦¦¦¥¥¥¥¥¤¤¤££££¢¢¢¢¡¡¡    ŸŸŸžžžœœœœ›››šš™™™˜˜˜———––•••”””““’’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰‰ˆˆ‡‡††………„„ƒƒ‚‚€€~~}}||{{zzzyyxxwwvvvuuttssrrrqqpppoonnmmmllkkkjjjiihhhgggfffeedddccccbbbaaa```____^^^]]]]\\\\[[[ZZZZZYYYYXXXXWWWWWVVVVVUUUUUTTTTTTSSSSSRRRRRRRQQQQQQQPPPPPPPPOOOOOOONNNNNNNNNMMMMMMMMMLLLLLLLLLLLKKKKKKKKKKKKJJJJJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµ´´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²²±±±±±±±±±°°°°°°°¯¯¯¯¯¯¯®®®®®®®­­­­­­¬¬¬¬¬¬««««««ªªªªª©©©©©¨¨¨¨¨§§§§§¦¦¦¦¥¥¥¤¤¤¤¤££££¢¢¢¡¡¡¡   ŸŸŸŸžžžœœœ›››ššš™™™˜˜———–––•••””“““’’‘‘‘ŽŽŒŒŒ‹‹ŠŠ‰‰‰ˆˆ‡‡††……„„„ƒƒ‚‚€€~~}}||{{{zzyyxxwwvvvuuttsssrrqqpppoonnnmmlllkkjjjiiihhhggfffeeedddcccbbbaaa````___^^^^]]]\\\\[[[[[ZZZYYYYXXXXXWWWWWVVVVVUUUUUTTTTTTSSSSSSRRRRRRQQQQQQQPPPPPPPOOOOOOONNNNNNNNNMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKKJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²²±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­¬¬¬¬¬«««««ªªªªªª©©©©©©¨¨¨¨§§§§¦¦¦¦¦¥¥¥¥¤¤¤¤££££¢¢¢¢¡¡¡   ŸŸŸŸžžžœœœœ›››ššš™™˜˜˜———–––••”””“““’’‘‘ŽŽŽŒŒ‹‹‹ŠŠ‰‰ˆˆˆ‡‡††……„„„ƒƒ‚‚€€~~}}||{{{zzyyxxwwwvvuutttssrrqqqppooonnmmlllkkkjjiiihhhgggffeeedddccccbbbaaa````___^^^]]]]\\\\[[[[ZZZZYYYYYXXXXWWWWVVVVVVUUUUUUTTTTTSSSSSRRRRRRQQQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµ´´´´´´´´´´´´´³³³³³³³³³³³²²²²²²²²²²±±±±±±±±±°°°°°°°¯¯¯¯¯¯¯¯®®®®®®­­­­­­­¬¬¬¬¬¬¬«««««ªªªªª©©©©©¨¨¨¨¨§§§§§¦¦¦¦¥¥¥¥¤¤¤¤¤££££¢¢¢¡¡¡    ŸŸŸŸžžžœœœ›››ššš™™™˜˜˜———––•••”””““’’’‘‘ŽŽŽŒŒ‹‹‹ŠŠ‰‰ˆˆ‡‡‡††……„„„ƒƒ‚‚€€~~}}||{{{zzyyxxxwwvvuutttssrrqqqppooonnmmmllkkkjjjiihhhgggfffeeedddcccbbbaaa````____^^^]]]\\\\[[[[[ZZZZYYYYXXXXXWWWWWVVVVVUUUUUTTTTTSSSSSSSRRRRRRRQQQQQQPPPPPPPPOOOOOOONNNNNNNNNMMMMMMMMMMLLLLLLLLLLLKKKKKKKKKKKKKJJJJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»ººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµ´´´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²²±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®­­­­­­¬¬¬¬¬¬««««««ªªªªªª©©©©©¨¨¨¨§§§§§¦¦¦¦¥¥¥¥¥¤¤¤¤£££¢¢¢¢¢¡¡¡   ŸŸŸŸžžžžœœ››››ššš™™™˜˜———–––•••””“““’’‘‘‘ŽŽŒŒ‹‹ŠŠŠ‰‰ˆˆ‡‡‡††……„„ƒƒƒ‚‚€€~~}}|||{{zzyyxxxwwvvuuuttssrrrqqpppoonnnmmlllkkjjjiiihhhggfffeeeddddccbbbaaaa````___^^^]]]]]\\\[[[[ZZZZZYYYYXXXXXWWWWVVVVVUUUUUUTTTTTTSSSSSSRRRRRRQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKKKJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²²±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­¬¬¬¬¬¬«««««ªªªªª©©©©©¨¨¨¨¨¨§§§§§¦¦¦¦¥¥¥¥¤¤¤¤££££¢¢¢¢¡¡¡    ŸŸŸŸžžžœœœ›››ššš™™™˜˜˜———–––••”””“““’’‘‘‘ŽŽŒŒŒ‹‹ŠŠŠ‰‰ˆˆ‡‡‡††……„„ƒƒƒ‚‚€€~~}}|||{{zzyyxxxwwvvuuuttsssrrqqpppoonnnmmlllkkkjjiiihhhgggfffeeedddcccbbbaaa````____^^^]]]]\\\\[[[[ZZZZYYYYXXXXXWWWWWWVVVVVUUUUUTTTTTSSSSSSRRRRRRRQQQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDD»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµ´´´´´´´´´´´´´³³³³³³³³³³³²²²²²²²²²²±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®­­­­­­¬¬¬¬¬¬««««««ªªªªªª©©©©©¨¨¨¨¨§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤££££¢¢¢¢¡¡¡¡   ŸŸŸŸžžžœœœ›››ššš™™™˜˜˜——–––•••”””““’’’‘‘ŽŽŽŒŒŒ‹‹ŠŠŠ‰‰ˆˆ‡‡‡††……„„ƒƒƒ‚‚€€~~}}|||{{zzyyxxxwwvvuuuttsssrrqqqppooonnmmmllkkkjjjiiihhgggfffeeedddcccbbbbaaa````___^^^^]]]]\\\\[[[ZZZZZYYYYYXXXXWWWWWVVVVVUUUUUUTTTTTTSSSSSSRRRRRRQQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNMMMMMMMMMMLLLLLLLLLLLKKKKKKKKKKKKKJJJJJJJJJJJJJIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDD»»»»»»»ºººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµ´´´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²²±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®­­­­­­­¬¬¬¬¬¬«««««ªªªªªª©©©©©¨¨¨¨¨§§§§§¦¦¦¦¥¥¥¥¤¤¤¤¤££££¢¢¢¢¡¡¡    ŸŸŸŸžžžœœœ›››ššš™™™˜˜˜———–––•••””“““’’‘‘‘ŽŽŽŒŒŒ‹‹ŠŠ‰‰‰ˆˆ‡‡†††……„„ƒƒƒ‚‚€€~~}}|||{{zzyyyxxwwvvvuuttsssrrqqqppooonnnmmlllkkjjjiiihhhgggfffeeedddcccbbbaaa````____^^^]]]]\\\\[[[[[ZZZZYYYYXXXXXWWWWWVVVVVUUUUUUTTTTTSSSSSSRRRRRRRQQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKKKJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDD»»»»»»ººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²²²±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®­­­­­­­¬¬¬¬¬¬«««««««ªªªªªª©©©©¨¨¨¨¨§§§§§¦¦¦¦¥¥¥¥¥¤¤¤¤££££¢¢¢¢¡¡¡¡   ŸŸŸŸžžžœœœœ›››ššš™™™˜˜˜———–––••”””““’’’‘‘‘ŽŽŒŒ‹‹‹ŠŠ‰‰‰ˆˆ‡‡†††……„„ƒƒƒ‚‚€€~~}}|||{{zzyyyxxwwvvvuutttssrrrqqpppoonnnmmmllkkkjjiiihhhgggfffeeedddccccbbbaaa````___^^^^]]]]\\\\[[[[ZZZZZYYYYXXXXXWWWWWVVVVUUUUUUTTTTTTTSSSSSSRRRRRRRQQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNMMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDD»»»»»»ººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµ´´´´´´´´´´´´³³³³³³³³³³³³²²²²²²²²²²²±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®­­­­­­­¬¬¬¬¬¬«««««ªªªªªª©©©©©¨¨¨¨¨¨§§§§§¦¦¦¦¥¥¥¥¤¤¤¤£££££¢¢¢¢¡¡¡   ŸŸŸŸžžžžœœœ›››ššš™™™™˜˜———–––•••”””““’’’‘‘‘ŽŽŒŒ‹‹‹ŠŠ‰‰ˆˆˆ‡‡†††……„„ƒƒƒ‚‚€€~~}}|||{{zzyyyxxwwwvvuutttssrrrqqpppoonnnmmmllkkkjjjiiihhhggffffeeedddcccbbbaaaa````___^^^]]]]\\\\\[[[[ZZZZYYYYXXXXXWWWWWWVVVVVUUUUUUTTTTTSSSSSSRRRRRRRQQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLLKKKKKKKKKKKKJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDD»»»»»ºººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµ´´´´´´´´´´´´´³³³³³³³³³³³²²²²²²²²²²±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®­­­­­­­¬¬¬¬¬¬¬««««««ªªªªªª©©©©©¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤££££¢¢¢¡¡¡¡    ŸŸŸŸžžžœœœœ›››ššš™™™˜˜˜———–––•••””“““’’’‘‘ŽŽŽŒŒŒ‹‹ŠŠŠ‰‰ˆˆˆ‡‡††………„„ƒƒ‚‚‚€€~~}}}||{{zzzyyxxwwwvvuuuttsssrrqqqppooonnmmmlllkkjjjiiihhhgggfffeeedddccccbbbaaa````____^^^^]]]\\\\[[[[ZZZZZYYYYYXXXXXWWWWVVVVVUUUUUUTTTTTTSSSSSSSRRRRRRRQQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNMMMMMMMMMMLLLLLLLLLLLKKKKKKKKKKKKKJJJJJJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDºººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²²²±±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­¬¬¬¬¬¬««««««ªªªªªª©©©©©©¨¨¨¨¨§§§§§¦¦¦¦¥¥¥¥¥¤¤¤¤££££¢¢¢¢¡¡¡¡   ŸŸŸŸžžžœœœ›››ššš™™™˜˜˜˜———––•••”””“““’’‘‘‘ŽŽŽŒŒŒ‹‹ŠŠŠ‰‰ˆˆ‡‡‡††………„„ƒƒ‚‚‚€€~~}}}||{{zzzyyxxxwwvvuuuttsssrrqqqppooonnnmmlllkkkjjjiihhhggggfffeeedddcccbbbbaaa````___^^^^]]]]\\\\[[[[ZZZZZYYYYXXXXXWWWWWVVVVVVUUUUUUTTTTTTSSSSSSRRRRRRQQQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNNMMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEºººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµ´´´´´´´´´´´´³³³³³³³³³³³³²²²²²²²²²²²±±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®­­­­­­­¬¬¬¬¬¬««««««ªªªªªª©©©©©¨¨¨¨¨§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤£££¢¢¢¢¡¡¡¡    ŸŸŸŸžžžœœœœ›››ššš™™™˜˜˜———–––•••””“““’’’‘‘‘ŽŽŽŒŒŒ‹‹ŠŠŠ‰‰ˆˆ‡‡‡††………„„ƒƒ‚‚‚€€~~}}}||{{zzzyyxxxwwvvuuuttsssrrqqqpppoonnnmmmlllkkjjjiiihhhgggfffeeedddccccbbbaaa````____^^^^]]]\\\\[[[[[ZZZZZYYYYYXXXXWWWWWVVVVVUUUUUUTTTTTTSSSSSSRRRRRRRQQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLLKKKKKKKKKKKKJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµ´´´´´´´´´´´´´´³³³³³³³³³³³²²²²²²²²²²±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®­­­­­­­¬¬¬¬¬¬«««««««ªªªªªª©©©©©¨¨¨¨¨¨§§§§¦¦¦¦¦¥¥¥¥¤¤¤¤£££££¢¢¢¢¡¡¡¡   ŸŸŸŸžžžœœœ››››ššš™™™˜˜˜———–––•••””“““’’’‘‘‘ŽŽŒŒ‹‹‹ŠŠ‰‰‰ˆˆ‡‡‡††………„„ƒƒ‚‚‚€€~~}}}||{{zzzyyxxxwwvvvuutttssrrrqqpppoonnnmmmlllkkjjjiiihhhgggfffeeeddddcccbbbbaaa````___^^^^]]]]\\\\\[[[[ZZZZYYYYYXXXXWWWWWWVVVVVUUUUUUTTTTTTTSSSSSSRRRRRRRQQQQQQQPPPPPPPPPOOOOOOOONNNNNNNNNMMMMMMMMMMLLLLLLLLLLLKKKKKKKKKKKKKKJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµ´´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®­­­­­­­¬¬¬¬¬¬««««««ªªªªªª©©©©©¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤££££¢¢¢¢¡¡¡¡   ŸŸŸŸžžžžœœœ›››ššš™™™˜˜˜————––•••”””“““’’‘‘‘ŽŽŽŒŒ‹‹‹ŠŠ‰‰‰ˆˆ‡‡‡††……„„„ƒƒ‚‚‚€€~~}}}||{{{zzyyxxxwwvvvuutttssrrrqqqppooonnnmmlllkkkjjjiihhhhgggfffeeedddcccbbbbaaaa````___^^^^]]]]\\\\[[[[ZZZZZYYYYYXXXXXWWWWWVVVVVUUUUUUTTTTTTSSSSSSRRRRRRRQQQQQQQPPPPPPPPPOOOOOOOONNNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKKJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµ´´´´´´´´´´´´³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®­­­­­­­¬¬¬¬¬¬¬««««««ªªªªªª©©©©©©¨¨¨¨¨§§§§§¦¦¦¦¥¥¥¥¥¤¤¤¤££££¢¢¢¢¡¡¡¡¡   ŸŸŸŸžžžœœœ›››šššš™™™˜˜˜———–––•••”””““’’’‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠ‰‰‰ˆˆ‡‡‡††……„„„ƒƒ‚‚‚€€~~}}}||{{{zzyyxxxwwvvvuutttsssrrqqqpppoonnnmmmllkkkjjjiiihhhgggfffeeeedddcccbbbbaaa````___^^^^^]]]]\\\\[[[[ZZZZZYYYYXXXXXWWWWWVVVVVVUUUUUUTTTTTTSSSSSSSRRRRRRRQQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLLLKKKKKKKKKKKKJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEºººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµ´´´´´´´´´´´´´´´³³³³³³³³³³³²²²²²²²²²²±±±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®­­­­­­­¬¬¬¬¬¬¬««««««ªªªªªª©©©©©¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤££££¢¢¢¢¡¡¡¡   ŸŸŸŸžžžžœœœ›››ššš™™™˜˜˜———–––•••”””“““’’’‘‘‘ŽŽŽŒŒŒ‹‹ŠŠŠ‰‰ˆˆˆ‡‡†††……„„„ƒƒ‚‚‚€€~~}}}||{{{zzyyyxxwwwvvuuuttsssrrqqqpppoonnnmmmlllkkkjjjiiihhhgggfffeeedddcccbbbbaaaa````___^^^^]]]]\\\\[[[[[ZZZZZYYYYYXXXXXWWWWWVVVVVUUUUUUTTTTTTSSSSSSRRRRRRRRQQQQQQQPPPPPPPPPOOOOOOOOONNNNNNNNNMMMMMMMMMMLLLLLLLLLLLKKKKKKKKKKKKKKKJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEºººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµ´´´´´´´´´´´´´³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®­­­­­­­¬¬¬¬¬¬«««««««ªªªªªª©©©©©¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¤¤¤¤¤££££¢¢¢¢¡¡¡¡    ŸŸŸŸžžžžœœœ››››ššš™™™˜˜˜———–––•••”””“““’’’‘‘ŽŽŒŒŒ‹‹ŠŠŠ‰‰ˆˆˆ‡‡†††……„„„ƒƒ‚‚‚€€~~}}}||{{{zzyyyxxwwwvvuuuttsssrrrqqpppooonnmmmlllkkkjjjiiihhhgggfffeeeddddcccbbbaaaa````____^^^^]]]]\\\\[[[[[ZZZZYYYYYXXXXXWWWWWVVVVVUUUUUUTTTTTTTSSSSSSRRRRRRRQQQQQQQPPPPPPPPPOOOOOOOOONNNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLKKKKKKKKKKKKKJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEºººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­¬¬¬¬¬¬¬««««««ªªªªªª©©©©©©¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤££££¢¢¢¢¡¡¡¡   ŸŸŸŸžžžžœœœœ›››šššš™™™˜˜˜———–––•••”””“““’’‘‘‘ŽŽŒŒ‹‹‹ŠŠŠ‰‰ˆˆˆ‡‡†††……„„„ƒƒ‚‚‚€€~~}}}||{{{zzyyyxxwwwvvuuutttssrrrqqpppooonnnmmlllkkkjjjiiihhhgggfffeeeedddccccbbbaaaa````___^^^^]]]]\\\\[[[[[ZZZZZYYYYYXXXXXWWWWWVVVVVVUUUUUUTTTTTTSSSSSSSRRRRRRRQQQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´´´´´´´´³³³³³³³³³³³³²²²²²²²²²²±±±±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­¬¬¬¬¬¬¬««««««ªªªªªª©©©©©©¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¤¤¤¤£££££¢¢¢¢¡¡¡¡    ŸŸŸŸžžžžœœœ››››ššš™™™˜˜˜———–––•••”””“““’’’‘‘‘ŽŽŽŒŒ‹‹‹ŠŠ‰‰‰ˆˆ‡‡‡†††……„„„ƒƒ‚‚‚€€~~}}}||{{{zzyyyxxxwwvvvuutttssrrrqqqpppoonnnmmmlllkkkjjjiiihhhgggfffeeeddddcccbbbaaaa````____^^^^]]]]\\\\\[[[[ZZZZYYYYYXXXXXWWWWWVVVVVVUUUUUUTTTTTTSSSSSSSRRRRRRRQQQQQQQQPPPPPPPPPOOOOOOOOONNNNNNNNNNMMMMMMMMMMLLLLLLLLLLLLKKKKKKKKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµ´´´´´´´´´´´´´´³³³³³³³³³³³²²²²²²²²²²²±±±±±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®­­­­­­­¬¬¬¬¬¬¬««««««ªªªªªª©©©©©©¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤£££££¢¢¢¢¡¡¡¡   ŸŸŸŸžžžžœœœœ›››ššš™™™™˜˜˜———–––•••”””“““’’’‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠ‰‰‰ˆˆ‡‡‡††………„„ƒƒƒ‚‚€€~~~}}|||{{zzzyyxxxwwvvvuutttsssrrqqqpppoonnnmmmlllkkkjjjiiihhhgggffffeeedddccccbbbaaaa````___^^^^]]]]\\\\\[[[[[ZZZZZYYYYYXXXXXWWWWWVVVVVVUUUUUUTTTTTTSSSSSSSRRRRRRRQQQQQQQPPPPPPPPOOOOOOOOONNNNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLKKKKKKKKKKKKKKJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEºººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬««««««ªªªªªª©©©©©©¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤££££¢¢¢¢¢¡¡¡¡   ŸŸŸŸžžžžœœœ››››ššš™™™™˜˜˜———–––•••”””“““’’’‘‘ŽŽŒŒŒ‹‹ŠŠŠ‰‰‰ˆˆ‡‡‡††………„„ƒƒƒ‚‚€€~~~}}|||{{zzzyyxxxwwvvvuuuttsssrrrqqpppooonnmmmlllkkkjjjiiihhhgggffffeeeddddcccbbbbaaaa````___^^^^]]]]]\\\\[[[[ZZZZZYYYYYXXXXXWWWWWVVVVVVUUUUUUTTTTTTSSSSSSSRRRRRRRRQQQQQQQQPPPPPPPPPOOOOOOOONNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEºººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµ´´´´´´´´´´´´´´´³³³³³³³³³³³³²²²²²²²²²²±±±±±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­¬¬¬¬¬¬««««««ªªªªªª©©©©©©¨¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤££££¢¢¢¢¡¡¡¡¡   ŸŸŸŸžžžžœœœœ›››šššš™™™˜˜˜———–––•••”””“““’’’‘‘‘ŽŽŒŒŒ‹‹ŠŠŠ‰‰‰ˆˆ‡‡‡††………„„ƒƒƒ‚‚€€~~~}}|||{{zzzyyxxxwwvvvuuuttsssrrrqqpppooonnnmmmlllkkkjjjiiihhhgggfffeeeedddccccbbbaaaa````___^^^^^]]]]\\\\[[[[[ZZZZZYYYYYXXXXXWWWWWWVVVVVVUUUUUUTTTTTTSSSSSSRRRRRRRQQQQQQQQPPPPPPPPPOOOOOOOOONNNNNNNNNNNMMMMMMMMMMLLLLLLLLLLLLKKKKKKKKKKKKKKKJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEºººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµ´´´´´´´´´´´´´´´³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­¬¬¬¬¬¬¬«««««««ªªªªªª©©©©©©¨¨¨¨¨§§§§§§¦¦¦¦¦¥¥¥¥¤¤¤¤¤££££¢¢¢¢¡¡¡¡¡   ŸŸŸŸžžžžœœœ››››ššš™™™˜˜˜˜———–––•••”””“““’’’‘‘‘ŽŽŽŒŒŒ‹‹ŠŠŠ‰‰ˆˆˆ‡‡‡††………„„ƒƒƒ‚‚€€~~~}}|||{{zzzyyxxxwwwvvuuuttsssrrrqqqpppoonnnmmmlllkkkjjjiiihhhggggfffeeeddddcccbbbbaaaa````___^^^^^]]]]\\\\[[[[[ZZZZYYYYYXXXXXXWWWWWVVVVVVUUUUUUTTTTTTTSSSSSSSRRRRRRRQQQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLLKKKKKKKKKKKKKKJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²±±±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­¬¬¬¬¬¬¬««««««ªªªªªª©©©©©©¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤£££££¢¢¢¢¡¡¡¡    ŸŸŸŸžžžžœœœ››››ššš™™™˜˜˜————–––•••”””“““’’’‘‘ŽŽŽŒŒ‹‹‹ŠŠŠ‰‰ˆˆˆ‡‡‡††………„„ƒƒƒ‚‚€€~~~}}|||{{zzzyyxxxwwwvvuuutttssrrrqqqpppooonnmmmlllkkkjjjiiihhhhgggfffeeeddddcccbbbbaaaa````____^^^^]]]]\\\\\[[[[[ZZZZZYYYYYXXXXXWWWWWVVVVVVUUUUUUTTTTTTSSSSSSSRRRRRRRQQQQQQQQPPPPPPPPPPOOOOOOOOONNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´³³³³³³³³³³³³²²²²²²²²²²±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­¬¬¬¬¬¬¬«««««««ªªªªªª©©©©©©¨¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤££££¢¢¢¢¡¡¡¡    ŸŸŸŸžžžžœœœ››››ššš™™™™˜˜˜———–––•••”””“““’’’‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠ‰‰‰ˆˆˆ‡‡†††………„„ƒƒƒ‚‚€€~~~}}|||{{zzzyyyxxwwwvvvuutttsssrrqqqpppooonnnmmmlllkkkjjjiiihhhgggffffeeeddddcccbbbbaaaa````____^^^^]]]]\\\\[[[[[ZZZZZYYYYYXXXXXWWWWWWVVVVVVUUUUUUTTTTTTTSSSSSSSRRRRRRRQQQQQQQQPPPPPPPPOOOOOOOOOONNNNNNNNNNNMMMMMMMMMMLLLLLLLLLLLLKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEºº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµ´´´´´´´´´´´´´´´³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬«««««««ªªªªª©©©©©©¨¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤££££¢¢¢¢¡¡¡¡¡    ŸŸŸŸžžžœœœœ›››šššš™™™˜˜˜————–––•••”””“““’’’‘‘‘ŽŽŒŒŒ‹‹‹ŠŠ‰‰‰ˆˆˆ‡‡†††………„„ƒƒƒ‚‚€€~~~}}|||{{zzzyyyxxwwwvvvuutttsssrrrqqpppooonnnmmmlllkkkjjjiiihhhhgggfffeeeedddccccbbbbaaa````____^^^^^]]]]\\\\[[[[[ZZZZZYYYYYXXXXXWWWWWWVVVVVVUUUUUTTTTTTTSSSSSSSRRRRRRRRQQQQQQQQPPPPPPPPPOOOOOOOONNNNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLLKKKKKKKKKKKKKKKJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEºº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®­­­­­­­¬¬¬¬¬¬¬«««««««ªªªªªª©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤£££££¢¢¢¢¡¡¡¡    ŸŸŸŸžžžžœœœœ›››šššš™™™˜˜˜————–––•••”””“““’’’‘‘‘ŽŽŽŒŒŒ‹‹ŠŠŠ‰‰‰ˆˆ‡‡‡†††……„„„ƒƒƒ‚‚€€~~~}}|||{{{zzyyyxxxwwvvvuuuttsssrrrqqqpppoonnnmmmlllkkkjjjiiihhhhgggfffeeeedddccccbbbbaaaa````____^^^^]]]]\\\\\[[[[ZZZZZYYYYYXXXXXXWWWWWWVVVVVVUUUUUUTTTTTTTSSSSSSSRRRRRRRQQQQQQQPPPPPPPPPPOOOOOOOOOONNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEºº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´³³³³³³³³³³³³³²²²²²²²²²²²±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬«««««««ªªªªªª©©©©©©¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤£££££¢¢¢¢¡¡¡¡    ŸŸŸŸžžžžœœœœ›››šššš™™™˜˜˜˜———–––•••”””““““’’‘‘‘ŽŽŽŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆ‡‡‡†††……„„„ƒƒƒ‚‚€€~~~}}|||{{{zzyyyxxxwwvvvuuutttssrrrqqqpppooonnnmmllllkkkjjjiiihhhggggfffeeeedddccccbbbbaaaa````____^^^^]]]]\\\\\[[[[[ZZZZZYYYYYXXXXXWWWWWVVVVVVUUUUUUTTTTTTTSSSSSSSRRRRRRRRQQQQQQQQQPPPPPPPOOOOOOOOOONNNNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLLLKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´³³³³³³³³³³³²²²²²²²²²²²²²±±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­¬¬¬¬¬¬«««««««ªªªªªª©©©©©©©¨¨¨¨¨§§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤£££££¢¢¢¢¡¡¡¡    ŸŸŸŸžžžžœœœœ›››šššš™™™˜˜˜———––––•••”””“““’’’‘‘‘ŽŽŽŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆ‡‡‡†††……„„„ƒƒƒ‚‚€€~~~}}|||{{{zzyyyxxxwwvvvuuutttssrrrqqqpppooonnnmmmlllkkkjjjiiiihhhgggfffeeeedddccccbbbbaaaa````____^^^^]]]]\\\\\[[[[[ZZZZZYYYYYXXXXXXWWWWWVVVVVVVUUUUUUTTTTTTTSSSSSSRRRRRRRQQQQQQQQQPPPPPPPPPPOOOOOOOONNNNNNNNNNMMMMMMMMMMMMMLLLLLLLLLLLKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFF¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµ´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬«««««««ªªªªªª©©©©©©¨¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤££££¢¢¢¢¢¡¡¡¡    ŸŸŸŸŸžžžœœœœ››››ššš™™™™˜˜˜———–––•••””””“““’’’‘‘‘ŽŽŒŒŒ‹‹‹ŠŠŠ‰‰ˆˆˆ‡‡‡†††……„„„ƒƒƒ‚‚€€~~~}}|||{{{zzyyyxxxwwwvvuuutttsssrrrqqpppooonnnmmmlllkkkkjjjiiihhhgggffffeeeddddccccbbbbaaa`````____^^^^]]]]]\\\\[[[[[ZZZZZYYYYYXXXXXWWWWWWVVVVVVUUUUUUTTTTTTTSSSSSSSSRRRRRRRRQQQQQQQPPPPPPPPPOOOOOOOOOONNNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFF¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´³³³³³³³³³³³³³²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬««««««ªªªªªªª©©©©©©¨¨¨¨¨¨§§§§§¦¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤££££¢¢¢¢¢¡¡¡¡    ŸŸŸŸžžžžœœœ››››šššš™™™˜˜˜————–––•••””””““’’’‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠ‰‰‰ˆˆˆ‡‡‡††………„„„ƒƒ‚‚‚€€~~~}}}||{{{zzzyyxxxwwwvvvuutttsssrrrqqqpppooonnnmmmllkkkkjjjiiihhhhgggfffeeeeddddcccbbbbaaaa````____^^^^]]]]]\\\\[[[[[ZZZZZYYYYYYXXXXXWWWWWWVVVVVVUUUUUUUTTTTTTSSSSSSSRRRRRRRRQQQQQQQQQPPPPPPPPOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLLLKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFF¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³²²²²²²²²²²²²²±±±±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­¬¬¬¬¬¬¬¬«««««««ªªªªªªª©©©©©©¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤£££££¢¢¢¢¢¡¡¡¡    ŸŸŸŸŸžžžžœœœœ››››ššš™™™™˜˜˜———––––•••”””“““’’’‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠ‰‰‰ˆˆˆ‡‡‡††………„„„ƒƒ‚‚‚€€~~~}}}||{{{zzzyyxxxwwwvvvuutttsssrrrqqqpppooonnnmmmlllkkkjjjiiiihhhgggffffeeeddddccccbbbaaaa`````____^^^^]]]]]\\\\\[[[[ZZZZZZYYYYYXXXXXWWWWWVVVVVVUUUUUUUTTTTTTTSSSSSSSSRRRRRRRQQQQQQQQPPPPPPPPPPOOOOOOOOONNNNNNNNNNMMMMMMMMMMMMMLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFF¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµ´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬««««««ªªªªªª©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤£££££¢¢¢¢¡¡¡¡¡    ŸŸŸŸžžžžœœœ››››šššš™™™˜˜˜˜———–––•••””””“““’’’‘‘‘ŽŽŽŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡†††………„„„ƒƒ‚‚‚€€~~~}}}||{{{zzzyyyxxwwwvvvuuutttssrrrqqqpppooonnnmmmlllkkkkjjjiiihhhggggfffeeeeddddcccbbbbaaaa````____^^^^^]]]]\\\\\[[[[ZZZZZZYYYYYXXXXXXWWWWWWVVVVVVUUUUUUTTTTTTSSSSSSSSRRRRRRRRQQQQQQQQQPPPPPPPPOOOOOOOOOONNNNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFF¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´³³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­¬¬¬¬¬¬««««««««ªªªªªªª©©©©©©¨¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤£££££¢¢¢¢¢¡¡¡¡    ŸŸŸŸŸžžžžœœœœ›››šššš™™™™˜˜˜————–––•••”””“““’’’’‘‘‘ŽŽŽŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡†††………„„„ƒƒ‚‚‚€€~~~}}}||{{{zzzyyyxxwwwvvvuuutttssrrrqqqpppooonnnmmmmlllkkkjjjiiihhhhgggffffeeeedddccccbbbaaaa`````____^^^^]]]]]\\\\\[[[[[ZZZZZYYYYYXXXXXWWWWWWVVVVVVUUUUUUUTTTTTTTTSSSSSSRRRRRRRQQQQQQQQQQPPPPPPPPPOOOOOOOOONNNNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLLLLKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFF¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬«««««««ªªªªªª©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤££££¢¢¢¢¢¡¡¡¡    ŸŸŸŸŸžžžžœœœœ›››šššš™™™˜˜˜˜———––––•••”””“““’’’‘‘‘ŽŽŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆ‡‡‡†††………„„„ƒƒ‚‚‚€€~~~}}}||{{{zzzyyyxxxwwvvvuuutttsssrrrqqppppooonnnmmmlllkkkjjjiiiihhhggggfffeeeedddccccbbbbaaaa`````____^^^^]]]]]\\\\[[[[[ZZZZZYYYYYYXXXXXXWWWWWWVVVVVVUUUUUUTTTTTTTSSSSSSSRRRRRRRRRQQQQQQQPPPPPPPPPPOOOOOOOOOONNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFF¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬«««««««ªªªªªªª©©©©©©¨¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤£££££¢¢¢¢¢¡¡¡¡    ŸŸŸŸžžžžœœœœ››››ššš™™™™˜˜˜˜———–––•••””””“““’’’‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆ‡‡‡†††………„„ƒƒƒ‚‚‚€€~~~}}}|||{{zzzyyyxxxwwvvvuuutttsssrrrqqqpppooonnnmmmlllkkkkjjjiiihhhggggffffeeeddddccccbbbbaaaa````____^^^^]]]]]\\\\\[[[[[ZZZZZZYYYYYXXXXXWWWWWWVVVVVVUUUUUUUTTTTTTTSSSSSSSRRRRRRRRQQQQQQQQQPPPPPPPPPOOOOOOOOOONNNNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFF¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªª©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤£££££¢¢¢¢¡¡¡¡¡    ŸŸŸŸŸžžžžœœœœ›››šššš™™™˜˜˜˜————–––•••”””““““’’’‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠŠ‰‰ˆˆˆ‡‡‡†††………„„ƒƒƒ‚‚‚€€~~~}}}|||{{zzzyyyxxxwwwvvuuutttsssrrrqqqpppooonnnmmmllllkkkjjjiiihhhhggggfffeeeedddccccbbbbaaaa`````____^^^^^]]]]\\\\\[[[[ZZZZZZYYYYYXXXXXXWWWWWWVVVVVVUUUUUUTTTTTTTTSSSSSSSSRRRRRRRQQQQQQQQPPPPPPPPPPPOOOOOOOOONNNNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFF¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±°°°°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬«««««««ªªªªªªª©©©©©©¨¨¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤¤£££££¢¢¢¢¡¡¡¡¡    ŸŸŸŸžžžžœœœœ››››šššš™™™˜˜˜————––––•••”””“““’’’‘‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠ‰‰‰ˆˆˆ‡‡‡†††………„„ƒƒƒ‚‚‚€€~~~}}}|||{{zzzyyyxxxwwwvvvuutttsssrrrqqqpppooonnnnmmmlllkkkjjjiiiihhhhgggfffeeeeddddccccbbbbaaaa````____^^^^^]]]]\\\\\[[[[[[ZZZZZYYYYYXXXXXWWWWWWVVVVVVVUUUUUUUTTTTTTTSSSSSSSRRRRRRRRRQQQQQQQQPPPPPPPPPOOOOOOOOOOONNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFF¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªª©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤££££¢¢¢¢¢¡¡¡¡¡    ŸŸŸŸŸžžžžœœœ››››šššš™™™™˜˜˜————–––•••””””“““’’’‘‘‘ŽŽŽŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡‡†††………„„ƒƒƒ‚‚‚€€~~~}}}|||{{zzzyyyxxxwwwvvvuuutttssrrrrqqqpppooonnnmmmlllkkkkjjjiiihhhhgggffffeeeeddddcccbbbbaaaa`````____^^^^^]]]]]\\\\[[[[[ZZZZZYYYYYYXXXXXXWWWWWWVVVVVVUUUUUUTTTTTTTTSSSSSSSSRRRRRRRQQQQQQQQQPPPPPPPPPOOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFF¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬««««««ªªªªªªª©©©©©©©¨¨¨¨¨¨§§§§§¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤£££££¢¢¢¢¢¡¡¡¡    ŸŸŸŸŸžžžžœœœœ››››ššš™™™™˜˜˜˜———––––•••”””““““’’’‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡‡†††……„„„ƒƒƒ‚‚‚€€~~~}}}|||{{{zzyyyxxxwwwvvvuuutttsssrrrqqqpppooonnnmmmllllkkkjjjiiiihhhggggffffeeeddddccccbbbbaaaa`````____^^^^]]]]]\\\\\[[[[[ZZZZZZYYYYYXXXXXWWWWWWVVVVVVVUUUUUUUTTTTTTSSSSSSSSRRRRRRRRRQQQQQQQPPPPPPPPPPPOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFF¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±±°°°°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬««««««««ªªªªªªª©©©©©©¨¨¨¨¨§§§§§§§¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤£££££¢¢¢¢¢¡¡¡¡¡    ŸŸŸŸŸžžžœœœœœ››››ššš™™™™˜˜˜————–––••••”””“““’’’’‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡‡†††……„„„ƒƒƒ‚‚‚€€~~~}}}|||{{{zzyyyxxxwwwvvvuuutttsssrrrqqqpppooonnnmmmmlllkkkjjjjiiihhhhgggffffeeeddddccccbbbbbaaa`````____^^^^^]]]]]\\\\\[[[[ZZZZZZYYYYYXXXXXXXWWWWWVVVVVVUUUUUUUTTTTTTTTSSSSSSSRRRRRRRRQQQQQQQQQQPPPPPPPPOOOOOOOOOOONNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGFFFF¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­¬¬¬¬¬¬¬¬¬«««««««ªªªªªª©©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤£££££¢¢¢¢¢¡¡¡¡    ŸŸŸŸŸžžžžœœœœ››››šššš™™™™˜˜˜———––––•••””””“““’’’‘‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡†††………„„„ƒƒƒ‚‚‚€€~~~}}}|||{{{zzzyyyxxwwwvvvuuutttsssrrrqqqppppoonnnnmmmlllkkkkjjjiiiihhhgggffffeeeeddddccccbbbbaaaa`````____^^^^]]]]]\\\\\[[[[[ZZZZZZYYYYYXXXXXXWWWWWWVVVVVVVUUUUUUTTTTTTTSSSSSSSSSRRRRRRRQQQQQQQQQPPPPPPPPPPOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGF¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²²²±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬««««««««ªªªªªªª©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤£££££¢¢¢¢¢¡¡¡¡¡    ŸŸŸŸžžžžœœœœ››››ššš™™™™˜˜˜˜———––––•••”””““““’’’‘‘‘ŽŽŽŽŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆ‡‡‡†††………„„„ƒƒƒ‚‚‚€€~~~}}}|||{{{zzzyyyxxxwwvvvuuutttsssrrrqqqqpppooonnnmmmllllkkkjjjiiiihhhggggffffeeeddddccccbbbbbaaaa````____^^^^^]]]]]\\\\\[[[[[ZZZZZYYYYYYXXXXXXWWWWWWVVVVVVUUUUUUUTTTTTTTTSSSSSSSRRRRRRRRRQQQQQQQQPPPPPPPPPPOOOOOOOOOONNNNNNNNNNNMMMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGF¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­¬¬¬¬¬¬¬¬¬«««««««ªªªªªª©©©©©©©¨¨¨¨¨¨¨§§§§§¦¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤¤£££££¢¢¢¢¡¡¡¡¡    ŸŸŸŸŸžžžžœœœœ››››šššš™™™™˜˜˜————–––••••”””“““’’’’‘‘‘ŽŽŽŒŒ‹‹‹‹ŠŠ‰‰‰ˆˆˆ‡‡‡†††………„„„ƒƒƒ‚‚‚€€~~~}}}|||{{{zzzyyyxxxwwwvvvuuttttssrrrrqqqpppooonnnmmmmlllkkkjjjjiiihhhhgggffffeeeeddddccccbbbbaaaa`````____^^^^^]]]]\\\\\[[[[[[ZZZZZYYYYYYXXXXXWWWWWWWVVVVVVVUUUUUUTTTTTTTSSSSSSSSSRRRRRRRQQQQQQQQQQPPPPPPPPPOOOOOOOOOONNNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGF¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬«««««««ªªªªªªª©©©©©©©¨¨¨¨¨§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¤¤¤¤££££££¢¢¢¢¢¡¡¡¡¡    ŸŸŸŸžžžžžœœœœ›››šššš™™™™˜˜˜˜———––––•••””””“““’’’‘‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡‡†††………„„„ƒƒƒ‚‚‚€€~~~}}}|||{{{zzzyyyxxxwwwvvvuuutttsssrrrqqqpppooonnnnmmmlllkkkjjjjiiiihhhggggffffeeeedddccccbbbbaaaaa````____^^^^^]]]]]\\\\\\[[[[ZZZZZYYYYYYXXXXXXXWWWWWVVVVVVVUUUUUUUTTTTTTTSSSSSSSSRRRRRRRRRQQQQQQQQPPPPPPPPPPPOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGG¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²±±±±±±±±±±±°°°°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬«««««««««ªªªªªª©©©©©©¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤£££££¢¢¢¢¢¡¡¡¡¡    ŸŸŸŸŸžžžžœœœœ››››šššš™™™™˜˜˜————–––••••””””“““’’’‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡‡†††………„„„ƒƒƒ‚‚‚€€~~~}}}|||{{{zzzyyyxxxwwwvvvuuutttsssrrrqqqppppooonnnmmmlllkkkkjjjjiiihhhhgggffffeeeeddddccccbbbbaaaa`````____^^^^^]]]]]\\\\\[[[[[ZZZZZZYYYYYXXXXXXWWWWWWWVVVVVVUUUUUUTTTTTTTTTSSSSSSSRRRRRRRRQQQQQQQQQQPPPPPPPPPOOOOOOOOOOONNNNNNNNNNNMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGG¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´³³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬«««««««ªªªªªªª©©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤££££££¢¢¢¢¢¡¡¡¡    ŸŸŸŸŸžžžžžœœœ›››››šššš™™™˜˜˜˜————–––••••”””““““’’’‘‘‘ŽŽŽŽŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡‡†††………„„„ƒƒƒ‚‚‚€€~~~}}}|||{{{zzzyyyxxxwwwvvvuuutttsssrrrqqqqpppooonnnmmmllllkkkjjjjiiihhhhggggfffeeeedddddcccbbbbaaaaa`````____^^^^]]]]]\\\\\\[[[[[ZZZZZYYYYYYXXXXXXWWWWWWVVVVVVVUUUUUUUTTTTTTTSSSSSSSSRRRRRRRRRQQQQQQQQPPPPPPPPPPPOOOOOOOOOONNNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGG¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬««««««««ªªªªªªª©©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤£££££¢¢¢¢¢¡¡¡¡¡    ŸŸŸŸŸžžžžœœœœ››››šššš™™™™˜˜˜˜———––––••••”””“““’’’’‘‘‘ŽŽŽŒŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡‡†††………„„„ƒƒƒ‚‚‚€€~~~}}}|||{{{zzzyyyxxxwwwvvvuuutttssssrrrqqqpppooonnnmmmmlllkkkjjjjiiiihhhggggffffeeeeddddccccbbbbaaaa`````____^^^^^]]]]]\\\\\[[[[[ZZZZZZYYYYYYXXXXXXWWWWWWVVVVVVVUUUUUUTTTTTTTTTSSSSSSSRRRRRRRRRQQQQQQQQQPPPPPPPPPPOOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGG¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­¬¬¬¬¬¬¬¬¬«««««««ªªªªªªª©©©©©©©©¨¨¨¨¨§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤£££££¢¢¢¢¢¢¡¡¡¡    ŸŸŸŸŸžžžžžœœœœœ››››šššš™™™˜˜˜˜————–––••••””””“““’’’‘‘‘ŽŽŽŒŒŒ‹‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡‡†††………„„„ƒƒƒ‚‚‚€€~~~}}}|||{{{zzzyyyxxxwwwvvvuuuttttsssrrrqqqpppoooonnnmmmlllkkkkjjjjiiihhhhggggfffeeeeddddcccccbbbaaaaa`````____^^^^]]]]]]\\\\\[[[[[ZZZZZYYYYYYYXXXXXXWWWWWVVVVVVVVUUUUUUUTTTTTTTSSSSSSSSSRRRRRRRQQQQQQQQQQPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGG¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´³³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬««««««««ªªªªªªªª©©©©©©¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££¢¢¢¢¢¡¡¡¡¡¡    ŸŸŸŸžžžžžœœœœ››››šššš™™™™˜˜˜˜————–––••••”””““““’’’‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠŠ‰‰‰‰ˆˆˆ‡‡‡†††………„„„ƒƒƒ‚‚‚€€~~~}}}|||{{{zzzyyyxxxwwwvvvvuuutttsssrrrqqqppppooonnnmmmllllkkkjjjjiiihhhhggggffffeeeeddddccccbbbbaaaaa````____^^^^^^]]]]]\\\\[[[[[[ZZZZZZYYYYYXXXXXXWWWWWWWVVVVVVUUUUUUUUTTTTTTTTSSSSSSSRRRRRRRRRQQQQQQQQPPPPPPPPPPPPOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGG¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªª©©©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤¤£££££¢¢¢¢¢¡¡¡¡     ŸŸŸŸŸžžžžœœœœ››››šššš™™™™˜˜˜————––––•••””””“““’’’’‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡‡††††………„„„ƒƒƒ‚‚‚€€~~~}}}|||{{{zzzyyyyxxxwwwvvvuuutttsssrrrqqqppppooonnnmmmmlllkkkkjjjiiiihhhhgggffffeeeeddddccccbbbbbaaaa`````____^^^^^]]]]]\\\\\[[[[[[ZZZZZYYYYYYXXXXXXWWWWWWVVVVVVVVUUUUUUTTTTTTTTSSSSSSSSRRRRRRRRQQQQQQQQQQPPPPPPPPPPOOOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGG¸¸¸¸¸¸¸¸¸¸¸¸¸·······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±±±°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬«««««««ªªªªªªªª©©©©©©¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤£££££¢¢¢¢¢¡¡¡¡¡     ŸŸŸŸžžžžžœœœœ››››šššš™™™™˜˜˜˜————–––••••”””““““’’’‘‘‘‘ŽŽŽŽŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡‡†††………„„„ƒƒƒ‚‚‚€€€~~~}}}|||{{{zzzyyyxxxwwwvvvuuutttsssrrrqqqqpppooonnnnmmmllllkkkjjjjiiihhhhggggffffeeeeddddccccbbbbaaaaa````____^^^^^^]]]]]\\\\\[[[[[ZZZZZZYYYYYYXXXXXXWWWWWWWVVVVVVUUUUUUUUTTTTTTTSSSSSSSSRRRRRRRRRQQQQQQQQQPPPPPPPPPPOOOOOOOOOOONNNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGG¸¸¸¸¸¸¸¸¸¸··························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´³³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªª©©©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤££££££¢¢¢¢¢¡¡¡¡     ŸŸŸŸŸžžžžœœœœ››››šššš™™™™˜˜˜————––––••••”””““““’’’‘‘‘ŽŽŽŒŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡‡†††………„„„ƒƒƒ‚‚‚€€€~~~}}}|||{{{zzzyyyxxxwwwvvvuuutttssssrrrqqqpppoooonnnmmmllllkkkjjjjiiiihhhhgggffffeeeeddddccccbbbbbaaaa`````_____^^^^]]]]]\\\\\\[[[[[ZZZZZYYYYYYYXXXXXXWWWWWWVVVVVVVVUUUUUUTTTTTTTTSSSSSSSSRRRRRRRRRQQQQQQQQQPPPPPPPPPPPOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGG¸¸¸¸¸¸¸¸¸¸··························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬¬««««««ªªªªªªªª©©©©©©©¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤£££££¢¢¢¢¢¡¡¡¡¡    ŸŸŸŸŸžžžžžœœœœ›››››ššš™™™™˜˜˜˜————––––•••””””“““’’’’‘‘‘ŽŽŽŒŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡‡†††………„„„ƒƒƒ‚‚‚€€€~~~}}}|||{{{zzzyyyxxxwwwvvvuuutttssssrrrqqqppppooonnnmmmmlllkkkkjjjiiiihhhhggggffffeeedddddccccbbbbaaaaa`````____^^^^^]]]]]\\\\\[[[[[[ZZZZZZYYYYYXXXXXXXWWWWWWVVVVVVVUUUUUUUUTTTTTTSSSSSSSSSRRRRRRRRQQQQQQQQQQQPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNMMMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGG¸¸¸¸¸¸¸¸¸·······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±±±°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬««««««««ªªªªªªª©©©©©©©¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¡¡¡¡¡     ŸŸŸŸžžžžžœœœœ››››šššš™™™™˜˜˜˜————–––••••”””““““’’’‘‘‘‘ŽŽŽŒŒŒ‹‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡‡†††………„„„ƒƒƒ‚‚‚€€€~~~}}}|||{{{zzzyyyxxxwwwvvvuuuttttsssrrrqqqppppooonnnnmmmllllkkkjjjjiiihhhhggggffffeeeeddddccccbbbbbaaaaa````_____^^^^^]]]]\\\\\\[[[[[[ZZZZZYYYYYYXXXXXXWWWWWWWVVVVVVVUUUUUUUTTTTTTTTSSSSSSSRRRRRRRRRRQQQQQQQQQPPPPPPPPPPPOOOOOOOOOONNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGG¸¸¸¸¸·························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««ªªªªªªªªª©©©©©©¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤££££££¢¢¢¢¢¡¡¡¡¡    ŸŸŸŸŸžžžžœœœœœ›››ššššš™™™™˜˜˜————––––••••”””““““’’’‘‘‘‘ŽŽŽŽŒŒŒ‹‹‹ŠŠŠŠ‰‰‰ˆˆˆ‡‡‡†††………„„„ƒƒƒ‚‚‚€€€~~~}}}|||{{{zzzyyyxxxwwwvvvuuuutttsssrrrqqqqpppooonnnnmmmllllkkkjjjjiiiihhhhgggffffeeeeedddcccccbbbbbaaaa`````____^^^^^]]]]]\\\\\\[[[[[ZZZZZZYYYYYYXXXXXXWWWWWWWVVVVVVUUUUUUUUUTTTTTTSSSSSSSSSSRRRRRRRQQQQQQQQQQQPPPPPPPPPPOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHGGGG¸¸¸···························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²²²±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªªª©©©©©©©¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤¤£££££¢¢¢¢¢¡¡¡¡¡     ŸŸŸŸžžžžžœœœœœ››››šššš™™™™˜˜˜˜————––––•••””””“““’’’’‘‘‘ŽŽŽŽŒŒŒ‹‹‹ŠŠŠ‰‰‰‰ˆˆˆ‡‡‡†††………„„„ƒƒƒ‚‚‚€€€~~~}}}|||{{{zzzyyyxxxwwwvvvvuuutttsssrrrqqqqpppoooonnnmmmmlllkkkkjjjiiiihhhhggggffffeeeeddddcccccbbbbaaaa`````_____^^^^^]]]]]\\\\\[[[[[[ZZZZZYYYYYYYXXXXXXWWWWWWWVVVVVVVUUUUUUUTTTTTTTTSSSSSSSSRRRRRRRRRQQQQQQQQQPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNMMMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHGG¸¸¸·························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªªªª©©©©©©©¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤£££££¢¢¢¢¢¢¡¡¡¡     ŸŸŸŸŸžžžžœœœœ›››››šššš™™™˜˜˜˜˜———––––••••”””““““’’’’‘‘‘ŽŽŽŒŒŒŒ‹‹‹ŠŠŠ‰‰‰‰ˆˆˆ‡‡‡†††………„„„ƒƒƒ‚‚‚€€€~~~}}}|||{{{zzzyyyxxxwwwvvvvuuutttssssrrrqqqppppooonnnmmmmllllkkkjjjjiiiihhhggggffffeeeedddddccccbbbbbaaaa`````_____^^^^]]]]]]\\\\\[[[[[ZZZZZZZYYYYYXXXXXXXWWWWWWVVVVVVVUUUUUUUUTTTTTTTTSSSSSSSSRRRRRRRRRQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOONNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHGG¸¸······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªªªª©©©©©©©¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¡¡¡¡¡     ŸŸŸŸŸžžžžœœœœœ››››šššš™™™™˜˜˜˜————––––••••”””““““’’’‘‘‘‘ŽŽŽŒŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡‡‡†††………„„„ƒƒƒ‚‚‚€€€~~~}}}|||{{{zzzyyyxxxxwwwvvvuuutttssssrrrqqqppppooonnnnmmmllllkkkjjjjiiiihhhhggggffffeeeeddddcccccbbbbaaaa`````_____^^^^^]]]]]\\\\\\[[[[[[ZZZZZYYYYYYXXXXXXWWWWWWWVVVVVVVUUUUUUUUTTTTTTTTSSSSSSSSRRRRRRRRRQQQQQQQQQQPPPPPPPPPPOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHG························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªªªª©©©©©©©¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤££££££¢¢¢¢¢¡¡¡¡¡     ŸŸŸŸŸžžžžžœœœœ›››››šššš™™™™˜˜˜˜————––––•••””””“““’’’’‘‘‘ŽŽŽŽŒŒŒ‹‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡‡‡†††………„„„ƒƒƒ‚‚‚€€€~~~}}}|||{{{zzzyyyxxxxwwwvvvuuuttttsssrrrqqqqpppooonnnnmmmmlllkkkkjjjiiiihhhhggggffffeeeedddddccccbbbbaaaaa`````_____^^^^^]]]]]\\\\\\[[[[[ZZZZZZYYYYYYXXXXXXXWWWWWWVVVVVVVUUUUUUUUTTTTTTTTSSSSSSSSRRRRRRRRRRQQQQQQQQPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHH························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««ªªªªªªªª©©©©©©©¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤¤£££££¢¢¢¢¢¢¡¡¡¡¡    ŸŸŸŸŸŸžžžžœœœœ››››ššššš™™™˜˜˜˜————––––••••””””“““’’’’‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠŠŠ‰‰‰ˆˆˆ‡‡‡††††………„„„ƒƒƒ‚‚‚€€€~~~}}}|||{{{zzzyyyyxxxwwwvvvuuuutttsssrrrrqqqpppoooonnnmmmmlllkkkkjjjjiiiihhhhggggfffeeeeeddddccccbbbbbaaaa``````____^^^^^]]]]]]\\\\\[[[[[[ZZZZZYYYYYYYXXXXXXWWWWWWWVVVVVVVUUUUUUUUTTTTTTTSSSSSSSSSRRRRRRRRRQQQQQQQQQQPPPPPPPPPPPOOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHH·····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬«««««««««ªªªªªªª©©©©©©©©¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤££££££¢¢¢¢¢¡¡¡¡¡     ŸŸŸŸŸžžžžžœœœœ›››››šššš™™™™˜˜˜˜————––––••••”””““““’’’‘‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠŠŠ‰‰‰ˆˆˆ‡‡‡††††………„„„ƒƒƒ‚‚‚€€€~~~}}}|||{{{zzzyyyyxxxwwwvvvuuuutttsssrrrrqqqppppooonnnnmmmllllkkkjjjjiiiihhhhggggffffeeeedddddccccbbbbaaaaa`````_____^^^^^]]]]]\\\\\\[[[[[ZZZZZZZYYYYYXXXXXXXWWWWWWVVVVVVVVUUUUUUUTTTTTTTTTSSSSSSSRRRRRRRRRRQQQQQQQQQQPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHH··················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬¬«««««««ªªªªªªªªª©©©©©©¨¨¨¨¨¨¨¨§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤£££££¢¢¢¢¢¢¡¡¡¡¡    ŸŸŸŸŸŸžžžžœœœœ››››šššš™™™™™˜˜˜————––––••••””””““““’’’‘‘‘‘ŽŽŽŒŒŒŒ‹‹‹ŠŠŠ‰‰‰‰ˆˆˆ‡‡‡†††…………„„„ƒƒƒ‚‚‚€€€~~~}}}|||{{{zzzzyyyxxxwwwvvvvuuutttssssrrrqqqppppooonnnnmmmllllkkkkjjjjiiihhhhhgggfffffeeeeddddccccbbbbbaaaa``````____^^^^^]]]]]]\\\\\[[[[[[ZZZZZZYYYYYYYXXXXXWWWWWWWWVVVVVVUUUUUUUUUTTTTTTTSSSSSSSSSRRRRRRRRRQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHH··················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬«««««««««ªªªªªªª©©©©©©©©¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤££££££¢¢¢¢¢¡¡¡¡¡     ŸŸŸŸŸžžžžžœœœœœ››››šššš™™™™˜˜˜˜————––––••••””””“““’’’’‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹ŠŠŠ‰‰‰‰ˆˆˆ‡‡‡†††…………„„„ƒƒƒ‚‚‚€€€~~~}}}|||{{{zzzzyyyxxxwwwvvvvuuutttssssrrrqqqppppoooonnnmmmmlllkkkkjjjjiiiihhhhggggffffeeeeddddcccccbbbbaaaaa`````_____^^^^^]]]]]\\\\\\[[[[[ZZZZZZZYYYYYYXXXXXXXWWWWWWVVVVVVVVUUUUUUUTTTTTTTTTSSSSSSSSRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHH·················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬«««««««ªªªªªªªªª©©©©©©¨¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤¤¤££££¢¢¢¢¢¢¡¡¡¡¡     ŸŸŸŸŸžžžžžœœœœ››››šššš™™™™™˜˜˜˜————––––•••””””““““’’’’‘‘‘ŽŽŽŽŒŒŒ‹‹‹‹ŠŠŠ‰‰‰ˆˆˆˆ‡‡‡†††………„„„„ƒƒƒ‚‚‚€€€~~~}}}|||{{{{zzzyyyxxxwwwwvvvuuuttttsssrrrqqqqpppoooonnnmmmmllllkkkkjjjiiiihhhhggggfffffeeeeddddccccbbbbbaaaaa`````_____^^^^^]]]]]\\\\\[[[[[[[ZZZZZYYYYYYYXXXXXXWWWWWWWWVVVVVVUUUUUUUUUTTTTTTTSSSSSSSSSRRRRRRRRRRQQQQQQQQQPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHH·············¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³²²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬¬««««««««ªªªªªªª©©©©©©©©¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤££££££¢¢¢¢¢¡¡¡¡¡¡    ŸŸŸŸŸŸžžžžœœœœ›››››šššš™™™™˜˜˜˜————––––••••””””““““’’’‘‘‘‘ŽŽŽŒŒŒ‹‹‹‹ŠŠŠ‰‰‰ˆˆˆˆ‡‡‡†††………„„„„ƒƒƒ‚‚‚€€€~~~}}}|||{{{{zzzyyyxxxwwwwvvvuuuttttsssrrrrqqqppppooonnnnmmmllllkkkkjjjjiiiihhhhggggffffeeeedddddccccbbbbbaaaa``````____^^^^^^]]]]\\\\\\\[[[[[ZZZZZZZYYYYYXXXXXXXXWWWWWWVVVVVVVVUUUUUUUTTTTTTTTSSSSSSSSSRRRRRRRRRQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMMLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHH············¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªªªª©©©©©©©¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤£££££¢¢¢¢¢¢¡¡¡¡¡     ŸŸŸŸŸžžžžžœœœœœ››››ššššš™™™™˜˜˜˜————––––••••””””“““’’’’‘‘‘‘ŽŽŽŒŒŒ‹‹‹ŠŠŠŠ‰‰‰ˆˆˆ‡‡‡‡†††………„„„„ƒƒƒ‚‚‚€€€~~~}}}|||{{{{zzzyyyxxxxwwwvvvuuuutttsssrrrrqqqppppooonnnnmmmmlllkkkkjjjjiiiihhhhggggffffeeeeeddddcccccbbbbaaaaa`````_____^^^^^]]]]]]\\\\\[[[[[[ZZZZZZYYYYYYYXXXXXXWWWWWWWVVVVVVVUUUUUUUUTTTTTTTTSSSSSSSSRRRRRRRRRRRQQQQQQQQQPPPPPPPPPPPOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHH············¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««ªªªªªªªª©©©©©©©©¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤££££££¢¢¢¢¢¡¡¡¡¡¡    ŸŸŸŸŸŸžžžžœœœœ›››››šššš™™™™™˜˜˜—————––––•••””””““““’’’’‘‘‘ŽŽŽŒŒŒŒ‹‹‹ŠŠŠŠ‰‰‰ˆˆˆ‡‡‡‡†††………„„„ƒƒƒƒ‚‚‚€€€~~~}}}||||{{{zzzyyyxxxxwwwvvvuuuutttssssrrrqqqppppoooonnnmmmmllllkkkkjjjiiiihhhhhgggfffffeeeedddddccccbbbbbaaaa``````____^^^^^^]]]]]\\\\\\[[[[[ZZZZZZZYYYYYYXXXXXXXWWWWWWVVVVVVVVUUUUUUUUTTTTTTTTSSSSSSSSSSRRRRRRRRQQQQQQQQQQPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHH·········¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬«««««««««ªªªªªªªª©©©©©©©¨¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¤¤¤¤¤¤¤£££££¢¢¢¢¢¢¡¡¡¡¡     ŸŸŸŸŸžžžžžœœœœœ››››ššššš™™™™˜˜˜˜————––––••••””””““““’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹ŠŠŠŠ‰‰‰ˆˆˆ‡‡‡‡†††………„„„ƒƒƒƒ‚‚‚€€€~~~}}}||||{{{zzzyyyxxxxwwwvvvuuuutttssssrrrqqqqpppoooonnnnmmmllllkkkkjjjjiiiihhhhggggffffeeeeeddddcccccbbbbaaaaa`````_____^^^^^]]]]]]\\\\\[[[[[[[ZZZZZYYYYYYYXXXXXXWWWWWWWWVVVVVVVUUUUUUUUTTTTTTTTTSSSSSSSSRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPOOOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIHHHHHHHH······¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬««««««««ªªªªªªªª©©©©©©©©¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¡¡¡¡¡     ŸŸŸŸŸžžžžžœœœœœ››››šššš™™™™˜˜˜˜˜————––––••••”””““““’’’’‘‘‘‘ŽŽŽŒŒŒŒ‹‹‹ŠŠŠ‰‰‰‰ˆˆˆ‡‡‡††††………„„„ƒƒƒƒ‚‚‚€€€~~~}}}||||{{{zzzyyyyxxxwwwvvvvuuutttssssrrrrqqqppppooonnnnmmmmllllkkkjjjjiiiihhhhgggggffffeeeeddddcccccbbbbbaaaaa`````_____^^^^^]]]]]\\\\\\[[[[[[ZZZZZZYYYYYYXXXXXXXXWWWWWWVVVVVVVVUUUUUUUUTTTTTTTTSSSSSSSSSRRRRRRRRRRQQQQQQQQQPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIHHHHH······¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬««««««««««ªªªªªªª©©©©©©©¨¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¡¡¡¡¡¡     ŸŸŸŸŸžžžžœœœœ›››››šššš™™™™˜˜˜˜————––––••••””””““““’’’’‘‘‘‘ŽŽŽŒŒŒ‹‹‹‹ŠŠŠ‰‰‰‰ˆˆˆ‡‡‡††††………„„„ƒƒƒƒ‚‚‚€€€~~~}}}||||{{{zzzyyyyxxxwwwvvvvuuuttttsssrrrrqqqppppooonnnnmmmmllllkkkkjjjjiiiihhhhggggffffeeeedddddccccbbbbbbaaaa`````_____^^^^^^]]]]]\\\\\\[[[[[[ZZZZZZYYYYYYYXXXXXXWWWWWWWWVVVVVVVUUUUUUUTTTTTTTTTTSSSSSSSSRRRRRRRRRQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIHHHHH······¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªªªªª©©©©©©©¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡     ŸŸŸŸŸžžžžžœœœœœ››››ššššš™™™™˜˜˜˜————––––••••””””““““’’’’‘‘‘ŽŽŽŽŒŒŒ‹‹‹‹ŠŠŠ‰‰‰ˆˆˆˆ‡‡‡††††………„„„ƒƒƒƒ‚‚‚€€€~~~}}}||||{{{zzzyyyyxxxwwwwvvvuuuttttsssrrrrqqqqpppoooonnnmmmmllllkkkkjjjjiiiihhhhggggffffeeeeeddddcccccbbbbbaaaaa`````_____^^^^^]]]]]]\\\\\\[[[[[ZZZZZZZYYYYYYXXXXXXXWWWWWWWVVVVVVVUUUUUUUUUTTTTTTTTSSSSSSSSRRRRRRRRRRRQQQQQQQQQQPPPPPPPPPPPOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHH··¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªª©©©©©©©©¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¡¡¡¡¡¡    ŸŸŸŸŸŸžžžžžœœœœ›››››šššš™™™™˜˜˜˜˜————––––••••”””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹ŠŠŠŠ‰‰‰ˆˆˆˆ‡‡‡††††………„„„ƒƒƒƒ‚‚‚€€€~~~}}}||||{{{zzzyyyyxxxwwwwvvvuuuutttssssrrrqqqqppppooonnnnmmmmllllkkkjjjjiiiihhhhgggggffffeeeedddddccccbbbbbaaaaa``````____^^^^^^]]]]]\\\\\\[[[[[[ZZZZZZYYYYYYYXXXXXXXWWWWWWWVVVVVVVVUUUUUUUTTTTTTTTTSSSSSSSSSRRRRRRRRRQQQQQQQQQQPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIH¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªªªªª©©©©©©©¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡     ŸŸŸŸŸžžžžžœœœœ›››››šššš™™™™™˜˜˜˜————––––••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹ŠŠŠŠ‰‰‰ˆˆˆˆ‡‡‡†††…………„„„ƒƒƒ‚‚‚‚€€€~~~}}}}|||{{{zzzzyyyxxxwwwwvvvuuuutttssssrrrqqqqppppooonnnnmmmmllllkkkkjjjjiiiihhhhggggfffffeeeedddddccccbbbbbaaaaa`````_____^^^^^]]]]]]\\\\\\[[[[[[ZZZZZZYYYYYYXXXXXXXXWWWWWWWVVVVVVVUUUUUUUUUTTTTTTTTSSSSSSSSRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIII¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««ªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡¡    ŸŸŸŸŸŸžžžžžœœœœœ››››ššššš™™™™˜˜˜˜—————––––••••””””““““’’’‘‘‘‘‘ŽŽŽŒŒŒŒ‹‹‹ŠŠŠŠ‰‰‰ˆˆˆ‡‡‡‡†††…………„„„ƒƒƒ‚‚‚‚€€€~~~}}}}|||{{{zzzzyyyxxxxwwwvvvuuuutttssssrrrrqqqppppooonnnnnmmmllllkkkkjjjjiiiihhhhhggggffffeeeedddddcccccbbbbaaaaa``````____^^^^^^]]]]]]\\\\\\[[[[[[ZZZZZZYYYYYYYXXXXXXWWWWWWWVVVVVVVVVUUUUUUUTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQPPPPPPPPPPPOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIII¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªª©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤£££££¢¢¢¢¢¢¢¡¡¡¡¡     ŸŸŸŸŸžžžžžœœœœ›››››ššššš™™™™˜˜˜˜————––––•••••””””“““’’’’‘‘‘‘ŽŽŽŽŒŒŒ‹‹‹‹ŠŠŠ‰‰‰‰ˆˆˆ‡‡‡‡†††…………„„„ƒƒƒ‚‚‚‚€€€~~~}}}}|||{{{zzzzyyyxxxxwwwvvvvuuuttttsssrrrrqqqqpppoooonnnnmmmmlllkkkkjjjjjiiiihhhhggggffffeeeeedddddccccbbbbbaaaaa`````_____^^^^^]]]]]]]\\\\\[[[[[[ZZZZZZZYYYYYYXXXXXXXWWWWWWWWVVVVVVVUUUUUUUUTTTTTTTTTSSSSSSSSSRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIII¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««ªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¡¡¡¡¡¡     ŸŸŸŸŸžžžžžžœœœœœ›››››šššš™™™™™˜˜˜˜————––––••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒ‹‹‹‹ŠŠŠ‰‰‰‰ˆˆˆ‡‡‡‡†††…………„„„ƒƒƒ‚‚‚‚€€€~~~}}}}|||{{{zzzzyyyxxxxwwwvvvvuuuttttsssrrrrqqqqppppooonnnnmmmmllllkkkkjjjjiiiihhhhggggfffffeeeedddddcccccbbbbaaaaaa`````_____^^^^^^]]]]]\\\\\\[[[[[[ZZZZZZYYYYYYYXXXXXXXWWWWWWWVVVVVVVVVUUUUUUUTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIII¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤¤£££££¢¢¢¢¢¢¡¡¡¡¡¡     ŸŸŸŸŸžžžžžœœœœœ››››ššššš™™™™˜˜˜˜—————––––••••””””““““’’’’‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆ‡‡‡‡†††………„„„„ƒƒƒ‚‚‚‚€€€~~~}}}}|||{{{{zzzyyyxxxxwwwvvvvuuuttttssssrrrqqqqppppoooonnnmmmmllllkkkkjjjjiiiihhhhhggggffffeeeeeddddcccccbbbbbaaaaa`````_____^^^^^^]]]]]]\\\\\[[[[[[[ZZZZZZYYYYYYXXXXXXXXWWWWWWWVVVVVVVVUUUUUUUUTTTTTTTTTSSSSSSSSSRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIII¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬««««««««ªªªªªªªª©©©©©©©©©¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤£££££££¢¢¢¢¢¡¡¡¡¡¡     ŸŸŸŸŸžžžžžžœœœœœ›››››šššš™™™™™˜˜˜˜————––––•••••””””“““’’’’‘‘‘‘ŽŽŽŒŒŒŒ‹‹‹ŠŠŠŠ‰‰‰ˆˆˆˆ‡‡‡††††………„„„„ƒƒƒ‚‚‚‚€€€~~~}}}}|||{{{{zzzyyyyxxxwwwwvvvuuuutttssssrrrrqqqppppoooonnnnmmmllllkkkkjjjjjiiiihhhhggggfffffeeeedddddcccccbbbbaaaaaa`````_____^^^^^^]]]]]\\\\\\\[[[[[ZZZZZZZYYYYYYYXXXXXXXWWWWWWVVVVVVVVVUUUUUUUUTTTTTTTTSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIII¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªª©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡     ŸŸŸŸŸŸžžžžžœœœœœ››››ššššš™™™™™˜˜˜˜————––––••••””””““““’’’’‘‘‘‘ŽŽŽŒŒŒŒ‹‹‹ŠŠŠŠ‰‰‰ˆˆˆˆ‡‡‡††††………„„„„ƒƒƒ‚‚‚‚€€€~~~}}}}|||{{{{zzzyyyyxxxwwwwvvvuuuutttssssrrrrqqqppppoooonnnnmmmmllllkkkkjjjjiiiihhhhggggfffffeeeeeddddcccccbbbbbaaaaa``````_____^^^^^]]]]]]\\\\\\[[[[[[ZZZZZZZYYYYYYXXXXXXXWWWWWWWWVVVVVVVUUUUUUUUTTTTTTTTTTSSSSSSSSSRRRRRRRRRRQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIII¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤£££££££¢¢¢¢¢¡¡¡¡¡      ŸŸŸŸŸžžžžžœœœœ›››››ššššš™™™™˜˜˜˜—————––––••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰ˆˆˆˆ‡‡‡††††………„„„„ƒƒƒ‚‚‚‚€€€~~~}}}}|||{{{{zzzyyyyxxxwwwwvvvuuuuttttsssrrrrqqqqppppooonnnnmmmmllllkkkkjjjjiiiihhhhhggggffffeeeeedddddccccbbbbbbaaaaa`````______^^^^^]]]]]\\\\\\\[[[[[[ZZZZZZYYYYYYYYXXXXXXWWWWWWWVVVVVVVVVUUUUUUUUTTTTTTTTTSSSSSSSSRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIII¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªª©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤¤££££££¢¢¢¢¢¡¡¡¡¡¡     ŸŸŸŸŸŸžžžžžœœœœœ›››››šššš™™™™˜˜˜˜˜————––––••••”””””““““’’’’‘‘‘ŽŽŽŽŒŒŒ‹‹‹‹ŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡††††………„„„„ƒƒƒ‚‚‚‚€€€~~~}}}}|||{{{{zzzyyyyxxxwwwwvvvvuuuttttsssrrrrqqqqppppoooonnnmmmmllllkkkkkjjjjiiiihhhhgggggffffeeeedddddcccccbbbbbaaaaa``````_____^^^^^^]]]]]\\\\\\[[[[[[[ZZZZZZYYYYYYYXXXXXXXWWWWWWWWVVVVVVVUUUUUUUUTTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIII¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡      ŸŸŸŸŸžžžžžœœœœœ›››››šššš™™™™™˜˜˜˜—————––––••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠ‰‰‰‰ˆˆˆ‡‡‡‡††††………„„„„ƒƒƒ‚‚‚‚€€€~~~}}}}|||{{{{zzzyyyyxxxxwwwvvvvuuuttttssssrrrqqqqppppoooonnnnmmmmllllkkkkjjjjiiiihhhhhggggfffffeeeedddddcccccbbbbbaaaaa`````______^^^^^]]]]]]\\\\\\[[[[[[ZZZZZZZYYYYYYYXXXXXXXWWWWWWWVVVVVVVVUUUUUUUUUTTTTTTTTTSSSSSSSSSRRRRRRRRRRQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJIIIIIIII¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªª©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££¢¢¢¢¢¢¡¡¡¡¡¡     ŸŸŸŸŸžžžžžžœœœœœ››››ššššš™™™™™˜˜˜˜————–––––••••””””““““’’’’‘‘‘‘ŽŽŽŒŒŒŒ‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆ‡‡‡‡†††…………„„„ƒƒƒƒ‚‚‚€€€~~~~}}}||||{{{zzzzyyyxxxxwwwvvvvuuuutttssssrrrrqqqppppoooonnnnmmmmllllkkkkjjjjiiiiihhhhggggfffffeeeeeddddcccccbbbbbaaaaaa`````_____^^^^^^]]]]]]\\\\\[[[[[[[ZZZZZZZYYYYYYXXXXXXXWWWWWWWWWVVVVVVVUUUUUUUUTTTTTTTTTSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJIIIIIIII¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªª©©©©©©©¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤£££££££¢¢¢¢¢¢¡¡¡¡¡      ŸŸŸŸŸžžžžžœœœœœ›››››ššššš™™™™˜˜˜˜˜————––––••••”””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆ‡‡‡‡†††…………„„„ƒƒƒƒ‚‚‚€€€~~~~}}}||||{{{zzzzyyyxxxxwwwvvvvuuuutttssssrrrrqqqqppppooonnnnmmmmllllkkkkkjjjjiiiihhhhgggggffffeeeeedddddcccccbbbbbaaaaa`````______^^^^^]]]]]]\\\\\\\[[[[[ZZZZZZZYYYYYYYYXXXXXXXWWWWWWWVVVVVVVUUUUUUUUUTTTTTTTTTTSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJIIIIII¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡¡     ŸŸŸŸŸŸžžžžœœœœœ››››ššššš™™™™™˜˜˜˜—————––––••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰ˆˆˆˆ‡‡‡‡†††…………„„„ƒƒƒƒ‚‚‚€€€~~~~}}}||||{{{zzzzyyyxxxxwwwwvvvuuuuttttsssrrrrqqqqppppoooonnnnmmmmllllkkkkjjjjiiiihhhhhggggfffffeeeeeddddcccccbbbbbbaaaa``````_____^^^^^^]]]]]]\\\\\\[[[[[[[ZZZZZZYYYYYYYXXXXXXXWWWWWWWWVVVVVVVVUUUUUUUUTTTTTTTTTSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJIII¶¶¶¶µµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªªª©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¢¢¡¡¡¡¡     ŸŸŸŸŸŸžžžžžœœœœœ›››››ššššš™™™™˜˜˜˜˜————–––––••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰ˆˆˆˆ‡‡‡‡†††…………„„„ƒƒƒƒ‚‚‚€€€~~~~}}}||||{{{zzzzyyyxxxxwwwwvvvuuuuttttsssrrrrqqqqppppoooonnnnmmmmllllkkkkjjjjiiiiihhhhgggggffffeeeeedddddcccccbbbbbaaaaa``````_____^^^^^]]]]]]]\\\\\\[[[[[[ZZZZZZZYYYYYYYXXXXXXXWWWWWWWVVVVVVVVUUUUUUUUUTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJIII¶¶¶µµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡      ŸŸŸŸŸŸžžžžžœœœœœ›››››šššš™™™™™˜˜˜˜˜————––––••••””””“““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰ˆˆˆˆ‡‡‡††††…………„„„ƒƒƒƒ‚‚‚€€€~~~~}}}||||{{{zzzzyyyyxxxwwwwvvvuuuuttttssssrrrqqqqppppoooonnnnmmmmlllllkkkkjjjjiiiihhhhgggggfffffeeeedddddcccccbbbbbaaaaa``````______^^^^^]]]]]]\\\\\\[[[[[[[ZZZZZZZYYYYYYXXXXXXXWWWWWWWWWVVVVVVVVUUUUUUUUTTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJIIµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡¡     ŸŸŸŸŸŸžžžžžœœœœœ›››››ššššš™™™™™˜˜˜˜————–––––••••””””“““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡††††…………„„„ƒƒƒƒ‚‚‚€€€~~~~}}}||||{{{zzzzyyyyxxxwwwwvvvvuuuttttssssrrrrqqqqppppooonnnnmmmmlllllkkkkjjjjiiiiihhhhggggfffffeeeeedddddcccccbbbbbaaaaa``````_____^^^^^^]]]]]]\\\\\\[[[[[[ZZZZZZZYYYYYYYYXXXXXXXWWWWWWWVVVVVVVVUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¡¡¡¡¡      ŸŸŸŸŸŸžžžžžœœœœœ›››››ššššš™™™™˜˜˜˜—————–––––••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡††††…………„„„ƒƒƒƒ‚‚‚€€€~~~~}}}||||{{{zzzzyyyyxxxwwwwvvvvuuuutttssssrrrrqqqqppppoooonnnnmmmmllllkkkkjjjjiiiiihhhhhggggffffeeeeedddddcccccbbbbbaaaaa``````______^^^^^]]]]]]\\\\\\\[[[[[[[ZZZZZZYYYYYYYXXXXXXXWWWWWWWWVVVVVVVVVUUUUUUUUTTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡¡     ŸŸŸŸŸŸžžžžžœœœœœ›››››ššššš™™™™˜˜˜˜˜—————––––••••”””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆ‡‡‡‡††††………„„„„ƒƒƒƒ‚‚‚€€€~~~~}}}||||{{{{zzzyyyyxxxxwwwvvvvuuuuttttsssrrrrqqqqppppoooonnnnmmmmllllkkkkkjjjjiiiihhhhhgggggffffeeeeedddddcccccbbbbbaaaaa``````_____^^^^^^]]]]]]\\\\\\[[[[[[[ZZZZZZZYYYYYYYXXXXXXXXWWWWWWWVVVVVVVVUUUUUUUUTTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¡¡¡¡¡¡     ŸŸŸŸŸŸžžžžžžœœœœœ››››šššššš™™™™˜˜˜˜˜————–––––••••””””“““““’’’’‘‘‘‘ŽŽŽŽŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆ‡‡‡‡††††………„„„„ƒƒƒƒ‚‚‚€€€~~~~}}}||||{{{{zzzyyyyxxxxwwwvvvvuuuuttttsssrrrrqqqqppppoooonnnnmmmmlllllkkkkjjjjiiiiihhhhgggggffffeeeeeeddddcccccbbbbbaaaaaa``````_____^^^^^^]]]]]\\\\\\\[[[[[[[ZZZZZZZYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVUUUUUUUUUTTTTTTTTTTSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡¡¡     ŸŸŸŸŸŸžžžžžœœœœœ›››››ššššš™™™™™˜˜˜˜—————––––•••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰ˆˆˆˆ‡‡‡‡††††………„„„„ƒƒƒƒ‚‚‚€€€~~~~}}}||||{{{{zzzyyyyxxxxwwwwvvvuuuuttttssssrrrrqqqqppppoooonnnnmmmmllllkkkkjjjjjiiiihhhhhggggfffffeeeeedddddcccccbbbbbaaaaa``````_____^^^^^^^]]]]]]\\\\\\[[[[[[ZZZZZZZYYYYYYYYXXXXXXXWWWWWWWWVVVVVVVVUUUUUUUUTTTTTTTTTTSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤£££££££¢¢¢¢¢¢¡¡¡¡¡¡     ŸŸŸŸŸŸžžžžžžœœœœœ›››››šššš™™™™™˜˜˜˜˜—————––––••••”””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰ˆˆˆˆ‡‡‡‡†††…………„„„„ƒƒƒƒ‚‚‚€€€~~~~}}}||||{{{{zzzzyyyxxxxwwwwvvvuuuuttttssssrrrrqqqqppppoooonnnnmmmmllllkkkkkjjjjiiiihhhhhgggggfffffeeeedddddcccccbbbbbaaaaaa``````_____^^^^^^]]]]]]\\\\\\\[[[[[[ZZZZZZZYYYYYYYXXXXXXXWWWWWWWWVVVVVVVVVUUUUUUUUUTTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžœœœœœ›››››ššššš™™™™™˜˜˜˜˜————–––––••••””””““““’’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡†††…………„„„„ƒƒƒ‚‚‚‚€€€~~~~}}}}|||{{{{zzzzyyyxxxxwwwwvvvvuuuttttssssrrrrqqqqppppoooonnnnmmmmmllllkkkkjjjjiiiiihhhhgggggfffffeeeeedddddcccccbbbbbaaaaa``````______^^^^^^]]]]]]\\\\\\[[[[[[ZZZZZZZZYYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¡¡¡¡¡¡     ŸŸŸŸŸŸžžžžžœœœœœ›››››ššššš™™™™˜˜˜˜˜—————––––•••••””””““““’’’’’‘‘‘‘ŽŽŽŽŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡†††…………„„„„ƒƒƒ‚‚‚‚€€€~~~~}}}}|||{{{{zzzzyyyxxxxwwwwvvvvuuuuttttsssrrrrqqqqppppoooonnnnmmmmmllllkkkkjjjjjiiiihhhhhgggggffffeeeeedddddcccccbbbbbbaaaaa``````_____^^^^^^]]]]]]\\\\\\\[[[[[[[ZZZZZZYYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVUUUUUUUUUTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžœœœœœ›››››ššššš™™™™™˜˜˜˜˜—————––––••••”””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡††††…………„„„„ƒƒƒ‚‚‚‚€€€~~~~}}}}|||{{{{zzzzyyyyxxxwwwwvvvvuuuuttttssssrrrqqqqpppppoooonnnnmmmmllllkkkkkjjjjiiiihhhhhgggggfffffeeeeedddddcccccbbbbbaaaaa``````______^^^^^^]]]]]]\\\\\\[[[[[[[ZZZZZZZYYYYYYYYXXXXXXXWWWWWWWWVVVVVVVVVUUUUUUUUUTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¡¡¡¡¡¡     ŸŸŸŸŸŸžžžžžœœœœœœ›››››ššššš™™™™™˜˜˜˜—————–––––••••””””“““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡††††…………„„„„ƒƒƒ‚‚‚‚€€€~~~~}}}}|||{{{{zzzzyyyyxxxwwwwvvvvuuuuttttssssrrrrqqqqppppoooonnnnmmmmlllllkkkkjjjjiiiiihhhhhggggfffffeeeeedddddcccccbbbbbbaaaaa``````_____^^^^^^]]]]]]]\\\\\\\[[[[[[ZZZZZZZYYYYYYYXXXXXXXXWWWWWWWVVVVVVVVVUUUUUUUUUTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKJJJJJJJJµµµµµµµµ´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤£££££££¢¢¢¢¢¢¡¡¡¡¡¡     ŸŸŸŸŸŸžžžžžžœœœœœœ›››››šššš™™™™™˜˜˜˜˜————–––––••••”””””““““’’’’‘‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒ‚‚‚‚€€€~~~~}}}}|||{{{{zzzzyyyyxxxxwwwvvvvuuuuttttssssrrrrqqqqppppoooonnnnnmmmmllllkkkkkjjjjiiiiihhhhgggggfffffeeeedddddcccccbbbbbbaaaaaa``````_____^^^^^^]]]]]]\\\\\\\[[[[[[ZZZZZZZZYYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVVUUUUUUUUUTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKJJJJJJJJµµµµµµ´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤£££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžœœœœœ›››››ššššš™™™™™˜˜˜˜˜————–––––••••”””””““““’’’’‘‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„ƒƒƒƒ‚‚‚‚€€€~~~~}}}}||||{{{zzzzyyyyxxxxwwwwvvvuuuuttttssssrrrrqqqqppppoooonnnnnmmmmllllkkkkkjjjjiiiiihhhhgggggfffffeeeeedddddcccccbbbbbbaaaaa``````______^^^^^^]]]]]]\\\\\\\[[[[[[ZZZZZZZYYYYYYYYXXXXXXXWWWWWWWWVVVVVVVVVUUUUUUUUUTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKJJJJJµµµµ´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¡¡¡¡¡¡     ŸŸŸŸŸŸžžžžžžœœœœœ››››››ššššš™™™™™˜˜˜˜—————––––•••••””””“““““’’’’‘‘‘‘ŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„ƒƒƒƒ‚‚‚‚€€€~~~~}}}}||||{{{zzzzyyyyxxxxwwwwvvvuuuuttttssssrrrrrqqqpppppoooonnnnmmmmlllllkkkkjjjjjiiiihhhhhggggfffffeeeeeddddddcccccbbbbbaaaaaa``````_____^^^^^^]]]]]]\\\\\\\[[[[[[[ZZZZZZZYYYYYYYYXXXXXXXWWWWWWWWWVVVVVVVVUUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKJJJµµµµ´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤¤££££££¢¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœ›››››ššššš™™™™™˜˜˜˜˜————–––––••••”””””““““’’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„ƒƒƒƒ‚‚‚‚€€€~~~~}}}}||||{{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqppppoooonnnnmmmmmllllkkkkkjjjjiiiiihhhhgggggfffffeeeeedddddcccccbbbbbaaaaaa``````______^^^^^^]]]]]]]\\\\\\[[[[[[[ZZZZZZZYYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVVUUUUUUUUUTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKJJJµµ´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤££££££¢¢¢¢¢¢¢¡¡¡¡¡¡     ŸŸŸŸŸŸžžžžžžœœœœœ›››››ššššš™™™™™˜˜˜˜˜—————–––––••••”””””““““’’’’‘‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††………„„„„ƒƒƒƒ‚‚‚‚€€€~~~~}}}}||||{{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqppppoooonnnnnmmmmllllkkkkkjjjjiiiiihhhhhgggggfffffeeeeedddddcccccbbbbbaaaaaa``````_____^^^^^^]]]]]]]\\\\\\[[[[[[[ZZZZZZZZYYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVVUUUUUUUUUTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKJ´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžœœœœœ›››››ššššš™™™™™˜˜˜˜˜—————––––•••••””””“““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††………„„„„ƒƒƒƒ‚‚‚‚€€€~~~~}}}}||||{{{{zzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqpppppoooonnnnmmmmlllllkkkkjjjjjiiiihhhhhgggggfffffeeeeedddddcccccbbbbbbaaaaa``````______^^^^^^^]]]]]]\\\\\\[[[[[[[ZZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKK´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¡¡¡¡¡¡¡     ŸŸŸŸŸŸžžžžžžœœœœœ››››››ššššš™™™™™˜˜˜˜—————–––––••••”””””““““’’’’’‘‘‘‘ŽŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡†††…………„„„„ƒƒƒƒ‚‚‚‚€€€~~~~}}}}||||{{{{zzzzyyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqqppppoooonnnnmmmmmllllkkkkjjjjjiiiiihhhhhggggfffffeeeeeddddddcccccbbbbbaaaaaa``````_____^^^^^^^]]]]]]\\\\\\\[[[[[[[ZZZZZZZYYYYYYYYXXXXXXXWWWWWWWWWVVVVVVVVUUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKK´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœœ›››››ššššš™™™™™˜˜˜˜˜—————––––•••••”””””““““’’’’‘‘‘‘‘ŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€~~~~}}}}||||{{{{zzzzyyyyxxxwwwwvvvvuuuuttttssssrrrrrqqqqppppoooonnnnnmmmmllllkkkkkjjjjjiiiihhhhhgggggfffffeeeeedddddccccccbbbbbaaaaaa``````_____^^^^^^^]]]]]]\\\\\\\[[[[[[[ZZZZZZZYYYYYYYXXXXXXXXWWWWWWWWWVVVVVVVVUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKK´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤££££££¢¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœœ›››››ššššš™™™™™˜˜˜˜˜—————––––•••••”””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹‹ŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuutttttssssrrrrqqqqppppooooonnnnmmmmllllkkkkkjjjjjiiiihhhhhgggggfffffeeeeedddddccccccbbbbbaaaaaa``````______^^^^^^]]]]]]]\\\\\\[[[[[[[ZZZZZZZZYYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVVUUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKK´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœ›››››ššššš™™™™™˜˜˜˜˜—————–––––•••••””””“““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqpppppoooonnnnmmmmlllllkkkkjjjjjiiiiihhhhhgggggfffffeeeeedddddcccccbbbbbbaaaaaa``````______^^^^^^]]]]]]\\\\\\\[[[[[[[ZZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVVUUUUUUUUUUTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQQQPPPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKK´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœœ›››››ššššš™™™™™˜˜˜˜˜—————––––•••••”””””““““’’’’’‘‘‘‘ŽŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqqppppoooonnnnmmmmmllllkkkkkjjjjjiiiihhhhhgggggfffffeeeeedddddccccccbbbbbaaaaaa``````______^^^^^^]]]]]]]\\\\\\\[[[[[[[ZZZZZZZYYYYYYYYXXXXXXXWWWWWWWWWVVVVVVVVUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLKKKKKKKKKKKKK´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœ›››››šššššš™™™™™˜˜˜˜˜—————––––•••••””””“““““’’’’‘‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrrqqqqppppoooonnnnnmmmmlllllkkkkjjjjjiiiihhhhhgggggfffffeeeeeedddddcccccbbbbbbaaaaaa``````______^^^^^^]]]]]]\\\\\\\[[[[[[[ZZZZZZZZYYYYYYYXXXXXXXXXWWWWWWWWVVVVVVVVVUUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQQPPPPPPPPPPPOOOOOOOOOOOOOOONNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKKKKKKKKKK´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœ››››››ššššš™™™™™˜˜˜˜˜—————–––––•••••””””“““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttsssssrrrrqqqqppppooooonnnnmmmmlllllkkkkjjjjjiiiiihhhhhgggggfffffeeeeeddddddcccccbbbbbbaaaaaa``````______^^^^^^]]]]]]\\\\\\\[[[[[[[ZZZZZZZZYYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVVUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLKKKKKKKKK´´´´´´´´´³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœ››››››ššššš™™™™™˜˜˜˜˜————–––––•••••”””””““““’’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuutttttssssrrrrqqqqpppppoooonnnnmmmmmllllkkkkkjjjjjiiiiihhhhgggggfffffeeeeeddddddcccccbbbbbbaaaaaa``````______^^^^^^]]]]]]]\\\\\\\[[[[[[[ZZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWWVVVVVVVVVUUUUUUUUUTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPOOOOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKKKKKK´´´´´´´´´³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœœ›››››ššššš™™™™™˜˜˜˜˜—————–––––•••••””””“““““’’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvvuuuuttttssssrrrrqqqqpppppoooonnnnmmmmmlllllkkkkjjjjjiiiiihhhhhgggggfffffeeeeedddddccccccbbbbbbaaaaa```````______^^^^^^]]]]]]]\\\\\\\[[[[[[[ZZZZZZZYYYYYYYYXXXXXXXWWWWWWWWWVVVVVVVVVUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQQQPPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKKKKKK´´´´´´³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœ›››››šššššš™™™™™˜˜˜˜˜—————–––––•••••””””“““““’’’’‘‘‘‘‘ŽŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€~~~~}}}}||||{{{{zzzzyyyyxxxxxwwwwvvvvuuuuttttssssrrrrqqqqqppppoooonnnnnmmmmlllllkkkkjjjjjiiiiihhhhhgggggfffffeeeeeedddddcccccbbbbbbaaaaaa``````______^^^^^^]]]]]]]\\\\\\\[[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWWVVVVVVVVUUUUUUUUUTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLKKKKK´´´´´³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸŸžžžžžœœœœœœ›››››ššššš™™™™™˜˜˜˜˜—————–––––•••••”””””““““’’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††……………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrrqqqqppppooooonnnnmmmmmllllkkkkkjjjjjiiiiihhhhhgggggfffffeeeeedddddccccccbbbbbbaaaaa```````______^^^^^^]]]]]]]\\\\\\\[[[[[[[ZZZZZZZZYYYYYYYXXXXXXXXWWWWWWWWWVVVVVVVVVUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKK´´´´´³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬«««««««««««ªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¡¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœœ››››››ššššš™™™™™˜˜˜˜˜—————–––––•••••””””“““““’’’’’‘‘‘‘ŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttsssssrrrrqqqqpppppoooonnnnmmmmmlllllkkkkjjjjjiiiiihhhhhgggggfffffeeeeeddddddccccccbbbbbaaaaaa``````______^^^^^^^]]]]]]\\\\\\\[[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXXWWWWWWWWVVVVVVVVVUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKK´´³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬«««««««««ªªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸŸžžžžžžœœœœœœ›››››ššššš™™™™™˜˜˜˜˜˜—————–––––••••”””””“““““’’’’‘‘‘‘‘ŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttsssssrrrrqqqqpppppoooonnnnnmmmmlllllkkkkkjjjjiiiiihhhhhgggggffffffeeeeedddddccccccbbbbbaaaaaa```````______^^^^^^]]]]]]]\\\\\\\[[[[[[[[ZZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVVVUUUUUUUUUUTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLK´³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬«««««««««««ªªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££¢¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸŸžžžžžžœœœœœ››››››ššššš™™™™™˜˜˜˜˜—————–––––•••••”””””““““’’’’’‘‘‘‘‘ŽŽŽŽŽŒŒŒŒ‹‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuutttttssssrrrrqqqqqppppoooonnnnnmmmmmllllkkkkkjjjjjiiiiihhhhhgggggfffffeeeeeddddddcccccbbbbbbaaaaaa```````______^^^^^^]]]]]]]\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWWVVVVVVVVUUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLL´³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸžžžžžœœœœœ››››››šššššš™™™™™˜˜˜˜˜—————–––––•••••””””“““““’’’’’‘‘‘‘ŽŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuuuttttssssrrrrqqqqqppppooooonnnnmmmmmlllllkkkkjjjjjiiiiihhhhhgggggfffffeeeeeeddddddcccccbbbbbbaaaaa```````______^^^^^^^]]]]]]\\\\\\\\[[[[[[[ZZZZZZZZYYYYYYYXXXXXXXXWWWWWWWWWVVVVVVVVVVUUUUUUUUUTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLL³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««««««ªªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸžžžžžžœœœœœ››››››ššššš™™™™™˜˜˜˜˜——————–––––••••”””””“““““’’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvvuuuuttttssssrrrrrqqqqpppppoooonnnnmmmmmlllllkkkkkjjjjiiiiihhhhhhgggggfffffeeeeeddddddcccccbbbbbbaaaaaa```````______^^^^^^^]]]]]]\\\\\\\[[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXXWWWWWWWWVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQQPPPPPPPPPPPPPOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLL³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœœ›››››šššššš™™™™™˜˜˜˜˜—————–––––•••••”””””““““’’’’’‘‘‘‘‘ŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvvuuuuttttsssssrrrrqqqqpppppoooonnnnnmmmmmllllkkkkkjjjjjiiiiihhhhhgggggfffffeeeeeedddddccccccbbbbbbaaaaaa``````______^^^^^^^]]]]]]]\\\\\\\[[[[[[[[ZZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWWVVVVVVVVVVUUUUUUUUUTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQQQPPPPPPPPPPPPPOOOOOOOOOOOOOOONNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLL³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬«««««««««««ªªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸžžžžžžœœœœœ››››››ššššš™™™™™™˜˜˜˜˜—————–––––•••••”””””““““’’’’’‘‘‘‘ŽŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxxwwwwvvvvuuuuttttsssssrrrrqqqqqppppoooonnnnnmmmmmllllkkkkkjjjjjiiiiihhhhhgggggffffffeeeeeddddddcccccbbbbbbaaaaaa```````______^^^^^^^]]]]]]]\\\\\\[[[[[[[[ZZZZZZZYYYYYYYYYXXXXXXXXWWWWWWWWWVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLL³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««ªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœœ›››››šššššš™™™™™˜˜˜˜˜—————–––––•••••”””””“““““’’’’‘‘‘‘‘ŽŽŽŽŽŒŒŒŒ‹‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxxwwwwvvvvuuuutttttssssrrrrqqqqqppppooooonnnnnmmmmlllllkkkkkjjjjjiiiihhhhhhgggggfffffeeeeeedddddccccccbbbbbbaaaaaa``````______^^^^^^^]]]]]]]\\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYXXXXXXXXXWWWWWWWWWVVVVVVVVVUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLL³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››ššššš™™™™™™˜˜˜˜˜—————–––––•••••”””””“““““’’’’‘‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡†††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxxwwwwvvvvuuuutttttssssrrrrrqqqqpppppoooonnnnnmmmmlllllkkkkkjjjjjiiiiihhhhhgggggffffffeeeeeddddddccccccbbbbbaaaaaa```````______^^^^^^^]]]]]]]\\\\\\\[[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXXWWWWWWWWVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRRRQQQQQQQQQQQPPPPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMLLLLLLLLLL³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬«««««««««««ªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸŸžžžžžžœœœœœœ›››››šššššš™™™™™˜˜˜˜˜˜————––––––•••••”””””““““’’’’’‘‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡†††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyyxxxxwwwwvvvvuuuuuttttssssrrrrrqqqqpppppoooonnnnnmmmmmllllkkkkkjjjjjiiiiiihhhhggggggfffffeeeeeedddddccccccbbbbbbaaaaaa```````______^^^^^^]]]]]]]\\\\\\\\[[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWWWVVVVVVVVVUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMLLLLLLLLLL³³³³³³³³³³²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœœ››››››ššššš™™™™™™˜˜˜˜˜—————–––––•••••”””””“““““’’’’’‘‘‘‘ŽŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰‰ˆˆˆˆ‡‡‡‡††††……………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzzyyyyxxxxwwwwvvvvvuuuuttttsssssrrrrqqqqpppppooooonnnnmmmmmlllllkkkkkjjjjjiiiiihhhhhgggggffffffeeeeeddddddccccccbbbbbbaaaaaa``````______^^^^^^^]]]]]]]\\\\\\\[[[[[[[ZZZZZZZZYYYYYYYYYXXXXXXXXWWWWWWWWWVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMLLLLLLLLL³³³³³³³²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸžžžžžžœœœœœœ›››››šššššš™™™™™˜˜˜˜˜——————–––––•••••”””””“““““’’’’‘‘‘‘‘ŽŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰‰ˆˆˆˆ‡‡‡‡††††……………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzzyyyyxxxxwwwwvvvvvuuuuttttsssssrrrrqqqqqppppooooonnnnnmmmmlllllkkkkkjjjjjiiiiihhhhhhgggggfffffeeeeeedddddccccccbbbbbbaaaaaa```````______^^^^^^^]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYXXXXXXXXXWWWWWWWWWVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPPPOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMLLLLLL³³³³³³³²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœœ›››››ššššš™™™™™™˜˜˜˜˜—————––––––•••••””””“““““’’’’’‘‘‘‘‘ŽŽŽŽŽŒŒŒŒ‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰ˆˆˆˆ‡‡‡‡††††……………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzzyyyyxxxxwwwwvvvvvuuuutttttssssrrrrqqqqqpppppoooonnnnnmmmmmlllllkkkkjjjjjiiiiiihhhhhgggggffffffeeeeedddddccccccbbbbbbbaaaaaa``````______^^^^^^^]]]]]]]]\\\\\\\[[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXXWWWWWWWWVVVVVVVVVVUUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMLLLLLL³³³³³³²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬«««««««««««ªªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››ššššš™™™™™˜˜˜˜˜˜—————–––––•••••”””””“““““’’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆˆ‡‡‡‡††††…………„„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{{zzzzyyyyxxxxwwwwwvvvvuuuutttttssssrrrrrqqqqpppppooooonnnnmmmmmlllllkkkkkjjjjjiiiiihhhhhggggggfffffeeeeeddddddccccccbbbbbbaaaaaa```````______^^^^^^^]]]]]]]\\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXXWWWWWWWWWVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPPPOOOOOOOOOOOOOOONNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMLLLLL³³³²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««ªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡       ŸŸŸŸŸŸžžžžžžžœœœœœ››››››šššššš™™™™™˜˜˜˜˜——————–––––•••••”””””“““““’’’’‘‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡‡††††…………„„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{{zzzzyyyyxxxxxwwwwvvvvuuuuuttttssssrrrrrqqqqpppppooooonnnnnmmmmlllllkkkkkjjjjjiiiiihhhhhhgggggfffffeeeeeeddddddcccccbbbbbbaaaaaaa``````_______^^^^^^]]]]]]]]\\\\\\\[[[[[[[ZZZZZZZZYYYYYYYYYXXXXXXXXWWWWWWWWWVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMLL³³³²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬«««««««««««ªªªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¡¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››ššššš™™™™™™˜˜˜˜˜—————–––––••••••””””“““““’’’’’‘‘‘‘‘ŽŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡‡††††…………„„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{{zzzzyyyyxxxxxwwwwvvvvuuuuuttttsssssrrrrqqqqqppppooooonnnnnmmmmmlllllkkkkjjjjjjiiiiihhhhhgggggffffffeeeeeddddddccccccbbbbbbaaaaaa```````______^^^^^^^^]]]]]]\\\\\\\[[[[[[[[ZZZZZZZZZYYYYYYYXXXXXXXXXWWWWWWWWWWVVVVVVVVUUUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMLL³³²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬«««««««««««ªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸžžžžžžžœœœœœœ››››››šššššš™™™™™˜˜˜˜˜˜—————–––––•••••”””””“““““’’’’’‘‘‘‘‘ŽŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡‡††††…………„„„„ƒƒƒƒƒ‚‚‚‚€€€€~~~~}}}}|||||{{{{zzzzyyyyxxxxxwwwwvvvvuuuuuttttsssssrrrrqqqqqpppppoooonnnnnmmmmmlllllkkkkkjjjjjiiiiihhhhhggggggfffffeeeeeeddddddccccccbbbbbaaaaaaa```````______^^^^^^^]]]]]]]\\\\\\\\[[[[[[[ZZZZZZZZYYYYYYYYYXXXXXXXXWWWWWWWWWVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMML²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžžœœœœœœ›››››šššššš™™™™™™˜˜˜˜˜——————–––––•••••”””””“““““’’’’’‘‘‘‘ŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡††††…………„„„„ƒƒƒƒƒ‚‚‚‚€€€€~~~~}}}}|||||{{{{zzzzyyyyxxxxxwwwwvvvvvuuuuttttsssssrrrrrqqqqpppppooooonnnnmmmmmlllllkkkkkjjjjjiiiiihhhhhhgggggffffffeeeeeddddddccccccbbbbbbaaaaaaa``````______^^^^^^^^]]]]]]]\\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXXWWWWWWWWWVVVVVVVVVUUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMM²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššššš™™™™™˜˜˜˜˜˜—————–––––•••••”””””““““““’’’’‘‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰ˆˆˆˆ‡‡‡‡†††††…………„„„„ƒƒƒƒƒ‚‚‚‚€€€€~~~~}}}}|||||{{{{zzzzyyyyyxxxxwwwwvvvvvuuuutttttssssrrrrrqqqqpppppooooonnnnnmmmmllllllkkkkkjjjjjiiiiihhhhhggggggfffffeeeeeeddddddccccccbbbbbbaaaaaa```````______^^^^^^^]]]]]]]\\\\\\\\[[[[[[[ZZZZZZZZYYYYYYYYYXXXXXXXXWWWWWWWWWWVVVVVVVVVVUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMM²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡       ŸŸŸŸŸŸžžžžžžžœœœœœœ››››››šššššš™™™™™˜˜˜˜˜——————–––––•••••”””””“““““’’’’’‘‘‘‘‘ŽŽŽŽŽŒŒŒŒ‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰ˆˆˆˆ‡‡‡‡†††††…………„„„„ƒƒƒƒƒ‚‚‚‚€€€€~~~~}}}}|||||{{{{zzzzyyyyyxxxxwwwwvvvvvuuuutttttssssrrrrrqqqqqpppppoooonnnnnmmmmmlllllkkkkkjjjjjiiiiihhhhhhgggggfffffeeeeeeddddddccccccbbbbbbaaaaaaa``````_______^^^^^^^]]]]]]]\\\\\\\[[[[[[[[ZZZZZZZZZYYYYYYYXXXXXXXXXXWWWWWWWWWVVVVVVVVVUUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMM²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¡¡¡¡¡¡       ŸŸŸŸŸŸŸžžžžžžœœœœœœœ›››››šššššš™™™™™™˜˜˜˜˜—————––––––•••••”””””“““““’’’’’‘‘‘‘‘ŽŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠ‰‰‰‰ˆˆˆˆˆ‡‡‡‡†††††…………„„„„ƒƒƒƒƒ‚‚‚‚€€€€~~~~}}}}|||||{{{{zzzzyyyyyxxxxwwwwwvvvvuuuuuttttsssssrrrrqqqqqpppppoooonnnnnmmmmmlllllkkkkkjjjjjiiiiiihhhhhgggggffffffeeeeeedddddcccccccbbbbbbaaaaaa```````_______^^^^^^]]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYYXXXXXXXXWWWWWWWWWVVVVVVVVVVVUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRRRQQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMMMMMMMMMM²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸžžžžžžžœœœœœœ››››››ššššš™™™™™™˜˜˜˜˜˜—————–––––•••••””””””““““’’’’’‘‘‘‘‘ŽŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠ‰‰‰‰ˆˆˆˆˆ‡‡‡‡††††……………„„„„ƒƒƒƒ‚‚‚‚‚€€€€~~~~}}}}|||||{{{{zzzzzyyyyxxxxwwwwwvvvvuuuuuttttsssssrrrrqqqqqpppppooooonnnnnmmmmmllllkkkkkkjjjjjiiiiihhhhhggggggffffffeeeeeddddddccccccbbbbbbaaaaaaa```````______^^^^^^^]]]]]]]]\\\\\\[[[[[[[[ZZZZZZZZZYYYYYYYYXXXXXXXXXWWWWWWWWWVVVVVVVVVVUUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMM²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««ªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡       ŸŸŸŸŸŸŸžžžžžžœœœœœ››››››šššššš™™™™™™˜˜˜˜˜——————–––––•••••”””””“““““’’’’’‘‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹‹ŠŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡‡††††……………„„„„ƒƒƒƒ‚‚‚‚‚€€€€~~~~}}}}}||||{{{{zzzzzyyyyxxxxxwwwwvvvvuuuuutttttssssrrrrrqqqqpppppooooonnnnnmmmmmlllllkkkkkjjjjjiiiiihhhhhhgggggffffffeeeeeeddddddcccccbbbbbbbaaaaaa```````_______^^^^^^^]]]]]]]\\\\\\\\[[[[[[[ZZZZZZZZYYYYYYYYYXXXXXXXXWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMMMMMMMM²²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸžžžžžžžœœœœœœ››››››šššššš™™™™™˜˜˜˜˜˜—————–––––••••••”””””“““““’’’’’‘‘‘‘‘ŽŽŽŽŽŒŒŒŒ‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡††††……………„„„„ƒƒƒƒ‚‚‚‚‚€€€€~~~~}}}}}||||{{{{zzzzzyyyyxxxxxwwwwvvvvvuuuutttttssssrrrrrqqqqqpppppoooonnnnnmmmmmlllllkkkkkjjjjjjiiiiihhhhhggggggfffffeeeeeeddddddccccccbbbbbbaaaaaaa```````______^^^^^^^]]]]]]]]\\\\\\\[[[[[[[[ZZZZZZZZZYYYYYYYXXXXXXXXXXWWWWWWWWWVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRRRQQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMMMMMM²²²²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡       ŸŸŸŸŸŸžžžžžžžœœœœœœ›››››››ššššš™™™™™™˜˜˜˜˜——————–––––•••••””””””““““’’’’’’‘‘‘‘ŽŽŽŽŽŒŒŒŒ‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡††††……………„„„„ƒƒƒƒ‚‚‚‚‚€€€€~~~~}}}}}||||{{{{zzzzzyyyyxxxxxwwwwvvvvvuuuutttttssssrrrrrqqqqqpppppooooonnnnmmmmmlllllkkkkkkjjjjjiiiiihhhhhhgggggffffffeeeeedddddddccccccbbbbbbaaaaaaa``````_______^^^^^^^]]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYYXXXXXXXXWWWWWWWWWWVVVVVVVVVUUUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSSSSRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMMMMM²²²²²²²²²±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªªª©©©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡       ŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššššš™™™™™˜˜˜˜˜˜—————––––––•••••”””””“““““’’’’’‘‘‘‘‘ŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠ‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡††††……………„„„„ƒƒƒƒ‚‚‚‚‚€€€€~~~~}}}}}||||{{{{zzzzzyyyyxxxxxwwwwvvvvvuuuutttttsssssrrrrrqqqqpppppooooonnnnnmmmmmlllllkkkkkjjjjjiiiiiihhhhhggggggfffffeeeeeeddddddccccccbbbbbbbaaaaaa```````_______^^^^^^]]]]]]]]\\\\\\\[[[[[[[[ZZZZZZZZZYYYYYYYYXXXXXXXXXXWWWWWWWWVVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNMMMMMMMM²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§§¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡       ŸŸŸŸŸŸŸžžžžžžœœœœœœœ›››››šššššš™™™™™™˜˜˜˜˜——————–––––••••••”””””“““““’’’’’‘‘‘‘‘ŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠ‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡††††…………„„„„„ƒƒƒƒ‚‚‚‚‚€€€€~~~~}}}}}||||{{{{{zzzzyyyyxxxxxwwwwvvvvvuuuuuttttsssssrrrrrqqqqpppppooooonnnnnmmmmmlllllkkkkkjjjjjjiiiiihhhhhhgggggffffffeeeeeedddddcccccccbbbbbbaaaaaa```````_______^^^^^^^]]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYYXXXXXXXXXWWWWWWWWWWVVVVVVVVVUUUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRRRQQQQQQQQQQQQQPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMM²²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªªª©©©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡       ŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššššš™™™™™™˜˜˜˜˜——————–––––•••••””””””“““““’’’’’‘‘‘‘‘ŽŽŽŽŽŒŒŒŒ‹‹‹‹‹ŠŠŠŠŠ‰‰‰‰ˆˆˆˆˆ‡‡‡‡†††††…………„„„„„ƒƒƒƒ‚‚‚‚‚€€€€~~~~}}}}}||||{{{{{zzzzyyyyyxxxxwwwwwvvvvuuuuutttttssssrrrrrqqqqqpppppoooonnnnnmmmmmlllllkkkkkkjjjjjiiiiihhhhhhgggggffffffeeeeeeddddddccccccbbbbbbbaaaaaa```````_______^^^^^^]]]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZZYYYYYYYXXXXXXXXXXWWWWWWWWWVVVVVVVVVVVUUUUUUUUUTTTTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMMM²²²²²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««ªªªªªªªªªªª©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸŸžžžžžžœœœœœœœ›››››ššššššš™™™™™˜˜˜˜˜˜—————––––––•••••”””””“““““’’’’’’‘‘‘‘ŽŽŽŽŽŒŒŒŒ‹‹‹‹‹ŠŠŠŠŠ‰‰‰‰ˆˆˆˆˆ‡‡‡‡†††††…………„„„„„ƒƒƒƒ‚‚‚‚‚€€€€~~~~}}}}}||||{{{{{zzzzyyyyyxxxxwwwwwvvvvuuuuutttttssssrrrrrqqqqqpppppooooonnnnmmmmmmlllllkkkkkjjjjjiiiiiihhhhhggggggfffffeeeeeeedddddcccccccbbbbbbaaaaaa````````______^^^^^^^]]]]]]]]\\\\\\\[[[[[[[[[ZZZZZZZZYYYYYYYYYXXXXXXXXWWWWWWWWWWWVVVVVVVVVUUUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRRRQQQQQQQQQQQQQPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNMMMMM²²²±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««ªªªªªªªªªª©©©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡       ŸŸŸŸŸŸŸžžžžžžžœœœœœœ››››››šššššš™™™™™™˜˜˜˜˜——————–––––••••••”””””“““““’’’’’‘‘‘‘‘ŽŽŽŽŽŒŒŒŒŒ‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰ˆˆˆˆˆ‡‡‡‡†††††…………„„„„„ƒƒƒƒ‚‚‚‚‚€€€€~~~~}}}}}||||{{{{{zzzzyyyyyxxxxwwwwwvvvvvuuuutttttsssssrrrrqqqqqpppppooooonnnnnmmmmmlllllkkkkkjjjjjjiiiiihhhhhhgggggffffffeeeeeeddddddccccccbbbbbbaaaaaaa```````_______^^^^^^^]]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZZYYYYYYYYXXXXXXXXXXWWWWWWWWWVVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNMM²²²±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬«««««««««««ªªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸŸžžžžžžœœœœœœ›››››››ššššš™™™™™™˜˜˜˜˜˜——————–––––•••••”””””““““““’’’’’‘‘‘‘‘ŽŽŽŽŒŒŒŒŒ‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡†††††…………„„„„„ƒƒƒƒ‚‚‚‚‚€€€€~~~~}}}}}||||{{{{{zzzzyyyyyxxxxxwwwwvvvvvuuuutttttsssssrrrrrqqqqpppppooooonnnnnmmmmmllllllkkkkkjjjjjiiiiihhhhhhggggggffffffeeeeedddddddccccccbbbbbbaaaaaa````````______^^^^^^^^]]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYYXXXXXXXXXWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSSRRRRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPPOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNMM²²±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««ªªªªªªªªªªª©©©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡       ŸŸŸŸŸŸŸžžžžžžžœœœœœœ››››››šššššš™™™™™™˜˜˜˜˜˜—————––––––•••••”””””“““““’’’’’‘‘‘‘‘‘ŽŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠ‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡††††……………„„„„„ƒƒƒƒ‚‚‚‚‚€€€€~~~~}}}}}||||{{{{{zzzzzyyyyxxxxxwwwwvvvvvuuuuuttttsssssrrrrrqqqqqpppppoooonnnnnnmmmmmlllllkkkkkjjjjjiiiiiihhhhhggggggffffffeeeeeeddddddccccccbbbbbbaaaaaaa```````_______^^^^^^^]]]]]]]]\\\\\\\\[[[[[[[ZZZZZZZZZYYYYYYYYXXXXXXXXXXXWWWWWWWWVVVVVVVVVVVUUUUUUUUUUUTTTTTTTTTTTSSSSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQQPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNM±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§§¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤£££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡       ŸŸŸŸŸŸŸžžžžžžžœœœœœœ›››››››šššššš™™™™™™˜˜˜˜˜——————–––––••••••”””””“““““’’’’’‘‘‘‘‘ŽŽŽŽŽŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠ‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡††††……………„„„„ƒƒƒƒƒ‚‚‚‚€€€€~~~~~}}}}|||||{{{{zzzzzyyyyxxxxxwwwwvvvvvuuuuuttttsssssrrrrrqqqqqpppppooooonnnnnmmmmmlllllkkkkkjjjjjjiiiiihhhhhhgggggffffffeeeeeedddddddccccccbbbbbbaaaaaaa```````_______^^^^^^^]]]]]]]]\\\\\\\[[[[[[[[[ZZZZZZZYYYYYYYYYYXXXXXXXXXWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNmlt-0.9.0/demo/mlt_all000066400000000000000000000000221215300731300145740ustar00rootroot00000000000000melt \ clip* \ $* mlt-0.9.0/demo/mlt_attributes000066400000000000000000000004651215300731300162250ustar00rootroot00000000000000melt clip1.dv \ meta.attr.location=1 meta.attr.location.markup="Location" \ meta.attr.exclusive=1 meta.attr.exclusive.markup="Exclusive" \ meta.attr.special=1 meta.attr.special.markup="Special" \ meta.attr.super=1 meta.attr.super.0="Line 1" meta.attr.super.1="Line 2" \ -filter data_show:%etv.properties \ $* mlt-0.9.0/demo/mlt_audio_stuff000066400000000000000000000002001215300731300163320ustar00rootroot00000000000000melt \ clip*.dv \ -track music1.ogg \ -filter volume:0.5 normalise= track=0 \ -transition mix out=9999 a_track=0 b_track=1 \ $* mlt-0.9.0/demo/mlt_avantika_title000066400000000000000000000000261215300731300170270ustar00rootroot00000000000000melt \ pango.mlt \ $* mlt-0.9.0/demo/mlt_bouncy000066400000000000000000000003221215300731300153260ustar00rootroot00000000000000melt \ clip3.dv \ -filter \ watermark:clip1.dv \ composite.start=10%/10%:20%x20% \ composite.key[33]=30%/70%:25%x25% \ composite.key[66]=70%/30%:15%x15% \ composite.end=70%/70%:20%x20% \ composite.out=100 \ $* mlt-0.9.0/demo/mlt_bouncy_ball000066400000000000000000000003761215300731300163310ustar00rootroot00000000000000melt \ clip3.dv \ -track \ clip1.dv \ -transition \ region:circle \ composite.geometry="10%,10%:20%x20%;33=30%/70%:25%x25%;66=70%/30%:15%x15%;-1=70%/70%:20%x20%" \ composite.out=100 \ composite.softness=0.1 \ a_track=0 \ b_track=1 \ in=0 \ out=5000 \ $* mlt-0.9.0/demo/mlt_clock_in_and_out000066400000000000000000000004171215300731300173260ustar00rootroot00000000000000melt \ clip2.dv in=100 out=174 -blank 99 clip3.dv in=100 \ -track \ -blank 49 clip3.mpeg in=100 out=249 \ -transition luma:luma1.pgm softness=0.5 in=50 out=74 a_track=0 b_track=1 \ -transition luma:luma1.pgm softness=0.2 in=175 out=199 a_track=0 b_track=1 reverse=1 \ $* mlt-0.9.0/demo/mlt_composite_transition000066400000000000000000000003521215300731300203060ustar00rootroot00000000000000melt \ clip1.dv out=74 \ -track \ -blank 49 clip2.mpeg \ -transition composite:57%/10%:33%x33% end=0%/0%:100%x100% progressive=1 distort=true in=50 out=74 a_track=0 b_track=1 \ -transition mix:-1 in=50 out=74 a_track=0 b_track=1 \ $* mlt-0.9.0/demo/mlt_effect_in_middle000066400000000000000000000001111215300731300172630ustar00rootroot00000000000000melt \ clip1.mpeg in=100 out=500 \ -filter greyscale in=100 out=199 \ $* mlt-0.9.0/demo/mlt_fade_black000066400000000000000000000004441215300731300160670ustar00rootroot00000000000000melt \ colour:black out=199 \ -track \ clip3.mpeg in=100 out=299 \ -transition luma in=0 out=49 a_track=0 b_track=1 \ -transition luma in=150 out=199 a_track=0 b_track=1 reverse=1 \ -filter volume in=0 out=49 track=1 gain=0 end=1.0 \ -filter volume in=150 out=199 track=1 gain=1.0 end=0 \ $* mlt-0.9.0/demo/mlt_fade_in_and_out000066400000000000000000000005111215300731300171250ustar00rootroot00000000000000melt \ clip1.dv out=74 -blank 99 clip3.dv in=25 \ -track \ -blank 49 clip2.mpeg out=149 \ -transition luma in=50 out=74 a_track=0 b_track=1 \ -transition luma in=175 out=199 a_track=0 b_track=1 reverse=1 \ -transition mix:-1 in=50 out=74 a_track=0 b_track=1 \ -transition mix:-1 in=175 out=199 a_track=0 b_track=1 reverse=1 \ $* mlt-0.9.0/demo/mlt_intro000066400000000000000000000002611215300731300151640ustar00rootroot00000000000000melt \ music1.ogg in=100 out=224 \ -track \ watermark1.png out=124 \ clip3.mpeg \ -mix 25 \ -mixer luma resource=luma1.pgm softness=0.2 \ -transition mix:-1 in=100 out=124 \ $* mlt-0.9.0/demo/mlt_jcut000066400000000000000000000002751215300731300150030ustar00rootroot00000000000000melt \ -blank 49 \ clip2.dv in=100 \ -track \ clip1.dv out=99 \ -transition \ mix start=0 end=1 in=49 out=50 a_track=1 b_track=0 \ -transition \ mix:1 in=51 out=99 a_track=1 b_track=0 \ $* mlt-0.9.0/demo/mlt_lcut000066400000000000000000000003651215300731300150050ustar00rootroot00000000000000melt \ clip1.dv out=100 \ -track \ -blank 49 \ clip2.dv in=100 \ -transition \ luma in=50 out=55 a_track=0 b_track=1 \ -transition \ mix:1 in=50 out=98 a_track=1 b_track=0 \ -transition \ mix start=1 end=0 in=99 out=100 a_track=1 b_track=0 \ $* mlt-0.9.0/demo/mlt_levels000066400000000000000000000001061215300731300153210ustar00rootroot00000000000000melt \ *.dv \ -filter gamma:1.5 \ -filter volume normalise=-20db \ $* mlt-0.9.0/demo/mlt_my_name_is000066400000000000000000000007231215300731300161540ustar00rootroot00000000000000melt \ clip3.dv \ -track \ "+My name is Inigo Montoya.txt" out=99 -blank 49 "+Prepare to die!.txt" out=99 \ -track \ -blank 74 "+You killed my father.txt" out=74 \ -transition composite:50%/20%:5%x4% end=10%/20%:80%x12% distort=1 halign=centre valign=centre in=0 out=99 a_track=0 b_track=1 \ -transition composite:0%/70%:100%x10% end=100%/70%:100%x10% in=75 out=149 a_track=0 b_track=2 \ -transition composite:25%/25%:50%x50%! in=150 out=249 a_track=0 b_track=1 \ $* mlt-0.9.0/demo/mlt_news000066400000000000000000000014641215300731300150130ustar00rootroot00000000000000melt \ colour:black out=199 \ -track \ clip1.dv in=0 out=0 -repeat 99 clip1.dv \ -track \ clip2.dv out=199 \ -track \ pango: text=" Breaking News MLT Rocks India" bgcolour=0xff000080 out=149 \ pango: text=" Breaking News MLT Rocks the World" bgcolour=0xff000080 out=349 \ -transition mix:0.5 always_active=1 a_track=0 b_track=2 \ -transition composite geometry=50%/15%:37.5%x40% a_track=0 b_track=1 in=0 out=174 \ -transition composite geometry=10%/15%:37.5%x40% a_track=0 b_track=2 in=0 out=199 \ -transition composite geometry="50%/15%:37.5%x40%;-1=0%/0%:100%x100%" a_track=0 b_track=1 in=175 out=199 distort=1 \ -transition composite geometry=10%/65%:90%x20% a_track=0 b_track=3 in=0 out=199 \ -transition composite geometry=10%/65%:90%x20% a_track=1 b_track=3 in=200 out=499 \ $* mlt-0.9.0/demo/mlt_obscure000066400000000000000000000002441215300731300154740ustar00rootroot00000000000000melt \ clip2.mpeg \ -filter obscure:25%/25%:25%x25%:10x10 in=0 out=68 \ -filter region:circle.png filter=obscure composite.start=55%/25%:12%x50% in=68 out=200 \ $* mlt-0.9.0/demo/mlt_pango_keyframes000066400000000000000000000001471215300731300172060ustar00rootroot00000000000000melt \ color:#03CF0 \ -filter watermark:pango_keyframes.mpl composite.halign=c composite.valign=m \ $* mlt-0.9.0/demo/mlt_push000066400000000000000000000006301215300731300150100ustar00rootroot00000000000000melt \ -blank 49 colour:black out=25 -blank 999 \ -track \ clip3.dv in=200 out=275 \ -track \ -blank 49 \ clip2.dv in=200 \ -transition \ composite in=50 out=75 a_track=0 b_track=1 \ start=0/0:100%x100%:100 \ end=100%/0:100%x100%:100 \ -transition \ composite in=50 out=75 a_track=0 b_track=2 \ start=-100%/0:100%x100%:100 \ end=0/0:100%x100%:100 \ -transition \ mix:-1 in=50 out=75 a_track=1 b_track=2 \ $* mlt-0.9.0/demo/mlt_slideshow000066400000000000000000000001341215300731300160310ustar00rootroot00000000000000melt \ photos/.all.jpg ttl=75 \ -filter luma:luma1.pgm luma.softness=0.1 luma.invert=0 \ $* mlt-0.9.0/demo/mlt_slideshow2000066400000000000000000000004671215300731300161240ustar00rootroot00000000000000melt \ photos/.all.jpg ttl=75 \ -attach crop center=1 \ -attach affine transition.cycle=225 transition.geometry="0=0/0:100%x100%;74=-100/-100:120%x120%;75=-60/-60:110%x110%;149=0/0:110%x110%;150=0/-60:110%x110%;224=-60/0:110%x110%" \ -filter luma cycle=75 duration=25 \ -track music1.ogg \ -transition mix \ $* mlt-0.9.0/demo/mlt_slideshow_black000066400000000000000000000004041215300731300171650ustar00rootroot00000000000000melt photos/.all.jpg ttl=100 \ -filter watermark:colour:black reverse=1 composite.geometry="15%/15%:10%/10%;0.1625=0/0:100%x100%;-.1625=;-1=70%/70%:10%x10%" composite.mirror_off=1 composite.cycle=100 composite.fill=1 composite.valign=c composite.halign=c \ $* mlt-0.9.0/demo/mlt_squeeze000066400000000000000000000011061215300731300155110ustar00rootroot00000000000000melt \ clip1.dv out=124 clip2.dv out=149 clip3.dv in=75 out=224 clip1.dv \ -track \ -blank 99 colour:black out=49 -blank 99 colour:black out=49 -blank 99 colour:black out=49 \ -group progressive=1 distort=1 \ -transition composite geometry="0%/0%:100%x100%;25=50%/0%:5%x100%;-1=0%/0%:100%x100%" a_track=1 b_track=0 in=100 out=149 \ -transition composite geometry="0%/0%:100%x100%;25=0%/50%:100%x5%;-1=0%/0%:100%x100%" a_track=1 b_track=0 in=250 out=299 \ -transition composite geometry="0%/0%:100%x100%;25=100%/0%:5%x100%;-1=0%/0%:100%x100%" a_track=1 b_track=0 in=400 out=449 \ $* mlt-0.9.0/demo/mlt_squeeze_box000066400000000000000000000010551215300731300163640ustar00rootroot00000000000000melt \ clip1.dv out=124 clip2.dv out=149 clip3.dv in=75 out=224 clip1.dv \ -track \ -blank 99 colour:black out=49 -blank 99 colour:black out=49 -blank 99 colour:black out=49 \ -group progressive=1 \ -transition composite:0%/0%:100%x100% key[25]=50%/0%:5%x100% end=0%/0%:100%x100% a_track=1 b_track=0 in=100 out=149 \ -transition composite:0%/0%:100%x100% key[25]=0%/50%:100%x5% end=0%/0%:100%x100% a_track=1 b_track=0 in=250 out=299 \ -transition composite:0%/0%:100%x100% key[25]=100%/0%:5%x100% end=0%/0%:100%x100% a_track=1 b_track=0 in=400 out=449 \ $* mlt-0.9.0/demo/mlt_swf_variables000066400000000000000000000003551215300731300166640ustar00rootroot00000000000000melt clip1.dv \ -track txtField.swf variables="title=My Title&subtitle=The Subtitle" out=120 \ -transition composite geometry="0/0:100%x100%:80%;100=0/0:100%x100%:80%;119=0/0:100%x100%:0" \ a_track=0 b_track=1 out=120 progressive=1 \ $* mlt-0.9.0/demo/mlt_ticker000066400000000000000000000005731215300731300153200ustar00rootroot00000000000000melt \ clip1.dv out=299 \ -track \ colour:0 out=299 \ -track \ "+The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog..txt" \ out=299 \ -transition \ composite a_track=0 b_track=1 out=299 distort=1 \ start=0/70%:100%x64:100 \ -transition \ composite a_track=0 b_track=2 out=299 titles=1 \ start=100%/70%:999%x20% \ end=-299%/70%:999%x20% \ $* mlt-0.9.0/demo/mlt_title_over_gfx000066400000000000000000000006741215300731300170610ustar00rootroot00000000000000melt \ watermark1.png out=9999 \ -track \ "+title over gfx.txt" fgcolour=0x000000ff \ -track \ clip1.dv \ -transition \ composite start=30%/20%:40%x60% \ in=50 \ out=199 \ a_track=0 \ b_track=1 \ distort=1 \ -transition \ composite:0%/75%:100%x20%:0 \ in=50 \ out=199 \ a_track=2 \ b_track=0 \ key[24]=0%/75%:100%x20%:100 \ key[-25]=0%/75%:100%x20%:100 \ luma=luma1.pgm \ end=0%/75%:100%x20%:0 \ distort=1 \ $* mlt-0.9.0/demo/mlt_titleshadow_watermark000066400000000000000000000007011215300731300204340ustar00rootroot00000000000000melt \ "+hello~world.txt" align=1 out=1000 \ -track "+hello~world.txt" align=1 out=1000 fgcolour=0x000000ff \ -track watermark1.png out=1000 \ -track clip3.dv \ -filter greyscale track=2 \ -transition composite:21%/11%:100%x100%:50 end=61%/41%:100%x100% out=99 a_track=3 b_track=1 \ -transition composite:20%/10%:100%x100% end=60%/40%:100%x100% out=99 a_track=3 b_track=0 \ -transition composite:85%/80%:10%x10%:30 out=1000 a_track=3 b_track=2 \ $* mlt-0.9.0/demo/mlt_voiceover000066400000000000000000000010251215300731300160310ustar00rootroot00000000000000melt \ "+voice over demo.txt" \ family="Sans" size="72" weight="700" fgcolour=0x00000000 \ bgcolour=0xff9933aa \ pad=10 \ -track music1.ogg \ -track clip1.dv out=149 clip2.mpeg \ -transition \ mix:0.0 \ end=0.6 \ in=75 \ out=99 \ a_track=2 \ b_track=1 \ -transition \ mix:0.6 \ in=100 \ out=299 \ a_track=2 \ b_track=1 \ -transition \ mix:0.6 \ end=0.0 \ in=300 \ out=324 \ a_track=2 \ b_track=1 \ -transition \ composite:0%/80%:100%x20% \ distort=1 \ in=100 \ out=299 \ a_track=2 \ b_track=0 \ $* mlt-0.9.0/demo/mlt_watermark000066400000000000000000000002321215300731300160240ustar00rootroot00000000000000melt \ clip2.dv out=1000 \ -track \ watermark1.png out=1000 \ -transition composite fill=1 in=0 out=1000 a_track=0 b_track=1 geometry=85%/5%:10%x10% \ $* mlt-0.9.0/demo/new.mlt000066400000000000000000000026551215300731300145520ustar00rootroot00000000000000 clip2.mpeg clip3.mpeg greyscale luma luma 1 mlt-0.9.0/demo/pango.mlt000066400000000000000000000024751215300731300150650ustar00rootroot00000000000000 clip1.dv pango +.txt GJ-TTAvantika 36 1 0xffffddff 0x8c101080 8 composite 1 0 -70%/65%:100%x35%:0 0/65%:100%x35%:100 0/65%:100%x35%:100 0/65%:100%x35%:0 centre centre mlt-0.9.0/demo/pango_keyframes.mpl000066400000000000000000000000761215300731300171220ustar00rootroot000000000000000=Hello 40= 50=World~the end 90= mlt-0.9.0/demo/svg.mlt000066400000000000000000000054221215300731300145530ustar00rootroot00000000000000 ]> pixbuf mlt-0.9.0/demo/txtField.swf000066400000000000000000000105201215300731300155350ustar00rootroot00000000000000CWS n xœ¥™ T“g–ÇŸä}ñ“NÇàƒ/ ˆbò†á#`$$`m  E”îØ!*šDí(sÖºž©Ué9±Cu‚«Ûºuµ¢ ƒbYjÏ©»3»Ý®íÔN;³çŒÝ£UùÜûü%Åi»³ÝY{úëõÿÞçÞÿsŸ'/™ 1¦¸ÌØìÇ™-DÅÛ&1–å.¯0­´åIõ5Õµým‰ºÒë­3éõ›7o–7'Ë.÷ózCFF†>1IŸ”¤£ §¡Öë¨×Õz4j³„ 6§§Ì]Uç­rÕJüïŽõ®Þ%jõDÙúšºoÊÖzdG¹k½S.sÕèëuzƒœ¨çu(Édu;^—»Øåª6[x–”WíðTJEnW…Óã¡òŽjÉú´1KÿíìGÖ;mô¯9)Ѩ3tI©Å†dSbºÉ¬#&&>²öaæÃ¥v§×Qîð:¾g±1Õ””ñèâ?ËXî*¯ªhøA‹'3¥,ý·¦÷ÃæY^öÍ8ë6º«qFåezgµ³ÆYëõÐH iy™©Âå®qxÍŽººêª2/¨¯×y*]e6;69u|¼YúÉÄ¿ÖíÌnÿˇ\S£d{¼+9ÛSÜPçÔ¯tz\ÝeNJ×L\»¼¸«69ËóÜ®x©s¸=Nž¿DXÀ“ÑÅTUëñ:jËœËmfZ-WU•›Ò2V£Á’’—aË3r’ÓlyF 22 Ö¼Œô,ýw–ª•»Ê6ò!OT+ÿ?T{di šË]õ|ÝiÛ__õ{JH¸h>§ÉÙ}·Uºákõ¥jË¿;ÜZmù£Ã}(þÆñ?–øÞ+­Ÿxñ™%fUŽÓŸð4z)*Øß¿#­Xýâå¢Fze*V_ºÌ VQQ1®gø3’Ü8uÚüÞ›S«ß4Ïa™Ï4±S¦(h-]=›1%Û¡˜òœÇQëaÓY8‹`Él=ûÛª8¤ˆQnUv*ULõصç˜âîÁÑOª"ó[·èÊ¿¬ÖÏ´^,µx­ëèá{¹LqïïsŒ¿_ÿØ’=Ÿ>m,ú|!kÑåAxù…è+J*¾ØúþgÔ¯å:¥ÌØ– ¡í?Zu ›Ñ¾é=+.êlÿö^´¿º½ˆ-øùìБз^ØõäyÕþ§OäØ VÜdm7YÐGÇ×öeÿqá[sÿÝ4oøÆµxÛEå§?õçcóoþËã×~õ“¥±¿`3~QÇ‚‡U Éù©lš­E¾tëŠ"á½Ýâ;;ñ!Ò_Ù¹áñ"6Í|‰›Ù±rK‡äYÕ|qòé«NFÅ–± MŸ³)í)7ž=~º›Íøª„ÍèµÙ¬×ö/›v€U®dН¬*]ñJ1 Ò±ðùÿð³O¦½œ}õ_ûîxWÍûàƒEMlå½Få…®Y³> ¾Ñ·®ñÝãU\ˆLðº8Ìküy»¯kÆQÚù,éæû'®ýÎ<ä¬å^>)ޝÚêºqý“‹øboãšLñÇgÂ_^RÜé]ÖM —ŠK^ngá[’ó^OXå/ß*±“!Ýlñ‹•‹¿èld¿Lèfòû¡î“ÍË×.Ŧú;øþ­›ÚkVzÕ?\*èunNú¯Úã¯ÌÞ=ÃþëjyÍÌs]íÎßìt¥ßˆùìë[?Í”/~ü§ýQ¿wŦ½ž×ôìž¿É$VÌJX9s²*æb^VϪŸ¸£Z7ÝñEâOŒ»´»´×Cvimlá4öí^,´~÷p>qÚhqÇX1X îøÓf°<,pݶ~pŽÄ+ä1-›}¯ˆøöÝbÄ%Äc÷Ww—Bw#ÞDT mFÜ€x¿ eÚ{‡‰½w}ˆÛ ¢–e}JÄßÜV‹¼²†¸în2ô(Vâ{Ï‚MЋ™Žê—€«‰|_:òÓ&èØ…ûyL†[ne¸•áV†[ne¸•áV†[ne¸•áV†[ne¸•áV†[ne¸•áV†[ne¸åº¨r13Á‰‰æ¹šÈ=›¨¯O0¡ %ÑÄRÆ4`(1 éy`‘×á,W§–Nè…T“ßšc¢j(\9¡”@)Re5­Í're5Ö–B/Ef)ôRÜœ;ÐÑŽt,#½˜n(êÄY8±/'M»‚U`må—wŒ­&2ªÈ•bºÓ|• «\Xå¢U¥¬Ž*—²).fn¬ucbnTóЪ9’ñF<݈§Qa#U³°Mˆ7!ÞŒÌ͈(Î'òî ¸? XÛÀòÇÑÏ …jâK#°‰Øý@Ïã)§D¬VyÎyV9b%ÞfMÄîÅl›À÷µMà•· ÜÉ6¡wÈ'lø)oø)oø)s6ÛIú¡IðMÙO¬œâ#®™Úú¡Klrö ü–îŽÝ?@Ü1Ö †îÛÀ£"cð?(±ôjA¯ôjA¯ølA¯ôjA¯ôjE¯VôjE¯VôjE¯VôjE¯VôjE/);UØ6‹èæÃ®Ûð´âÝÄêѽD‰Þ~mÈä<½q+â£àqdîŽÒ ÷¹+$òÏìQ89 'œ{„ã‚vÄGä:ý Äüðà§ú{‰¼»ÝýèîGw?ºûÑÝî<ó Ð.ŒÐ®Ûéæ#Þ9C<4Ôý<±{¬“x}´›øáX/xŠO8I«öobÎobΜgˆ;hÎoÑýlý Ox[~°G8%\¸ÈûžÂåÊ1âÚϹ‡Sðp NÁÃ)x8\Ù)¼#ð¯5œ>bðƒ6¢–vñŽà9(œ¦ Lj|_§ÉC”óD^ó4Uè%òj§±£$?…3”Óvyß3è{™\Ù#œÅ;+ÄÒÞÏbïg±÷³ää ð.ú¾+Ô!jG: ìΑ‡ýÄ&:Çs˜Ï9̇ó ‘Ï­óì@ÍÔì ý´pžª½ v—À>°Á=Â8¼‡Pí>1±‹˜ØEºigˆ|VØu'æÓ‰ùtb§]8¯.œWΫ çÕ…óêÂyuἺ°¶ k»0·.Ì­ sãʯ„nšMŸ”3DßHâK`Ø€ƒ`‡p•/Óí$òÊ—Qù2*_†ÏøìÏøìÏøìÏøìAµøìAµTëAµøì…Ï^øì…Ï^øì…Ï^øì…Ï^øäô ¿¤ç‰Á4ÿ>øéƒŸ>øéƒŸ>øéƒŸ>øéƒŸ>:‘N"÷Ó?}ðÓ‡{~§v§v…Ní4ñúhØöƒà è®Òéúqûñ)èGÇ~t¤Iuy¯~ôêÇ$¯  û‰uôŽ»†¯ׄ^ÑÝ'¼‡Oñv7€Ý `wØÝv7€Ý  ×z `ÚTÿ èþ‰êœç¤ÏË Âá V bÕ Âá ÒÚhI)v?ˆ–fCD•˜2J\3F<4 EBƒX§(±P´  ]%†‹Ç”¡Ä”±0"¯Ž ᨎ á¨.VŽÄ"ÖB×!–‰/„ФDƒQ5®&ÞfZâšQq„:ò§*1’ž†€¡Dî<’ôY`ô¹ %±Ô@‰µPt Jœ'(B‰ªñ0býp$âhP‚C\3ª&òï x j‰6r8{™G{ £D‰vEkc@-‘;&†¹óh8¦ÊÐ#¡Ï%(1 šXIßÉðü8pt-(#_%ÎcP?õcP?†ÖF@‰ç‚‡-VÉPT¢·BM«B‰‡†"ˆ·Y$‘Ÿ ×cˆ|ïjr®%Þ¹'#Ž–øZ•¨¡Ó !Jt¯4”N¼Í"ˆŠH"÷À•h"¯©ÁN5¨©¡ú*1–â"ßE,*Äb>±XKÓž‡8 ”@525`ÜD…8Üí8òM¬‘À"wÎcÑF§‡¾ñØ{<öÎN´FSÆ¢ˆü>ÄÃm<ÜÆãø*J´¾ ÄP"?ÙÚu ÑFOðyÑáŒt¸:ÜIr´PBD=ö®Ç rFB‰&ò‰éq+ô¸‡œ±DÛh2µD¾/=î["Í9ŒÈð8 ”ˆkFc«‰•# ˆŠEP Di,‰¨O&¦Œ™ð4ŠÌç‰Ê×S(ß@ŠL…ž†ØDPd!¶B·!ÎÃÄ$‘¯ž$òïÕy¬“1ÿk)”i“ŸŒØˆü4Ð f¥±¬²‚6èv° ¸íFzÏDù”ŒäJM䮸SQ5ž&y#öÈós[Á\0\Ú‘#¦Ò44DþNKÅ´SQ3Óã4ƒ<Í!SZ@ÓHÑ뇉ªq‘Ï? ®ÒP' ÞÒà-Öf!6ƒÙ`.˜ÚÁ01g‘޳HÇ;'o<)!b&23ù籚È33ñÕ!ûÊÄédât2q:™4ÿdbʘOÓ°ÖD¼ÍÌ㉶ÑÄVÐÚÁ0TÌB÷,øÌ‚«,Üv®Ë È§‘…³à,˜Xµç¸ïg3¹ 'ò÷’o3NÜŒ7ã¦ñœ8Pâ; —TãMˆgK³%þ­9ÿ‰Öi÷pñ%…›x_¹OàútqŽÔý`ñЊX?œ€X }Ž4‡*l]Ëø/²•,ðGù#3ÿÏÇ9‚òoR‘¼”GáU&¢ÐÔ@”NZÜRøFMžˆ–F,E‹‡¿¼¸|\JJLL—Š+’ÝUëò6Ô9%«Ë]çr㉲d©®–VV=_éõH+§{“³\fÛ§¨ˆÀ6Ï ÚþöÜÊW%%»Ž_±L¸^È<×{«¼ÕNVRUîtIÅÎz/ëšFÏ(i¥tµhÝGß䌇ò_W‹LTL}ŽzTUÀâöPjööéz ‚ØöÑ—þãkå—ìUIäg“ý¾§¯¹@ ¢ˆŒt—ì¨Ç? ¨þk“êÁ#õõ“ê+•uoÎ7jôýµ[÷Pm›Tûå„}«á™Ä€z~c@½úÕ¤úº" ¶WMªÛ^ ¨{oMªëæTÏÚIÕÒPKnLªC@5Ù'Uñb@ýq?W— üêMxªø ðTaáOûo›tÑXmlt-0.9.0/demo/watermark1.png000066400000000000000000000025111215300731300160160ustar00rootroot00000000000000‰PNG  IHDRr ß”sBIT|dˆIDATxœÅ–klSe€Ÿïœ^Ö]º²K·Ø SÙÄýq QƒšEBЂ  Ô#ˆÊ`D¢MH:&2A.M AÁ~(ˆ(Œàl#(Þ ™®ƒmÀºuëÚœµ”­]õ—ï¯s¾Ëû|ïõûiDQ½9ÀSÀlÐÊA8€ ðö+ˆýÀQ·Ë9NŸT¼ ¨€1"À4›Ü.g0Õ")l!h>`i2˜É(X97øp.°ø]Q½Uÿ ¨¨^YQ½ É6˜Œ‚Æ%EÌ}ÌJq^Ò%À£¨ÞçÒ ÀòT§WhdÚd S+-©–]Šê]¨¨Þùé`^_ˆ¶®0¤‰æRT¯2¨¨Þ"`{ÊãÊ‚åµyd=ÇNžÓsbje"eÚ3°[Q½qßÇ,\ä$Ûb2 _.b~M.Kì˜ ‚o~ìÀ–-3i¼iT{…q ¢z­è©ŸÜ:ƒ ϪŸëÁªLÛ¹pe€ŽnÝ­ fØÈ4'MöDYûŠê}Ø3Úê‹Äæºb&O0Ðüsöažžn …3¿9x:Àwç‚„ÂZ25Un—ó¼ì¨^¶˜<0Ö8îéC©°`·(-2R`“ÉÊÐ-“”ÚÔTgQûˆ^.7Q:»#‰jþöyšNIÀ¤ÄѬ ‰u/Øùô­±|ü¦ƒšê,ÐÛåÕMW¹pEï^v›žšÇ=}D¢ºUÖ,‰ÚG¬ì~ÃÁ×JÉÉŒ»{€š#6RQjæà;ãy|Jw5QYff½jgK]1³4 ì<ÒÍŒ•­4î¿Îo…âs{ùé Fc¿Ðc$‹YðÉš±Œ+4âï‹rðt/³¦ecË–ðu…y¾ÁG—?B¶EbKBL[.öS·åƒC±«(51±ÄÄáï ¾ÓÜnWù ´«‹fÚWhäzO„Y«ZÙôù æ­mãÂeÝGíõ%äÊú£¼’`éÔJ ‹õ’¸ÔC.í%znë 30¨Ÿ´Ëá¥÷Ú9ûÇ-ÊŠŒl[Q‚5K}¨*“^+­´9p³WϨû&š©¾'#¾j`PcéûWi>¯w— ÅF>¬+!Ã$F@OŸ¢%­ˆqdGõ2€y¶ 2gº£AP£dsâlÝ=à‘(ó¹ÿî Jò äÊdAËÅ~Ba#-ÚºÂ|v¢'KÓ@,ñyšüpèéè³~o&ÁŽúÊ·ÛV8¢Q¿õ­ƒÌ¯±’oÕêVHã‹æÞ”¦?¸]ÎVÉír†Ðoj °ç¨€192ÛVß ôGiÜwƒ,R݇ID¬}Ūr#CAÝ|àNöÞo¿}éË’ž·ãžFšÝ.çWñý>OSØQ½Ì<ȧ~ Rk ²ÌŒÅ,Qû¨Y1ðú¼|,f‰}Ç{8êîKëfúaC}rÌ-—ZXôn{¼ÐSHxØír¶$ލš¡·ÈÀ 0¥ÂBýÜ<Ê&Â]‡ý|t¨›pdTX'0Çírž>‘´LÕ; ´/AäƒÞ/ÍFA8B:À·Àl·Ëy3ÙähïRX¬ÊÓQ†@ä?‡Á«€Z  ½ëêïVá.[SYô¿Ë?wdÆ|Šp¹IEND®B`‚mlt-0.9.0/docs/000077500000000000000000000000001215300731300132375ustar00rootroot00000000000000mlt-0.9.0/docs/framework.txt000066400000000000000000001530131215300731300160000ustar00rootroot00000000000000Framework Documentation Copyright (C) 2004-2009 Ushodaya Enterprises Limited Author: Charles Yates Last Revision: 2005-05-08 MLT FRAMEWORK ------------- Preamble: MLT is a multimedia framework designed for television broadcasting. As such, it provides a pluggable architecture for the inclusion of new audio/video sources, filters, transitions and playback devices. The framework provides the structure and utility functionality on which all of the MLT applications and services are defined. On its own, the framework provides little more than 'abstract classes' and utilities for managing resources, such as memory, properties, dynamic object loading and service instantiation. This document is split roughly into 3 sections. The first section provides a basic overview of MLT, the second section shows how it's used and the final section shows structure and design, with an emphasis on how the system is extended. Target Audience: This document is provided as a 'road map' for the framework and should be considered mandatory reading for anyone wishing to develop code at the MLT level. This includes: 1. framework maintainers; 2. module developers; 3. application developers; 4. anyone interested in MLT. The emphasis of the document is in explaining the public interfaces, as opposed to the implementation details. It is not required reading for the MLT client/server integration - please refer to libmvsp.txt and mvsp.txt for more details on this area. SECTION 1 - BASIC OVERVIEW -------------------------- Basic Design Information: MLT is written in C. The framework has no dependencies other than the standard C99 and POSIX libraries. It follows a basic Object Oriented design paradigm, and as such, much of the design is loosely based on the Producer/Consumer design pattern. It employs Reverse Polish Notation for the application of audio and video FX. The framework is designed to be colour space neutral - the currently implemented modules, however, are very much 8bit YUV422 oriented. In theory, the modules could be entirely replaced. A vague understanding of these terms is assumed throughout the remainder of this document. Structure and Flow: The general structure of an MLT 'network' is simply the connection of a 'producer' to a 'consumer': +--------+ +--------+ |Producer|-->|Consumer| +--------+ +--------+ A typical consumer requests MLT Frame objects from the producer, does something with them and when finished with a frame, closes it. /\ A common confusion with the producer/consumer terminology used here is /!!\ that a consumer may 'produce' something. For example, the libdv consumer \!!/ produces DV and the libdv producer seems to consume DV. However, the \/ naming conventions refer only to producers and consumers of MLT Frames. To put it another way - a producer produces MLT Frame objects and a consumer consumes MLT Frame objects. An MLT Frame essentially provides an uncompressed image and its associated audio samples. Filters may also be placed between the producer and the consumer: +--------+ +------+ +--------+ |Producer|-->|Filter|-->|Consumer| +--------+ +------+ +--------+ A service is the collective name for producers, filters, transitions and consumers. The communications between a connected consumer and producer or service are carried out in 3 phases: * get the frame * get the image * get the audio MLT employs 'lazy evaluation' - the image and audio need not be extracted from the source until the get image and audio methods are invoked. In essence, the consumer pulls from what it's connected to - this means that threading is typically in the domain of the consumer implementation and some basic functionality is provided on the consumer class to ensure realtime throughput. SECTION 2 - USAGE ----------------- Hello World: Before we go in to the specifics of the framework architecture, a working example of usage is provided. The following simply provides a media player: #include #include #include int main( int argc, char *argv[] ) { // Initialise the factory if ( mlt_factory_init( NULL ) == 0 ) { // Create the default consumer mlt_consumer hello = mlt_factory_consumer( NULL, NULL ); // Create via the default producer mlt_producer world = mlt_factory_producer( NULL, argv[ 1 ] ); // Connect the producer to the consumer mlt_consumer_connect( hello, mlt_producer_service( world ) ); // Start the consumer mlt_consumer_start( hello ); // Wait for the consumer to terminate while( !mlt_consumer_is_stopped( hello ) ) sleep( 1 ); // Close the consumer mlt_consumer_close( hello ); // Close the producer mlt_producer_close( world ); // Close the factory mlt_factory_close( ); } else { // Report an error during initialisation fprintf( stderr, "Unable to locate factory modules\n" ); } // End of program return 0; } This is a simple example - it doesn't provide any seeking capabilities or runtime configuration options. The first step of any MLT application is the factory initialisation - this ensures that the environment is configured and MLT can function. The factory is covered in more detail below. All services are instantiated via the factories, as shown by the mlt_factory_consumer and mlt_factory_producer calls above. There are similar factories for filters and transitions. There are details on all the standard services in services.txt. The defaults requested here are a special case - the NULL usage requests that we use the default producers and consumers. The default producer is "loader". This producer matches file names to locate a service to use and attaches 'normalising filters' (such as scalers, deinterlacers, resamplers and field normalisers) to the loaded content - these filters ensure that the consumer gets what it asks for. The default consumer is "sdl". The combination of loader and sdl will provide a media player. In this example, we connect the producer and then start the consumer. We then wait until the consumer is stopped (in this case, by the action of the user closing the SDL window) and finally close the consumer, producer and factory before exiting the application. Note that the consumer is threaded - waiting for an event of some sort is always required after starting and before stopping or closing the consumer. Also note, you can override the defaults as follows: $ MLT_CONSUMER=xml ./hello file.avi This will create a XML document on stdout. $ MLT_CONSUMER=xml MLT_PRODUCER=avformat ./hello file.avi This will play the video using the avformat producer directly, thus it will bypass the normalising functions. $ MLT_CONSUMER=libdv ./hello file.avi > /dev/dv1394 This might, if you're lucky, do on the fly, realtime conversions of file.avi to DV and broadcast it to your DV device. Factories: As shown in the 'Hello World' example, factories create service objects. The framework itself provides no services - they are provided in the form of a plugin structure. A plugin is organised in the form of a 'module' and a module can provide many services of different types. Once the factory is initialised, all the configured services are available for use. The complete set of methods associated to the factory are as follows: int mlt_factory_init( char *prefix ); const char *mlt_factory_prefix( ); char *mlt_environment( char *name ); mlt_producer mlt_factory_producer( char *name, void *input ); mlt_filter mlt_factory_filter( char *name, void *input ); mlt_transition mlt_factory_transition( char *name, void *input ); mlt_consumer mlt_factory_consumer( char *name, void *input ); void mlt_factory_close( ); The mlt_factory_prefix returns the path to the location of the installed modules directory. This can be specified in the mlt_factory_init call itself, or it can be specified via the MLT_REPOSITORY environment variable, or in the absence of either of those, it will default to the install prefix/shared/mlt/modules. The mlt_environment provides read only access to a collection of name=value pairs as shown in the following table: +------------------+------------------------------------+------------------+ |Name |Description |Values | +------------------+------------------------------------+------------------+ |MLT_NORMALISATION |The normalisation of the system |PAL or NTSC | +------------------+------------------------------------+------------------+ |MLT_PRODUCER |The default producer |"loader" or other | +------------------+------------------------------------+------------------+ |MLT_CONSUMER |The default consumer |"sdl" or other | +------------------+------------------------------------+------------------+ |MLT_TEST_CARD |The default test card producer |any producer | +------------------+------------------------------------+------------------+ These values are initialised from the environment variables of the same name. As shown above, a producer can be created using the 'default normalising' producer, and they can also be requested by name. Filters and transitions are always requested by name - there is no concept of a 'default' for these. Service Properties: As shown in the services.txt document, all services have their own set of properties than can be manipulated to affect their behaviour. In order to set properties on a service, we need to retrieve the properties object associated to it. For producers, this is done by invoking: mlt_properties properties = mlt_producer_properties( producer ); All services have a similar method associated to them. Once retrieved, setting and getting properties can be done directly on this object, for example: mlt_properties_set( properties, "name", "value" ); A more complete description of the properties object is found below. Playlists: So far, we've shown a simple producer/consumer configuration - the next phase is to organise producers in playlists. Let's assume that we're adapting the Hello World example, and wish to queue a number of files for playout, ie: hello *.avi Instead of invoking mlt_factory_producer directly, we'll create a new function called create_playlist. This function is responsible for creating the playlist, creating each producer and appending to the playlist. mlt_producer create_playlist( int argc, char **argv ) { // We're creating a playlist here mlt_playlist playlist = mlt_playlist_init( ); // We need the playlist properties to ensure clean up mlt_properties properties = mlt_playlist_properties( playlist ); // Loop through each of the arguments int i = 0; for ( i = 1; i < argc; i ++ ) { // Create the producer mlt_producer producer = mlt_factory_producer( NULL, argv[ i ] ); // Add it to the playlist mlt_playlist_append( playlist, producer ); // Close the producer (see below) mlt_producer_close( producer ); } // Return the playlist as a producer return mlt_playlist_producer( playlist ); } Notice that we close the producer after the append. Actually, what we're doing is closing our reference to it - the playlist creates its own reference to the producer on append and insert, and it will close its reference when the playlist is destroyed[*]. Note also that if you append multiple instances of the same producer, it will create multiple references to it. Now all we need do is to replace these lines in the main function: // Create a normalised producer mlt_producer world = mlt_factory_producer( NULL, argv[ 1 ] ); with: // Create a playlist mlt_producer world = create_playlist( argc, argv ); and we have a means to play multiple clips. [*] This reference functionality was introduced in mlt 0.1.2 - it is 100% compatable with the early mechanism of registering the reference and destructor with the properties of the playlist object. Filters: Inserting filters between the producer and consumer is just a case of instantiating the filters, connecting the first to the producer, the next to the previous filter and the last filter to the consumer. For example: // Create a producer from something mlt_producer producer = mlt_factory_producer( ... ); // Create a consumer from something mlt_consumer consumer = mlt_factory_consumer( ... ); // Create a greyscale filter mlt_filter filter = mlt_factory_filter( "greyscale", NULL ); // Connect the filter to the producer mlt_filter_connect( filter, mlt_producer_service( producer ), 0 ); // Connect the consumer to filter mlt_consumer_connect( consumer, mlt_filter_service( filter ) ); As with producers and consumers, filters can be manipulated via their properties object - the mlt_filter_properties method can be invoked and properties can be set as needed. The additional argument in the filter connection is an important one as it dictates the 'track' on which the filter operates. For basic producers and playlists, there's only one track (0), and as you will see in the next section, even multiple tracks have a single track output. Attached Filters: All services can have attached filters. Consider the following example: // Create a producer mlt_producer producer = mlt_factory_producer( NULL, clip ); // Get the service object of the producer mlt_producer service = mlt_producer_service( producer ); // Create a filter mlt_filter filter = mlt_factory_filter( "greyscale" ); // Create a playlist mlt_playlist playlist = mlt_playlist_init( ); // Attach the filter to the producer mlt_service_attach( producer, filter ); // Construct a playlist with various cuts from the producer mlt_playlist_append_io( producer, 0, 99 ); mlt_playlist_append_io( producer, 450, 499 ); mlt_playlist_append_io( producer, 200, 399 ); // We can close the producer and filter now mlt_producer_close( producer ); mlt_filter_close( filter ); When this is played out, the greyscale filter will be executed for each frame in the playlist which comes from that producer. Further, each cut can have their own filters attached which are executed after the producer's filters. As an example: // Create a new filter filter = mlt_factory_filter( "invert", NULL ); // Get the second 'clip' in the playlist producer = mlt_playlist_get_clip( 1 ); // Get the service object of the clip service = mlt_producer_service( producer ); // Attach the filter mlt_service_attach( producer, filter ); // Close the filter mlt_filter_close( filter ); Even the playlist itself can have an attached filter: // Create a new filter filter = mlt_factory_filter( "watermark", "+Hello.txt" ); // Get the service object of the playlist service = mlt_playlist_service( playlist ); // Attach the filter mlt_service_attach( service, filter ); // Close the filter mlt_filter_close( filter ); And, of course, the playlist, being a producer, can be cut up and placed on another playlist, and filters can be attached to those cuts or on the new playlist itself and so on ad nauseum. The main advantage of attached filters is that they remain attached and don't suffer from the maintenance problems associated with items being inserted and displacing calculated in/out points - this being a major issue if you exclusively use the connect or insert detached filters in a multitrack field (described below). Introducing the Mix: The mix is the simplest way to introduce transitions between adjacent clips on a playlist. Consider the following playlist: +-+----------------------+----------------------------+-+ |X|A |B |X| +-+----------------------+----------------------------+-+ Let's assume that the 'X' is a 'black clip' of 50 frames long. When you play this out, you'll get a 50 frames of black, abrupt cut into A, followed by an abrupt cut into B, and finally into black again. The intention is to convert this playlist into something like: +-+---------------------+-+------------------------+-+ |X|A |A|B |B| |A| |B| |X| +-+---------------------+-+------------------------+-+ Where the clips which refer to 2 clips represent a transition. Notice that the representation of the second playlist is shorter than the first - this is to be expected - a single transition of 50 frames between two clips will reduce the playtime of the result by 50 frames. This is done via the use of the mlt_playlist_mix method. So, assuming you get a playlist as shown in the original diagram, to do the first mix, you could do something like: // Create a transition mlt_transition transition = mlt_factor_transition( "luma", NULL ); // Mix the first and second clips for 50 mlt_playlist_mix( playlist, 0, 50, transition ); // Close the transition mlt_transition_close( transition ); This would give you the first transition, subsequently, you would apply a similar technique to mix clips 1 and 2. Note that this would create a new clip on the playlist, so the next mix would be between 3 and 4. As a general hint, to simplify the requirement to know the next clip index, you might find the following simpler: // Get the number of clips on the playlist int i = mlt_playlist_count( ); // Iterate through them in reverse order while ( i -- ) { // Create a transition mlt_transition transition = mlt_factor_transition( "luma", NULL ); // Mix the first and second clips for 50 mlt_playlist_mix( playlist, i, 50, transition ); // Close the transition mlt_transition_close( transition ); } There are other techniques, like using the mlt_playlist_join between the current clip and the newly created one (you can determine if a new clip was created by comparing the playlist length before and after the mix call). Internally, the mlt_playlist_mix call generates a tractor and multitrack as described below. Like the attached filters, the mix makes life very simple when you're inserting items into the playlist. Also note that it allows a simpler user interface - instead of enforcing the use of a complex multitrack object, you can do many operations on a single track. Thus, additional tracks can be used to introduce audio dubs, mixes or composites which are independently positioned and aren't affected by manipulations on other tracks. But hey, if you want a bombastic, confusing and ultimately frustrating traditional NLE experience, that functionality is provided too ;-). Practicalities and Optimisations: In the previous two sections I've introduced some powerful functionality designed to simplify MLT usage. However, a general issue comes into this - what happens when you introduce a transition between two cuts from the same bit of video footage? Anyone who is familiar with video compression will be aware that seeking isn't always without consequence from a performance point of view. So if you happen to require two frames from the same clip for a transition, the processing is going to be excessive and the result will undoubtedly be very unpleasant, especially if you're rendering in realtime... So how do we get round this? Actually, it's very simple - you invoke mlt_producer_optimise on the top level object after a modification and MLT will determine how to handle it. Internally, it determines the maximum number of overlapping instances throughout the object and creates clones and assigns clone indexes as required. In the mix example above, you can simply call: // Optimise the playlist mlt_producer_optimise( mlt_playlist_producer( playlist ) ); after the mix calls have be done. Note that this is automatically applied to deserialised MLT XML. Multiple Tracks and Transitions: MLT's approach to multiple tracks is governed by two requirements: 1) The need for a consumer and producer to communicate with one another via a single frame; 2) The desire to be able to serialise and manipulate a 'network' (or filter graph if you prefer). We can visualise a multitrack in the way that an NLE presents it: +-----------------+ +-----------------------+ 0: |a1 | |a2 | +---------------+-+--------------------------+-+---------------------+ 1: |b1 | +------------------------------+ The overlapping areas of track 0 and 1 would (presumably) have some kind of transition - without a transition, the frames from b1 and b2 would be shown during the areas of overlap (ie: by default, the higher numbered track takes precedence over the lower numbered track). MLT has a multitrack object, but it is not a producer in the sense that it can be connected directly to a consumer and everything will work correctly. A consumer would treat it precisely as it would a normal producer, and, in the case of the multitrack above, you would never see anything from track 1 other than the transitions between the clips - the gap between a1 and a2 would show test frames. This happens because a consumer pulls one frame from the producer it's connected to while a multitrack will provide one frame per track. Something, somewhere, must ensure that all frames are pulled from the multitrack and elect the correct frame to pass on. Hence, MLT provides a wrapper for the multitrack, which is called a 'tractor', and its the tractors task to ensure that all tracks are pulled evenly, the correct frame is output and that we have 'producer like' behaviour. Thus, a multitrack is conceptually 'pulled' by a tractor as shown here: +----------+ |multitrack| | +------+ | +-------+ | |track0|-|--->|tractor| | +------+ | |\ | | | | \ | | +------+ | | \ | | |track1|-|--->|---o---|---> | +------+ | | / | | | | / | | +------+ | |/ | | |track2|-|--->| | | +------+ | +-------+ +----------+ With a combination of the two, we can now connect multitracks to consumers. The last non-test card will be retrieved and passed on. The tracks can be producers, playlists, or even other tractors. Now we wish to insert filters and transitions between the multitrack and the tractor. We can do this directly by inserting filters directly between the tractor and the multitrack, but this involves a lot of connecting and reconnecting left and right producers and consumers, and it seemed only fair that we should be able to automate that process. So in keeping with our agricultural theme, the concept of the 'field' was born. We 'plant' filters and transitions in the field and the tractor pulls the multitrack (think of a combine harvester :-)) over the field and produces a 'bail' (sorry - kidding - frame :-)). Conceptually, we can see it like this: +----------+ |multitrack| | +------+ | +-------------+ +-------+ | |track0|-|--->|field |--->|tractor| | +------+ | | | |\ | | | | filters | | \ | | +------+ | | and | | \ | | |track1|-|--->| transitions |--->|---o---|---> | +------+ | | | | / | | | | | | / | | +------+ | | | |/ | | |track2|-|--->| |--->| | | +------+ | +-------------+ +-------+ +----------+ So, we need to create the tractor first, and from that we obtain the multitrack and field objects. We can populate these and finally connect the tractor to a consumer. In essence, this is how it looks to the consumer: +-----------------------------------------------+ |tractor +--------------------------+ | | +----------+ | +-+ +-+ +-+ +-+ | | | |multitrack| | |f| |f| |t| |t| | | | | +------+ | | |i| |i| |r| |r| | | | | |track0|-|--->| |l|- ->|l|- ->|a|--->|a|\| | | | +------+ | | |t| |t| |n| |n| | | | | | | |e| |e| |s| |s| |\ | | | +------+ | | |r| |r| |i| |i| | \| | | |track1|-|- ->| |0|--->|1|--->|t|--->|t|-|--o---> | | +------+ | | | | | | |i| |i| | /| | | | | | | | | |o| |o| |/ | | | +------+ | | | | | | |n| |n| | | | | |track2|-|- ->| | |- ->| |--->|0|- ->|1|/| | | | +------+ | | | | | | | | | | | | | +----------+ | +-+ +-+ +-+ +-+ | | | +--------------------------+ | +-----------------------------------------------+ An example will hopefully clarify this. Let's assume that we want to provide a 'watermark' to our hello world example. We have already extended the example to play multiple clips, and now we will place a text based watermark, reading 'Hello World' in the top left hand corner: mlt_producer create_tracks( int argc, char **argv ) { // Create the tractor mlt_tractor tractor = mlt_tractor_new( ); // Obtain the field mlt_field field = mlt_tractor_field( tractor ); // Obtain the multitrack mlt_multitrack multitrack = mlt_tractor_multitrack( tractor ); // Create a composite transition mlt_transition transition = mlt_factory_transition( "composite", "10%/10%:15%x15%" ); // Create track 0 mlt_producer track0 = create_playlist( argc, argv ); // Create the watermark track - note we NEED loader for scaling here mlt_producer track1 = mlt_factory_producer( "loader", "pango" ); // Get the length of track0 mlt_position length = mlt_producer_get_playtime( track0 ); // Set the properties of track1 mlt_properties properties = mlt_producer_properties( track1 ); mlt_properties_set( properties, "text", "Hello\nWorld" ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", length - 1 ); mlt_properties_set_position( properties, "length", length ); mlt_properties_set_int( properties, "a_track", 0 ); mlt_properties_set_int( properties, "b_track", 1 ); // Now set the properties on the transition properties = mlt_transition_properties( transition ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", length - 1 ); // Add our tracks to the multitrack mlt_multitrack_connect( multitrack, track0, 0 ); mlt_multitrack_connect( multitrack, track1, 1 ); // Now plant the transition mlt_field_plant_transition( field, transition, 0, 1 ); // Close our references mlt_producer_close( track0 ); mlt_producer_close( track1 ); mlt_transition_close( transition ); // Return the tractor return mlt_tractor_producer( tractor ); } Now all we need do is to replace these lines in the main function: // Create a playlist mlt_producer world = create_playlist( argc, argv ); with: // Create a watermarked playlist mlt_producer world = create_tracks( argc, argv ); and we have a means to play multiple clips with a horribly obtrusive watermark - just what the world needed, right? ;-) Incidentally, the same thing could be achieved with the more trivial watermark filter inserted between the producer and the consumer. SECTION 3 - STRUCTURE AND DESIGN -------------------------------- Class Hierarchy: The mlt framework consists of an OO class hierarchy which consists of the following public classes and abstractions: mlt_properties mlt_frame mlt_service mlt_producer mlt_playlist mlt_tractor mlt_filter mlt_transition mlt_consumer mlt_deque mlt_pool mlt_factory Each class defined above can be read as extending the classes above and to the left. The following sections describe the properties, stacking/queuing and memory pooling functionality provided by the framework - these are key components and a basic understanding of these is required for the remainder of the documentation. mlt_properties: The properties class is the base class for the frame and service classes. It is designed to provide an efficient lookup table for various types of information, such as strings, integers, floating points values and pointers to data and data structures. All properties are indexed by a unique string. The most basic use of properties is as follows: // 1. Create a new, empty properties set; mlt_properties properties = mlt_properties_new( ); // 2. Assign the value "world" to the property "hello"; mlt_properties_set( properties, "hello", "world" ); // 3. Retrieve and print the value of "hello"; printf( "%s\n", mlt_properties_get( properties, "hello" ) ); // 4. Reassign "hello" to "world!"; mlt_properties_set( properties, "hello", "world!" ); // 5. Retrieve and print the value of "hello"; printf( "%s\n", mlt_properties_get( properties, "hello" ) ); // 6. Assign the value "0" to "int"; mlt_properties_set( properties, "int", "0" ); // 7. Retrieve and print the integer value of "int"; printf( "%d\n", mlt_properties_get_int( properties, "int" ) ); // 8. Assign the integer value 50 to "int2"; mlt_properties_set_int( properties, "int2", 50 ); // 9. Retrieve and print the double value of "int2"; printf( "%s\n", mlt_properties_get( properties, "int2" ) ); Steps 2 through 5 demonstrate that the "name" is unique - set operations on an existing "name" change the value. They also free up memory associated to the previous value. Note that it also possible to change type in this way too. Steps 6 and 7 demonstrate that the properties object handles deserialisation from strings. The string value of "0" is set, the integer value of 0 is retrieved. Steps 8 and 9 demonstrate that the properties object handles serialisation to strings. To show all the name/value pairs in a properties, it is possible to iterate through them: for ( i = 0; i < mlt_properties_count( properties ); i ++ ) printf( "%s = %s\n", mlt_properties_get_name( properties, i ), mlt_properties_get_value( properties, i ) ); Note that properties are retrieved in the order in which they are set. Properties are also used to hold pointers to memory. This is done via the set_data call: uint8_t *image = malloc( size ); mlt_properties_set_data( properties, "image", image, size, NULL, NULL ); In this example, we specify that the pointer can be retrieved from properties by a subsequent request to get_data: image = mlt_properties_get_data( properties, "image", &size ); or: image = mlt_properties_get_data( properties, "image", NULL ); if we don't wish to retrieve the size. Two points here: 1) The allocated memory remains after the properties object is closed unless you specify a destructor. In the case above, this can be done with: mlt_properties_set_data( properties, "image", image, size, free, NULL ); When the properties are closed, or the value of "image" is changed, the destructor is invoked. 2) The string value returned by mlt_properties_get is NULL. Typically, you wouldn't wish to serialise an image as a string, but other structures might need such functionality - you can specify a serialiser as the last argument if required (declaration is char *serialise( void * )). Properties also provides some more advanced usage capabilities. It has the ability to inherit all serialisable values from another properties object: mlt_properties_inherit( this, that ); It has the ability to mirror properties set on this on another set of properties: mlt_properties_mirror( this, that ); After this call, all serialisable values set on this are passed on to that. mlt_deque: Stacks and queues are essential components in the MLT framework. Being of a lazy disposition, we elected to implement a 'Double Ended Queue' (deque) - this encapsulates the functionality of both. The API of the deque is defined as follows: mlt_deque mlt_deque_init( ); int mlt_deque_count( mlt_deque this ); int mlt_deque_push_back( mlt_deque this, void *item ); void *mlt_deque_pop_back( mlt_deque this ); int mlt_deque_push_front( mlt_deque this, void *item ); void *mlt_deque_pop_front( mlt_deque this ); void *mlt_deque_peek_back( mlt_deque this ); void *mlt_deque_peek_front( mlt_deque this ); void mlt_deque_close( mlt_deque this ); The stacking operations are used in a number of places: * Reverse Polish Notation (RPN) image and audio operations * memory pooling The queuing operations are used in: * the consumer base class; * consumer implementations may require further queues. mlt_pool: The MLT framework provides memory pooling capabilities through the mlt_pool API. Once initilialised, these can be seen as a straightforward drop in replacement for malloc/realloc/free functionality. The background behind this API is that malloc/free operations are notoriously inefficient, especially when dealing with large blocks of memory (such as an image). On linux, malloc is optimised for memory allocations less than 128k - memory blocks allocated of these sizes or less are retained in the process heap for subsequent reuse, thus bypassing the kernel calls for repeated allocation/frees for small blocks of memory. However, blocks of memory larger than that require kernel calls and this has a detrimental impact on performance. The mlt_pool design is simply to hold a list of stacks - there is one stack per 2^n bytes (where n is between 8 and 31). When an alloc is called, the requested size is rounded to the next 2^n, the stack is retrieved for that size, and an item is popped or created if the stack is empty. Each item has a 'header', situated immediately before the returned address - this holds the 'stack' to which the item belongs. When an item is released, we retrieve the header, obtain the stack and push it back. Thus, from the programmers point of view, the API is the same as the traditional malloc/realloc/free calls: void *mlt_pool_alloc( int size ); void *mlt_pool_realloc( void *ptr, int size ); void mlt_pool_release( void *release ); mlt_frame: A frame object is essentially defined as: +------------+ |frame | +------------+ | properties | | image stack| | audio stack| +------------+ The life cycle of a frame can be represented as follows: +-----+----------------------+-----------------------+---------------------+ |Stage|Producer |Filter |Consumer | +-----+----------------------+-----------------------+---------------------+ | 0.0 | | |Request frame | +-----+----------------------+-----------------------+---------------------+ | 0.1 | |Receives request | | | | |Request frame | | +-----+----------------------+-----------------------+---------------------+ | 0.2 |Receives request | | | | |Generates frame for | | | | |current position | | | | |Increments position | | | +-----+----------------------+-----------------------+---------------------+ | 0.3 | |Receives frame | | | | |Updates frame | | +-----+----------------------+-----------------------+---------------------+ | 0.4 | | |Receives frame | +-----+----------------------+-----------------------+---------------------+ Note that neither the filter nor the consumer have any conception of 'position' until they receive a frame. Speed and position are properties of the producer, and they are assigned to the frame object when the producer creates it. Step 0.3 is a critical one here - if the filter determines that the frame is of interest to it, then it should manipulate the image and/or audio stacks and properties as required. Assuming that the filter deals with both image and audio, then it should push data and methods on to the stacks which will deal with the processing. This can be done with the mlt_frame_push_image and audio methods. In order for the filter to register interest in the frame, the stacks should hold: image stack: [ producer_get_image ] [ data1 ] [ data2 ] [ filter_get_image ] audio stack: [ producer_get_audio ] [ data ] [ filter_get_audio ] The filter_get methods are invoked automatically when the consumer invokes a get_image on the frame. +-----+----------------------+-----------------------+---------------------+ |Stage|Producer |Filter |Consumer | +-----+----------------------+-----------------------+---------------------+ | 1.0 | | |frame_get_image | +-----+----------------------+-----------------------+---------------------+ | 1.1 | |filter_get_image: | | | | | pop data2 and data1 | | | | | frame_get_image | | +-----+----------------------+-----------------------+---------------------+ | 1.2 |producer_get_image | | | | | Generates image | | | +-----+----------------------+-----------------------+---------------------+ | 1.3 | |Receives image | | | | |Updates image | | +-----+----------------------+-----------------------+---------------------+ | 1.4 | | |Receives image | +-----+----------------------+-----------------------+---------------------+ Obviously, if the filter isn't interested in the image, then it should leave the stack alone, and then the consumer will retrieve its image directly from the producer. Similarly, audio is handled as follows: +-----+----------------------+-----------------------+---------------------+ |Stage|Producer |Filter |Consumer | +-----+----------------------+-----------------------+---------------------+ | 2.0 | | |frame_get_audio | +-----+----------------------+-----------------------+---------------------+ | 2.1 | |filter_get_audio: | | | | | pop data | | | | | frame_get_audio | | +-----+----------------------+-----------------------+---------------------+ | 2.2 |producer_get_audio | | | | | Generates audio | | | +-----+----------------------+-----------------------+---------------------+ | 2.3 | |Receives audio | | | | |Updates audio | | +-----+----------------------+-----------------------+---------------------+ | 2.4 | | |Receives audio | +-----+----------------------+-----------------------+---------------------+ And finally, when the consumer is done with the frame, it should close it. Note that a consumer may not evaluate both image and audio for any given frame, especially in a realtime environment. See 'Realtime Considerations' below. By default, a frame has the following properties: +------------------+------------------------------------+------------------+ |Name |Description |Values | +------------------+------------------------------------+------------------+ |_position |The producers frame position |0 to n | +------------------+------------------------------------+------------------+ |_speed |The producers speed |double | +------------------+------------------------------------+------------------+ |image |The generated image |NULL or pointer | +------------------+------------------------------------+------------------+ |alpha |The generated alpha mask |NULL or pointer | +------------------+------------------------------------+------------------+ |width |The width of the image | | +------------------+------------------------------------+------------------+ |height |The height of the image | | +------------------+------------------------------------+------------------+ |normalised_width |The normalised width of the image |720 | +------------------+------------------------------------+------------------+ |normalised_height |The normalised height of the image |576 or 480 | +------------------+------------------------------------+------------------+ |progressive |Indicates progressive/interlaced |0 or 1 | +------------------+------------------------------------+------------------+ |top_field_first |Indicates top field first |0 or 1 | +------------------+------------------------------------+------------------+ |audio |The generated audio |NULL or pointer | +------------------+------------------------------------+------------------+ |frequency |The frequency of the audio | | +------------------+------------------------------------+------------------+ |channels |The channels of the audio | | +------------------+------------------------------------+------------------+ |samples |The samples of the audio | | +------------------+------------------------------------+------------------+ |aspect_ratio |The sample aspect ratio of the image|double | +------------------+------------------------------------+------------------+ |test_image |Used to indicate no image available |0 or 1 | +------------------+------------------------------------+------------------+ |test_audio |Used to indicate no audio available |0 or 1 | +------------------+------------------------------------+------------------+ The consumer can attach the following properties which affect the default behaviour of a frame: +------------------+------------------------------------+------------------+ |test_card_producer|Synthesise test images from here |NULL or pointer | +------------------+------------------------------------+------------------+ |consumer_aspect_ |Apply this aspect ratio to the test |double | |ratio |card producer | | +------------------+------------------------------------+------------------+ |rescale.interp |Use this scale method for test image|"string" | +------------------+------------------------------------+------------------+ While most of these are mainly self explanatory, the normalised_width and normalised_height values require a little explanation. These are required to ensure that effects are consistently handled as PAL or NTSC, regardless of the consumers or producers width/height image request. The test_image and audio flags are used to determine when images and audio should be synthesised. Additional properties may be provided by the producer implementation, and filters, transitions and consumers may add additional properties to communicate specific requests. These are documented in modules.txt. The complete API for the mlt frame is as follows: mlt_frame mlt_frame_init( ); mlt_properties mlt_frame_properties( mlt_frame this ); int mlt_frame_is_test_card( mlt_frame this ); int mlt_frame_is_test_audio( mlt_frame this ); double mlt_frame_get_aspect_ratio( mlt_frame this ); int mlt_frame_set_aspect_ratio( mlt_frame this, double value ); mlt_position mlt_frame_get_position( mlt_frame this ); int mlt_frame_set_position( mlt_frame this, mlt_position value ); int mlt_frame_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ); uint8_t *mlt_frame_get_alpha_mask( mlt_frame this ); int mlt_frame_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ); int mlt_frame_push_get_image( mlt_frame this, mlt_get_image get_image ); mlt_get_image mlt_frame_pop_get_image( mlt_frame this ); int mlt_frame_push_frame( mlt_frame this, mlt_frame that ); mlt_frame mlt_frame_pop_frame( mlt_frame this ); int mlt_frame_push_service( mlt_frame this, void *that ); void *mlt_frame_pop_service( mlt_frame this ); int mlt_frame_push_audio( mlt_frame this, void *that ); void *mlt_frame_pop_audio( mlt_frame this ); void mlt_frame_close( mlt_frame this ); mlt_service: The service base class extends properties and allows 0 to m inputs and 0 to n outputs and is represented as follows: +-----------+ - ->| |- -> - ->| Service |- -> - ->| | +-----------+ | properties| +-----------+ Descendents of service impose restrictions on how inputs and outputs can be connected and will provide a basic set of properties. Typically, the service instance is encapsulated by the descendent in order for it to ensure that its connection rules are followed. A service does not define any properties when constructed. It should be noted that producers, filters and transitions my be serialised (say, via the xml consumer), and care should be taken to distinguish between serialisable and transient properties. The convention used is to prefix transient properties with an underscore. The public interface is defined by the following functions: int mlt_service_init( mlt_service this, void *child ); mlt_properties mlt_service_properties( mlt_service this ); int mlt_service_connect_producer( mlt_service this, mlt_service producer, int index ); int mlt_service_get_frame( mlt_service this, mlt_frame_ptr frame, int index ); void mlt_service_close( mlt_service this ); Typically, only direct descendents of services need invoke these methods and developers are encouraged to use those extensions when defining new services. mlt_producer: A producer has 0 inputs and 1 output: +-----------+ | | | Producer |---> | | +-----------+ | service | +-----------+ A producer provides an abstraction for file readers, pipes, streams or any other image or audio input. When instantiated, a producer has the following properties: +------------------+------------------------------------+------------------+ |Name |Description |Values | +------------------+------------------------------------+------------------+ |mlt_type |The producers type |mlt_producer | +------------------+------------------------------------+------------------+ |_position |The producers frame position |0 to n | +------------------+------------------------------------+------------------+ |_speed |The producers speed |double | +------------------+------------------------------------+------------------+ |fps |The output frames per second |25 or 29.97 | +------------------+------------------------------------+------------------+ |in |The in point in frames |0 to length - 1 | +------------------+------------------------------------+------------------+ |out |The out point in frames |in to length - 1 | +------------------+------------------------------------+------------------+ |length |The length of the input in frames |0 to n | +------------------+------------------------------------+------------------+ |aspect_ratio |aspect_ratio of the source |0 to n | +------------------+------------------------------------+------------------+ |eof |end of clip behaviour |"pause" or "loop" | +------------------+------------------------------------+------------------+ |resource |Constructor argument (ie: file name)|"" | +------------------+------------------------------------+------------------+ Additional properties may be provided by the producer implementation. The public interface is defined by the following functions: mlt_producer mlt_producer_new( ); int mlt_producer_init( mlt_producer this, void *child ); mlt_service mlt_producer_service( mlt_producer this ); mlt_properties mlt_producer_properties( mlt_producer this ); int mlt_producer_seek( mlt_producer this, mlt_position position ); mlt_position mlt_producer_position( mlt_producer this ); mlt_position mlt_producer_frame( mlt_producer this ); int mlt_producer_set_speed( mlt_producer this, double speed ); double mlt_producer_get_speed( mlt_producer this ); double mlt_producer_get_fps( mlt_producer this ); int mlt_producer_set_in_and_out( mlt_producer this, mlt_position in, mlt_position out ); mlt_position mlt_producer_get_in( mlt_producer this ); mlt_position mlt_producer_get_out( mlt_producer this ); mlt_position mlt_producer_get_playtime( mlt_producer this ); mlt_position mlt_producer_get_length( mlt_producer this ); void mlt_producer_prepare_next( mlt_producer this ); void mlt_producer_close( mlt_producer this ); mlt_filter: The public interface is defined by the following functions: int mlt_filter_init( mlt_filter this, void *child ); mlt_filter mlt_filter_new( ); mlt_service mlt_filter_service( mlt_filter this ); mlt_properties mlt_filter_properties( mlt_filter this ); mlt_frame mlt_filter_process( mlt_filter this, mlt_frame that ); int mlt_filter_connect( mlt_filter this, mlt_service producer, int index ); void mlt_filter_set_in_and_out( mlt_filter this, mlt_position in, mlt_position out ); int mlt_filter_get_track( mlt_filter this ); mlt_position mlt_filter_get_in( mlt_filter this ); mlt_position mlt_filter_get_out( mlt_filter this ); void mlt_filter_close( mlt_filter ); mlt_transition: The public interface is defined by the following functions: int mlt_transition_init( mlt_transition this, void *child ); mlt_transition mlt_transition_new( ); mlt_service mlt_transition_service( mlt_transition this ); mlt_properties mlt_transition_properties( mlt_transition this ); int mlt_transition_connect( mlt_transition this, mlt_service producer, int a_track, int b_track ); void mlt_transition_set_in_and_out( mlt_transition this, mlt_position in, mlt_position out ); int mlt_transition_get_a_track( mlt_transition this ); int mlt_transition_get_b_track( mlt_transition this ); mlt_position mlt_transition_get_in( mlt_transition this ); mlt_position mlt_transition_get_out( mlt_transition this ); mlt_frame mlt_transition_process( mlt_transition this, mlt_frame a_frame, mlt_frame b_frame ); void mlt_transition_close( mlt_transition this ); mlt_consumer: The public interface is defined by the following functions: int mlt_consumer_init( mlt_consumer this, void *child ); mlt_service mlt_consumer_service( mlt_consumer this ); mlt_properties mlt_consumer_properties( mlt_consumer this ); int mlt_consumer_connect( mlt_consumer this, mlt_service producer ); int mlt_consumer_start( mlt_consumer this ); mlt_frame mlt_consumer_get_frame( mlt_consumer this ); mlt_frame mlt_consumer_rt_frame( mlt_consumer this ); int mlt_consumer_stop( mlt_consumer this ); int mlt_consumer_is_stopped( mlt_consumer this ); void mlt_consumer_close( mlt_consumer ); Specialised Producers: There are two major types of specialised producers - playlists and tractors. The following sections describe these. mlt_playlist: mlt_playlist mlt_playlist_init( ); mlt_producer mlt_playlist_producer( mlt_playlist this ); mlt_service mlt_playlist_service( mlt_playlist this ); mlt_properties mlt_playlist_properties( mlt_playlist this ); int mlt_playlist_count( mlt_playlist this ); int mlt_playlist_clear( mlt_playlist this ); int mlt_playlist_append( mlt_playlist this, mlt_producer producer ); int mlt_playlist_append_io( mlt_playlist this, mlt_producer producer, mlt_position in, mlt_position out ); int mlt_playlist_blank( mlt_playlist this, mlt_position length ); mlt_position mlt_playlist_clip( mlt_playlist this, mlt_whence whence, int index ); int mlt_playlist_current_clip( mlt_playlist this ); mlt_producer mlt_playlist_current( mlt_playlist this ); int mlt_playlist_get_clip_info( mlt_playlist this, mlt_playlist_clip_info *info, int index ); int mlt_playlist_insert( mlt_playlist this, mlt_producer producer, int where, mlt_position in, mlt_position out ); int mlt_playlist_remove( mlt_playlist this, int where ); int mlt_playlist_move( mlt_playlist this, int from, int to ); int mlt_playlist_resize_clip( mlt_playlist this, int clip, mlt_position in, mlt_position out ); void mlt_playlist_close( mlt_playlist this ); mlt_tractor: mlt-0.9.0/docs/install.txt000066400000000000000000000126731215300731300154570ustar00rootroot00000000000000Installation Documentation Copyright (C) 2004-2009 Ushodaya Enterprises Limited Author: Charles Yates Last Revision: 2009-05-08 INSTALL ------- This document provides a description of the MLT project installation and organisation. Directories ----------- The directory heirarchy is defined as follows: + demo - A selection of samples to show off capabilities. + docs - Location of all documentation + src - All project source is provided here + framework - The mlt media framework + modules - All services are defined here + avformat - libavformat dependent services + core - Independent MLT services + dv - libdv dependent services + gtk2 - pango and pixbuf dependent services + normalize - audio normalisation functions (**) + plus - throwaway silliness + resample - libresample dependent services (**) + sdl - SDL dependent services + vorbis - vorbis dependenent services + xml - XML (de)serialization services + xine - Xine-derived sources (**) + melt - A media playing test application (**) + tests - Reserved for regression and unit tests Additional subdirectories may be nested below those shown and should be documented in their parent. (*) Not posted to CVS due to licensing issues. (**) Contains GPL dependencies or code. Dependencies ------------ The MLT core is dependent on: * a C99 compliant C compiler * posix threading * standard posix libraries The MLT applications and libraries provided are all dependent on the core. The modules have the following dependencies: ----------- ---------------------------------------------------------- MODULE DESCRIPTION ----------- ---------------------------------------------------------- avformat Provided from ffmpeg CVS and compiled as a shared library. URL: http://ffmpeg.sf.net ----------- ---------------------------------------------------------- dv libdv 0.102 or later. URL: http://libdv.sf.net ----------- ---------------------------------------------------------- gtk2 GTK2 and associated dependencies. URL: http://www.gtk.org ----------- ---------------------------------------------------------- resample libsamplerate 0.15 or later URL: http://www.mega-nerd.com/SRC/ (GPL) ----------- ---------------------------------------------------------- sdl SDL 1.2 or later. URL: http://www.libsdl.org ----------- ---------------------------------------------------------- vorbis libvorbis 1.0.1 or later. URL: http://www.vorbis.com/ ----------- ---------------------------------------------------------- xml libxml2 2.5 or later. URL: http://www.xmlsoft.org/ ----------- ---------------------------------------------------------- Configuration ------------- Configuration is triggered from the top level directory via a ./configure script. Each source bearing subdirectory shown above have their own configure script which are called automatically from the top level. Typically, new modules can be introduced without modification to the configure script and arguments are accepted and passed through to all subdirectories. More information on usage is found by running: ./configure --help NB: This script must be run to register new services after a CVS checkout or subsequent update. Compilation ----------- Makefiles are generated during configuration and these are based on a per directory template which must be provided by the developer. Testing ------- To execute the mlt tools without installation, or to test a new version on a system with an already installed mlt version, you should run: . setenv NB: This applies to your current shell only and it assumes sh or bash. Installation ------------ The install is triggered by running make install from the top level directory. The framework produces a single shared object which is installed in $prefix/lib/ and public header files which are installed in $prefix/include/mlt/framework. The modules produce a shared object per module and update text files containing a list of modules provided by this build. These are installed in $prefix/share/mlt/modules. It is at the discretion of the module to install additional support files. To allow the development of external components, mlt-config and scripts are generated and installed in $prefix/bin. After install, only those modules listed are usable by the server. No module is loaded unless explicitly requested via server configuration or usage. External modules are also placed in this $prefix/share/mlt/modules, and the installation of those must modify the text file accordingly before they will be considered at runtime. Development ----------- All compilation in the project has {top-level-dir}/src on the include path. All headers are included as: #include All external modules have {prefix}/include/mlt on the include path. All headers should also be included as: #include This allows migration of source between external and internal modules. The configuration and Makefile template requirements will require attention though. mlt-0.9.0/docs/melt.1000066400000000000000000000057241215300731300142720ustar00rootroot00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.4. .TH MELT "1" "June 2013" "melt 0.9.0" "User Commands" .SH NAME melt \- author, play, and encode multitrack audio/video compositions .SH SYNOPSIS .B melt [\fIoptions\fR] [\fIproducer \fR[\fIname=value\fR]\fI* \fR]\fI+\fR .SH OPTIONS .TP \fB\-attach\fR filter[:arg] [name=value]* Attach a filter to the output .TP \fB\-attach\-cut\fR filter[:arg] [name=value]* Attach a filter to a cut .HP \fB\-attach\-track\fR filter[:arg] [name=value]* Attach a filter to a track .TP \fB\-attach\-clip\fR filter[:arg] [name=value]* Attach a filter to a producer .TP \fB\-audio\-track\fR | \fB\-hide\-video\fR Add an audio\-only track .TP \fB\-blank\fR frames Add blank silence to a track .TP \fB\-consumer\fR id[:arg] [name=value]* Set the consumer (sink) .TP \fB\-debug\fR Set the logging level to debug .TP \fB\-filter\fR filter[:arg] [name=value]* Add a filter to the current track .TP \fB\-group\fR [name=value]* Apply properties repeatedly .TP \fB\-help\fR Show this message .TP \fB\-jack\fR Enable JACK transport synchronization .TP \fB\-join\fR clips Join multiple clips into one cut .TP \fB\-mix\fR length Add a mix between the last two cuts .TP \fB\-mixer\fR transition Add a transition to the mix .TP \fB\-null\-track\fR | \fB\-hide\-track\fR Add a hidden track .TP \fB\-profile\fR name Set the processing settings .TP \fB\-progress\fR Display progress along with position .TP \fB\-remove\fR Remove the most recent cut .TP \fB\-repeat\fR times Repeat the last cut .TP \fB\-query\fR List all of the registered services .TP \fB\-query\fR "consumers" | "consumer"=id List consumers or show info about one .TP \fB\-query\fR "filters" | "filter"=id List filters or show info about one .TP \fB\-query\fR "producers" | "producer"=id List producers or show info about one .TP \fB\-query\fR "transitions" | "transition"=id List transitions, show info about one .TP \fB\-query\fR "profiles" | "profile"=id List profiles, show info about one .TP \fB\-query\fR "presets" | "preset"=id List presets, show info about one .TP \fB\-query\fR "formats" List audio/video formats .TP \fB\-query\fR "audio_codecs" List audio codecs .TP \fB\-query\fR "video_codecs" List video codecs .TP \fB\-serialise\fR [filename] Write the commands to a text file .TP \fB\-silent\fR Do not display position/transport .TP \fB\-split\fR relative\-frame Split the last cut into two cuts .TP \fB\-swap\fR Rearrange the last two cuts .TP \fB\-track\fR Add a track .TP \fB\-transition\fR id[:arg] [name=value]* Add a transition .TP \fB\-verbose\fR Set the logging level to verbose .TP \fB\-version\fR Show the version and copyright .TP \fB\-video\-track\fR | \fB\-hide\-audio\fR Add a video\-only track .PP For more help: .SH COPYRIGHT Copyright \(co 2002\-2012 Ushodaya Enterprises Limited .br This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. mlt-0.9.0/docs/melt.txt000066400000000000000000000343501215300731300147460ustar00rootroot00000000000000Melt Documentation Copyright (C) 2004-2009 Ushodaya Enterprised Limited Author: Charles Yates Author: Dan Dennedy Last Revision: 2011-04-03 MELT ----- Preamble: Melt was developed as a test tool for the MLT framework. It can be thought of as a powerful, if somewhat obscure, multitrack command line oriented video editor. The following details the usage of the tool and as a result, provides a lot of insight into the workings of the MLT framework. Usage: melt [options] [producer [name=value]* ]+ Options: -attach filter[:arg] [name=value]* Attach a filter to the output -attach-cut filter[:arg] [name=value]* Attach a filter to a cut -attach-track filter[:arg] [name=value]* Attach a filter to a track -attach-clip filter[:arg] [name=value]* Attach a filter to a producer -audio-track | -hide-video Add an audio-only track -blank frames Add blank silence to a track -consumer id[:arg] [name=value]* Set the consumer (sink) -debug Set the logging level to debug -filter filter[:arg] [name=value]* Add a filter to the current track -group [name=value]* Apply properties repeatedly -help Show this message -jack Enable JACK transport synchronization -join clips Join multiple clips into one cut -mix length Add a mix between the last two cuts -mixer transition Add a transition to the mix -null-track | -hide-track Add a hidden track -profile name Set the processing settings -progress Display progress along with the position -remove Remove the most recent cut -repeat times Repeat the last cut -query List all of the registered services -query "consumers" | "consumer"=id List consumers or show info about one -query "filters" | "filter"=id List filters or show info about one -query "producers" | "producer"=id List producers or show info about one -query "transitions" | "transition"=id List transitions or show info about one -query "profiles" | "profile"=id List profiles or show info about one -query "presets" | "preset"=id List presets or show info about one -query "formats" List audio/video formats -query "audio_codecs" List audio codecs -query "video_codecs" List video codecs -serialise [filename] Write the commands to a text file -silent Do not display position/transport help -split relative-frame Split the last cut into two cuts -swap Rearrange the last two cuts -track Add a track -transition id[:arg] [name=value]* Add a transition -verbose Set the logging level to verbose -version Show the version and copyright message -video-track | -hide-audio Add a video-only track General rules: 1. Order is incredibly important; 2. Error checking on command line parsing is weak; 3. Please refer to services.txt for details on services available; 4. The MLT framework, from which melt has inherited its naming convention, is very mlt-centric. Producers produce MLT frame objects and consumers consume MLT frame objects. The distinction is important - a DV producer does not produce DV, it produces MLT frames from a DV source, and similarly a DV consumer does not consume DV, it consumes MLT frames and produces DV frames. Terminology: 'Producers' typically refer to files but may also indicate devices (such as dv1394 input or video4linux). Hence, the more generic term is used [the more generic usage is out of scope for now...]. 'Filters' are frame modifiers - they always guarantee that for every frame they receive, they output *precisely* one frame. Never more, never less, ever. Nothing says that a filter cannot generate frames though 'Transitions' collect frames from two tracks (a and b) and output 1 modified frame on their 'a track', and 1 unmodified frame on their 'b track'. Never more, never less, ever. 'Consumers' collect frames from a producer, do something with them and destroy them. Collectively, these are known as 'services'. All services have 'properties' associated to them. These are typically defaulted or evaluated and may be overriden on a case by case basis. All services except consumers obey in and out properties. Consumers have no say in the flow of frames [though they may give the illusion that they do]. They get frames from a connected producer, use them, destroy them and get more. Basics: To play a file with the default SDL PAL consumer, usage is: $ melt file Note that 'file' can be anything that melt has a known 'producer' mapping for (so this can be anything from .dv to .txt). You can also specify the producer directly, for example: $ melt avformat:file.mpeg Would force the direct use of avformat for loading the file. Properties: Properties can be assigned to the producer by adding additional name=value pairs after the producer: $ melt file in=50 out=100 something="something else" Note that while some properties have meaning to all producers (for example: in, out and length are guaranteed to be valid for all, though typically, length is determined automatically), the validity of others are dependent on the producer - however, properties will always be assigned and silently ignored if they won't be used. Multiple Files: Multiple files of different types can be used: $ melt a.dv b.mpg c.png Properties can be assigned to each file: $ melt a.dv in=50 out=100 b.mpg out=500 c.png out=500 MLT will take care of 'normalising' the output of a producer to ensure that the consumer gets what it needs. So, in the case above, the mlt framework will ensure that images are rescaled and audio resampled to meet the requirements of your configuration (which, by default, will be PAL). See 'Appendix A: Normalisation Rules' below. Filters: Filters are frame modifiers - they can change the contents of the audio or the images associated to a frame. $ melt a.dv -filter greyscale As with producers, properties may be specified on filters too. Again, in and out properties are common to all, so to apply a filter to a range of frames, you would use something like: $ melt a.dv -filter greyscale in=0 out=50 Again, filters have their own set of rules about properties and will silently ignore properties that do not apply. Groups: The -group switch is provided to force default properties on the following 'services'. For example: $ melt -group in=0 out=49 clip* would play the first 50 frames of all clips that match the wild card pattern. Note that the last -group settings also apply to the following filters, transitions and consumers, so: $ melt -group in=0 out=49 clip* -filter greyscale is *probably not* what you want (ie: the greyscale filter would only be applied to the first 50 frames). To shed the group properties, you can use any empty group: $ melt -group in=0 out=49 clip* -group -filter greyscale Attached Filters: As described above, the -filter switch applies filters to an entire track. To localise filters to a specific clip on a track, you have to know information about the lengths of the clip and all clips leading up to it. In practise, this is horrifically impractical, especially at a command line level (and not even that practical from a programing point of view...). The -attach family of switches simplify things enormously. By default, -attach will attach a filter to the last service created, so: $ melt clip1.dv clip2.dv -attach greyscale clip3.dv would only apply the filter to clip2.dv. You can further narrow down the area of the effect by specifying in/out points on the attached filter. This might seem simple so far, but there is a catch... consider the following: $ melt clip1.dv -attach watermark:+hello.txt -attach invert The second attached filter is actually attached to the watermark. You might think, yay, nice (and it is :-)), but, it might not be what you want. For example you might want to attach both to clip1.dv. To do that, you can use: $ melt clip1.dv -attach-cut watermark:+hello.txt -attach-cut invert As you shall see below, there are still another couple of gotchas associated to -attach, and even another variant :-). Mixes: The -mix switch provides the simplest means to introduce transitions between adjacent clips. For example: $ melt clip1.dv clip2.dv -mix 25 -mixer luma -mixer mix:-1 would provide both an audio and video transition between clip1 and clip2. This functionality supercedes the enforced use of the -track and -transition switches from earlier versions of melt and makes life a lot easier :-). These can be used in combination, so you can for example do a fade from black and to black using the following: $ melt colour:black out=24 clip1.dv -mix 25 -mixer luma \ colour:black out=24 -mix 25 -mixer luma while this may not be immediately obvious, consider what's happening as the command line is being parsed from left to right: Input: Track ----------------------- ----------------------------------------------------- colour:black out=24 [black] clip1.dv [black][clip1.dv] -mix 25 [black+clip1.dv][clip1.dv] -mixer luma [luma:black+clip1.dv][clip1.dv] colour:black out=24 [luma:black+clip1.dv][clip1.dv][black] -mix 25 [luma:black+clip1.dv][clip1.dv][clip1.dv+black] -mixer luma [luma:black+clip1.dv][clip1.dv][luma:clip1.dv+black] Obviously, the clip1.dv instances refer to different parts of the clip, but hopefully that will demonstrate what happens as we construct the track. You will find more details on the mix in the framework.txt. Mix and Attach: As noted, -attach normally applies to the last created service - so, you can attach a filter to the transition region using: $ melt clip1.dv clip2.dv -mix 25 -mixer luma -attach watermark:+Transition.txt Again, nice, but take care - if you want the attached filter to be associated to the region following the transition, use -attach-cut instead. Splits, Joins, Removes and Swaps: COMPLEX - needs simplification.... Introducing Tracks and Blanks: So far, all of the examples have shown the definition of a single playlist, or more accurately, track. When multiple tracks exist, the consumer will receive a frame from the 'highest numbered' track that is generating a non-blank frame. It is best to visualise a track arrangement, so we'll start with an example: $ melt a.dv -track b.dv in=0 out=49 This can be visualised as follows: +------------------+ |a | +-------+----------+ |b | +-------+ Playout will show the first 50 frames of b and the 51st frame shown will be the 51st frame of a. This rule also applies to audio only producers on the second track, for example, the following would show the video from the a track, but the audio would come from the second track: $ melt a.dv -track b.mp3 in=0 out=49 To have the 51st frame be the first frame of b, we can use the -blank switch: $ melt a.dv out=49 -track -blank 49 b.dv Which we can visualise as: +-------+ |a | +-------+-------------------+ |b | +-------------------+ Now playout will continue as though a and b clips are on the same track (which on its own, is about as useful as reversing the process of slicing bread). Transitions: Where tracks become useful is in the placing of transitions. Here we need tracks to overlap, so a useful multitrack definition could be given as: $ melt a.dv out=49 \ -track \ -blank 24 b.dv \ -transition luma in=25 out=49 a_track=0 b_track=1 Now we're cooking - our visualisation would be something like: +-------+ |a | +---+---+--------------+ |b | +------------------+ Playout will now show the first 25 frames of a and then a fade transition for 25 frames between a and b, and will finally playout the remainder of b. Reversing a Transition: When we visualise a track definition, we also see situations like: +-------+ +----------+ |a1 | |a2 | +---+---+--------------+----+-----+ |b | +-----------------------+ In this case, we have two transitions, a1 to b and b to a2. In this scenario, we define a command line as follows: $ melt a.dv out=49 -blank 49 a2.dv \ -track \ -blank 24 b.dv out=99 \ -transition luma in=25 out=49 a_track=0 b_track=1 \ -transition luma in=100 out=124 reverse=1 a_track=0 b_track=1 Serialisation: Melt has a built in serialisation mechanism - you can build up your command, test it via any consumer and then add a -serialise file.melt switch to save it. The saved file can be subsequently used as a clip by melt or other MLT applications. Take care though - paths to files are saved as provided on the command line.... A more expressive serialisation can be obtained with the xml consumer - this will provide an xml document which can be used freely in melt and other MLT applications. See mlt-xml.txt for more information. Missing Features: Some filters/transitions should be applied on the output frame regardless of which track it comes from - for example, you might have a 3rd text track or a watermark which you want composited on every frame, and of course, there's the obscure filter.... melt only supports this in two invocations - as a simple example: $ melt a.dv -track -blank 100 b.dv -consumer xml:basic.mlt $ melt basic.mlt -filter watermark:watermark.png mlt-0.9.0/docs/mlt++.txt000066400000000000000000000404311215300731300147240ustar00rootroot00000000000000MLT++ ----- This mlt sub-project provides a C++ wrapping for the MLT library. Usage ----- Use the following definitions in a Makefile to compile and link with mlt++: CXXFLAGS=`pkg-config --cflags mlt-framework` -Wall LDFLAGS=-lmlt++ `pkg-config --libs mlt-framework` Include files for the classes can either be explicitly included, ie: #include etc Or you can include all using: #include All definitions are placed in an Mlt namespace, and adhere closely to the C naming convention. Mappings always follow the pattern: Factory methods: mlt_factory_init ==> Mlt::Factory::init mlt_factory_producer ==> Mlt::Factory::producer mlt_factory_filter ==> Mlt::Factory::filter mlt_factory_transition ==> Mlt::Factory::transition mlt_factory_consumer ==> Mlt::Factory::consumer mlt_factory_close ==> Mlt::Factory::close NB: Factory usage for service construction is optional. Types: mlt_properties ==> Mlt::Properties mlt_frame ==> Mlt::Frame mlt_service ==> Mlt::Service mlt_producer ==> Mlt::Producer mlt_filter ==> Mlt::Filter mlt_transition ==> Mlt::Transition mlt_consumer ==> Mlt::Consumer Methods: mlt_type_method ==> Mlt::Type.method ie: mlt_playlist_append ==> Mlt::Playlist.append Parent methods are available directly on children. Additionally, you can specify: using namespace Mlt; To avoid the enforced use of the Mlt:: prefix. Enumerators and macros are reused directly from the C library. Class Hierarchy --------------- The currently mapped objects are shown in the following hierarchy: Factory Properties Frame Service Consumer Field Filter Multitrack Producer Playlist Tractor Transition Special Cases ------------- Care should be taken with wrapper objects. Taking, as an example, the C function that returns the immediate consumer of a service: mlt_service mlt_service_consumer( mlt_service ); This maps to: Mlt::Service *Mlt::Service.consumer( ); Note that you get an object back - it is never the original c++ object, but a wrapping object. This is done to keep consistency with the C api which may instantiate C instances - therefore it cannot be assumed that a C++ object exists for all mlt service instances. As such, it is mandatory that you delete these objects. The original will not be affected. However, all other modifications (to properties or its state of connection) will be reflected in the original object. This approach excludes the use of RTTI to determine the real type of the object - this can only be done by parsing the objects properties. Objects may be invalid - always use the is_valid method to check validity before use. Limitations ----------- The mechanisms for the definition of new services are deliberately excluded from the C++ wrappings - this is done to ensure that service networks constructed can be serialised and used by existing applications which are based on the C API (such as melted). Hello World ----------- The mlt++ wrapper is a c++ wrapper for the mlt C library. As such, it provides clean C++ access to the underlying library. An example of use is as follows: #include using namespace Mlt; int main( void ) { Factory::init( ); Producer p( "pango:", "Hello World" ); Consumer c( "sdl" ); c.connect( p ); c.run( ); return 0; } This is a fairly typical example of mlt++ usage - create a 'producer' (an object which produces 'frames'), create a 'consumer' (an object which consumes frames), connect them together, start the consumer and wait until done (here we just wait for the user to close the window). In this case, we construct a window as a consumer using the 'sdl' consumer (SDL is a standard portable library which provides platform independent access to accelerated video display and audio) and use the 'pango' producer to generate frames with the words 'Hello World' (pango is a library from the gtk toolkit). The main point of this example is to show that mlt uses existing libraries to provide its functionality - this keeps the framework itself very small. Note that mlt is designed to be housed in GUI or server type applications - typically, applications don't wait around for the consumer to be stopped in the manner shown. So far, we've introduced the Producer and Consumer mlt classes. We'll cover each of these in more detail later in the tutorial, but for now, we'll briefly cover the remaining classes. Playlists --------- Another simple class is the Playlist - this is direct extension of Producer and it allows you to maintain a list of producer objects. As a simple example of the Playlist in action, we'll convert the example above into an application which plays multiple video or audio files. #include using namespace Mlt; int main( int argc, char **argv ) { Factory::init( ); Playlist list; for ( int i = 1; i < argc; i ++ ) { Producer p( argv[i] ); if ( p.is_valid( ) ) list.append( p ); } Consumer c( "sdl" ); c.connect( list ); c.run( ); return 0; } Now you can run the program as: ./player *.avi *.mp3 *.jpg etc In this case, we construct a playlist by simply appending producers to it. Notice that although the scope of the Producer is limited to the inner for loop, we can safely add it to the playlist - this is due to the fact that all mlt objects maintain reference counts and no object is really destroyed until all the references are gone. In this case, when the list object goes out of scope, all the producers we created will automatically be destroyed. Filters ------- So far, we've shown how you can load and play media. We've given a brief intro to the Playlist container, now it's time to start manipulating things... For the next example, I'll add a 'watermark' to the video - a watermark is used by broadcasters to brand the channel and normally consists of a logo of some sort. We'll just use some black text on a partially transparent red background. #include using namespace Mlt; int main( int argc, char **argv ) { Factory::init( ); Playlist list; for ( int i = 1; i < argc; i ++ ) { Producer p( argv[i] ); if ( p.is_valid( ) ) list.append( p ); } Filter f( "watermark", "pango:" ); f.set( "producer.text", "MLT++" ); f.set( "producer.fgcolour", "0x000000ff" ); f.set( "producer.bgcolour", "0xff000080" ); list.attach( f ); Consumer c( "sdl" ); c.connect( list ); c.run( ); return 0; } Notice that the watermark filter reuses the 'pango' producer we showed in the first example. In fact, you could use any producer here - if you wanted to use a graphic or a video, you would just construct the filter with a full path to that as the second argument. We manipulate the filter using the set method - this method was also shown in the first example. Finally, we attach the filter to the playlist. This ensure that all frames that are obtained from the playlist are watermarked. Cuts ---- When you add a clip to a playlist, the a cut object is created - this is merely a wrapper for the producer, spanning the specified in and out points. Whenever you retrieve a clip from a playlist, you will always get a cut object. This allows you to attach filters to a specific part of a producer and should the position of the cut in the playlist change, then the filter will remain correctly associated to it. A producer and a cut are generally identical in behaviour, but should you need to distinguish between them, you can use: if ( producer.is_cut( ) ) and to retrieve the parent of a cut, you can use: Producer parent = producer.parent_cut( ); Filters that are attached directly to a parent are executed before any filters attached to the cut. Tractor ------- A tractor is an object that allows the manipulation of multiple video and audio tracks. Stepping away from the player example we've been tinkering with for a minute, let's assume we want to do something like dub a video with some audio. This a very trivial thing to do: Tractor *dub( char *video_file, char *audio_file ) { Tractor *tractor = new Tractor( ); Producer video( video_file ); Producer audio( audio_file ); tractor->set_track( video, 0 ); tractor->set_track( audio, 1 ); return tractor; } That's all that needs to be done - you can now connect the returned object to a consumer, or add it to a playlist, or even apply it as a track to another tractor. Transition ---------- Let's now assume we want to mix the audio between two tracks - to do this, we need to introduce the concept of a transition. A transition in mlt is a service which combines frames from two producers to produce a new frame. Tractor *mix( char *video_file, char *audio_file ) { Tractor *tractor = new Tractor( ); Transition mix( "mix" ); Producer video( video_file ); Producer audio( audio_file ); tractor.set_track( video, 0 ); tractor.set_track( audio, 1 ); tractor.field.plant_transition( mix, 0, 1 ); return tractor; } The tractor returned will now mix the audio from the original video and the audio. Mix --- There is a convenience function which simplifies the process of applying transitions betwee adjacent cuts on a playlist. This is often preferable to use over the constuction of your own tractor and transition set up. To apply a 25 frame luma transition between the first and second cut on the playlist, you could use: Transition luma; playlist.mix( 0, 25, luma ); Events ------ Typically, applications need to be informed when changes occur in an mlt++ object. This facilitates application services such as undo/redo management, or project rendering in a timeline type widget and many other types of operations which an application needs. As an example, consider the following: class Xml { private: Consumer consumer; Tractor &tractor; public: Xml( MltTractor &tractor ) : tractor( tractor ), consumer( "xml" ) { consumer.connect( tractor ); tractor.listen( tractor, "producer-changed", ( mlt_listener )Xml::listener ); } static void listener( Properties *tractor, Xml *object ) { object->activate( ); } void activate( ) { consumer.start( ); } }; Now, each time the tractor is changed, the XML representation is output to stderr. That's All Folks... ------------------- And that, believe it or not, is a fairly complete summary of the classes you'll typically be interfacing with in mlt++. Obviously, there's a little more to it than this - a couple of intrisinc classes have been glossed over (notably, the Properties and Service base classes). The next section will cover all of the above, but in much more detail... DIGGING DEEPER -------------- The previous section was designed to give you a whistle stop tour through the major framework classes. This section will take you through the scenic route. Introducing Base Classes ------------------------ Services in mlt are the collective noun for Producers, Filters, Transitions and Consumer. A Service is also the base class from which all of these classes extend. It provides the basic connectivity which has been shown throughout the examples in the previous section. Properties are the main way in which we communicate with the Services - essentially, it provides get/set methods for named values. All services extend Properties. Properties ---------- Properties provide the general mechanism for communicating with Services - through the Properties interface, we are able to manipulate and serialise a services state. For example, to dump all the properties to stdout, you can use something like: void dump( Properties &properties ) { for ( int i = 0; i < properties.count( ); i ++ ) cout << Properties.get_name( i ) << " = " << Properties.get( i ) << endl; } Note that the properties object handles type conversion, so the following is acceptable: properties.set( "hello", "10.5" ); int hello_int = properties.get_int( "hello" ); double hello_double = properties.get_double( "hello" ); A couple of convenience methods are provide to examine or serialise property objects. For example: properties.debug( ); will report all serialisable properties on stderr, in the form: Object: [ ref=1, in=0, out=0, track=0, u=75, v=150, _unique_id=15, mlt_type=filter, mlt_service=sepia ] Services -------- Typically, all the services are constructed via the specific classes constructor. Often, you will receive Service objects rather than their specific type. In order to access the extended classes interface, you will need to create a reference. For example, given an arbitrary Service object, you can determine its type by using the type method - this will return a 'service_type' which has values of producer_type, filter_type etc. Alternatively, you can create a wrapping object and check on its validity. bool do_we_have_a_producer( Service &service ) { Producer producer( service ); return producer.is_valid( ); } Events ------ Servers and MLT XML Docs ------------------------ For various reasons, you might want to serialise a producer to a string. To do this, you just need to specify a property to write to: Consumer xml( "xml", "buffer" ); xml.connect( producer ); xml.start( ); buffer = xml.get( "buffer" ); You can use any name you want, and you can change it using the "resource" property. Any name with a '.' in it is considered to be a file. Hence, you can use a xml consumer to store multiple instances of the same MLT object - useful if you want to provide undo/redo capabilities in an editing application. Should you receive an XML document as a string, and you want to send it on to a server, you can use: Consumer client( "mvsp", "localhost:5250" ); client.set( "xml", buffer ); client.start( ); If you need to obtain an MLT object from a XML string: Producer producer( "xml-string", buffer ); The following shows a working example of an extended server: class ShotcutServer : public Melted { public: ShotcutServer( char *id, int port ) : Melted( id, port ) { } void set_receive_doc( bool doc ) { set( "push-parser-off", doc ); } // Reject all commands other than push/receive Response *execute( char *command ) { mvsp_response response = mvsp_response_init( ); mvsp_response_set_error( response, 400, "Not OK" ); return new Response( response ); } // Push document handler Response *received( char *command, char *doc ) { mvsp_response response = mvsp_response_init( ); // Use doc in some way and assign Response if ( doc != NULL ) mvsp_response_set_error( response, 200, "OK" ); return new Response( response ); } // Push service handler Response *push( char *command, Service *service ) { mvsp_response response = mvsp_response_init( ); // Use service in some way and assign Response if ( service != NULL ) mvsp_response_set_error( response, 200, "OK" ); return new Response( response ); } }; NB: Should you be incorporating this into a GUI application, remember that the execute, received and push methods are invoked from a thread - make sure that you honour the locking requirements of your GUI toolkit before interacting with the UI. mlt-0.9.0/docs/mlt-xml.txt000066400000000000000000000516701215300731300154030ustar00rootroot00000000000000MLT XML Schema Documentation Copyright (C) 2004-2009 Ushodaya Enterprised Limited Authors: Charles Yates Last Revision: 2009-05-08 MLT XML ------- Preamble: This is the MLT projects XML serialisation/deserialisation format - as such, it closely mirrors the internal structure of the MLT API. If you just want to go straight to the DTD, then see mlt/src/modules/xml/mlt-xml.dtd, which gets installed at $(prefix)/share/mlt/modules/xml/mlt-xml.dtd. Currently, the XML parser is non-validating. Introduction: A MLT XML document is essentially a list of 'producers' - a producer is an mlt object which generates mlt frames (images and associated audio samples). There are 3 types of producer: * Basic Producers - these are typically file or device oriented feeds; * Playlists - these are arrangements of multiple producers; * Multitracks - these are the fx encapsulators. In the mlt model, producers are created and attached to 'consumers' - consumers are software playback components (such as SDL), or wrappers for hardware drivers (such as sdi) or even the XML serialising consumer itself (the latter doesn't receive frames - it merely interrogates the connected producer for its configuration). Although MLT XML was defined as a serialisation mechanism for instantiated MLT components, this document will concentrate on the hand authoring of MLT XML documents. Rules: As shall become apparent through the remainder of this document, the basic tenet of MLT XML authoring is to organise the document in the following manner: 1) create producer elements for each unique media clip in the project; 2) create playlists for each track; 3) create a multitrack and specify filters and transitions; 4) adding global filters. While other uses of MLT XML exist, the approach taken here is to maximise efficiency for complex projects. Basic Producers: The simplest MLT XML document is: clip1.dv The XML wrapping is of course superfluous here - loading this document with MLT is identical to loading the clip directly. Of course, you can specify additional properties. For example, consider an MPEG file with multiple soundtracks - you could define a MLT XML document to ensure that the second audio track is loaded: clip1.mpeg 1 NB: This relies on the mpeg being handled by the avformat producer, rather than the mcmpeg one. See services.txt for more details. A more useful example comes with the pango producer for a text producer. TODO: pango example... Notes: 1) It is better not to specify in/out points when defining basic producers as these can be specified in the playlists. The reasoning is that in/out restricts the amount of the clip available, and could lead to the same clip being loaded multiple times if you need different regions of the clip elsewhere; 2) A MLT XML doc can be specified as a resource, so XML docs can naturally encapsulate other XML docs. Playlists: Playlists provide a 'collection' structure for producers. These can be used to define 'tracks' in the multitrack approach, or simple playlists for sequential, single track playout. As an example, the following defines two basic producers and a playlist with 3 items: clip1.dv clip2.dv Here we see how the playlist defines the in/out points of the basic producers. Notes: 1) All in/out points are absolute frame positions relative to the producer being appended to the playlist; 2) MLT XML documents are currently authored for a specific normalisation; 3) The last 'producer' in the document is the default for play out; 4) Playlists can reference the same producer multiple times. In/out regions do not need to be contiguous - duplication and skipping is acceptable. Interlude - Introducing Multitracks: So far we've defined basic producers and playlists/tracks - the tractor is the element that allows us to arrange our tracks and specify filters and transitions. Similarly to a playlist, a tractor is a container. Note that MLT doesn't see a filter or a transition as a producer in the normal sense - filters and transitions are passive when it comes to seeking. Internally, seeks are carried out on the producers. This is an important point - MLT does not follow a traditional graph oriented model. Visualising an MLT tractor and it's interaction with the consumer will assist here: +----------------------------------------------+ |tractor | | +----------+ +-+ +-+ +-+ +-+ | | |multitrack| |f| |f| |t| |t| | | | +------+ | |i| |i| |r| |r| | | | |track0|-|--->|l|- ->|l|- ->|a|--->|a|\ | | | +------+ | |t| |t| |n| |n| \ | | | | |e| |e| |s| |s| \ | | | +------+ | |r| |r| |i| |i| \ | +--------+ | | |track1|-|- ->|0|--->|1|--->|t|--->|t|-----|--->|consumer| | | +------+ | | | | | |i| |i| / | +--------+ | | | | | | | |o| |o| / | ^ | | +------+ | | | | | |n| |n| / | | | | |track2|-|- ->| |- ->| |--->|0|- ->|1|/ | | | | +------+ | | | | | | | | | | | | +----------+ +-+ +-+ +-+ +-+ | | +----------------------------------------------+ | ^ | | | +-----------+ | |APPLICATION|--------------------------------------------+ +-----------+ Internally, all frames from all tracks pass through all the filters and transitions - these are told which tracks to deal and which regions of the tracks to work on. Note that the application communicates with the producer - it can alter playback speed, position, or even which producer is connected to which consumer. The consumer receives the first non-blank frame (see below). It has no say in the order in which gets them (the sdl consumer when used with melt might appear to be an exception - it isn't - it simply has a route back to the application to allow the application to interpret key presses). Tractors: To create a multitrack XML, we can use two playlists and introduce a tractor. For the purposes of demonstration, I'll add a filter here too: clip1.dv clip2.dv 0 greyscale Here we see that blank frames are inserted into the first playlist and a blank is provided at the beginning of the second - this can be visualised in the traditional timeline widget as follows: +-------+ +-------------+ |a | |a | +-------+---+-------------+ |b | +---+ Adding the filter on the top track, gives us: +-------+ +-------------+ |a | |a | +-------+---+-------------+ |greyscale | --------+---+-------------+ |b | +---+ Note that it's only applied to the visible parts of the top track. The requirement to apply a filter to the output, as opposed to a specific track leads us to the final item in the Rules section above. As an example, let's assume we wish to watermark all output, then we could use the following: clip1.dv clip2.dv 0 greyscale watermark watermark1.png Here we employ another tractor and we define a single track (being the tractor we previously defined) and apply a watermarking filter there. This is simply provided as an example - the watermarking functionality could be better handled at the playout stage itself (ie: as a filter automatically placed between all producers and the consumer). Tracks act like "layers" in an image processing program like the GIMP. The bottom-most track takes highest priority and higher layers are overlays and do not appear unless there are gaps in the lower layers or unless a transition is applied that merges the tracks on the specifed region. Practically speaking, for A/B video editing it does not mean too much, and it will work as expected; however, as a general rule apply any CGI (graphic overlays with pixbuf or titles with pango) on tracks higher than your video tracks. Also, this means that any audio-only tracks that are lower than your video tracks will play rather than the audio from the video clip. Remember, nothing is affected like mixing or compositing until one applies a transition or appropriate filter. clip1.dv clip2.mpeg 0 1 luma 0 1 mix 0.0 1.0 A "luma" transition is a video wipe processor that takes a greyscale bitmap for the wipe definition. When one does not specify a bitmap, luma performs a dissolve. The "mix" transition does an audio mix, but it interpolates between the gain scaling factors between the start and end properties - in this example, from 0.0 (none of track B) to 1.0 (all of track B). Because the bottom track starts out with a gap specified using the element, the upper track appears during the blank segment. See the demos and services.txt to get an idea of the capabilities of the included transitions. Flexibility: The information presented above is considered the MLT XML "normal" form. This is the output generated by the xml consumer, for example, when used with melt. It is the output generated when you use the "XML to File" consumer in the demo script, which beginners will find most useful for learning to use MLT XML. This section describes alternative forms the xml producer accepts. First of all, the normal form is more of a linear format with producers and playlists defined prior to their usage in a multitrack. The producer also accepts a hierarchical format with producers as children of tracks or playlist entries and with playlists as children of tracks: clip1.dv Obviously, this example is meant to demonstrate hierarchy and not effective use of playlist or multitrack! Secondly, as part of error handling, the producer is forgiving if you fail to supply , , and where one can be understood. This affords an abbreviated syntax that is less verbose and perhaps less intimidating for a human to read and understand. One can simplify the above example as: clip1.dv Yes, filters and transitions can be added to the above example after the closing multitrack tag () because it is still enclosed within the mlt body tags. If you specify in and out on a producer and it has been enclosed within an or , then the edit points apply to the playlist entry and not to the producer itself. This facilitates re-use of media: clip1.dv In the above example, the producer attribute of the entry element is a reference to the preceding producer. All references must follow the definition. The edit points supplied on the producer above will not affect the entry that references it below because the producer knows the clip is a playlist entry and optimises this situation. The advantage is that one does not need to determine every clip to be included ahead of time and specify them outside the context of the mutlitrack timeline. This form of authoring will be easier for many to visualise as a non-linear editor's timeline. Here is a more complex example: clip2.mpeg clip3.mpeg Did you notice something different in the last example? Properties can be expressed using XML attributes on the element as well. However, only non-service-specific properties are supported in this way. For example, "mlt_service" is available to any producer, filter, or transition. However, "resource" is actually service-specific. Notice the syntax of the last property, on the last transition. The producer accepts property values using the "value" attribute as well as using element text. We have seen a few different ways of expressing property values. There are a couple more for properties that can accept XML data. For example, the GDK pixbuf producer with librsvg can handle embedded SVG, and the Pango producer can handle embedded Pango markup. You can enclose the embedded XML using a CDATA section: ... ]]> Please ensure the opening CDATA tag immediately follows the opening property tag and that the section closing tag immediately precedes the closing property tag. However, the producer can also accept inline embedded XML: Currently, there is no namespace handling so a conflict will occur only on any embedded XML that contains an element named "property" because the producer collects embedded XML until it reaches a closing property tag. Entities and Parameterisation: The MLT XML producer parser supports XML entities. An example: ]> pango &msg; If you are embedding another XML document into a property value not using a CNODE section, then any DOCTYPE section must be relocated before any of the xml elements to be well-formed. See demo/svg.mlt for an example. Entities can be used to parameterise MLT XML! Using the above example, the entity declared serves as the default value for &msg;. The entity content can be overridden from the resource property supplied to the xml producer. The syntax is the familiar, url-encoded query string used with HTTP, e.g.: file?name=value&name=value... There are a couple of rules of usage. The melted LOAD command and melt command line tool require you to preface the URL with "xml:" because the query string destroys the filename extension matching peformed by the auto-loader. Also, melt looks for '=' to tokenise property settings. Therefore, one uses ':' between name and value instead of '='. Finally, since melt is run from the shell, one must enclose the URL within single quotes to prevent shell filename expansion, or similar. Needless to say, the ability to parameterise MLT XML compositions is an extremely powerful tool. An example for you to play with is available in demo/entity.mlt. Try overriding the name from melt: melt 'xml:entity.mlt?name:Charlie' Technically, the entity declaration is not needed in the head of the XML document if you always supply the parameter. However, you run the risk of unpredictable behviour without one. Therefore, it is safest and a best practice to always supply an entity declaration. It is improves the readability as one does not need to search for the entity references to see what parameters are available. Tips and Technique: If one finds the above hierarchical, abbreviated format intuitive, start with a simple template and fill and extend as needed: ...add a playlist for each track... ...add filters and transitions... By using a playlist for each track, it is easier to iteratively add new clips and blank regions as you develop the project. You will not have to use or later add when necessary. A more advanced template that allows sequencing multitracks is: ...add a playlist for each track... ...add filters and transitions... ...add a playlist for each track... ...add filters and transitions... If you end up making a collection of templates for various situations, then consider using XML Entities to make the template more effective by moving anything that should parameterised into an entity. If you want to have a silent, black background for audio and video fades, then make the top track simply . Then, use composite and volume effects. See the "Fade from/to black/silence" demo for an example (demo/mlt_fade_black). If you apply the reverse=1 property to a transition like "luma," then be careful because it also inherently swaps the roles of A and B tracks. Therefore, you need to might need to swap the a_track and b_track values if it did not turn out the way you expected. See the "Clock in and out" for an example (demo/mlt_clock_in_and_out). mlt-0.9.0/mlt++.pc.in000066400000000000000000000002271215300731300141630ustar00rootroot00000000000000 Name: mlt++ Description: C++ API for MLT multimedia framework Version: ${version} Requires: mlt-framework Libs: -L${libdir} ${libs} Cflags: ${cflags} mlt-0.9.0/mlt-config-template000066400000000000000000000015061215300731300161040ustar00rootroot00000000000000export package=framework export field=0 while [ "$1" != "" ] do case $1 in --help ) field=0 ;; --version ) field=-1 ;; --prefix ) field=-2 ;; --prefix=* ) prefix="${i#--prefix=}" ;; --cflags ) field=2 ;; --libs ) field=3 ;; --list ) field=1; package="" ;; * ) package=$1 ;; esac shift done if [ "$field" = "0" ] then echo "Usage: mlt-config [ --version ] | [ --prefix=dir ] [ [ package ] [ --cflags ] [ --libs ] ]" elif [ "$field" = "-1" ] then echo $version elif [ "$field" = "-2" ] then config=`which mlt-config` dir=`dirname $config` dir=`dirname $dir` echo $dir elif [ -f "$prefix/share/mlt/packages.dat" ] then grep "^$package" $prefix/share/mlt/packages.dat | cut -f $field else echo mlt-config cannot find package $package. fi echo >&2 "mlt-config is deprecated. Please use pkg-config instead." mlt-0.9.0/mlt-framework.pc.in000066400000000000000000000002051215300731300160240ustar00rootroot00000000000000 Name: mlt-framework Description: MLT multimedia framework Version: ${version} Requires: Libs: -L${libdir} ${libs} Cflags: ${cflags} mlt-0.9.0/presets/000077500000000000000000000000001215300731300137745ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/000077500000000000000000000000001215300731300156275ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/000077500000000000000000000000001215300731300174465ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/AAC000066400000000000000000000001401215300731300177500ustar00rootroot00000000000000f=mp4 acodec=aac ab=256k vn=1 video_off=1 meta.preset.extension=m4a meta.preset.note=audio only mlt-0.9.0/presets/consumer/avformat/Flash000066400000000000000000000003221215300731300204230ustar00rootroot00000000000000f=flv acodec=libmp3lame ab=128k ar=44100 vcodec=flv minrate=0 vb=1M progressive=1 meta.preset.extension=flv meta.preset.note=This is the old Sorenson H.263-based codec. Most people use H.264 with Flash now. mlt-0.9.0/presets/consumer/avformat/MJPEG000066400000000000000000000001331215300731300202300ustar00rootroot00000000000000f=avi vcodec=mjpeg qscale=4 acodec=libmp3lame ab=256k threads=1 meta.preset.extension=avi mlt-0.9.0/presets/consumer/avformat/MP3000066400000000000000000000001411215300731300177640ustar00rootroot00000000000000f=mp3 acodec=mp3 ab=256k vn=1 video_off=1 meta.preset.extension=mp3 meta.preset.note=audio only mlt-0.9.0/presets/consumer/avformat/MPEG-2000066400000000000000000000003131215300731300202550ustar00rootroot00000000000000f=mpeg acodec=mp2 ab=256k ar=48000 vcodec=mpeg2video minrate=0 vb=8M trellis=1 bf=2 b_strategy=1 mbd=rd cmp=satd subcmp=satd meta.preset.extension=mpg meta.preset.note=a general purpose MPEG-2 preset mlt-0.9.0/presets/consumer/avformat/MPEG-4000066400000000000000000000003151215300731300202610ustar00rootroot00000000000000f=mp4 acodec=libmp3lame ab=128k ar=44100 vcodec=mpeg4 minrate=0 vb=2M mbd=rd trellis=1 flags=+mv4+aic cmp=satd subcmp=satd progressive=1 meta.preset.extension=mp4 meta.preset.note=Part 2 Simple Profile mlt-0.9.0/presets/consumer/avformat/MPEG-4-ASP000066400000000000000000000003231215300731300207010ustar00rootroot00000000000000f=mp4 acodec=libmp3lame ab=128k ar=44100 vcodec=mpeg4 minrate=0 vb=2M mbd=rd trellis=1 cmp=satd subcmp=satd bf=2 flags=+mv4+aic+qpel meta.preset.extension=mp4 meta.preset.note=Part 2 Advanced Simple Profile mlt-0.9.0/presets/consumer/avformat/Sony-PSP000066400000000000000000000004311215300731300207570ustar00rootroot00000000000000width=480 height=272 aspect=@16/9 progressive=1 f=psp acodec=aac ar=32000 ab=96k vcodec=libx264 threads=0 vpre=medium preset=medium vprofile=main flags2=-dct8x8 vb=1M refs=1 bf=1 x264opts=ref=1:bframes=1 meta.preset.extension=mp4 meta.preset.note=for Sony PlayStation Portable mlt-0.9.0/presets/consumer/avformat/Vorbis000066400000000000000000000002001215300731300206250ustar00rootroot00000000000000f=ogg acodec=vorbis ab=256k vn=1 video_off=1 meta.preset.name=Ogg Vorbis meta.preset.extension=ogg meta.preset.note=audio only mlt-0.9.0/presets/consumer/avformat/WAV000066400000000000000000000001371215300731300200270ustar00rootroot00000000000000f=wav acodec=pcm_s16le vn=1 video_off=1 meta.preset.extension=wav meta.preset.note=audio only mlt-0.9.0/presets/consumer/avformat/XDCAM-HD422000066400000000000000000000005051215300731300207460ustar00rootroot00000000000000vcodec=mpeg2video top_field_first=1 pix_fmt=yuv422p minrate=50M maxrate=50M vb=50M dc=10 flags2=+ivlc+non_linear_q intra_vlc=1 non_linear_qant=1 lmin=1*QP2LAMBDA rc_max_vbv_use=1 rc_min_vbv_use=1 qmin=1 qmax=12 bufsize=36408333 bf=2 vtag=xd5c acodec=pcm_s16le meta.preset.extension=mov meta.preset.note=use with mxf or mov mlt-0.9.0/presets/consumer/avformat/atsc_1080i_50/000077500000000000000000000000001215300731300215255ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/atsc_1080i_50/DNxHD000066400000000000000000000002651215300731300223600ustar00rootroot00000000000000f=mov vcodec=dnxhd vb=185M threads=2 acodec=pcm_s16le meta.preset.extension=mov meta.preset.note=A lightly compressed intermediate codec developed by Avid also known as SMPTE VC-3 mlt-0.9.0/presets/consumer/avformat/atsc_1080i_5994/000077500000000000000000000000001215300731300217135ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/atsc_1080i_5994/DNxHD000066400000000000000000000002651215300731300225460ustar00rootroot00000000000000f=mov vcodec=dnxhd vb=220M threads=2 acodec=pcm_s16le meta.preset.extension=mov meta.preset.note=A lightly compressed intermediate codec developed by Avid also known as SMPTE VC-3 mlt-0.9.0/presets/consumer/avformat/atsc_1080p_2398/000077500000000000000000000000001215300731300217155ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/atsc_1080p_2398/DNxHD000066400000000000000000000002651215300731300225500ustar00rootroot00000000000000f=mov vcodec=dnxhd vb=175M threads=2 acodec=pcm_s16le meta.preset.extension=mov meta.preset.note=A lightly compressed intermediate codec developed by Avid also known as SMPTE VC-3 mlt-0.9.0/presets/consumer/avformat/atsc_1080p_24/000077500000000000000000000000001215300731300215355ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/atsc_1080p_24/DNxHD000066400000000000000000000002651215300731300223700ustar00rootroot00000000000000f=mov vcodec=dnxhd vb=175M threads=2 acodec=pcm_s16le meta.preset.extension=mov meta.preset.note=A lightly compressed intermediate codec developed by Avid also known as SMPTE VC-3 mlt-0.9.0/presets/consumer/avformat/atsc_1080p_25/000077500000000000000000000000001215300731300215365ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/atsc_1080p_25/DNxHD000066400000000000000000000002651215300731300223710ustar00rootroot00000000000000f=mov vcodec=dnxhd vb=185M threads=2 acodec=pcm_s16le meta.preset.extension=mov meta.preset.note=A lightly compressed intermediate codec developed by Avid also known as SMPTE VC-3 mlt-0.9.0/presets/consumer/avformat/atsc_1080p_2997/000077500000000000000000000000001215300731300217225ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/atsc_1080p_2997/DNxHD000066400000000000000000000002651215300731300225550ustar00rootroot00000000000000f=mov vcodec=dnxhd vb=220M threads=2 acodec=pcm_s16le meta.preset.extension=mov meta.preset.note=A lightly compressed intermediate codec developed by Avid also known as SMPTE VC-3 mlt-0.9.0/presets/consumer/avformat/atsc_1080p_30/000077500000000000000000000000001215300731300215325ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/atsc_1080p_30/DNxHD000066400000000000000000000002651215300731300223650ustar00rootroot00000000000000f=mov vcodec=dnxhd vb=220M threads=2 acodec=pcm_s16le meta.preset.extension=mov meta.preset.note=A lightly compressed intermediate codec developed by Avid also known as SMPTE VC-3 mlt-0.9.0/presets/consumer/avformat/atsc_1080p_50/000077500000000000000000000000001215300731300215345ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/atsc_1080p_50/DNxHD000066400000000000000000000002651215300731300223670ustar00rootroot00000000000000f=mov vcodec=dnxhd vb=185M threads=2 acodec=pcm_s16le meta.preset.extension=mov meta.preset.note=A lightly compressed intermediate codec developed by Avid also known as SMPTE VC-3 mlt-0.9.0/presets/consumer/avformat/atsc_1080p_5994/000077500000000000000000000000001215300731300217225ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/atsc_1080p_5994/DNxHD000066400000000000000000000002651215300731300225550ustar00rootroot00000000000000f=mov vcodec=dnxhd vb=220M threads=2 acodec=pcm_s16le meta.preset.extension=mov meta.preset.note=A lightly compressed intermediate codec developed by Avid also known as SMPTE VC-3 mlt-0.9.0/presets/consumer/avformat/atsc_1080p_60/000077500000000000000000000000001215300731300215355ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/atsc_1080p_60/DNxHD000066400000000000000000000002651215300731300223700ustar00rootroot00000000000000f=mov vcodec=dnxhd vb=220M threads=2 acodec=pcm_s16le meta.preset.extension=mov meta.preset.note=A lightly compressed intermediate codec developed by Avid also known as SMPTE VC-3 mlt-0.9.0/presets/consumer/avformat/atsc_720p_2398/000077500000000000000000000000001215300731300216355ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/atsc_720p_2398/DNxHD000066400000000000000000000002641215300731300224670ustar00rootroot00000000000000f=mov vcodec=dnxhd vb=90M threads=2 acodec=pcm_s16le meta.preset.extension=mov meta.preset.note=A lightly compressed intermediate codec developed by Avid also known as SMPTE VC-3 mlt-0.9.0/presets/consumer/avformat/atsc_720p_50/000077500000000000000000000000001215300731300214545ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/atsc_720p_50/DNxHD000066400000000000000000000002651215300731300223070ustar00rootroot00000000000000f=mov vcodec=dnxhd vb=175M threads=2 acodec=pcm_s16le meta.preset.extension=mov meta.preset.note=A lightly compressed intermediate codec developed by Avid also known as SMPTE VC-3 mlt-0.9.0/presets/consumer/avformat/atsc_720p_5994/000077500000000000000000000000001215300731300216425ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/atsc_720p_5994/DNxHD000066400000000000000000000002651215300731300224750ustar00rootroot00000000000000f=mov vcodec=dnxhd vb=220M threads=2 acodec=pcm_s16le meta.preset.extension=mov meta.preset.note=A lightly compressed intermediate codec developed by Avid also known as SMPTE VC-3 mlt-0.9.0/presets/consumer/avformat/atsc_720p_60/000077500000000000000000000000001215300731300214555ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/atsc_720p_60/DNxHD000066400000000000000000000002651215300731300223100ustar00rootroot00000000000000f=mov vcodec=dnxhd vb=220M threads=2 acodec=pcm_s16le meta.preset.extension=mov meta.preset.note=A lightly compressed intermediate codec developed by Avid also known as SMPTE VC-3 mlt-0.9.0/presets/consumer/avformat/dv_ntsc/000077500000000000000000000000001215300731300211065ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/dv_ntsc/D10000066400000000000000000000005351215300731300213600ustar00rootroot00000000000000f=mxf_d10 vcodec=mpeg2video pix_fmt=yuv422p minrate=50M maxrate=50M vb=50M g=0 flags=+ildct+low_delay dc=10 flags2=+ivlc+non_linear_q ps=1 qmin=1 qmax=3 bufsize=1669k rc_init_occupancy=1669k rc_buf_aggressivity=0.25 acodec=pcm_s16le meta.preset.extension=mxf meta.preset.note=Intra-frame only, 50 Mb/s MPEG-2 also known as Sony IMX or SMPTE 365M mlt-0.9.0/presets/consumer/avformat/dv_ntsc/DV000066400000000000000000000002011215300731300213330ustar00rootroot00000000000000pix_fmt=yuv411p vcodec=dvvideo acodec=pcm_s16le meta.preset.note=The popular standard definition camcorder digital video format mlt-0.9.0/presets/consumer/avformat/dv_ntsc/DVCPRO50000066400000000000000000000001531215300731300221720ustar00rootroot00000000000000pix_fmt=yuv422p vcodec=dvvideo acodec=pcm_s16le meta.preset.note=Double the amount of chroma as normal DV mlt-0.9.0/presets/consumer/avformat/dv_ntsc/DVD000066400000000000000000000004161215300731300214470ustar00rootroot00000000000000f=dvd vcodec=mpeg2video acodec=ac3 vb=6000k maxrate=9000k minrate=0 bufsize=1835008 packetsize=2048 muxrate=10080000 ab=192k ar=48000 g=18 me_range=63 trellis=1 meta.preset.extension=vob meta.preset.note=Process the output with a DVD authoring tool such as dvdauthor. mlt-0.9.0/presets/consumer/avformat/dv_ntsc_wide/000077500000000000000000000000001215300731300221165ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/dv_ntsc_wide/D10000066400000000000000000000005351215300731300223700ustar00rootroot00000000000000f=mxf_d10 vcodec=mpeg2video pix_fmt=yuv422p minrate=50M maxrate=50M vb=50M g=0 flags=+ildct+low_delay dc=10 flags2=+ivlc+non_linear_q ps=1 qmin=1 qmax=3 bufsize=1669k rc_init_occupancy=1669k rc_buf_aggressivity=0.25 acodec=pcm_s16le meta.preset.extension=mxf meta.preset.note=Intra-frame only, 50 Mb/s MPEG-2 also known as Sony IMX or SMPTE 365M mlt-0.9.0/presets/consumer/avformat/dv_ntsc_wide/DV000066400000000000000000000002011215300731300223430ustar00rootroot00000000000000pix_fmt=yuv411p vcodec=dvvideo acodec=pcm_s16le meta.preset.note=The popular standard definition camcorder digital video format mlt-0.9.0/presets/consumer/avformat/dv_ntsc_wide/DVCPRO50000066400000000000000000000001531215300731300232020ustar00rootroot00000000000000pix_fmt=yuv422p vcodec=dvvideo acodec=pcm_s16le meta.preset.note=Double the amount of chroma as normal DV mlt-0.9.0/presets/consumer/avformat/dv_ntsc_wide/DVD000066400000000000000000000004161215300731300224570ustar00rootroot00000000000000f=dvd vcodec=mpeg2video acodec=ac3 vb=6000k maxrate=9000k minrate=0 bufsize=1835008 packetsize=2048 muxrate=10080000 ab=192k ar=48000 g=18 me_range=63 trellis=1 meta.preset.extension=vob meta.preset.note=Process the output with a DVD authoring tool such as dvdauthor. mlt-0.9.0/presets/consumer/avformat/dv_pal/000077500000000000000000000000001215300731300207135ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/dv_pal/D10000066400000000000000000000005561215300731300211700ustar00rootroot00000000000000f=mxf_d10 top_field_first=1 vcodec=mpeg2video pix_fmt=yuv422p minrate=50M maxrate=50M vb=50M g=0 flags=+ildct+low_delay dc=10 flags2=+ivlc+non_linear_q ps=1 qmin=1 qmax=3 bufsize=2000k rc_init_occupancy=2000k rc_buf_aggressivity=0.25 acodec=pcm_s16le meta.preset.extension=mxf meta.preset.note=Intra-frame only, 50 Mb/s MPEG-2 also known as Sony IMX or SMPTE 365M mlt-0.9.0/presets/consumer/avformat/dv_pal/DV000066400000000000000000000002011215300731300211400ustar00rootroot00000000000000pix_fmt=yuv420p vcodec=dvvideo acodec=pcm_s16le meta.preset.note=The popular standard definition camcorder digital video format mlt-0.9.0/presets/consumer/avformat/dv_pal/DVCPRO50000066400000000000000000000001531215300731300217770ustar00rootroot00000000000000pix_fmt=yuv422p vcodec=dvvideo acodec=pcm_s16le meta.preset.note=Double the amount of chroma as normal DV mlt-0.9.0/presets/consumer/avformat/dv_pal/DVD000066400000000000000000000004151215300731300212530ustar00rootroot00000000000000f=dvd vcodec=mpeg2video acodec=ac3 vb=5000k maxrate=8000k minrate=0 bufsize=1835008 packetsize=2048 muxrate=10080000 ab=192k ar=48000 g=15 me_range=63 trellis=1 meta.preset.extension=vob meta.preset.note=Process the output with a DVD authoring tool such as dvdauthor. mlt-0.9.0/presets/consumer/avformat/dv_pal_wide/000077500000000000000000000000001215300731300217235ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/dv_pal_wide/D10000066400000000000000000000005561215300731300222000ustar00rootroot00000000000000f=mxf_d10 top_field_first=1 vcodec=mpeg2video pix_fmt=yuv422p minrate=50M maxrate=50M vb=50M g=0 flags=+ildct+low_delay dc=10 flags2=+ivlc+non_linear_q ps=1 qmin=1 qmax=3 bufsize=2000k rc_init_occupancy=2000k rc_buf_aggressivity=0.25 acodec=pcm_s16le meta.preset.extension=mxf meta.preset.note=Intra-frame only, 50 Mb/s MPEG-2 also known as Sony IMX or SMPTE 365M mlt-0.9.0/presets/consumer/avformat/dv_pal_wide/DV000066400000000000000000000002011215300731300221500ustar00rootroot00000000000000pix_fmt=yuv420p vcodec=dvvideo acodec=pcm_s16le meta.preset.note=The popular standard definition camcorder digital video format mlt-0.9.0/presets/consumer/avformat/dv_pal_wide/DVCPRO50000066400000000000000000000001531215300731300230070ustar00rootroot00000000000000pix_fmt=yuv422p vcodec=dvvideo acodec=pcm_s16le meta.preset.note=Double the amount of chroma as normal DV mlt-0.9.0/presets/consumer/avformat/dv_pal_wide/DVD000066400000000000000000000004161215300731300222640ustar00rootroot00000000000000f=dvd vcodec=mpeg2video acodec=ac3 vb=5000k maxrate=8000k minrate=0 bufsize=1835008 packetsize=2048 muxrate=10080000 ab=192k ar=48000 g=15 me_range=63 trellis=1 meta.preset.extension=vob meta.preset.note=Process the output with a DVD authoring tool such as dvdauthor. mlt-0.9.0/presets/consumer/avformat/hdv_1080_25p/000077500000000000000000000000001215300731300213655ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/hdv_1080_25p/HDV000066400000000000000000000003111215300731300217240ustar00rootroot00000000000000f=mpegts acodec=mp2 ab=384k ar=48000 ac=2 vcodec=mpeg2video vb=25M g=15 trellis=1 bf=2 b_strategy=1 mbd=rd cmp=satd subcmp=satd meta.preset.extension=m2t meta.preset.note=HD MPEG-2 camcorder format mlt-0.9.0/presets/consumer/avformat/hdv_1080_30p/000077500000000000000000000000001215300731300213615ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/hdv_1080_30p/HDV000066400000000000000000000003111215300731300217200ustar00rootroot00000000000000f=mpegts acodec=mp2 ab=384k ar=48000 ac=2 vcodec=mpeg2video vb=25M g=15 trellis=1 bf=2 b_strategy=1 mbd=rd cmp=satd subcmp=satd meta.preset.extension=m2t meta.preset.note=HD MPEG-2 camcorder format mlt-0.9.0/presets/consumer/avformat/hdv_1080_50i/000077500000000000000000000000001215300731300213545ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/hdv_1080_50i/HDV000066400000000000000000000003111215300731300217130ustar00rootroot00000000000000f=mpegts acodec=mp2 ab=384k ar=48000 ac=2 vcodec=mpeg2video vb=25M g=15 trellis=1 bf=2 b_strategy=1 mbd=rd cmp=satd subcmp=satd meta.preset.extension=m2t meta.preset.note=HD MPEG-2 camcorder format mlt-0.9.0/presets/consumer/avformat/hdv_1080_60i/000077500000000000000000000000001215300731300213555ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/hdv_1080_60i/HDV000066400000000000000000000003111215300731300217140ustar00rootroot00000000000000f=mpegts acodec=mp2 ab=384k ar=48000 ac=2 vcodec=mpeg2video vb=25M g=15 trellis=1 bf=2 b_strategy=1 mbd=rd cmp=satd subcmp=satd meta.preset.extension=m2t meta.preset.note=HD MPEG-2 camcorder format mlt-0.9.0/presets/consumer/avformat/hdv_720_25p/000077500000000000000000000000001215300731300213055ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/hdv_720_25p/HDV000066400000000000000000000003111215300731300216440ustar00rootroot00000000000000f=mpegts acodec=mp2 ab=384k ar=48000 ac=2 vcodec=mpeg2video vb=25M g=15 trellis=1 bf=2 b_strategy=1 mbd=rd cmp=satd subcmp=satd meta.preset.extension=m2t meta.preset.note=HD MPEG-2 camcorder format mlt-0.9.0/presets/consumer/avformat/hdv_720_30p/000077500000000000000000000000001215300731300213015ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/hdv_720_30p/HDV000066400000000000000000000003111215300731300216400ustar00rootroot00000000000000f=mpegts acodec=mp2 ab=384k ar=48000 ac=2 vcodec=mpeg2video vb=25M g=15 trellis=1 bf=2 b_strategy=1 mbd=rd cmp=satd subcmp=satd meta.preset.extension=m2t meta.preset.note=HD MPEG-2 camcorder format mlt-0.9.0/presets/consumer/avformat/hdv_720_50p/000077500000000000000000000000001215300731300213035ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/hdv_720_50p/HDV000066400000000000000000000003111215300731300216420ustar00rootroot00000000000000f=mpegts acodec=mp2 ab=384k ar=48000 ac=2 vcodec=mpeg2video vb=25M g=15 trellis=1 bf=2 b_strategy=1 mbd=rd cmp=satd subcmp=satd meta.preset.extension=m2t meta.preset.note=HD MPEG-2 camcorder format mlt-0.9.0/presets/consumer/avformat/hdv_720_60p/000077500000000000000000000000001215300731300213045ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/hdv_720_60p/HDV000066400000000000000000000003111215300731300216430ustar00rootroot00000000000000f=mpegts acodec=mp2 ab=384k ar=48000 ac=2 vcodec=mpeg2video vb=25M g=15 trellis=1 bf=2 b_strategy=1 mbd=rd cmp=satd subcmp=satd meta.preset.extension=m2t meta.preset.note=HD MPEG-2 camcorder format mlt-0.9.0/presets/consumer/avformat/lossless/000077500000000000000000000000001215300731300213155ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/lossless/FFV1000066400000000000000000000002171215300731300217420ustar00rootroot00000000000000f=mkv acodec=flac vcodec=ffv1 threads=1 meta.preset.extension=mkv meta.preset.note=FFmpeg video codec 1 with FLAC audio in Matroska container mlt-0.9.0/presets/consumer/avformat/lossless/H.264000066400000000000000000000003171215300731300217420ustar00rootroot00000000000000f=mp4 acodec=aac ab=384k vcodec=libx264 intra=1 vb=0 g=0 bf=0 preset=medium qscale=1 qp=0 coder=ac meta.preset.extension=mp4 meta.preset.note=Intra-frame only, lossless compressed MPEG-4 AVC with AAC audio mlt-0.9.0/presets/consumer/avformat/lossless/HuffYUV000066400000000000000000000001631215300731300225340ustar00rootroot00000000000000f=mkv acodec=flac vcodec=huffyuv meta.preset.extension=mkv meta.preset.note=with FLAC audio in Matroska container mlt-0.9.0/presets/consumer/avformat/lossless/MJPEG000066400000000000000000000002261215300731300221020ustar00rootroot00000000000000progressive=1 f=avi acodec=pcm_s16le vcodec=mjpeg qscale=1 threads=1 meta.preset.extension=avi meta.preset.note=not lossless, but still high quality mlt-0.9.0/presets/consumer/avformat/lossless/MPEG-2000066400000000000000000000002541215300731300221300ustar00rootroot00000000000000f=mpeg acodec=ac3 ab=512k vcodec=mpeg2video intra=1 vb=0 g=0 bf=0 qscale=1 meta.preset.extension=mpg meta.preset.note=a little lossy, but intra-frame only with AC-3 audio mlt-0.9.0/presets/consumer/avformat/lossless/MPEG-4000066400000000000000000000002601215300731300221270ustar00rootroot00000000000000f=avi acodec=pcm_s16le vcodec=mpeg4 qscale=1 intra=1 g=0 vb=0 bf=0 meta.preset.extension=avi meta.preset.note=somewhat lossy, intra-frame only MPEG-4, with uncompressed audio mlt-0.9.0/presets/consumer/avformat/lossless/ProRes000066400000000000000000000002711215300731300224520ustar00rootroot00000000000000f=mov acodec=pcm_s16le vcodec=prores vb=0 g=0 bf=0 threads=1 vprofile=2 meta.preset.extension=mov meta.preset.note=Designed by Apple in California. Set vprofile=1 for LT or =3 for HQ. mlt-0.9.0/presets/consumer/avformat/stills/000077500000000000000000000000001215300731300207605ustar00rootroot00000000000000mlt-0.9.0/presets/consumer/avformat/stills/BMP000066400000000000000000000001161215300731300213170ustar00rootroot00000000000000progressive=1 f=image2 vcodec=bmp an=1 audio_off=1 meta.preset.extension=bmp mlt-0.9.0/presets/consumer/avformat/stills/DPX000066400000000000000000000001161215300731300213340ustar00rootroot00000000000000progressive=1 f=image2 vcodec=dpx an=1 audio_off=1 meta.preset.extension=dpx mlt-0.9.0/presets/consumer/avformat/stills/JPEG000066400000000000000000000001311215300731300214230ustar00rootroot00000000000000progressive=1 f=image2 vcodec=mjpeg qscale=1 an=1 audio_off=1 meta.preset.extension=jpg mlt-0.9.0/presets/consumer/avformat/stills/PNG000066400000000000000000000001161215300731300213250ustar00rootroot00000000000000progressive=1 f=image2 vcodec=png an=1 audio_off=1 meta.preset.extension=png mlt-0.9.0/presets/consumer/avformat/stills/PPM000066400000000000000000000001161215300731300213350ustar00rootroot00000000000000progressive=1 f=image2 vcodec=ppm an=1 audio_off=1 meta.preset.extension=ppm mlt-0.9.0/presets/consumer/avformat/stills/TGA000066400000000000000000000001201215300731300213070ustar00rootroot00000000000000progressive=1 f=image2 vcodec=targa an=1 audio_off=1 meta.preset.extension=tga mlt-0.9.0/presets/consumer/avformat/stills/TIFF000066400000000000000000000001171215300731300214320ustar00rootroot00000000000000progressive=1 f=image2 vcodec=tiff an=1 audio_off=1 meta.preset.extension=tif mlt-0.9.0/presets/consumer/avformat/webm000066400000000000000000000005231215300731300203230ustar00rootroot00000000000000f=webm acodec=vorbis ab=128k vcodec=libvpx g=120 rc_lookahead=16 quality=good speed=0 vprofile=0 qmax=51 qmin=11 slices=4 vb=2M maxrate=24M minrate=100k arnr_max_frames=7 arnr_strength=5 arnr_type=3 meta.preset.name=WebM meta.preset.extension=webm meta.preset.note=VP8 video with Ogg Vorbis audio in Matroska container: "Don't be evil" mlt-0.9.0/presets/consumer/avformat/x264-medium000066400000000000000000000002151215300731300213500ustar00rootroot00000000000000f=mp4 acodec=aac ab=256k vcodec=libx264 threads=0 vpre=medium preset=medium meta.preset.extension=mp4 meta.preset.name=H.264 High Profile mlt-0.9.0/presets/consumer/avformat/x264-medium-baseline000066400000000000000000000003161215300731300231320ustar00rootroot00000000000000f=mp4 acodec=aac ab=256k vcodec=libx264 threads=0 vpre=medium preset=medium vprofile=baseline coder=0 bf=0 flags2=-wpred-dct8x8 wpredp=0 meta.preset.extension=mp4 meta.preset.name=H.264 Baseline Profile mlt-0.9.0/presets/consumer/avformat/x264-medium-main000066400000000000000000000002521215300731300222730ustar00rootroot00000000000000f=mp4 acodec=aac ab=256k vcodec=libx264 threads=0 vpre=medium preset=medium vprofile=main flags2=-dct8x8 meta.preset.extension=mp4 meta.preset.name=H.264 Main Profile mlt-0.9.0/presets/consumer/avformat/x264-medium-pass1000066400000000000000000000004011215300731300223720ustar00rootroot00000000000000f=mp4 vcodec=libx264 threads=0 vpre=medium preset=medium fastfirstpass=1 partitions=-parti8x8-parti4x4-partp8x8-partb8x8 me_method=dia subq=2 refs=1 trellis=0 flags2=+bpyramid-mixed_refs+wpred-dct8x8+fastpskip pass=1 an=1 audio_off=1 meta.preset.hidden=1 mlt-0.9.0/presets/filter/000077500000000000000000000000001215300731300152615ustar00rootroot00000000000000mlt-0.9.0/presets/filter/brightness/000077500000000000000000000000001215300731300174315ustar00rootroot00000000000000mlt-0.9.0/presets/filter/brightness/from_black000066400000000000000000000000321215300731300214460ustar00rootroot00000000000000out=50 in=0 start=0 end=1 mlt-0.9.0/presets/filter/brightness/to_black000066400000000000000000000000321215300731300211250ustar00rootroot00000000000000out=50 in=0 start=1 end=0 mlt-0.9.0/presets/filter/movit.blur/000077500000000000000000000000001215300731300173625ustar00rootroot00000000000000mlt-0.9.0/presets/filter/movit.blur/blur_in000066400000000000000000000000311215300731300207310ustar00rootroot00000000000000radius=0=10.0; :1.0=0.0; mlt-0.9.0/presets/filter/movit.blur/blur_in_out000066400000000000000000000000531215300731300216240ustar00rootroot00000000000000radius=0=10.0; :1.0=0; :-1.0=0.0; -1=10.0; mlt-0.9.0/presets/filter/movit.blur/blur_out000066400000000000000000000000401215300731300211320ustar00rootroot00000000000000radius=0=0; :-1.0=0.0; -1=10.0; mlt-0.9.0/presets/filter/volume/000077500000000000000000000000001215300731300165705ustar00rootroot00000000000000mlt-0.9.0/presets/filter/volume/fade_in000066400000000000000000000000311215300731300200720ustar00rootroot00000000000000out=50 in=0 gain=0 end=1 mlt-0.9.0/presets/filter/volume/fade_out000066400000000000000000000000311215300731300202730ustar00rootroot00000000000000out=50 in=0 gain=1 end=0 mlt-0.9.0/profiles/000077500000000000000000000000001215300731300141325ustar00rootroot00000000000000mlt-0.9.0/profiles/Makefile000066400000000000000000000005141215300731300155720ustar00rootroot00000000000000include ../config.mak all: depend: distclean: clean: install: all uninstall install -d "$(DESTDIR)$(mltdatadir)/profiles" install -m 644 * "$(DESTDIR)$(mltdatadir)/profiles" rm -f "$(DESTDIR)$(mltdatadir)/profiles/"*~ rm -f "$(DESTDIR)$(mltdatadir)/profiles/Makefile" uninstall: rm -rf "$(DESTDIR)$(mltdatadir)/profiles" mlt-0.9.0/profiles/atsc_1080i_50000066400000000000000000000003061215300731300161330ustar00rootroot00000000000000description=HD 1080i 25 fps frame_rate_num=25 frame_rate_den=1 width=1920 height=1080 progressive=0 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_1080i_5994000066400000000000000000000003171215300731300163230ustar00rootroot00000000000000description=HD 1080i 29.97 fps frame_rate_num=30000 frame_rate_den=1001 width=1920 height=1080 progressive=0 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_1080i_60000066400000000000000000000003061215300731300161340ustar00rootroot00000000000000description=HD 1080i 30 fps frame_rate_num=30 frame_rate_den=1 width=1920 height=1080 progressive=0 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_1080p_2398000066400000000000000000000003171215300731300163250ustar00rootroot00000000000000description=HD 1080p 23.98 fps frame_rate_num=24000 frame_rate_den=1001 width=1920 height=1080 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_1080p_24000066400000000000000000000003061215300731300161430ustar00rootroot00000000000000description=HD 1080p 24 fps frame_rate_num=24 frame_rate_den=1 width=1920 height=1080 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_1080p_25000066400000000000000000000003061215300731300161440ustar00rootroot00000000000000description=HD 1080p 25 fps frame_rate_num=25 frame_rate_den=1 width=1920 height=1080 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_1080p_2997000066400000000000000000000003171215300731300163320ustar00rootroot00000000000000description=HD 1080p 29.97 fps frame_rate_num=30000 frame_rate_den=1001 width=1920 height=1080 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_1080p_30000066400000000000000000000003061215300731300161400ustar00rootroot00000000000000description=HD 1080p 30 fps frame_rate_num=30 frame_rate_den=1 width=1920 height=1080 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_1080p_50000066400000000000000000000003061215300731300161420ustar00rootroot00000000000000description=HD 1080p 50 fps frame_rate_num=50 frame_rate_den=1 width=1920 height=1080 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_1080p_5994000066400000000000000000000003171215300731300163320ustar00rootroot00000000000000description=HD 1080p 59.94 fps frame_rate_num=60000 frame_rate_den=1001 width=1920 height=1080 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_1080p_60000066400000000000000000000003061215300731300161430ustar00rootroot00000000000000description=HD 1080p 60 fps frame_rate_num=60 frame_rate_den=1 width=1920 height=1080 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_720p_2398000066400000000000000000000003151215300731300162430ustar00rootroot00000000000000description=HD 720p 23.98 fps frame_rate_num=24000 frame_rate_den=1001 width=1280 height=720 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_720p_24000066400000000000000000000003041215300731300160610ustar00rootroot00000000000000description=HD 720p 24 fps frame_rate_num=24 frame_rate_den=1 width=1280 height=720 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_720p_25000066400000000000000000000003041215300731300160620ustar00rootroot00000000000000description=HD 720p 25 fps frame_rate_num=25 frame_rate_den=1 width=1280 height=720 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_720p_2997000066400000000000000000000003151215300731300162500ustar00rootroot00000000000000description=HD 720p 29.97 fps frame_rate_num=30000 frame_rate_den=1001 width=1280 height=720 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_720p_30000066400000000000000000000003041215300731300160560ustar00rootroot00000000000000description=HD 720p 30 fps frame_rate_num=30 frame_rate_den=1 width=1280 height=720 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_720p_50000066400000000000000000000003041215300731300160600ustar00rootroot00000000000000description=HD 720p 50 fps frame_rate_num=50 frame_rate_den=1 width=1280 height=720 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_720p_5994000066400000000000000000000003151215300731300162500ustar00rootroot00000000000000description=HD 720p 59.94 fps frame_rate_num=60000 frame_rate_den=1001 width=1280 height=720 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/atsc_720p_60000066400000000000000000000003041215300731300160610ustar00rootroot00000000000000description=HD 720p 60 fps frame_rate_num=60 frame_rate_den=1 width=1280 height=720 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/cif_15000066400000000000000000000003001215300731300151140ustar00rootroot00000000000000description=CIF 15 fps frame_rate_num=15 frame_rate_den=1 width=352 height=288 progressive=1 sample_aspect_num=59 sample_aspect_den=54 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/cif_ntsc000066400000000000000000000003041215300731300156420ustar00rootroot00000000000000description=CIF NTSC frame_rate_num=30000 frame_rate_den=1001 width=352 height=288 progressive=1 sample_aspect_num=10 sample_aspect_den=11 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/cif_pal000066400000000000000000000002751215300731300154560ustar00rootroot00000000000000description=CIF PAL frame_rate_num=25 frame_rate_den=1 width=352 height=288 progressive=1 sample_aspect_num=59 sample_aspect_den=54 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/cvd_ntsc000066400000000000000000000003041215300731300156550ustar00rootroot00000000000000description=CVD NTSC frame_rate_num=30000 frame_rate_den=1001 width=352 height=480 progressive=0 sample_aspect_num=20 sample_aspect_den=11 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/cvd_pal000066400000000000000000000002751215300731300154710ustar00rootroot00000000000000description=CVD PAL frame_rate_num=25 frame_rate_den=1 width=352 height=576 progressive=0 sample_aspect_num=59 sample_aspect_den=27 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/dv_ntsc000066400000000000000000000003051215300731300155130ustar00rootroot00000000000000description=DV/DVD NTSC frame_rate_num=30000 frame_rate_den=1001 width=720 height=480 progressive=0 sample_aspect_num=8 sample_aspect_den=9 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/dv_ntsc_wide000066400000000000000000000003231215300731300165230ustar00rootroot00000000000000description=DV/DVD Widescreen NTSC frame_rate_num=30000 frame_rate_den=1001 width=720 height=480 progressive=0 sample_aspect_num=32 sample_aspect_den=27 display_aspect_num=16 display_aspect_den=9 colorspace=601 mlt-0.9.0/profiles/dv_pal000066400000000000000000000003001215300731300153130ustar00rootroot00000000000000description=DV/DVD PAL frame_rate_num=25 frame_rate_den=1 width=720 height=576 progressive=0 sample_aspect_num=16 sample_aspect_den=15 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/dv_pal_wide000066400000000000000000000003141215300731300163300ustar00rootroot00000000000000description=DV/DVD Widescreen PAL frame_rate_num=25 frame_rate_den=1 width=720 height=576 progressive=0 sample_aspect_num=64 sample_aspect_den=45 display_aspect_num=16 display_aspect_den=9 colorspace=601 mlt-0.9.0/profiles/hdv_1080_25p000066400000000000000000000003141215300731300157720ustar00rootroot00000000000000description=HDV 1440x1080p 25 fps frame_rate_num=25 frame_rate_den=1 width=1440 height=1080 progressive=1 sample_aspect_num=4 sample_aspect_den=3 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/hdv_1080_30p000066400000000000000000000003251215300731300157700ustar00rootroot00000000000000description=HDV 1440x1080p 29.97 fps frame_rate_num=30000 frame_rate_den=1001 width=1440 height=1080 progressive=1 sample_aspect_num=4 sample_aspect_den=3 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/hdv_1080_50i000066400000000000000000000003141215300731300157610ustar00rootroot00000000000000description=HDV 1440x1080i 25 fps frame_rate_num=25 frame_rate_den=1 width=1440 height=1080 progressive=0 sample_aspect_num=4 sample_aspect_den=3 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/hdv_1080_60i000066400000000000000000000003251215300731300157640ustar00rootroot00000000000000description=HDV 1440x1080i 29.97 fps frame_rate_num=30000 frame_rate_den=1001 width=1440 height=1080 progressive=0 sample_aspect_num=4 sample_aspect_den=3 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/hdv_720_25p000066400000000000000000000003041215300731300157110ustar00rootroot00000000000000description=HD 720p 25 fps frame_rate_num=25 frame_rate_den=1 width=1280 height=720 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/hdv_720_30p000066400000000000000000000003151215300731300157070ustar00rootroot00000000000000description=HD 720p 29.97 fps frame_rate_num=30000 frame_rate_den=1001 width=1280 height=720 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/hdv_720_50p000066400000000000000000000003041215300731300157070ustar00rootroot00000000000000description=HD 720p 50 fps frame_rate_num=50 frame_rate_den=1 width=1280 height=720 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/hdv_720_60p000066400000000000000000000003151215300731300157120ustar00rootroot00000000000000description=HD 720p 59.94 fps frame_rate_num=60000 frame_rate_den=1001 width=1280 height=720 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=709 mlt-0.9.0/profiles/qcif_15000066400000000000000000000003011215300731300152760ustar00rootroot00000000000000description=QCIF 15 fps frame_rate_num=15 frame_rate_den=1 width=176 height=144 progressive=1 sample_aspect_num=59 sample_aspect_den=54 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/qcif_ntsc000066400000000000000000000003051215300731300160240ustar00rootroot00000000000000description=QCIF NTSC frame_rate_num=30000 frame_rate_den=1001 width=176 height=144 progressive=1 sample_aspect_num=10 sample_aspect_den=11 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/qcif_pal000066400000000000000000000002761215300731300156400ustar00rootroot00000000000000description=QCIF PAL frame_rate_num=25 frame_rate_den=1 width=176 height=144 progressive=1 sample_aspect_num=59 sample_aspect_den=54 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/quarter_15000066400000000000000000000002771215300731300160530ustar00rootroot00000000000000description=QVGA 15 fps frame_rate_num=15 frame_rate_den=1 width=320 height=240 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/quarter_ntsc000066400000000000000000000003101215300731300165610ustar00rootroot00000000000000description=QVGA 29.97 fps frame_rate_num=30000 frame_rate_den=1001 width=320 height=240 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/quarter_ntsc_wide000066400000000000000000000003241215300731300175760ustar00rootroot00000000000000description=QVGA Widescreen 29.97 fps frame_rate_num=30000 frame_rate_den=1001 width=426 height=240 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=601 mlt-0.9.0/profiles/quarter_pal000066400000000000000000000003031215300731300163700ustar00rootroot00000000000000description=384x288 4:3 PAL frame_rate_num=25 frame_rate_den=1 width=384 height=288 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/quarter_pal_wide000066400000000000000000000003051215300731300174020ustar00rootroot00000000000000description=512x288 16:9 PAL frame_rate_num=25 frame_rate_den=1 width=512 height=288 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=601 mlt-0.9.0/profiles/sdi_486i_5994000066400000000000000000000003101215300731300160720ustar00rootroot00000000000000description=NTSC 29.97 fps frame_rate_num=30000 frame_rate_den=1001 width=720 height=486 progressive=0 sample_aspect_num=8 sample_aspect_den=9 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/sdi_486p_2398000066400000000000000000000003101215300731300160740ustar00rootroot00000000000000description=NTSC 23.98 fps frame_rate_num=24000 frame_rate_den=1001 width=720 height=486 progressive=1 sample_aspect_num=8 sample_aspect_den=9 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/square_ntsc000066400000000000000000000003021215300731300163770ustar00rootroot00000000000000description=VGA NTSC frame_rate_num=30000 frame_rate_den=1001 width=640 height=480 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/square_ntsc_wide000066400000000000000000000003161215300731300174140ustar00rootroot00000000000000description=VGA Widescreen NTSC frame_rate_num=30000 frame_rate_den=1001 width=854 height=480 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=601 mlt-0.9.0/profiles/square_pal000066400000000000000000000003031215300731300162050ustar00rootroot00000000000000description=768x576 4:3 PAL frame_rate_num=25 frame_rate_den=1 width=768 height=576 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/square_pal_wide000066400000000000000000000003071215300731300172210ustar00rootroot00000000000000description=1024x576 16:9 PAL frame_rate_num=25 frame_rate_den=1 width=1024 height=576 progressive=1 sample_aspect_num=1 sample_aspect_den=1 display_aspect_num=16 display_aspect_den=9 colorspace=601 mlt-0.9.0/profiles/svcd_ntsc000066400000000000000000000003051215300731300160410ustar00rootroot00000000000000description=SVCD NTSC frame_rate_num=30000 frame_rate_den=1001 width=480 height=480 progressive=0 sample_aspect_num=15 sample_aspect_den=11 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/svcd_ntsc_wide000066400000000000000000000003211215300731300170470ustar00rootroot00000000000000description=SVCD Widescreen NTSC frame_rate_num=30000 frame_rate_den=1001 width=480 height=480 progressive=0 sample_aspect_num=20 sample_aspect_den=11 display_aspect_num=16 display_aspect_den=9 colorspace=601 mlt-0.9.0/profiles/svcd_pal000066400000000000000000000002761215300731300156550ustar00rootroot00000000000000description=SVCD PAL frame_rate_num=25 frame_rate_den=1 width=480 height=576 progressive=0 sample_aspect_num=59 sample_aspect_den=36 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/svcd_pal_wide000066400000000000000000000003121215300731300166540ustar00rootroot00000000000000description=SVCD Widescreen PAL frame_rate_num=25 frame_rate_den=1 width=480 height=576 progressive=0 sample_aspect_num=59 sample_aspect_den=27 display_aspect_num=16 display_aspect_den=9 colorspace=601 mlt-0.9.0/profiles/vcd_ntsc000066400000000000000000000003041215300731300156550ustar00rootroot00000000000000description=VCD NTSC frame_rate_num=30000 frame_rate_den=1001 width=352 height=240 progressive=1 sample_aspect_num=10 sample_aspect_den=11 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/profiles/vcd_pal000066400000000000000000000002751215300731300154710ustar00rootroot00000000000000description=VCD PAL frame_rate_num=25 frame_rate_den=1 width=352 height=288 progressive=1 sample_aspect_num=59 sample_aspect_den=54 display_aspect_num=4 display_aspect_den=3 colorspace=601 mlt-0.9.0/reconfigure000077500000000000000000000002341215300731300145440ustar00rootroot00000000000000#!/bin/sh if [ -s "config.log" ]; then $(tail -1 config.log) $@ else echo The file \"config.log\" does not exist. echo You must run configure first. fi mlt-0.9.0/setenv000066400000000000000000000006321215300731300135370ustar00rootroot00000000000000 # Environment variable settings to allow execution without install export MLT_REPOSITORY=`pwd`/src/modules export MLT_DATA=`pwd`/src/modules export MLT_PROFILES_PATH=`pwd`/profiles export MLT_PRESETS_PATH=`pwd`/presets export LD_LIBRARY_PATH=\ `pwd`/src/framework:\ `pwd`/src/mlt++:\ $LD_LIBRARY_PATH #[ $(uname -s) = Darwin ] && export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH export PATH=`pwd`/src/melt:$PATH mlt-0.9.0/setenv_mc000066400000000000000000000003201215300731300142100ustar00rootroot00000000000000 # Environment variable settings to allow execution without install export LD_LIBRARY_PATH=\ `pwd`/../mpeg_sdk_release/bin:\ `pwd`/../dvcpro_sdk_release/lib:\ `pwd`/../sr_sdk_release/lib:\ $LD_LIBRARY_PATH mlt-0.9.0/src/000077500000000000000000000000001215300731300130765ustar00rootroot00000000000000mlt-0.9.0/src/examples/000077500000000000000000000000001215300731300147145ustar00rootroot00000000000000mlt-0.9.0/src/examples/Makefile000066400000000000000000000003171215300731300163550ustar00rootroot00000000000000CXXFLAGS += -Wall -g `pkg-config mlt++ --cflags` LDFLAGS += `pkg-config mlt++ --libs` CC=c++ all: play play: play.o play.o: play.cpp clean: $(RM) play play.o distclean: clean install: uninstall: mlt-0.9.0/src/examples/play.cpp000066400000000000000000000004341215300731300163660ustar00rootroot00000000000000 #include using namespace Mlt; int main( int, char **argv ) { Factory::init( NULL ); Profile profile; Producer producer( profile, argv[ 1 ] ); Consumer consumer( profile ); consumer.set( "rescale", "none" ); consumer.connect( producer ); consumer.run( ); return 0; } mlt-0.9.0/src/framework/000077500000000000000000000000001215300731300150735ustar00rootroot00000000000000mlt-0.9.0/src/framework/Makefile000066400000000000000000000062321215300731300165360ustar00rootroot00000000000000include ../../config.mak include config.mak NAME = libmlt$(LIBSUF) TARGET = $(NAME).$(version) ifeq ($(targetos), Darwin) NAME = libmlt$(LIBSUF) TARGET = libmlt.$(version)$(LIBSUF) SONAME = libmlt.$(soversion)$(LIBSUF) SHFLAGS += -install_name $(libdir)/$(SONAME) -current_version $(version) -compatibility_version $(soversion) else ifeq ($(targetos), MinGW) NAME = libmlt$(LIBSUF) TARGET = libmlt-$(soversion)$(LIBSUF) SHFLAGS += -Wl,--output-def,libmlt.def else NAME = libmlt$(LIBSUF) TARGET = $(NAME).$(version) SONAME = $(NAME).$(soversion) SHFLAGS += -Wl,-soname,$(SONAME) endif ifeq ($(targetos), Linux) SHFLAGS += -Wl,--version-script=mlt.vers endif OBJS = mlt_frame.o \ mlt_version.o \ mlt_geometry.o \ mlt_deque.o \ mlt_property.o \ mlt_properties.o \ mlt_events.o \ mlt_parser.o \ mlt_service.o \ mlt_producer.o \ mlt_multitrack.o \ mlt_playlist.o \ mlt_consumer.o \ mlt_filter.o \ mlt_transition.o \ mlt_field.o \ mlt_tractor.o \ mlt_factory.o \ mlt_repository.o \ mlt_pool.o \ mlt_tokeniser.o \ mlt_profile.o \ mlt_log.o \ mlt_cache.o \ mlt_animation.o INCS = mlt_consumer.h \ mlt_version.h \ mlt_factory.h \ mlt_filter.h \ mlt.h \ mlt_multitrack.h \ mlt_pool.h \ mlt_properties.h \ mlt_events.h \ mlt_parser.h \ mlt_repository.h \ mlt_tractor.h \ mlt_types.h \ mlt_deque.h \ mlt_field.h \ mlt_frame.h \ mlt_geometry.h \ mlt_playlist.h \ mlt_producer.h \ mlt_property.h \ mlt_service.h \ mlt_transition.h \ mlt_tokeniser.h \ mlt_profile.h \ mlt_log.h \ mlt_cache.h \ mlt_animation.h SRCS := $(OBJS:.o=.c) ifeq ($(targetos), MinGW) OBJS += ../win32/win32.o SRCS += ../win32/win32.c endif CFLAGS += $(RDYNAMIC) -DPREFIX_DATA="\"$(mltdatadir)\"" -DPREFIX_LIB="\"$(moduledir)\"" LDFLAGS += $(LIBDL) -lpthread -lm all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) ln -sf $(TARGET) $(NAME) if [ "$(targetos)" != "MinGW" ]; then \ ln -sf $(TARGET) $(SONAME) ; \ fi depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) $(NAME) $(SONAME) install: install -d $(DESTDIR)$(libdir) if [ "$(targetos)" = "MinGW" ]; then \ install -m 755 $(TARGET) $(DESTDIR)$(prefix) ; \ install -m 755 $(TARGET) $(DESTDIR)$(libdir)/libmlt.dll ; \ install -m 644 libmlt.def $(DESTDIR)$(libdir) ; \ else \ install -m 755 $(TARGET) $(DESTDIR)$(libdir) ; \ ln -sf $(TARGET) $(DESTDIR)$(libdir)/$(SONAME) ; \ ln -sf $(TARGET) $(DESTDIR)$(libdir)/$(NAME) ; \ fi install -d "$(DESTDIR)$(prefix)/include/mlt/framework" install -m 644 $(INCS) "$(DESTDIR)$(prefix)/include/mlt/framework" install -d "$(DESTDIR)$(mltdatadir)" install -m 644 metaschema.yaml "$(DESTDIR)$(mltdatadir)" uninstall: rm -f "$(DESTDIR)$(libdir)/$(TARGET)" if [ "$(targetos)" != "MinGW" ]; then \ rm -f "$(DESTDIR)$(libdir)/$(SONAME)" ; \ rm -f "$(DESTDIR)$(libdir)/$(NAME)" ; \ fi rm -rf "$(DESTDIR)$(prefix)/include/mlt/framework" rm -f "$(DESTDIR)$(mltdatadir)/metaschema.yaml" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/framework/configure000077500000000000000000000002111215300731300167740ustar00rootroot00000000000000#!/bin/sh echo "framework -I$prefix/include -I$prefix/include/mlt -D_REENTRANT -L$libdir -lmlt" >> ../../packages.dat echo > config.mak mlt-0.9.0/src/framework/metaschema.yaml000066400000000000000000000110731215300731300200700ustar00rootroot00000000000000--- # A metadata schema in Kwalify: http://www.kuwata-lab.com/kwalify/ # Version: 0.1 type: map mapping: "schema_version": # This should match the version comment above type: float required: yes "LC_NUMERIC": # If not provided LC_NUMERIC=C is used, not the system's locale. type: str required: no "type": # A service type type: str required: yes enum: [consumer, filter, producer, transition] "identifier": # The same value used to register and create the service type: str required: yes unique: yes "title": # The UI can use this for a field label type: str "copyright": # Who owns the rights to the module and/or service? type: str "version": # The version of the service implementation type: text "license": # The software license for the service implementation type: str "language": # A 2 character ISO 639-1 language code type: str required: yes "url": # A hyperlink to a related website type: str "creator": # The name and/or e-mail address of the original author type: str "contributor": # The name and/or e-mail of all source code contributors type: seq sequence: - type: str "tags": # A set of categories, this might become an enum type: seq sequence: - type: str "description": # A slightly longer description than title type: str "icon": # A graphical representation of the effect type: map mapping: "filename": type: str "content-type": type: str "content-encoding": type: str "content": type: str "notes": # Details about the usage and/or implementation - can be long type: str "bugs": # A list of known problems that users can try to avoid type: seq sequence: - type: str # Can be a sentence or paragraph, preferably not a hyperlink "parameters": # A list of all of the options for the service type: seq sequence: - type: map mapping: "identifier": # The key that must be used to set the mlt_property type: str required: yes "type": # An mlt_property_type type: str enum: - float - geometry - integer - properties # for passing options to encapsulated services - string - time # currently, mlt_position (frame), soon to be a time value "service-name": # for type: properties, a reference to another service type: str # format: type.service, e.g. transition.composite "title": # A UI can use this for a field label type: str "description": # A UI can use this for a tool tip or what's-this type: str "readonly": # If you set this property, it will be ignored type: bool default: no "required": # Is this property required? type: bool default: no "mutable": # The service will change behavior if this is set after # processing the first frame type: bool default: no "widget": # A hint to the UI about how to let the user set this type: str enum: - checkbox - color - combo - curve - directory - fileopen - filesave - font - knob - listbox - dropdown # aka HTML select or GtkOptionMenu - radio - rectangle # for use with type: geometry - slider - spinner - text - textbox # multi-line - timecode "minimum": # For numeric types, the minimal value type: number "maximum": # For numeric types, the maximal value type: number "default": # The default value to be used in a UI type: scalar # If not specified, the UI might be able to display # this as blank "unit": # A UI can display this as a label after the widget (e.g. %) type: str "scale": # the number of digits after decimal point when type: float type: int "format": # A hint about a custom string encoding, possibly scanf "values": # A list of acceptable string values type: seq # A UI can allow something outside the list with # widget: combo or if "other" is in this sequence sequence: - type: scalar mlt-0.9.0/src/framework/mlt.h000066400000000000000000000036351215300731300160470ustar00rootroot00000000000000/** * \file mlt.h * \brief header file for lazy client and implementation code :-) * * Copyright (C) 2003-2010 Ushodaya Enterprises Limited * \author Charles Yates * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_H_ #define _MLT_H_ /** \mainpage MLT API Reference Documentation * \par * We recommend that you look in Data Structures * or Files. * \par * Additional documentation about MLT, in general, can be found on the * MLT website. */ #ifdef __cplusplus extern "C" { #endif #include "mlt_factory.h" #include "mlt_frame.h" #include "mlt_deque.h" #include "mlt_multitrack.h" #include "mlt_producer.h" #include "mlt_transition.h" #include "mlt_consumer.h" #include "mlt_filter.h" #include "mlt_playlist.h" #include "mlt_properties.h" #include "mlt_field.h" #include "mlt_tractor.h" #include "mlt_tokeniser.h" #include "mlt_parser.h" #include "mlt_geometry.h" #include "mlt_profile.h" #include "mlt_repository.h" #include "mlt_log.h" #include "mlt_cache.h" #include "mlt_version.h" #ifdef __cplusplus } #endif #endif mlt-0.9.0/src/framework/mlt.vers000066400000000000000000000273321215300731300165770ustar00rootroot00000000000000MLT_0.8.8 { global: default_callback; mlt_audio_format_name; mlt_audio_format_size; mlt_cache_close; mlt_cache_get; mlt_cache_get_frame; mlt_cache_get_size; mlt_cache_init; mlt_cache_item_close; mlt_cache_item_data; mlt_cache_purge; mlt_cache_put; mlt_cache_put_frame; mlt_cache_set_size; mlt_consumer_close; mlt_consumer_connect; mlt_consumer_get_frame; mlt_consumer_init; mlt_consumer_is_stopped; mlt_consumer_new; mlt_consumer_position; mlt_consumer_properties; mlt_consumer_purge; mlt_consumer_put_frame; mlt_consumer_rt_frame; mlt_consumer_service; mlt_consumer_start; mlt_consumer_stop; mlt_consumer_stopped; mlt_deque_close; mlt_deque_count; mlt_deque_init; mlt_deque_insert; mlt_deque_peek; mlt_deque_peek_back; mlt_deque_peek_back_double; mlt_deque_peek_back_int; mlt_deque_peek_front; mlt_deque_peek_front_double; mlt_deque_peek_front_int; mlt_deque_pop_back; mlt_deque_pop_back_double; mlt_deque_pop_back_int; mlt_deque_pop_front; mlt_deque_pop_front_double; mlt_deque_pop_front_int; mlt_deque_push_back; mlt_deque_push_back_double; mlt_deque_push_back_int; mlt_deque_push_front; mlt_deque_push_front_double; mlt_deque_push_front_int; mlt_environment; mlt_environment_set; mlt_event_block; mlt_event_close; mlt_event_inc_ref; mlt_events_block; mlt_events_close_wait_for; mlt_events_disconnect; mlt_events_fire; mlt_events_init; mlt_events_listen; mlt_events_register; mlt_events_setup_wait_for; mlt_events_unblock; mlt_events_wait_for; mlt_event_unblock; mlt_factory_close; mlt_factory_consumer; mlt_factory_directory; mlt_factory_event_object; mlt_factory_filter; mlt_factory_init; mlt_factory_producer; mlt_factory_register_for_clean_up; mlt_factory_transition; mlt_field_close; mlt_field_disconnect_service; mlt_field_init; mlt_field_multitrack; mlt_field_new; mlt_field_plant_filter; mlt_field_plant_transition; mlt_field_properties; mlt_field_service; mlt_field_tractor; mlt_filter_close; mlt_filter_connect; mlt_filter_get_in; mlt_filter_get_length; mlt_filter_get_length2; mlt_filter_get_out; mlt_filter_get_position; mlt_filter_get_progress; mlt_filter_get_track; mlt_filter_init; mlt_filter_new; mlt_filter_process; mlt_filter_properties; mlt_filter_service; mlt_filter_set_in_and_out; mlt_frame_clone; mlt_frame_close; mlt_frame_get_alpha_mask; mlt_frame_get_aspect_ratio; mlt_frame_get_audio; mlt_frame_get_image; mlt_frame_get_original_producer; mlt_frame_get_position; mlt_frame_get_waveform; mlt_frame_init; mlt_frame_is_test_audio; mlt_frame_is_test_card; mlt_frame_original_position; mlt_frame_pop_audio; mlt_frame_pop_frame; mlt_frame_pop_get_image; mlt_frame_pop_service; mlt_frame_pop_service_int; mlt_frame_properties; mlt_frame_push_audio; mlt_frame_push_frame; mlt_frame_push_get_image; mlt_frame_push_service; mlt_frame_push_service_int; mlt_frame_replace_image; mlt_frame_service_stack; mlt_frame_set_alpha; mlt_frame_set_aspect_ratio; mlt_frame_set_audio; mlt_frame_set_image; mlt_frame_set_position; mlt_frame_unique_properties; mlt_frame_write_ppm; mlt_geometry_close; mlt_geometry_fetch; mlt_geometry_get_length; mlt_geometry_init; mlt_geometry_insert; mlt_geometry_interpolate; mlt_geometry_next_key; mlt_geometry_parse; mlt_geometry_parse_item; mlt_geometry_prev_key; mlt_geometry_refresh; mlt_geometry_remove; mlt_geometry_serialise; mlt_geometry_serialise_cut; mlt_geometry_set_length; mlt_global_properties; mlt_image_format_name; mlt_image_format_size; mlt_log; mlt_log_get_level; mlt_log_set_callback; mlt_log_set_level; mlt_multitrack_clip; mlt_multitrack_close; mlt_multitrack_connect; mlt_multitrack_count; mlt_multitrack_init; mlt_multitrack_producer; mlt_multitrack_properties; mlt_multitrack_refresh; mlt_multitrack_service; mlt_multitrack_track; mlt_parser_close; mlt_parser_new; mlt_parser_properties; mlt_parser_start; mlt_playlist_append; mlt_playlist_append_io; mlt_playlist_blank; mlt_playlist_blanks_from; mlt_playlist_blank_time; mlt_playlist_clear; mlt_playlist_clip; mlt_playlist_clip_is_mix; mlt_playlist_clip_length; mlt_playlist_clip_start; mlt_playlist_close; mlt_playlist_consolidate_blanks; mlt_playlist_count; mlt_playlist_current; mlt_playlist_current_clip; mlt_playlist_get_clip; mlt_playlist_get_clip_at; mlt_playlist_get_clip_index_at; mlt_playlist_get_clip_info; mlt_playlist_init; mlt_playlist_insert; mlt_playlist_insert_at; mlt_playlist_insert_blank; mlt_playlist_is_blank; mlt_playlist_is_blank_at; mlt_playlist_join; mlt_playlist_mix; mlt_playlist_mix_add; mlt_playlist_move; mlt_playlist_move_region; mlt_playlist_new; mlt_playlist_pad_blanks; mlt_playlist_producer; mlt_playlist_properties; mlt_playlist_remove; mlt_playlist_remove_region; mlt_playlist_repeat_clip; mlt_playlist_replace_with_blank; mlt_playlist_resize_clip; mlt_playlist_service; mlt_playlist_split; mlt_playlist_split_at; mlt_pool_alloc; mlt_pool_close; mlt_pool_init; mlt_pool_purge; mlt_pool_realloc; mlt_pool_release; mlt_producer_attach; mlt_producer_clear; mlt_producer_close; mlt_producer_cut; mlt_producer_cut_parent; mlt_producer_detach; mlt_producer_filter; mlt_producer_frame; mlt_producer_frame_time; mlt_producer_get_fps; mlt_producer_get_in; mlt_producer_get_length; mlt_producer_get_length_time; mlt_producer_get_out; mlt_producer_get_playtime; mlt_producer_get_speed; mlt_producer_init; mlt_producer_is_blank; mlt_producer_is_cut; mlt_producer_is_mix; mlt_producer_new; mlt_producer_optimise; mlt_producer_position; mlt_producer_prepare_next; mlt_producer_properties; mlt_producer_seek; mlt_producer_seek_time; mlt_producer_service; mlt_producer_set_in_and_out; mlt_producer_set_speed; mlt_profile_clone; mlt_profile_close; mlt_profile_dar; mlt_profile_fps; mlt_profile_from_producer; mlt_profile_init; mlt_profile_list; mlt_profile_load_file; mlt_profile_load_properties; mlt_profile_load_string; mlt_profile_sar; mlt_properties_close; mlt_properties_count; mlt_properties_debug; mlt_properties_dec_ref; mlt_properties_dir_list; mlt_properties_dump; mlt_properties_get; mlt_properties_get_data; mlt_properties_get_data_at; mlt_properties_get_double; mlt_properties_get_int; mlt_properties_get_int64; mlt_properties_get_lcnumeric; mlt_properties_get_name; mlt_properties_get_position; mlt_properties_get_time; mlt_properties_get_value; mlt_properties_inc_ref; mlt_properties_inherit; mlt_properties_init; mlt_properties_is_sequence; mlt_properties_load; mlt_properties_lock; mlt_properties_mirror; mlt_properties_new; mlt_properties_parse; mlt_properties_parse_yaml; mlt_properties_pass; mlt_properties_pass_list; mlt_properties_pass_property; mlt_properties_preset; mlt_properties_ref_count; mlt_properties_rename; mlt_properties_save; mlt_properties_serialise_yaml; mlt_properties_set; mlt_properties_set_data; mlt_properties_set_double; mlt_properties_set_int; mlt_properties_set_int64; mlt_properties_set_lcnumeric; mlt_properties_set_or_default; mlt_properties_set_position; mlt_properties_unlock; mlt_property_close; mlt_property_get_data; mlt_property_get_double; mlt_property_get_int; mlt_property_get_int64; mlt_property_get_position; mlt_property_get_string; mlt_property_get_string_l; mlt_property_get_time; mlt_property_init; mlt_property_pass; mlt_property_set_data; mlt_property_set_double; mlt_property_set_int; mlt_property_set_int64; mlt_property_set_position; mlt_property_set_string; mlt_repository_close; mlt_repository_consumers; mlt_repository_create; mlt_repository_filters; mlt_repository_init; mlt_repository_languages; mlt_repository_metadata; mlt_repository_presets; mlt_repository_producers; mlt_repository_register; mlt_repository_register_metadata; mlt_repository_transitions; mlt_sample_calculator; mlt_sample_calculator_to_now; mlt_sdl_mutex; mlt_service_apply_filters; mlt_service_attach; mlt_service_cache_get; mlt_service_cache_get_size; mlt_service_cache_purge; mlt_service_cache_put; mlt_service_cache_set_size; mlt_service_close; mlt_service_connect_producer; mlt_service_consumer; mlt_service_detach; mlt_service_filter; mlt_service_get_frame; mlt_service_get_producer; mlt_service_identify; mlt_service_init; mlt_service_lock; mlt_service_producer; mlt_service_profile; mlt_service_properties; mlt_service_set_profile; mlt_service_unlock; mlt_tokeniser_close; mlt_tokeniser_count; mlt_tokeniser_get_input; mlt_tokeniser_get_string; mlt_tokeniser_init; mlt_tokeniser_parse_new; mlt_tractor_close; mlt_tractor_connect; mlt_tractor_field; mlt_tractor_get_track; mlt_tractor_init; mlt_tractor_multitrack; mlt_tractor_new; mlt_tractor_producer; mlt_tractor_properties; mlt_tractor_refresh; mlt_tractor_service; mlt_tractor_set_track; mlt_transition_close; mlt_transition_connect; mlt_transition_get_a_track; mlt_transition_get_b_track; mlt_transition_get_in; mlt_transition_get_length; mlt_transition_get_out; mlt_transition_get_position; mlt_transition_get_progress; mlt_transition_get_progress_delta; mlt_transition_init; mlt_transition_new; mlt_transition_process; mlt_transition_properties; mlt_transition_service; mlt_transition_set_in_and_out; mlt_version_get_int; mlt_version_get_major; mlt_version_get_minor; mlt_version_get_revision; mlt_version_get_string; mlt_vlog; local: *; }; MLT_0.9.0 { global: mlt_animation_new; mlt_animation_parse; mlt_animation_refresh; mlt_animation_get_length; mlt_animation_set_length; mlt_animation_parse_item; mlt_animation_get_item; mlt_animation_insert; mlt_animation_remove; mlt_animation_interpolate; mlt_animation_next_key; mlt_animation_prev_key; mlt_animation_serialize_cut; mlt_animation_serialize; mlt_animation_close; mlt_properties_get_color; mlt_properties_set_color; mlt_properties_anim_get; mlt_properties_anim_set; mlt_properties_anim_get_int; mlt_properties_anim_set_int; mlt_properties_anim_get_double; mlt_properties_anim_set_double; mlt_properties_get_animation; mlt_properties_set_rect; mlt_properties_get_rect; mlt_properties_anim_set_rect; mlt_properties_anim_get_rect; mlt_property_interpolate; mlt_property_anim_get_double; mlt_property_anim_get_int; mlt_property_anim_get_string; mlt_property_anim_set_double; mlt_property_anim_set_int; mlt_property_anim_set_string; mlt_property_get_animation; mlt_property_set_rect; mlt_property_get_rect; mlt_property_anim_set_rect; mlt_property_anim_get_rect; mlt_service_filter_count; mlt_service_move_filter; } MLT_0.8.8; mlt-0.9.0/src/framework/mlt_animation.c000066400000000000000000000452321215300731300201000ustar00rootroot00000000000000/** * \file mlt_animation.c * \brief Property Animation class definition * \see mlt_animation_s * * Copyright (C) 2004-2013 Ushodaya Enterprises Limited * \author Charles Yates * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_animation.h" #include "mlt_tokeniser.h" #include "mlt_profile.h" #include #include #include /** \brief animation list node pointer */ typedef struct animation_node_s *animation_node; /** \brief private animation list node */ struct animation_node_s { struct mlt_animation_item_s item; animation_node next, prev; }; /** \brief Property Animation class * * This is the animation engine for a Property object. It is dependent upon * the mlt_property API and used by the various mlt_property_anim_* functions. */ struct mlt_animation_s { char *data; /**< the string representing the animation */ int length; /**< the maximum number of frames to use when interpreting negative keyframe positions */ double fps; /**< framerate to use when converting time clock strings to frame units */ locale_t locale; /**< pointer to a locale to use when converting strings to numeric values */ animation_node nodes; /**< a linked list of keyframes (and possibly non-keyframe values) */ }; /** Create a new animation object. * * \public \memberof mlt_animation_s * \return an animation object */ mlt_animation mlt_animation_new( ) { mlt_animation self = calloc( 1, sizeof( *self ) ); return self; } /** Re-interpolate non-keyframe nodess after a series of insertions or removals. * * \public \memberof mlt_animation_s * \param self an animation */ void mlt_animation_interpolate( mlt_animation self ) { // Parse all items to ensure non-keyframes are calculated correctly. if ( self->nodes ) { animation_node current = self->nodes; while ( current ) { if ( !current->item.is_key ) { double progress; mlt_property points[4]; animation_node prev = current->prev; animation_node next = current->next; while ( prev && !prev->item.is_key ) prev = prev->prev; while ( next && !next->item.is_key ) next = next->next; if ( !prev ) { current->item.is_key = 1; prev = current; } if ( !next ) { next = current; } points[0] = prev->prev? prev->prev->item.property : prev->item.property; points[1] = prev->item.property; points[2] = next->item.property; points[3] = next->next? next->next->item.property : next->item.property; progress = current->item.frame - prev->item.frame; progress /= next->item.frame - prev->item.frame; mlt_property_interpolate( current->item.property, points, progress, self->fps, self->locale, current->item.keyframe_type ); } // Move to the next item current = current->next; } } } /** Remove a node from the linked list. * * \private \memberof mlt_animation_s * \param self an animation * \param node the node to remove * \return false */ static int mlt_animation_drop( mlt_animation self, animation_node node ) { if ( node == self->nodes ) { self->nodes = node->next; if ( self->nodes ) { self->nodes->prev = NULL; self->nodes->item.is_key = 1; } } else if ( node->next && node->prev ) { node->prev->next = node->next; node->next->prev = node->prev; } else if ( node->next ) { node->next->prev = node->prev; } else if ( node->prev ) { node->prev->next = node->next; } mlt_property_close( node->item.property ); free( node ); return 0; } /** Reset an animation and free all strings and properties. * * \private \memberof mlt_animation_s * \param self an animation */ static void mlt_animation_clean( mlt_animation self ) { if ( self->data ) free( self->data ); self->data = NULL; while ( self->nodes ) mlt_animation_drop( self, self->nodes ); } /** Parse a string representing an animation. * * A semicolon is the delimiter between keyframe=value items in the string. * \public \memberof mlt_animation_s * \param self an animation * \param data the string representing an animation * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \param fps the framerate to use when evaluating time strings * \param locale the locale to use when converting strings to numbers * \return true if there was an error */ int mlt_animation_parse(mlt_animation self, const char *data, int length, double fps, locale_t locale ) { int error = 0; int i = 0; struct mlt_animation_item_s item; mlt_tokeniser tokens = mlt_tokeniser_init( ); // Clean the existing geometry mlt_animation_clean( self ); // Update the info on the data if ( data ) self->data = strdup( data ); self->length = length; self->fps = fps; self->locale = locale; item.property = mlt_property_init(); // Tokenise if ( data ) mlt_tokeniser_parse_new( tokens, (char*) data, ";" ); // Iterate through each token for ( i = 0; i < mlt_tokeniser_count( tokens ); i++ ) { char *value = mlt_tokeniser_get_string( tokens, i ); // If no data in keyframe, drop it (trailing semicolon) if ( !value || !strcmp( value, "" ) ) continue; // Reset item item.frame = item.is_key = 0; // Now parse the item mlt_animation_parse_item( self, &item, value ); // Now insert into place mlt_animation_insert( self, &item ); } mlt_animation_interpolate( self ); // Cleanup mlt_tokeniser_close( tokens ); mlt_property_close( item.property ); return error; } /** Conditionally refresh the animation if it is modified. * * \public \memberof mlt_animation_s * \param self an animation * \param data the string representing an animation * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \return true if there was an error */ int mlt_animation_refresh( mlt_animation self, const char *data, int length ) { if ( ( length != self->length )|| ( data && ( !self->data || strcmp( data, self->data ) ) ) ) return mlt_animation_parse( self, data, length, self->fps, self->locale ); return 0; } /** Get the length of the animation. * * If the animation was initialized with a zero or negative value, then this * gets the maximum frame number from animation's list of nodes. * \public \memberof mlt_animation_s * \param self an animation * \return the number of frames */ int mlt_animation_get_length( mlt_animation self ) { int length = 0; if ( self ) { if ( self->length > 0 ) { length = self->length; } else if ( self->nodes ) { animation_node node = self->nodes; while ( node ) { if ( node->item.frame > length ) length = node->item.frame; node = node->next; } } } return length; } /** Set the length of the animation. * * The length is used for interpreting negative keyframe positions as relative * to the length. It is also used when serializing an animation as a string. * \public \memberof mlt_animation_s * \param self an animation * \param length the length of the animation in frame units */ void mlt_animation_set_length( mlt_animation self, int length ) { if ( self ) self->length = length; } /** Parse a string representing an animation keyframe=value. * * This function does not affect the animation itself! But it will use some state * of the animation for the parsing (e.g. fps, locale). * It parses into a mlt_animation_item that you provide. * \p item->frame should be specified if the string does not have an equal sign and time field. * If an exclamation point (!) or vertical bar (|) character preceeds the equal sign, then * the keyframe interpolation is set to discrete. If a tilde (~) preceeds the equal sign, * then the keyframe interpolation is set to smooth (spline). * * \public \memberof mlt_animation_s * \param self an animation * \param item an already allocated animation item * \param value the string representing an animation * \return true if there was an error */ int mlt_animation_parse_item( mlt_animation self, mlt_animation_item item, const char *value ) { int error = 0; if ( value && strcmp( value, "" ) ) { // Determine if a position has been specified if ( strchr( value, '=' ) ) { // Parse an absolute time value. // Null terminate the string at the equal sign to prevent interpreting // a colon in the part to the right of the equal sign as indicative of a // a time value string. char *s = strdup( value ); char *p = strchr( s, '=' ); p[0] = '\0'; mlt_property_set_string( item->property, s ); item->frame = mlt_property_get_int( item->property, self->fps, self->locale ); free( s ); // The character preceeding the equal sign indicates interpolation method. p = strchr( value, '=' ) - 1; if ( p[0] == '|' || p[0] == '!' ) item->keyframe_type = mlt_keyframe_discrete; else if ( p[0] == '~' ) item->keyframe_type = mlt_keyframe_smooth; else item->keyframe_type = mlt_keyframe_linear; value = &p[2]; } // Special case - frame < 0 if ( item->frame < 0 ) item->frame += mlt_animation_get_length( self ); // Set remainder of string as item value. mlt_property_set_string( item->property, value ); item->is_key = 1; } else { error = 1; } return error; } /** Load an animation item for an absolute position. * * This performs interpolation if there is no keyframe at the \p position. * \public \memberof mlt_animation_s * \param self an animation * \param item an already allocated animation item that will be filled in * \param position the frame number for the point in time * \return true if there was an error */ int mlt_animation_get_item( mlt_animation self, mlt_animation_item item, int position ) { int error = 0; // Need to find the nearest keyframe to the position specifed animation_node node = self->nodes; // Iterate through the keyframes until we reach last or have while ( node && node->next && position >= node->next->item.frame ) node = node->next; if ( node ) { item->keyframe_type = node->item.keyframe_type; // Position is before the first keyframe. if ( position < node->item.frame ) { item->is_key = 0; mlt_property_pass( item->property, node->item.property ); } // Item exists. else if ( position == node->item.frame ) { item->is_key = node->item.is_key; mlt_property_pass( item->property, node->item.property ); } // Position is after the last keyframe. else if ( !node->next ) { item->is_key = 0; mlt_property_pass( item->property, node->item.property ); } // Interpolation needed. else { double progress; mlt_property points[4]; points[0] = node->prev? node->prev->item.property : node->item.property; points[1] = node->item.property; points[2] = node->next->item.property; points[3] = node->next->next? node->next->next->item.property : node->next->item.property; progress = position - node->item.frame; progress /= node->next->item.frame - node->item.frame; mlt_property_interpolate( item->property, points, progress, self->fps, self->locale, item->keyframe_type ); item->is_key = 0; } } else { item->frame = item->is_key = 0; error = 1; } item->frame = position; return error; } /** Insert an animation item. * * \public \memberof mlt_animation_s * \param self an animation * \param item an animation item * \return true if there was an error * \see mlt_animation_parse_item */ int mlt_animation_insert( mlt_animation self, mlt_animation_item item ) { int error = 0; animation_node node = calloc( 1, sizeof( *node ) ); node->item.frame = item->frame; node->item.is_key = 1; node->item.keyframe_type = item->keyframe_type; node->item.property = mlt_property_init(); mlt_property_pass( node->item.property, item->property ); // Determine if we need to insert or append to the list, or if it's a new list if ( self->nodes ) { // Get the first item animation_node current = self->nodes; // Locate an existing nearby item while ( current->next && item->frame > current->item.frame ) current = current->next; if ( item->frame < current->item.frame ) { if ( current == self->nodes ) self->nodes = node; if ( current->prev ) current->prev->next = node; node->next = current; node->prev = current->prev; current->prev = node; } else if ( item->frame > current->item.frame ) { if ( current->next ) current->next->prev = node; node->next = current->next; node->prev = current; current->next = node; } else { // Update matching node. current->item.frame = item->frame; current->item.is_key = 1; current->item.keyframe_type = item->keyframe_type; mlt_property_close( current->item.property ); current->item.property = node->item.property; free( node ); } } else { // Set the first item self->nodes = node; } return error; } /** Remove the keyframe at the specified position. * * \public \memberof mlt_animation_s * \param self an animation * \param position the frame number of the animation node to remove * \return true if there was an error */ int mlt_animation_remove( mlt_animation self, int position ) { int error = 1; animation_node node = self->nodes; while ( node && position != node->item.frame ) node = node->next; if ( node && position == node->item.frame ) error = mlt_animation_drop( self, node ); return error; } /** Get the keyfame at the position or the next following. * * \public \memberof mlt_animation_s * \param self an animation * \param item an already allocated animation item which will be updated * \param position the frame number at which to start looking for the next animation node * \return true if there was an error */ int mlt_animation_next_key( mlt_animation self, mlt_animation_item item, int position ) { animation_node node = self->nodes; while ( node && position > node->item.frame ) node = node->next; if ( node ) { item->frame = node->item.frame; item->is_key = node->item.is_key; item->keyframe_type = node->item.keyframe_type; mlt_property_pass( item->property, node->item.property ); } return ( node == NULL ); } /** Get the keyfame at the position or the next preceeding. * * \public \memberof mlt_animation_s * \param self an animation * \param item an already allocated animation item which will be updated * \param position the frame number at which to start looking for the previous animation node * \return true if there was an error */ int mlt_animation_prev_key( mlt_animation self, mlt_animation_item item, int position ) { animation_node node = self->nodes; while ( node && node->next && position >= node->next->item.frame ) node = node->next; if ( node ) { item->frame = node->item.frame; item->is_key = node->item.is_key; item->keyframe_type = node->item.keyframe_type; mlt_property_pass( item->property, node->item.property ); } return ( node == NULL ); } /** Serialize a cut of the animation. * * The caller is responsible for free-ing the returned string. * \public \memberof mlt_animation_s * \param self an animation * \param in the frame at which to start serializing animation nodes * \param out the frame at which to stop serializing nodes * \return a string representing the animation */ char *mlt_animation_serialize_cut( mlt_animation self, int in, int out ) { struct mlt_animation_item_s item; char *ret = malloc( 1000 ); size_t used = 0; size_t size = 1000; item.property = mlt_property_init(); if ( in == -1 ) in = 0; if ( out == -1 ) out = mlt_animation_get_length( self ); if ( ret ) { strcpy( ret, "" ); item.frame = in; while ( 1 ) { size_t item_len = 0; // If it's the first frame, then it's not necessarily a key if ( item.frame == in ) { if ( mlt_animation_get_item( self, &item, item.frame ) ) break; // If the first keyframe is larger than the current position // then do nothing here if ( self->nodes->item.frame > item.frame ) { item.frame ++; continue; } // To ensure correct seeding item.is_key = 1; } // Typically, we move from keyframe to keyframe else if ( item.frame < out ) { if ( mlt_animation_next_key( self, &item, item.frame ) ) break; // Special case - crop at the out point if ( item.frame > out ) mlt_animation_get_item( self, &item, out ); } // We've handled the last keyframe else { break; } // Determine length of string to be appended. if ( item.frame - in != 0 ) item_len += 20; if ( item.is_key ) item_len += strlen( mlt_property_get_string_l( item.property, self->locale ) ); // Reallocate return string to be long enough. while ( used + item_len + 2 > size ) // +2 for ';' and NULL { size += 1000; ret = realloc( ret, size ); } // Append item delimiter (;) if needed. if ( ret && used > 0 ) { used ++; strcat( ret, ";" ); } if ( ret ) { // Append keyframe time and keyframe/value delimiter (=). const char *s; switch (item.keyframe_type) { case mlt_keyframe_discrete: s = "|"; break; case mlt_keyframe_smooth: s = "~"; break; default: s = ""; break; } sprintf( ret + used, "%d%s=", item.frame - in, s ); // Append item value. if ( item.is_key ) strcat( ret, mlt_property_get_string_l( item.property, self->locale ) ); used = strlen( ret ); } item.frame ++; } } mlt_property_close( item.property ); return ret; } /** Serialize the animation. * * The caller is responsible for free-ing the returned string. * \public \memberof mlt_animation_s * \param self an animation * \return a string representing the animation */ char *mlt_animation_serialize( mlt_animation self ) { char *ret = mlt_animation_serialize_cut( self, -1, -1 ); if ( ret ) { if ( self->data ) free( self->data ); self->data = ret; ret = strdup( ret ); } return ret; } /** Close the animation and deallocate all of its resources. * * \public \memberof mlt_animation_s * \param self the animation to destroy */ void mlt_animation_close( mlt_animation self ) { if ( self ) { mlt_animation_clean( self ); free( self ); } } mlt-0.9.0/src/framework/mlt_animation.h000066400000000000000000000054411215300731300201030ustar00rootroot00000000000000/** * \file mlt_animation.h * \brief Property Animation class declaration * \see mlt_animation_s * * Copyright (C) 2004-2013 Ushodaya Enterprises Limited * \author Charles Yates * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef MLT_ANIMATION_H #define MLT_ANIMATION_H #include "mlt_types.h" #include "mlt_property.h" /** \brief An animation item that represents a keyframe-property combination. */ struct mlt_animation_item_s { int is_key; /**< a boolean of whether this is a key frame or an interpolated item */ int frame; /**< the frame number for this instance of the property */ mlt_property property; /**< the property for this point in time */ mlt_keyframe_type keyframe_type; /**< the method of interpolation for this key frame */ }; typedef struct mlt_animation_item_s *mlt_animation_item; /**< pointer to an animation item */ extern mlt_animation mlt_animation_new( ); extern int mlt_animation_parse(mlt_animation self, const char *data, int length, double fps, locale_t locale ); extern int mlt_animation_refresh( mlt_animation self, const char *data, int length ); extern int mlt_animation_get_length( mlt_animation self ); extern void mlt_animation_set_length( mlt_animation self, int length ); extern int mlt_animation_parse_item( mlt_animation self, mlt_animation_item item, const char *data ); extern int mlt_animation_get_item( mlt_animation self, mlt_animation_item item, int position ); extern int mlt_animation_insert( mlt_animation self, mlt_animation_item item ); extern int mlt_animation_remove( mlt_animation self, int position ); extern void mlt_animation_interpolate( mlt_animation self ); extern int mlt_animation_next_key( mlt_animation self, mlt_animation_item item, int position ); extern int mlt_animation_prev_key( mlt_animation self, mlt_animation_item item, int position ); extern char *mlt_animation_serialize_cut( mlt_animation self, int in, int out ); extern char *mlt_animation_serialize( mlt_animation self ); extern void mlt_animation_close( mlt_animation self ); #endif mlt-0.9.0/src/framework/mlt_cache.c000066400000000000000000000430101215300731300171540ustar00rootroot00000000000000/** * \file mlt_cache.c * \brief least recently used cache * \see mlt_profile_s * * Copyright (C) 2007-2012 Ushodaya Enterprises Limited * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_types.h" #include "mlt_log.h" #include "mlt_properties.h" #include "mlt_cache.h" #include "mlt_frame.h" #include #include /** the maximum number of data objects to cache per line */ #define MAX_CACHE_SIZE (200) /** the default number of data objects to cache per line */ #define DEFAULT_CACHE_SIZE (4) /** \brief Cache item class * * A cache item is a structure holding information about a data object including * a reference count that is used to control its lifetime. When you get a * a cache item from the cache, you hold a reference that prevents the data * from being released when the cache is full and something new is added. * When you close the cache item, the reference count is decremented. * The data object is destroyed when all cache items are closed and the cache * releases its reference. */ typedef struct mlt_cache_item_s { mlt_cache cache; /**< a reference to the cache to which this belongs */ void *object; /**< a parent object to the cache data that uniquely identifies this cached item */ void *data; /**< the opaque pointer to the cached data */ int size; /**< the size of the cached data */ int refcount; /**< a reference counter to control when destructor is called */ mlt_destructor destructor; /**< a function to release or destroy the cached data */ } mlt_cache_item_s; /** \brief Cache class * * This is a utility class for implementing a Least Recently Used (LRU) cache * of data blobs indexed by the address of some other object (e.g., a service). * Instead of sorting and manipulating linked lists, it tries to be simple and * elegant by copying pointers between two arrays of fixed size to shuffle the * order of elements. * * This class is useful if you have a service that wants to cache something * somewhat large, but will not scale if there are many instances of the service. * Of course, the service will need to know how to recreate the cached element * if it gets flushed from the cache, * * The most obvious examples are the pixbuf and qimage producers that cache their * respective objects representing a picture read from a file. If the picture * is no longer in the cache, it can simply re-read it from file. However, a * picture is often repeated over many frames and makes sense to cache instead * of continually reading, parsing, and decoding. On the other hand, you might * want to load hundreds of pictures as individual producers, which would use * a lot of memory if every picture is held in memory! */ struct mlt_cache_s { int count; /**< the number of items currently in the cache */ int size; /**< the maximum number of items permitted in the cache <= \p MAX_CACHE_SIZE */ int is_frames; /**< indicates if this cache is used to cache frames */ void* *current; /**< pointer to the current array of pointers */ void* A[ MAX_CACHE_SIZE ]; void* B[ MAX_CACHE_SIZE ]; pthread_mutex_t mutex; /**< a mutex to prevent multi-threaded race conditions */ mlt_properties active; /**< a list of cache items some of which may no longer be in \p current but to which there are outstanding references */ mlt_properties garbage;/**< a list cache items pending release. A cache item is copied to this list when it is updated but there are outstanding references to the old data object. */ }; /** Get the data pointer from the cache item. * * \public \memberof mlt_cache_s * \param item a cache item * \param[out] size the number of bytes pointed at, if supplied when putting the data into the cache * \return the data pointer */ void *mlt_cache_item_data( mlt_cache_item item, int *size ) { if ( size && item ) *size = item->size; return item? item->data : NULL; } /** Close a cache item given its parent object pointer. * * \private \memberof mlt_cache_s * \param cache a cache * \param object the object to which the data object belongs * \param data the data object, which might be in the garbage list (optional) */ static void cache_object_close( mlt_cache cache, void *object, void* data ) { char key[19]; if ( cache->is_frames ) { // Frame caches are easy - just close the object as mlt_frame. mlt_frame_close( object ); return; } // Fetch the cache item from the active list by its owner's address sprintf( key, "%p", object ); mlt_cache_item item = mlt_properties_get_data( cache->active, key, NULL ); if ( item ) { mlt_log( NULL, MLT_LOG_DEBUG, "%s: item %p object %p data %p refcount %d\n", __FUNCTION__, item, item->object, item->data, item->refcount ); if ( item->destructor && --item->refcount <= 0 ) { // Destroy the data object item->destructor( item->data ); item->data = NULL; item->destructor = NULL; // Do not dispose of the cache item because it could likely be used // again. } } // Fetch the cache item from the garbage collection by its data address if ( data ) { sprintf( key, "%p", data ); item = mlt_properties_get_data( cache->garbage, key, NULL ); if ( item ) { mlt_log( NULL, MLT_LOG_DEBUG, "collecting garbage item %p object %p data %p refcount %d\n", item, item->object, item->data, item->refcount ); if ( item->destructor && --item->refcount <= 0 ) { item->destructor( item->data ); item->data = NULL; item->destructor = NULL; // We do not need the garbage-collected cache item mlt_properties_set_data( cache->garbage, key, NULL, 0, NULL, NULL ); } } } } /** Close a cache item. * * Release a reference and call the destructor on the data object when all * references are released. * * \public \memberof mlt_cache_item_s * \param item a cache item */ void mlt_cache_item_close( mlt_cache_item item ) { if ( item ) { pthread_mutex_lock( &item->cache->mutex ); cache_object_close( item->cache, item->object, item->data ); pthread_mutex_unlock( &item->cache->mutex ); } } /** Create a new cache. * * The default size is \p DEFAULT_CACHE_SIZE. * \public \memberof mlt_cache_s * \return a new cache or NULL if there was an error */ mlt_cache mlt_cache_init() { mlt_cache result = calloc( 1, sizeof( struct mlt_cache_s ) ); if ( result ) { result->size = DEFAULT_CACHE_SIZE; result->current = result->A; pthread_mutex_init( &result->mutex, NULL ); result->active = mlt_properties_new(); result->garbage = mlt_properties_new(); } return result; } /** Set the numer of items to cache. * * This must be called before using the cache. The size can not be more * than \p MAX_CACHE_SIZE. * \public \memberof mlt_cache_s * \param cache the cache to adjust * \param size the new size of the cache */ void mlt_cache_set_size( mlt_cache cache, int size ) { if ( size <= MAX_CACHE_SIZE ) cache->size = size; } /** Get the numer of possible cache items. * * \public \memberof mlt_cache_s * \param cache the cache to check * \return the current maximum size of the cache */ int mlt_cache_get_size( mlt_cache cache ) { return cache->size; } /** Destroy a cache. * * \public \memberof mlt_cache_s * \param cache the cache to destroy */ void mlt_cache_close( mlt_cache cache ) { if ( cache ) { while ( cache->count-- ) { void *object = cache->current[ cache->count ]; mlt_log( NULL, MLT_LOG_DEBUG, "%s: %d = %p\n", __FUNCTION__, cache->count, object ); cache_object_close( cache, object, NULL ); } mlt_properties_close( cache->active ); mlt_properties_close( cache->garbage ); pthread_mutex_destroy( &cache->mutex ); free( cache ); } } /** Remove cache entries for an object. * * \public \memberof mlt_cache_s * \param cache a cache * \param object the object that owns the cached data */ void mlt_cache_purge( mlt_cache cache, void *object ) { if (!cache) return; pthread_mutex_lock( &cache->mutex ); if ( cache && object ) { int i, j; void **alt = cache->current == cache->A ? cache->B : cache->A; for ( i = 0, j = 0; i < cache->count; i++ ) { void *o = cache->current[ i ]; if ( o == object ) { cache_object_close( cache, o, NULL ); } else { alt[ j++ ] = o; } } cache->count = j; cache->current = alt; } pthread_mutex_unlock( &cache->mutex ); } /** Shuffle the cache entries between the two arrays and return the cache entry for an object. * * \private \memberof mlt_cache_s * \param cache a cache object * \param object the object that owns the cached data * \return a cache entry if there was a hit or NULL for a miss */ static void** shuffle_get_hit( mlt_cache cache, void *object ) { int i = cache->count; int j = cache->count - 1; void **hit = NULL; void **alt = cache->current == cache->A ? cache->B : cache->A; if ( cache->count > 0 && cache->count < cache->size ) { // first determine if we have a hit while ( i-- && !hit ) { void **o = &cache->current[ i ]; if ( *o == object ) hit = o; } // if there was no hit, we will not be shuffling out an entry // and are still filling the cache if ( !hit ) ++j; // reset these i = cache->count; hit = NULL; } // shuffle the existing entries to the alternate array while ( i-- ) { void **o = &cache->current[ i ]; if ( !hit && *o == object ) { hit = o; } else if ( j > 0 ) { alt[ --j ] = *o; // mlt_log( NULL, MLT_LOG_DEBUG, "%s: shuffle %d = %p\n", __FUNCTION__, j, alt[j] ); } } return hit; } /** Put a chunk of data in the cache. * * This function and mlt_cache_get() are not scalable with a large volume * of unique \p object paramter values. Therefore, it does not make sense * to use it for a frame/image cache using the frame position for \p object. * Instead, use mlt_cache_put_frame() for that. * * \public \memberof mlt_cache_s * \param cache a cache object * \param object the object to which this data belongs * \param data an opaque pointer to the data to cache * \param size the size of the data in bytes * \param destructor a pointer to a function that can destroy or release a reference to the data. */ void mlt_cache_put( mlt_cache cache, void *object, void* data, int size, mlt_destructor destructor ) { pthread_mutex_lock( &cache->mutex ); void **hit = shuffle_get_hit( cache, object ); void **alt = cache->current == cache->A ? cache->B : cache->A; // add the object to the cache if ( hit ) { // release the old data cache_object_close( cache, *hit, NULL ); // the MRU end gets the updated data hit = &alt[ cache->count - 1 ]; } else if ( cache->count < cache->size ) { // more room in cache, add it to MRU end hit = &alt[ cache->count++ ]; } else { // release the entry at the LRU end cache_object_close( cache, cache->current[0], NULL ); // The MRU end gets the new item hit = &alt[ cache->count - 1 ]; } *hit = object; mlt_log( NULL, MLT_LOG_DEBUG, "%s: put %d = %p, %p\n", __FUNCTION__, cache->count - 1, object, data ); // Fetch the cache item char key[19]; sprintf( key, "%p", object ); mlt_cache_item item = mlt_properties_get_data( cache->active, key, NULL ); if ( !item ) { item = calloc( 1, sizeof( mlt_cache_item_s ) ); if ( item ) mlt_properties_set_data( cache->active, key, item, 0, free, NULL ); } if ( item ) { // If updating the cache item but not all references are released // copy the item to the garbage collection. if ( item->refcount > 0 && item->data ) { mlt_cache_item orphan = calloc( 1, sizeof( mlt_cache_item_s ) ); if ( orphan ) { mlt_log( NULL, MLT_LOG_DEBUG, "adding to garbage collection object %p data %p\n", item->object, item->data ); *orphan = *item; sprintf( key, "%p", orphan->data ); // We store in the garbage collection by data address, not the owner's! mlt_properties_set_data( cache->garbage, key, orphan, 0, free, NULL ); } } // Set/update the cache item item->cache = cache; item->object = object; item->data = data; item->size = size; item->destructor = destructor; item->refcount = 1; } // swap the current array cache->current = alt; pthread_mutex_unlock( &cache->mutex ); } /** Get a chunk of data from the cache. * * \public \memberof mlt_cache_s * \param cache a cache object * \param object the object for which you are trying to locate the data * \return a mlt_cache_item if found or NULL if not found or has been flushed from the cache */ mlt_cache_item mlt_cache_get( mlt_cache cache, void *object ) { mlt_cache_item result = NULL; pthread_mutex_lock( &cache->mutex ); void **hit = shuffle_get_hit( cache, object ); void **alt = cache->current == cache->A ? cache->B : cache->A; if ( hit ) { // copy the hit to the MRU end alt[ cache->count - 1 ] = *hit; hit = &alt[ cache->count - 1 ]; char key[19]; sprintf( key, "%p", *hit ); result = mlt_properties_get_data( cache->active, key, NULL ); if ( result && result->data ) { result->refcount++; mlt_log( NULL, MLT_LOG_DEBUG, "%s: get %d = %p, %p\n", __FUNCTION__, cache->count - 1, *hit, result->data ); } // swap the current array cache->current = alt; } pthread_mutex_unlock( &cache->mutex ); return result; } /** Shuffle the cache entries between the two arrays and return the frame for a position. * * \private \memberof mlt_cache_s * \param cache a cache object * \param position the position of the frame that you want * \return a frame if there was a hit or NULL for a miss */ static mlt_frame* shuffle_get_frame( mlt_cache cache, mlt_position position ) { int i = cache->count; int j = cache->count - 1; mlt_frame *hit = NULL; mlt_frame *alt = (mlt_frame*) ( cache->current == cache->A ? cache->B : cache->A ); if ( cache->count > 0 && cache->count < cache->size ) { // first determine if we have a hit while ( i-- && !hit ) { mlt_frame *o = (mlt_frame*) &cache->current[ i ]; if ( mlt_frame_original_position( *o ) == position ) hit = o; } // if there was no hit, we will not be shuffling out an entry // and are still filling the cache if ( !hit ) ++j; // reset these i = cache->count; hit = NULL; } // shuffle the existing entries to the alternate array while ( i-- ) { mlt_frame *o = (mlt_frame*) &cache->current[ i ]; if ( !hit && mlt_frame_original_position( *o ) == position ) { hit = o; } else if ( j > 0 ) { alt[ --j ] = *o; // mlt_log( NULL, MLT_LOG_DEBUG, "%s: shuffle %d = %p\n", __FUNCTION__, j, alt[j] ); } } return hit; } /** Put a frame in the cache. * * Unlike mlt_cache_put() this version is more suitable for caching frames * and their data - like images. However, this version does not use reference * counting and garbage collection. Rather, frames are cloned with deep copy * to avoid those things. * * \public \memberof mlt_cache_s * \param cache a cache object * \param frame the frame to cache * \see mlt_frame_get_frame */ void mlt_cache_put_frame( mlt_cache cache, mlt_frame frame ) { pthread_mutex_lock( &cache->mutex ); mlt_frame *hit = shuffle_get_frame( cache, mlt_frame_original_position( frame ) ); mlt_frame *alt = (mlt_frame*) ( cache->current == cache->A ? cache->B : cache->A ); // add the frame to the cache if ( hit ) { // release the old data mlt_frame_close( *hit ); // the MRU end gets the updated data hit = &alt[ cache->count - 1 ]; } else if ( cache->count < cache->size ) { // more room in cache, add it to MRU end hit = &alt[ cache->count++ ]; } else { // release the entry at the LRU end mlt_frame_close( cache->current[0] ); // The MRU end gets the new item hit = &alt[ cache->count - 1 ]; } *hit = mlt_frame_clone( frame, 1 ); mlt_log( NULL, MLT_LOG_DEBUG, "%s: put %d = %p\n", __FUNCTION__, cache->count - 1, frame ); // swap the current array cache->current = (void**) alt; cache->is_frames = 1; pthread_mutex_unlock( &cache->mutex ); } /** Get a frame from the cache. * * You must call mlt_frame_close() on the frame you receive from this. * * \public \memberof mlt_cache_s * \param cache a cache object * \param position the position of the frame that you want * \return a frame if found or NULL if not found or has been flushed from the cache * \see mlt_frame_put_frame */ mlt_frame mlt_cache_get_frame( mlt_cache cache, mlt_position position ) { mlt_frame result = NULL; pthread_mutex_lock( &cache->mutex ); mlt_frame *hit = shuffle_get_frame( cache, position ); mlt_frame *alt = (mlt_frame*) ( cache->current == cache->A ? cache->B : cache->A ); if ( hit ) { // copy the hit to the MRU end alt[ cache->count - 1 ] = *hit; hit = &alt[ cache->count - 1 ]; result = mlt_frame_clone( *hit, 1 ); mlt_log( NULL, MLT_LOG_DEBUG, "%s: get %d = %p\n", __FUNCTION__, cache->count - 1, *hit ); // swap the current array cache->current = (void**) alt; } pthread_mutex_unlock( &cache->mutex ); return result; } mlt-0.9.0/src/framework/mlt_cache.h000066400000000000000000000032561215300731300171710ustar00rootroot00000000000000/** * \file mlt_cache.h * \brief least recently used cache * \see mlt_cache_s * * Copyright (C) 2007-2012 Ushodaya Enterprises Limited * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_CACHE_H #define _MLT_CACHE_H #include "mlt_types.h" extern void *mlt_cache_item_data( mlt_cache_item item, int *size ); extern void mlt_cache_item_close( mlt_cache_item item ); extern mlt_cache mlt_cache_init(); extern void mlt_cache_set_size( mlt_cache cache, int size ); extern int mlt_cache_get_size( mlt_cache cache ); extern void mlt_cache_close( mlt_cache cache ); extern void mlt_cache_purge( mlt_cache cache, void *object ); extern void mlt_cache_put( mlt_cache cache, void *object, void* data, int size, mlt_destructor destructor ); extern mlt_cache_item mlt_cache_get( mlt_cache cache, void *object ); extern void mlt_cache_put_frame( mlt_cache cache, mlt_frame frame ); extern mlt_frame mlt_cache_get_frame( mlt_cache cache, mlt_position position ); #endif mlt-0.9.0/src/framework/mlt_consumer.c000066400000000000000000001450121215300731300177510ustar00rootroot00000000000000/** * \file mlt_consumer.c * \brief abstraction for all consumer services * \see mlt_consumer_s * * Copyright (C) 2003-2010 Ushodaya Enterprises Limited * \author Charles Yates * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_consumer.h" #include "mlt_factory.h" #include "mlt_producer.h" #include "mlt_frame.h" #include "mlt_profile.h" #include "mlt_log.h" #include #include #include #include /** Define this if you want an automatic deinterlace (if necessary) when the * consumer's producer is not running at normal speed. */ #undef DEINTERLACE_ON_NOT_NORMAL_SPEED /** This is not the ideal place for this, but it is needed by VDPAU as well. */ pthread_mutex_t mlt_sdl_mutex = PTHREAD_MUTEX_INITIALIZER; /** \brief private members of mlt_consumer */ typedef struct { int real_time; int ahead; mlt_image_format format; mlt_deque queue; pthread_t ahead_thread; pthread_mutex_t queue_mutex; pthread_cond_t queue_cond; pthread_mutex_t put_mutex; pthread_cond_t put_cond; mlt_frame put; int put_active; mlt_event event_listener; mlt_position position; int is_purge; /* additional fields added for the parallel work queue */ mlt_deque worker_threads; pthread_mutex_t done_mutex; pthread_cond_t done_cond; int consecutive_dropped; int consecutive_rendered; int process_head; int started; pthread_t *threads; /**< used to deallocate all threads */ } consumer_private; static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ); static void mlt_consumer_frame_show( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ); static void mlt_consumer_property_changed( mlt_properties owner, mlt_consumer self, char *name ); static void apply_profile_properties( mlt_consumer self, mlt_profile profile, mlt_properties properties ); static void on_consumer_frame_show( mlt_properties owner, mlt_consumer self, mlt_frame frame ); /** Initialize a consumer service. * * \public \memberof mlt_consumer_s * \param self the consumer to initialize * \param child a pointer to the object for the subclass * \param profile the \p mlt_profile_s to use (optional but recommended, * uses the environment variable MLT if self is NULL) * \return true if there was an error */ int mlt_consumer_init( mlt_consumer self, void *child, mlt_profile profile ) { int error = 0; memset( self, 0, sizeof( struct mlt_consumer_s ) ); self->child = child; consumer_private *priv = self->local = calloc( 1, sizeof( consumer_private ) ); error = mlt_service_init( &self->parent, self ); if ( error == 0 ) { // Get the properties from the service mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); // Apply profile to properties if ( profile == NULL ) { // Normally the application creates the profile and controls its lifetime // This is the fallback exception handling profile = mlt_profile_init( NULL ); mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); mlt_properties_set_data( properties, "_profile", profile, 0, (mlt_destructor)mlt_profile_close, NULL ); } apply_profile_properties( self, profile, properties ); // Default rescaler for all consumers mlt_properties_set( properties, "rescale", "bilinear" ); // Default read ahead buffer size mlt_properties_set_int( properties, "buffer", 25 ); mlt_properties_set_int( properties, "drop_max", 5 ); // Default audio frequency and channels mlt_properties_set_int( properties, "frequency", 48000 ); mlt_properties_set_int( properties, "channels", 2 ); // Default of all consumers is real time mlt_properties_set_int( properties, "real_time", 1 ); // Default to environment test card mlt_properties_set( properties, "test_card", mlt_environment( "MLT_TEST_CARD" ) ); // Hmm - default all consumers to yuv422 :-/ priv->format = mlt_image_yuv422; mlt_properties_set( properties, "mlt_image_format", mlt_image_format_name( priv->format ) ); mlt_properties_set( properties, "mlt_audio_format", mlt_audio_format_name( mlt_audio_s16 ) ); mlt_events_register( properties, "consumer-frame-show", ( mlt_transmitter )mlt_consumer_frame_show ); mlt_events_register( properties, "consumer-frame-render", ( mlt_transmitter )mlt_consumer_frame_render ); mlt_events_register( properties, "consumer-thread-started", NULL ); mlt_events_register( properties, "consumer-thread-stopped", NULL ); mlt_events_register( properties, "consumer-stopped", NULL ); mlt_events_listen( properties, self, "consumer-frame-show", ( mlt_listener )on_consumer_frame_show ); // Register a property-changed listener to handle the profile property - // subsequent properties can override the profile priv->event_listener = mlt_events_listen( properties, self, "property-changed", ( mlt_listener )mlt_consumer_property_changed ); // Create the push mutex and condition pthread_mutex_init( &priv->put_mutex, NULL ); pthread_cond_init( &priv->put_cond, NULL ); } return error; } /** Convert the profile into properties on the consumer. * * \private \memberof mlt_consumer_s * \param self a consumer * \param profile a profile * \param properties a properties list (typically, the consumer's) */ static void apply_profile_properties( mlt_consumer self, mlt_profile profile, mlt_properties properties ) { consumer_private *priv = self->local; mlt_event_block( priv->event_listener ); mlt_properties_set_double( properties, "fps", mlt_profile_fps( profile ) ); mlt_properties_set_int( properties, "frame_rate_num", profile->frame_rate_num ); mlt_properties_set_int( properties, "frame_rate_den", profile->frame_rate_den ); mlt_properties_set_int( properties, "width", profile->width ); mlt_properties_set_int( properties, "height", profile->height ); mlt_properties_set_int( properties, "progressive", profile->progressive ); mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) ); mlt_properties_set_int( properties, "sample_aspect_num", profile->sample_aspect_num ); mlt_properties_set_int( properties, "sample_aspect_den", profile->sample_aspect_den ); mlt_properties_set_double( properties, "display_ratio", mlt_profile_dar( profile ) ); mlt_properties_set_int( properties, "display_aspect_num", profile->display_aspect_num ); mlt_properties_set_int( properties, "display_aspect_num", profile->display_aspect_num ); mlt_properties_set_int( properties, "colorspace", profile->colorspace ); mlt_event_unblock( priv->event_listener ); } /** The property-changed event listener * * \private \memberof mlt_consumer_s * \param owner the events object * \param self the consumer * \param name the name of the property that changed */ static void mlt_consumer_property_changed( mlt_properties owner, mlt_consumer self, char *name ) { if ( !strcmp( name, "mlt_profile" ) ) { // Get the properies mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); // Get the current profile mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); // Load the new profile mlt_profile new_profile = mlt_profile_init( mlt_properties_get( properties, name ) ); if ( new_profile ) { // Copy the profile if ( profile != NULL ) { free( profile->description ); memcpy( profile, new_profile, sizeof( struct mlt_profile_s ) ); profile->description = strdup( new_profile->description ); } else { profile = new_profile; } // Apply to properties apply_profile_properties( self, profile, properties ); mlt_profile_close( new_profile ); } } else if ( !strcmp( name, "frame_rate_num" ) ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) { profile->frame_rate_num = mlt_properties_get_int( properties, "frame_rate_num" ); mlt_properties_set_double( properties, "fps", mlt_profile_fps( profile ) ); } } else if ( !strcmp( name, "frame_rate_den" ) ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) { profile->frame_rate_den = mlt_properties_get_int( properties, "frame_rate_den" ); mlt_properties_set_double( properties, "fps", mlt_profile_fps( profile ) ); } } else if ( !strcmp( name, "width" ) ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) profile->width = mlt_properties_get_int( properties, "width" ); } else if ( !strcmp( name, "height" ) ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) profile->height = mlt_properties_get_int( properties, "height" ); } else if ( !strcmp( name, "progressive" ) ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) profile->progressive = mlt_properties_get_int( properties, "progressive" ); } else if ( !strcmp( name, "sample_aspect_num" ) ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) { profile->sample_aspect_num = mlt_properties_get_int( properties, "sample_aspect_num" ); mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) ); } } else if ( !strcmp( name, "sample_aspect_den" ) ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) { profile->sample_aspect_den = mlt_properties_get_int( properties, "sample_aspect_den" ); mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) ); } } else if ( !strcmp( name, "display_aspect_num" ) ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) { profile->display_aspect_num = mlt_properties_get_int( properties, "display_aspect_num" ); mlt_properties_set_double( properties, "display_ratio", mlt_profile_dar( profile ) ); } } else if ( !strcmp( name, "display_aspect_den" ) ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) { profile->display_aspect_den = mlt_properties_get_int( properties, "display_aspect_den" ); mlt_properties_set_double( properties, "display_ratio", mlt_profile_dar( profile ) ); } } else if ( !strcmp( name, "colorspace" ) ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) profile->colorspace = mlt_properties_get_int( properties, "colorspace" ); } } /** The transmitter for the consumer-frame-show event * * Invokes the listener. * * \private \memberof mlt_consumer_s * \param listener a function pointer that will be invoked * \param owner the events object that will be passed to \p listener * \param self a service that will be passed to \p listener * \param args an array of pointers - the first entry is passed as a frame to \p listener */ static void mlt_consumer_frame_show( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) { if ( listener != NULL ) listener( owner, self, ( mlt_frame )args[ 0 ] ); } /** The transmitter for the consumer-frame-render event * * Invokes the listener. * * \private \memberof mlt_consumer_s * \param listener a function pointer that will be invoked * \param owner the events object that will be passed to \p listener * \param self a service that will be passed to \p listener * \param args an array of pointers - the first entry is passed as a frame to \p listener */ static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) { if ( listener != NULL ) listener( owner, self, ( mlt_frame )args[ 0 ] ); } /** A listener on the consumer-frame-show event * * Saves the position of the frame shown. * * \private \memberof mlt_consumer_s * \param owner the events object * \param consumer the consumer on which this event occurred * \param frame the frame that was shown */ static void on_consumer_frame_show( mlt_properties owner, mlt_consumer consumer, mlt_frame frame ) { if ( frame ) ( ( consumer_private*) consumer->local )->position = mlt_frame_get_position( frame ); } /** Create a new consumer. * * \public \memberof mlt_consumer_s * \param profile a profile (optional, but recommended) * \return a new consumer */ mlt_consumer mlt_consumer_new( mlt_profile profile ) { // Create the memory for the structure mlt_consumer self = malloc( sizeof( struct mlt_consumer_s ) ); // Initialise it if ( self != NULL && mlt_consumer_init( self, NULL, profile ) == 0 ) { // Return it return self; } else { free(self); return NULL; } } /** Get the parent service object. * * \public \memberof mlt_consumer_s * \param self a consumer * \return the parent service class * \see MLT_CONSUMER_SERVICE */ mlt_service mlt_consumer_service( mlt_consumer self ) { return self != NULL ? &self->parent : NULL; } /** Get the consumer properties. * * \public \memberof mlt_consumer_s * \param self a consumer * \return the consumer's properties list * \see MLT_CONSUMER_PROPERTIES */ mlt_properties mlt_consumer_properties( mlt_consumer self ) { return self != NULL ? MLT_SERVICE_PROPERTIES( &self->parent ) : NULL; } /** Connect the consumer to the producer. * * \public \memberof mlt_consumer_s * \param self a consumer * \param producer a producer * \return > 0 warning, == 0 success, < 0 serious error, * 1 = this service does not accept input, * 2 = the producer is invalid, * 3 = the producer is already registered with this consumer */ int mlt_consumer_connect( mlt_consumer self, mlt_service producer ) { return mlt_service_connect_producer( &self->parent, producer, 0 ); } /** Start the consumer. * * \public \memberof mlt_consumer_s * \param self a consumer * \return true if there was an error */ int mlt_consumer_start( mlt_consumer self ) { if ( !mlt_consumer_is_stopped( self ) ) return 0; consumer_private *priv = self->local; // Stop listening to the property-changed event mlt_event_block( priv->event_listener ); // Get the properies mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); // Determine if there's a test card producer char *test_card = mlt_properties_get( properties, "test_card" ); // Just to make sure nothing is hanging around... pthread_mutex_lock( &priv->put_mutex ); priv->put = NULL; priv->put_active = 1; pthread_mutex_unlock( &priv->put_mutex ); // Deal with it now. if ( test_card != NULL ) { if ( mlt_properties_get_data( properties, "test_card_producer", NULL ) == NULL ) { // Create a test card producer mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); mlt_producer producer = mlt_factory_producer( profile, NULL, test_card ); // Do we have a producer if ( producer != NULL ) { // Test card should loop I guess... mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "loop" ); //mlt_producer_set_speed( producer, 0 ); //mlt_producer_set_in_and_out( producer, 0, 0 ); // Set the test card on the consumer mlt_properties_set_data( properties, "test_card_producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); } } } else { // Allow the hash table to speed things up mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL ); } // The profile could have changed between a stop and a restart. apply_profile_properties( self, mlt_service_profile( MLT_CONSUMER_SERVICE(self) ), properties ); // Set the frame duration in microseconds for the frame-dropping heuristic int frame_rate_num = mlt_properties_get_int( properties, "frame_rate_num" ); int frame_rate_den = mlt_properties_get_int( properties, "frame_rate_den" ); int frame_duration = 0; if ( frame_rate_num && frame_rate_den ) { frame_duration = 1000000 / frame_rate_num * frame_rate_den; } mlt_properties_set_int( properties, "frame_duration", frame_duration ); // Check and run an ante command if ( mlt_properties_get( properties, "ante" ) ) if ( system( mlt_properties_get( properties, "ante" ) ) == -1 ) mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_ERROR, "system(%s) failed!\n", mlt_properties_get( properties, "ante" ) ); // Set the real_time preference priv->real_time = mlt_properties_get_int( properties, "real_time" ); // For worker threads implementation, buffer must be at least # threads if ( abs( priv->real_time ) > 1 && mlt_properties_get_int( properties, "buffer" ) <= abs( priv->real_time ) ) mlt_properties_set_int( properties, "_buffer", abs( priv->real_time ) + 1 ); // Get the image format to use for rendering threads const char* format = mlt_properties_get( properties, "mlt_image_format" ); if ( format ) { if ( !strcmp( format, "rgb24" ) ) priv->format = mlt_image_rgb24; else if ( !strcmp( format, "rgb24a" ) ) priv->format = mlt_image_rgb24a; else if ( !strcmp( format, "yuv420p" ) ) priv->format = mlt_image_yuv420p; else if ( !strcmp( format, "none" ) ) priv->format = mlt_image_none; else if ( !strcmp( format, "glsl" ) ) priv->format = mlt_image_glsl_texture; else priv->format = mlt_image_yuv422; } // Start the service if ( self->start != NULL ) return self->start( self ); return 0; } /** An alternative method to feed frames into the consumer. * * Only valid if the consumer itself is not connected. * * \public \memberof mlt_consumer_s * \param self a consumer * \param frame a frame * \return true (ignore self for now) */ int mlt_consumer_put_frame( mlt_consumer self, mlt_frame frame ) { int error = 1; // Get the service assoicated to the consumer mlt_service service = MLT_CONSUMER_SERVICE( self ); if ( mlt_service_producer( service ) == NULL ) { struct timeval now; struct timespec tm; consumer_private *priv = self->local; pthread_mutex_lock( &priv->put_mutex ); while ( priv->put_active && priv->put != NULL ) { gettimeofday( &now, NULL ); tm.tv_sec = now.tv_sec + 1; tm.tv_nsec = now.tv_usec * 1000; pthread_cond_timedwait( &priv->put_cond, &priv->put_mutex, &tm ); } if ( priv->put_active && priv->put == NULL ) priv->put = frame; else mlt_frame_close( frame ); pthread_cond_broadcast( &priv->put_cond ); pthread_mutex_unlock( &priv->put_mutex ); } else { mlt_frame_close( frame ); } return error; } /** Protected method for consumer to get frames from connected service * * \public \memberof mlt_consumer_s * \param self a consumer * \return a frame */ mlt_frame mlt_consumer_get_frame( mlt_consumer self ) { // Frame to return mlt_frame frame = NULL; // Get the service assoicated to the consumer mlt_service service = MLT_CONSUMER_SERVICE( self ); // Get the consumer properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); // Get the frame if ( mlt_service_producer( service ) == NULL && mlt_properties_get_int( properties, "put_mode" ) ) { struct timeval now; struct timespec tm; consumer_private *priv = self->local; pthread_mutex_lock( &priv->put_mutex ); while ( priv->put_active && priv->put == NULL ) { gettimeofday( &now, NULL ); tm.tv_sec = now.tv_sec + 1; tm.tv_nsec = now.tv_usec * 1000; pthread_cond_timedwait( &priv->put_cond, &priv->put_mutex, &tm ); } frame = priv->put; priv->put = NULL; pthread_cond_broadcast( &priv->put_cond ); pthread_mutex_unlock( &priv->put_mutex ); if ( frame != NULL ) mlt_service_apply_filters( service, frame, 0 ); } else if ( mlt_service_producer( service ) != NULL ) { mlt_service_get_frame( service, &frame, 0 ); } else { frame = mlt_frame_init( service ); } if ( frame != NULL ) { // Get the frame properties mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); // Get the test card producer mlt_producer test_card = mlt_properties_get_data( properties, "test_card_producer", NULL ); // Attach the test frame producer to it. if ( test_card != NULL ) mlt_properties_set_data( frame_properties, "test_card_producer", test_card, 0, NULL, NULL ); // Pass along the interpolation and deinterlace options // TODO: get rid of consumer_deinterlace and use profile.progressive mlt_properties_set( frame_properties, "rescale.interp", mlt_properties_get( properties, "rescale" ) ); mlt_properties_set_int( frame_properties, "consumer_deinterlace", mlt_properties_get_int( properties, "progressive" ) | mlt_properties_get_int( properties, "deinterlace" ) ); mlt_properties_set( frame_properties, "deinterlace_method", mlt_properties_get( properties, "deinterlace_method" ) ); mlt_properties_set_int( frame_properties, "consumer_tff", mlt_properties_get_int( properties, "top_field_first" ) ); } // Return the frame return frame; } /** Compute the time difference between now and a time value. * * \private \memberof mlt_consumer_s * \param time1 a time value to be compared against now * \return the difference in microseconds */ static inline long time_difference( struct timeval *time1 ) { struct timeval time2; time2.tv_sec = time1->tv_sec; time2.tv_usec = time1->tv_usec; gettimeofday( time1, NULL ); return time1->tv_sec * 1000000 + time1->tv_usec - time2.tv_sec * 1000000 - time2.tv_usec; } /** The thread procedure for asynchronously pulling frames through the service * network connected to a consumer. * * \private \memberof mlt_consumer_s * \param arg a consumer */ static void *consumer_read_ahead_thread( void *arg ) { // The argument is the consumer mlt_consumer self = arg; consumer_private *priv = self->local; // Get the properties of the consumer mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); // Get the width and height int width = mlt_properties_get_int( properties, "width" ); int height = mlt_properties_get_int( properties, "height" ); // See if video is turned off int video_off = mlt_properties_get_int( properties, "video_off" ); int preview_off = mlt_properties_get_int( properties, "preview_off" ); int preview_format = mlt_properties_get_int( properties, "preview_format" ); // Get the audio settings mlt_audio_format afmt = mlt_audio_s16; const char *format = mlt_properties_get( properties, "mlt_audio_format" ); if ( format ) { if ( !strcmp( format, "none" ) ) afmt = mlt_audio_none; else if ( !strcmp( format, "s32" ) ) afmt = mlt_audio_s32; else if ( !strcmp( format, "s32le" ) ) afmt = mlt_audio_s32le; else if ( !strcmp( format, "float" ) ) afmt = mlt_audio_float; else if ( !strcmp( format, "f32le" ) ) afmt = mlt_audio_f32le; else if ( !strcmp( format, "u8" ) ) afmt = mlt_audio_u8; } int counter = 0; double fps = mlt_properties_get_double( properties, "fps" ); int channels = mlt_properties_get_int( properties, "channels" ); int frequency = mlt_properties_get_int( properties, "frequency" ); int samples = 0; void *audio = NULL; // See if audio is turned off int audio_off = mlt_properties_get_int( properties, "audio_off" ); // Get the maximum size of the buffer int buffer = mlt_properties_get_int( properties, "buffer" ) + 1; // General frame variable mlt_frame frame = NULL; uint8_t *image = NULL; // Time structures struct timeval ante; // Average time for get_frame and get_image int count = 0; int skipped = 0; int64_t time_process = 0; int skip_next = 0; mlt_position pos = 0; mlt_position start_pos = 0; mlt_position last_pos = 0; int frame_duration = mlt_properties_get_int( properties, "frame_duration" ); int drop_max = mlt_properties_get_int( properties, "drop_max" ); if ( preview_off && preview_format != 0 ) priv->format = preview_format; mlt_events_fire( properties, "consumer-thread-started", NULL ); // Get the first frame frame = mlt_consumer_get_frame( self ); if ( frame ) { // Get the image of the first frame if ( !video_off ) { mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-frame-render", frame, NULL ); mlt_frame_get_image( frame, &image, &priv->format, &width, &height, 0 ); } if ( !audio_off ) { samples = mlt_sample_calculator( fps, frequency, counter++ ); mlt_frame_get_audio( frame, &audio, &afmt, &frequency, &channels, &samples ); } // Mark as rendered mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 ); last_pos = start_pos = pos = mlt_frame_get_position( frame ); } // Get the starting time (can ignore the times above) gettimeofday( &ante, NULL ); // Continue to read ahead while ( priv->ahead ) { // Put the current frame into the queue pthread_mutex_lock( &priv->queue_mutex ); while( priv->ahead && mlt_deque_count( priv->queue ) >= buffer ) pthread_cond_wait( &priv->queue_cond, &priv->queue_mutex ); if ( priv->is_purge ) { mlt_frame_close( frame ); priv->is_purge = 0; } else { mlt_deque_push_back( priv->queue, frame ); } pthread_cond_broadcast( &priv->queue_cond ); pthread_mutex_unlock( &priv->queue_mutex ); // Get the next frame frame = mlt_consumer_get_frame( self ); // If there's no frame, we're probably stopped... if ( frame == NULL ) continue; pos = mlt_frame_get_position( frame ); // Increment the counter used for averaging processing cost count ++; // All non-normal playback frames should be shown if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "_speed" ) != 1 ) { #ifdef DEINTERLACE_ON_NOT_NORMAL_SPEED mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 ); #endif // Indicate seeking or trick-play start_pos = pos; } // If skip flag not set or frame-dropping disabled if ( !skip_next || priv->real_time == -1 ) { if ( !video_off ) { // Reset width/height - could have been changed by previous mlt_frame_get_image width = mlt_properties_get_int( properties, "width" ); height = mlt_properties_get_int( properties, "height" ); // Get the image mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-frame-render", frame, NULL ); mlt_frame_get_image( frame, &image, &priv->format, &width, &height, 0 ); } // Indicate the rendered image is available. mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 ); // Reset consecutively-skipped counter skipped = 0; } else // Skip image processing { // Increment the number of consecutively-skipped frames skipped++; // If too many (1 sec) consecutively-skipped frames if ( skipped > drop_max ) { // Reset cost tracker time_process = 0; count = 1; mlt_log_verbose( self, "too many frames dropped - forcing next frame\n" ); } } // Always process audio if ( !audio_off ) { samples = mlt_sample_calculator( fps, frequency, counter++ ); mlt_frame_get_audio( frame, &audio, &afmt, &frequency, &channels, &samples ); } // Get the time to process this frame int64_t time_current = time_difference( &ante ); // If the current time is not suddenly some large amount if ( time_current < time_process / count * 20 || !time_process || count < 5 ) { // Accumulate the cost for processing this frame time_process += time_current; } else { mlt_log_debug( self, "current %"PRId64" threshold %"PRId64" count %d\n", time_current, (int64_t) (time_process / count * 20), count ); // Ignore the cost of this frame's time count--; } // Determine if we started, resumed, or seeked if ( pos != last_pos + 1 ) start_pos = pos; last_pos = pos; // Do not skip the first 20% of buffer at start, resume, or seek if ( pos - start_pos <= buffer / 5 + 1 ) { // Reset cost tracker time_process = 0; count = 1; } // Reset skip flag skip_next = 0; // Only consider skipping if the buffer level is low (or really small) if ( mlt_deque_count( priv->queue ) <= buffer / 5 + 1 ) { // Skip next frame if average cost exceeds frame duration. if ( time_process / count > frame_duration ) skip_next = 1; if ( skip_next ) mlt_log_debug( self, "avg usec %"PRId64" (%"PRId64"/%d) duration %d\n", time_process/count, time_process, count, frame_duration); } } // Remove the last frame mlt_frame_close( frame ); mlt_events_fire( properties, "consumer-thread-stopped", NULL ); return NULL; } /** Locate the first unprocessed frame in the queue. * * When playing with realtime behavior, we do not use the true head, but * rather an adjusted process_head. The process_head is adjusted based on * the rate of frame-dropping or recovery from frame-dropping. The idea is * that as the level of frame-dropping increases to move the process_head * closer to the tail because the frames are not completing processing prior * to their playout! Then, as frames are not dropped the process_head moves * back closer to the head of the queue so that worker threads can work * ahead of the playout point (queue head). * * \private \memberof mlt_consumer_s * \param self a consumer * \return an index into the queue */ static inline int first_unprocessed_frame( mlt_consumer self ) { consumer_private *priv = self->local; int index = priv->real_time <= 0 ? 0 : priv->process_head; while ( index < mlt_deque_count( priv->queue ) && MLT_FRAME( mlt_deque_peek( priv->queue, index ) )->is_processing ) index++; return index; } /** The worker thread procedure for parallel processing frames. * * \private \memberof mlt_consumer_s * \param arg a consumer */ static void *consumer_worker_thread( void *arg ) { // The argument is the consumer mlt_consumer self = arg; consumer_private *priv = self->local; // Get the properties of the consumer mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); // Get the width and height int width = mlt_properties_get_int( properties, "width" ); int height = mlt_properties_get_int( properties, "height" ); mlt_image_format format = priv->format; // See if video is turned off int video_off = mlt_properties_get_int( properties, "video_off" ); int preview_off = mlt_properties_get_int( properties, "preview_off" ); int preview_format = mlt_properties_get_int( properties, "preview_format" ); // General frame variable mlt_frame frame = NULL; uint8_t *image = NULL; if ( preview_off && preview_format != 0 ) format = preview_format; mlt_events_fire( properties, "consumer-thread-started", NULL ); // Continue to read ahead while ( priv->ahead ) { // Get the next unprocessed frame from the work queue pthread_mutex_lock( &priv->queue_mutex ); int index = first_unprocessed_frame( self ); while ( priv->ahead && index >= mlt_deque_count( priv->queue ) ) { mlt_log_debug( MLT_CONSUMER_SERVICE(self), "waiting in worker index = %d queue count = %d\n", index, mlt_deque_count( priv->queue ) ); pthread_cond_wait( &priv->queue_cond, &priv->queue_mutex ); index = first_unprocessed_frame( self ); } // Mark the frame for processing frame = mlt_deque_peek( priv->queue, index ); if ( frame ) { mlt_log_debug( MLT_CONSUMER_SERVICE(self), "worker processing index = %d frame " MLT_POSITION_FMT " queue count = %d\n", index, mlt_frame_get_position(frame), mlt_deque_count( priv->queue ) ); frame->is_processing = 1; mlt_properties_inc_ref( MLT_FRAME_PROPERTIES( frame ) ); } pthread_mutex_unlock( &priv->queue_mutex ); // If there's no frame, we're probably stopped... if ( frame == NULL ) continue; #ifdef DEINTERLACE_ON_NOT_NORMAL_SPEED // All non normal playback frames should be shown if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "_speed" ) != 1 ) mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 ); #endif // Get the image if ( !video_off ) { // Fetch width/height again width = mlt_properties_get_int( properties, "width" ); height = mlt_properties_get_int( properties, "height" ); mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-frame-render", frame, NULL ); mlt_frame_get_image( frame, &image, &format, &width, &height, 0 ); } mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 ); mlt_frame_close( frame ); // Tell a waiting thread (non-realtime main consumer thread) that we are done. pthread_mutex_lock( &priv->done_mutex ); pthread_cond_broadcast( &priv->done_cond ); pthread_mutex_unlock( &priv->done_mutex ); } mlt_events_fire( properties, "consumer-thread-stopped", NULL ); return NULL; } /** Start the read/render thread. * * \private \memberof mlt_consumer_s * \param self a consumer */ static void consumer_read_ahead_start( mlt_consumer self ) { consumer_private *priv = self->local; // We're running now priv->ahead = 1; // Create the frame queue priv->queue = mlt_deque_init( ); // Create the queue mutex pthread_mutex_init( &priv->queue_mutex, NULL ); // Create the condition pthread_cond_init( &priv->queue_cond, NULL ); // Create the read ahead if ( mlt_properties_get( MLT_CONSUMER_PROPERTIES( self ), "priority" ) ) { struct sched_param priority; priority.sched_priority = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( self ), "priority" ); pthread_attr_t thread_attributes; pthread_attr_init( &thread_attributes ); pthread_attr_setschedpolicy( &thread_attributes, SCHED_OTHER ); pthread_attr_setschedparam( &thread_attributes, &priority ); pthread_attr_setinheritsched( &thread_attributes, PTHREAD_EXPLICIT_SCHED ); pthread_attr_setscope( &thread_attributes, PTHREAD_SCOPE_SYSTEM ); if ( pthread_create( &priv->ahead_thread, &thread_attributes, consumer_read_ahead_thread, self ) < 0 ) pthread_create( &priv->ahead_thread, NULL, consumer_read_ahead_thread, self ); pthread_attr_destroy( &thread_attributes ); } else { pthread_create( &priv->ahead_thread, NULL, consumer_read_ahead_thread, self ); } priv->started = 1; } /** Start the worker threads. * * \private \memberof mlt_consumer_s * \param self a consumer */ static void consumer_work_start( mlt_consumer self ) { consumer_private *priv = self->local; int n = abs( priv->real_time ); pthread_t *thread = calloc( 1, sizeof( pthread_t ) * n ); // We're running now priv->ahead = 1; priv->threads = thread; // These keep track of the accelleration of frame dropping or recovery. priv->consecutive_dropped = 0; priv->consecutive_rendered = 0; // This is the position in the queue from which to look for a frame to process. // If we always start from the head, then we may likely not complete processing // before the frame is played out. priv->process_head = 0; // Create the queues priv->queue = mlt_deque_init(); priv->worker_threads = mlt_deque_init(); // Create the mutexes pthread_mutex_init( &priv->queue_mutex, NULL ); pthread_mutex_init( &priv->done_mutex, NULL ); // Create the conditions pthread_cond_init( &priv->queue_cond, NULL ); pthread_cond_init( &priv->done_cond, NULL ); // Create the read ahead if ( mlt_properties_get( MLT_CONSUMER_PROPERTIES( self ), "priority" ) ) { struct sched_param priority; pthread_attr_t thread_attributes; priority.sched_priority = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( self ), "priority" ); pthread_attr_init( &thread_attributes ); pthread_attr_setschedpolicy( &thread_attributes, SCHED_OTHER ); pthread_attr_setschedparam( &thread_attributes, &priority ); pthread_attr_setinheritsched( &thread_attributes, PTHREAD_EXPLICIT_SCHED ); pthread_attr_setscope( &thread_attributes, PTHREAD_SCOPE_SYSTEM ); while ( n-- ) { if ( pthread_create( thread, &thread_attributes, consumer_worker_thread, self ) < 0 ) if ( pthread_create( thread, NULL, consumer_worker_thread, self ) == 0 ) mlt_deque_push_back( priv->worker_threads, thread ); thread++; } pthread_attr_destroy( &thread_attributes ); } else { while ( n-- ) { if ( pthread_create( thread, NULL, consumer_worker_thread, self ) == 0 ) mlt_deque_push_back( priv->worker_threads, thread ); thread++; } } priv->started = 1; } /** Stop the read/render thread. * * \private \memberof mlt_consumer_s * \param self a consumer */ static void consumer_read_ahead_stop( mlt_consumer self ) { consumer_private *priv = self->local; // Make sure we're running // TODO improve support for atomic ops in general (see libavutil/atomic.h) #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 if ( __sync_val_compare_and_swap( &priv->started, 1, 0 ) ) { #else if ( priv->started ) { priv->started = 0; #endif // Inform thread to stop priv->ahead = 0; // Broadcast to the condition in case it's waiting pthread_mutex_lock( &priv->queue_mutex ); pthread_cond_broadcast( &priv->queue_cond ); pthread_mutex_unlock( &priv->queue_mutex ); // Broadcast to the put condition in case it's waiting pthread_mutex_lock( &priv->put_mutex ); pthread_cond_broadcast( &priv->put_cond ); pthread_mutex_unlock( &priv->put_mutex ); // Join the thread pthread_join( priv->ahead_thread, NULL ); // Destroy the frame queue mutex pthread_mutex_destroy( &priv->queue_mutex ); // Destroy the condition pthread_cond_destroy( &priv->queue_cond ); // Wipe the queue while ( mlt_deque_count( priv->queue ) ) mlt_frame_close( mlt_deque_pop_back( priv->queue ) ); // Close the queue mlt_deque_close( priv->queue ); } } /** Stop the worker threads. * * \private \memberof mlt_consumer_s * \param self a consumer */ static void consumer_work_stop( mlt_consumer self ) { consumer_private *priv = self->local; // Make sure we're running #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 if ( __sync_val_compare_and_swap( &priv->started, 1, 0 ) ) { #else if ( priv->started ) { priv->started = 0; #endif // Inform thread to stop priv->ahead = 0; // Broadcast to the queue condition in case it's waiting pthread_mutex_lock( &priv->queue_mutex ); pthread_cond_broadcast( &priv->queue_cond ); pthread_mutex_unlock( &priv->queue_mutex ); // Broadcast to the put condition in case it's waiting pthread_mutex_lock( &priv->put_mutex ); pthread_cond_broadcast( &priv->put_cond ); pthread_mutex_unlock( &priv->put_mutex ); // Broadcast to the done condition in case it's waiting pthread_mutex_lock( &priv->done_mutex ); pthread_cond_broadcast( &priv->done_cond ); pthread_mutex_unlock( &priv->done_mutex ); // Join the threads pthread_t *thread; while ( ( thread = mlt_deque_pop_back( priv->worker_threads ) ) ) pthread_join( *thread, NULL ); // Deallocate the array of threads if ( priv->threads ) free( priv->threads ); // Destroy the mutexes pthread_mutex_destroy( &priv->queue_mutex ); pthread_mutex_destroy( &priv->done_mutex ); // Destroy the conditions pthread_cond_destroy( &priv->queue_cond ); pthread_cond_destroy( &priv->done_cond ); // Wipe the queues while ( mlt_deque_count( priv->queue ) ) mlt_frame_close( mlt_deque_pop_back( priv->queue ) ); // Close the queues mlt_deque_close( priv->queue ); mlt_deque_close( priv->worker_threads ); } } /** Flush the read/render thread's buffer. * * \public \memberof mlt_consumer_s * \param self a consumer */ void mlt_consumer_purge( mlt_consumer self ) { if ( self ) { consumer_private *priv = self->local; pthread_mutex_lock( &priv->put_mutex ); if ( priv->put ) { mlt_frame_close( priv->put ); priv->put = NULL; } pthread_cond_broadcast( &priv->put_cond ); pthread_mutex_unlock( &priv->put_mutex ); if ( priv->started && priv->real_time ) pthread_mutex_lock( &priv->queue_mutex ); if ( self->purge ) self->purge( self ); while ( priv->started && mlt_deque_count( priv->queue ) ) mlt_frame_close( mlt_deque_pop_back( priv->queue ) ); if ( priv->started && priv->real_time ) { priv->is_purge = 1; pthread_cond_broadcast( &priv->queue_cond ); pthread_mutex_unlock( &priv->queue_mutex ); if ( abs( priv->real_time ) > 1 ) { pthread_mutex_lock( &priv->done_mutex ); pthread_cond_broadcast( &priv->done_cond ); pthread_mutex_unlock( &priv->done_mutex ); } } pthread_mutex_lock( &priv->put_mutex ); if ( priv->put ) { mlt_frame_close( priv->put ); priv->put = NULL; } pthread_cond_broadcast( &priv->put_cond ); pthread_mutex_unlock( &priv->put_mutex ); } } /** Use multiple worker threads and a work queue. */ static mlt_frame worker_get_frame( mlt_consumer self, mlt_properties properties ) { // Frame to return mlt_frame frame = NULL; consumer_private *priv = self->local; double fps = mlt_properties_get_double( properties, "fps" ); int threads = abs( priv->real_time ); int buffer = mlt_properties_get_int( properties, "_buffer" ); buffer = buffer > 0 ? buffer : mlt_properties_get_int( properties, "buffer" ); // This is a heuristic to determine a suitable minimum buffer size for the number of threads. int headroom = 2 + threads * threads; buffer = buffer < headroom ? headroom : buffer; // Start worker threads if not already started. if ( ! priv->ahead ) { int prefill = mlt_properties_get_int( properties, "prefill" ); prefill = prefill > 0 && prefill < buffer ? prefill : buffer; consumer_work_start( self ); // Fill the work queue. int i = buffer; while ( priv->ahead && i-- ) { frame = mlt_consumer_get_frame( self ); if ( frame ) { pthread_mutex_lock( &priv->queue_mutex ); mlt_deque_push_back( priv->queue, frame ); pthread_cond_signal( &priv->queue_cond ); pthread_mutex_unlock( &priv->queue_mutex ); } } // Wait for prefill while ( priv->ahead && first_unprocessed_frame( self ) < prefill ) { pthread_mutex_lock( &priv->done_mutex ); pthread_cond_wait( &priv->done_cond, &priv->done_mutex ); pthread_mutex_unlock( &priv->done_mutex ); } priv->process_head = threads; } // mlt_log_verbose( MLT_CONSUMER_SERVICE(self), "size %d done count %d work count %d process_head %d\n", // threads, first_unprocessed_frame( self ), mlt_deque_count( priv->queue ), priv->process_head ); // Feed the work queue while ( priv->ahead && mlt_deque_count( priv->queue ) < buffer ) { frame = mlt_consumer_get_frame( self ); if ( frame ) { pthread_mutex_lock( &priv->queue_mutex ); mlt_deque_push_back( priv->queue, frame ); pthread_cond_signal( &priv->queue_cond ); pthread_mutex_unlock( &priv->queue_mutex ); } } // Wait if not realtime. while ( priv->ahead && priv->real_time < 0 && !priv->is_purge && !( mlt_properties_get_int( MLT_FRAME_PROPERTIES( MLT_FRAME( mlt_deque_peek_front( priv->queue ) ) ), "rendered" ) ) ) { pthread_mutex_lock( &priv->done_mutex ); pthread_cond_wait( &priv->done_cond, &priv->done_mutex ); pthread_mutex_unlock( &priv->done_mutex ); } // Get the frame from the queue. pthread_mutex_lock( &priv->queue_mutex ); frame = mlt_deque_pop_front( priv->queue ); pthread_mutex_unlock( &priv->queue_mutex ); if ( ! frame ) { priv->is_purge = 0; return frame; } // Adapt the worker process head to the runtime conditions. if ( priv->real_time > 0 ) { if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "rendered" ) ) { priv->consecutive_dropped = 0; if ( priv->process_head > threads && priv->consecutive_rendered >= priv->process_head ) priv->process_head--; else priv->consecutive_rendered++; } else { priv->consecutive_rendered = 0; if ( priv->process_head < buffer - threads && priv->consecutive_dropped > threads ) priv->process_head++; else priv->consecutive_dropped++; } // mlt_log_verbose( MLT_CONSUMER_SERVICE(self), "dropped %d rendered %d process_head %d\n", // priv->consecutive_dropped, priv->consecutive_rendered, priv->process_head ); // Check for too many consecutively dropped frames if ( priv->consecutive_dropped > mlt_properties_get_int( properties, "drop_max" ) ) { int orig_buffer = mlt_properties_get_int( properties, "buffer" ); int prefill = mlt_properties_get_int( properties, "prefill" ); mlt_log_verbose( self, "too many frames dropped - " ); // If using a default low-latency buffer level (SDL) and below the limit if ( ( orig_buffer == 1 || prefill == 1 ) && buffer < (threads + 1) * 10 ) { // Auto-scale the buffer to compensate mlt_log_verbose( self, "increasing buffer to %d\n", buffer + threads ); mlt_properties_set_int( properties, "_buffer", buffer + threads ); priv->consecutive_dropped = fps / 2; } else { // Tell the consumer to render it mlt_log_verbose( self, "forcing next frame\n" ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 ); priv->consecutive_dropped = 0; } } } if ( priv->is_purge ) { priv->is_purge = 0; mlt_frame_close( frame ); frame = NULL; } return frame; } /** Get the next frame from the producer connected to a consumer. * * Typically, one uses this instead of \p mlt_consumer_get_frame to make * the asynchronous/real-time behavior configurable at runtime. * You should close the frame returned from this when you are done with it. * * \public \memberof mlt_consumer_s * \param self a consumer * \return a frame */ mlt_frame mlt_consumer_rt_frame( mlt_consumer self ) { // Frame to return mlt_frame frame = NULL; // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); consumer_private *priv = self->local; // Check if the user has requested real time or not if ( priv->real_time > 1 || priv->real_time < -1 ) { // see above return worker_get_frame( self, properties ); } else if ( priv->real_time == 1 || priv->real_time == -1 ) { int size = 1; // Is the read ahead running? if ( priv->ahead == 0 ) { int buffer = mlt_properties_get_int( properties, "buffer" ); int prefill = mlt_properties_get_int( properties, "prefill" ); consumer_read_ahead_start( self ); if ( buffer > 1 ) size = prefill > 0 && prefill < buffer ? prefill : buffer; } // Get frame from queue pthread_mutex_lock( &priv->queue_mutex ); while( priv->ahead && mlt_deque_count( priv->queue ) < size ) pthread_cond_wait( &priv->queue_cond, &priv->queue_mutex ); frame = mlt_deque_pop_front( priv->queue ); pthread_cond_broadcast( &priv->queue_cond ); pthread_mutex_unlock( &priv->queue_mutex ); } else // real_time == 0 { if ( !priv->ahead ) { priv->ahead = 1; mlt_events_fire( properties, "consumer-thread-started", NULL ); } // Get the frame in non real time frame = mlt_consumer_get_frame( self ); // This isn't true, but from the consumers perspective it is if ( frame != NULL ) mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 ); } return frame; } /** Callback for the implementation to indicate a stopped condition. * * \public \memberof mlt_consumer_s * \param self a consumer */ void mlt_consumer_stopped( mlt_consumer self ) { mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( self ), "running", 0 ); mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-stopped", NULL ); mlt_event_unblock( ( ( consumer_private* ) self->local )->event_listener ); } /** Stop the consumer. * * \public \memberof mlt_consumer_s * \param self a consumer * \return true if there was an error */ int mlt_consumer_stop( mlt_consumer self ) { // Get the properies mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); consumer_private *priv = self->local; // Just in case... mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_DEBUG, "stopping put waiting\n" ); pthread_mutex_lock( &priv->put_mutex ); priv->put_active = 0; pthread_cond_broadcast( &priv->put_cond ); pthread_mutex_unlock( &priv->put_mutex ); // Stop the consumer mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_DEBUG, "stopping consumer\n" ); // Cancel the read ahead threads priv->ahead = 0; if ( priv->started ) { // Unblock the consumer calling mlt_consumer_rt_frame pthread_mutex_lock( &priv->queue_mutex ); pthread_cond_broadcast( &priv->queue_cond ); pthread_mutex_unlock( &priv->queue_mutex ); } // Invoke the child callback if ( self->stop != NULL ) self->stop( self ); // Check if the user has requested real time or not and stop if necessary mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_DEBUG, "stopping read_ahead\n" ); if ( abs( priv->real_time ) == 1 ) consumer_read_ahead_stop( self ); else if ( abs( priv->real_time ) > 1 ) consumer_work_stop( self ); // Kill the test card mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL ); // Check and run a post command if ( mlt_properties_get( properties, "post" ) ) if (system( mlt_properties_get( properties, "post" ) ) == -1 ) mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_ERROR, "system(%s) failed!\n", mlt_properties_get( properties, "post" ) ); mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_DEBUG, "stopped\n" ); return 0; } /** Determine if the consumer is stopped. * * \public \memberof mlt_consumer_s * \param self a consumer * \return true if the consumer is stopped */ int mlt_consumer_is_stopped( mlt_consumer self ) { // Check if the consumer is stopped if ( self && self->is_stopped ) return self->is_stopped( self ); return 0; } /** Close and destroy the consumer. * * \public \memberof mlt_consumer_s * \param self a consumer */ void mlt_consumer_close( mlt_consumer self ) { if ( self != NULL && mlt_properties_dec_ref( MLT_CONSUMER_PROPERTIES( self ) ) <= 0 ) { // Get the childs close function void ( *consumer_close )( ) = self->close; if ( consumer_close ) { // Just in case... //mlt_consumer_stop( self ); self->close = NULL; consumer_close( self ); } else { consumer_private *priv = self->local; // Make sure it only gets called once self->parent.close = NULL; // Destroy the push mutex and condition pthread_mutex_destroy( &priv->put_mutex ); pthread_cond_destroy( &priv->put_cond ); mlt_service_close( &self->parent ); free( priv ); } } } /** Get the position of the last frame shown. * * \public \memberof mlt_consumer_s * \param consumer a consumer * \return the position */ mlt_position mlt_consumer_position( mlt_consumer consumer ) { return ( ( consumer_private* ) consumer->local )->position; } mlt-0.9.0/src/framework/mlt_consumer.h000066400000000000000000000152401215300731300177550ustar00rootroot00000000000000/** * \file mlt_consumer.h * \brief abstraction for all consumer services * \see mlt_consumer_s * * Copyright (C) 2003-2010 Ushodaya Enterprises Limited * \author Charles Yates * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_CONSUMER_H_ #define _MLT_CONSUMER_H_ #include "mlt_service.h" #include "mlt_events.h" #include /** \brief Consumer abstract service class * * A consumer is a service that pulls audio and video from the connected * producers, filters, and transitions. Typically a consumer is used to * output audio and/or video to a device, file, or socket. * * \extends mlt_service_s * \properties \em rescale the scaling algorithm to pass on to all scaling * filters, defaults to "bilinear" * \properties \em buffer the number of frames to use in the asynchronous * render thread, defaults to 25 * \properties \em prefill the number of frames to render before commencing * output when real_time <> 0, defaults to the size of buffer * \properties \em drop_max the maximum number of consecutively dropped frames, defaults to 5 * \properties \em frequency the audio sample rate to use in Hertz, defaults to 48000 * \properties \em channels the number of audio channels to use, defaults to 2 * \properties \em real_time the asynchronous behavior: 1 (default) for asynchronous * with frame dropping, -1 for asynchronous without frame dropping, 0 to disable (synchronous) * \properties \em test_card the name of a resource to use as the test card, defaults to * environment variable MLT_TEST_CARD. If undefined, the hard-coded default test card is * white silence. A test card is what appears when nothing is produced. * \event \em consumer-frame-show Subclass implementations fire this immediately after showing a frame * or when a frame should be shown (if audio-only consumer). * \event \em consumer-frame-render The base class fires this immediately before rendering a frame. * \event \em consumer-thread-started The base class fires when beginning execution of a rendering thread. * \event \em consumer-thread-stopped The base class fires when a rendering thread has ended. * \event \em consumer-stopped This is fired when the subclass implementation calls mlt_consumer_stopped(). * \properties \em fps video frames per second as floating point (read only) * \properties \em frame_rate_num the numerator of the video frame rate, overrides \p mlt_profile_s * \properties \em frame_rate_den the denominator of the video frame rate, overrides \p mlt_profile_s * \properties \em width the horizontal video resolution, overrides \p mlt_profile_s * \properties \em height the vertical video resolution, overrides \p mlt_profile_s * \properties \em progressive a flag that indicates if the video is interlaced * or progressive, overrides \p mlt_profile_s * \properties \em aspect_ratio the video sample (pixel) aspect ratio as floating point (read only) * \properties \em sample_aspect_num the numerator of the sample aspect ratio, overrides \p mlt_profile_s * \properties \em sample_aspect_den the denominator of the sample aspect ratio, overrides \p mlt_profile_s * \properties \em display_ratio the video frame aspect ratio as floating point (read only) * \properties \em display_aspect_num the numerator of the video frame aspect ratio, overrides \p mlt_profile_s * \properties \em display_aspect_den the denominator of the video frame aspect ratio, overrides \p mlt_profile_s * \properties \em priority the OS scheduling priority for the render threads when real_time is not 0. * \properties \em top_field_first when not progressive, whether interlace field order is top-field-first, defaults to 0. * Set this to -1 if the consumer does not care about the field order. * \properties \em mlt_image_format the image format to request in rendering threads, defaults to yuv422 * \properties \em mlt_audio_format the audio format to request in rendering threads, defaults to S16 */ struct mlt_consumer_s { /** A consumer is a service. */ struct mlt_service_s parent; /** Start the consumer to pull frames (virtual function). * * \param mlt_consumer a consumer * \return true if there was an error */ int ( *start )( mlt_consumer ); /** Stop the consumer (virtual function). * * \param mlt_consumer a consumer * \return true if there was an error */ int ( *stop )( mlt_consumer ); /** Get whether the consumer is running or stopped (virtual function). * * \param mlt_consumer a consumer * \return true if the consumer is stopped */ int ( *is_stopped )( mlt_consumer ); /** Purge the consumer of buffered data (virtual function). * * \param mlt_consumer a consumer */ void ( *purge )( mlt_consumer ); /** The destructor virtual function * * \param mlt_consumer a consumer */ void ( *close )( mlt_consumer ); void *local; /**< \private instance object */ void *child; /**< \private the object of a subclass */ }; #define MLT_CONSUMER_SERVICE( consumer ) ( &( consumer )->parent ) #define MLT_CONSUMER_PROPERTIES( consumer ) MLT_SERVICE_PROPERTIES( MLT_CONSUMER_SERVICE( consumer ) ) extern int mlt_consumer_init( mlt_consumer self, void *child, mlt_profile profile ); extern mlt_consumer mlt_consumer_new( mlt_profile profile ); extern mlt_service mlt_consumer_service( mlt_consumer self ); extern mlt_properties mlt_consumer_properties( mlt_consumer self ); extern int mlt_consumer_connect( mlt_consumer self, mlt_service producer ); extern int mlt_consumer_start( mlt_consumer self ); extern void mlt_consumer_purge( mlt_consumer self ); extern int mlt_consumer_put_frame( mlt_consumer self, mlt_frame frame ); extern mlt_frame mlt_consumer_get_frame( mlt_consumer self ); extern mlt_frame mlt_consumer_rt_frame( mlt_consumer self ); extern int mlt_consumer_stop( mlt_consumer self ); extern int mlt_consumer_is_stopped( mlt_consumer self ); extern void mlt_consumer_stopped( mlt_consumer self ); extern void mlt_consumer_close( mlt_consumer ); extern mlt_position mlt_consumer_position( mlt_consumer ); #endif mlt-0.9.0/src/framework/mlt_deque.c000066400000000000000000000215531215300731300172240ustar00rootroot00000000000000/** * \file mlt_deque.c * \brief double ended queue * \see mlt_deque_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // Local header files #include "mlt_deque.h" // System header files #include #include /** \brief Deque entry class * */ typedef union { void *addr; int value; double floating; } deque_entry; /** \brief Double-Ended Queue (deque) class * * The double-ended queue is a very versatile data structure. MLT uses it as * list, stack, and circular queue. */ struct mlt_deque_s { deque_entry *list; int size; int count; }; /** Create a deque. * * \public \memberof mlt_deque_s * \return a new deque */ mlt_deque mlt_deque_init( ) { mlt_deque self = calloc( 1, sizeof( struct mlt_deque_s ) ); return self; } /** Return the number of items in the deque. * * \public \memberof mlt_deque_s * \param self a deque * \return the number of items */ int mlt_deque_count( mlt_deque self ) { if ( self ) return self->count; else return 0; } /** Allocate space on the deque. * * \private \memberof mlt_deque_s * \param self a deque * \return true if there was an error */ static int mlt_deque_allocate( mlt_deque self ) { if ( self->count == self->size ) { self->list = realloc( self->list, sizeof( deque_entry ) * ( self->size + 20 ) ); self->size += 20; } return self->list == NULL; } /** Push an item to the end. * * \public \memberof mlt_deque_s * \param self a deque * \param item an opaque pointer * \return true if there was an error */ int mlt_deque_push_back( mlt_deque self, void *item ) { int error = mlt_deque_allocate( self ); if ( error == 0 ) self->list[ self->count ++ ].addr = item; return error; } /** Pop an item. * * \public \memberof mlt_deque_s * \param self a pointer * \return an opaque pointer */ void *mlt_deque_pop_back( mlt_deque self ) { return self->count > 0 ? self->list[ -- self->count ].addr : NULL; } /** Queue an item at the start. * * \public \memberof mlt_deque_s * \param self a deque * \param item an opaque pointer * \return true if there was an error */ int mlt_deque_push_front( mlt_deque self, void *item ) { int error = mlt_deque_allocate( self ); if ( error == 0 ) { memmove( &self->list[ 1 ], self->list, ( self->count ++ ) * sizeof( deque_entry ) ); self->list[ 0 ].addr = item; } return error; } /** Remove an item from the start. * * \public \memberof mlt_deque_s * \param self a pointer * \return an opaque pointer */ void *mlt_deque_pop_front( mlt_deque self ) { void *item = NULL; if ( self->count > 0 ) { item = self->list[ 0 ].addr; memmove( self->list, &self->list[ 1 ], ( -- self->count ) * sizeof( deque_entry ) ); } return item; } /** Inquire on item at back of deque but don't remove. * * \public \memberof mlt_deque_s * \param self a deque * \return an opaque pointer */ void *mlt_deque_peek_back( mlt_deque self ) { return self->count > 0 ? self->list[ self->count - 1 ].addr : NULL; } /** Inquire on item at front of deque but don't remove. * * \public \memberof mlt_deque_s * \param self a deque * \return an opaque pointer */ void *mlt_deque_peek_front( mlt_deque self ) { return self->count > 0 ? self->list[ 0 ].addr : NULL; } /** Inquire on item in deque but don't remove. * * \public \memberof mlt_deque_s * \param self a deque * \param index the position in the deque * \return an opaque pointer */ void *mlt_deque_peek( mlt_deque self, int index ) { return self->count > index ? self->list[ index ].addr : NULL; } /** Insert an item in a sorted fashion. * * Optimized for the equivalent of \p mlt_deque_push_back. * * \public \memberof mlt_deque_s * \param self a deque * \param item an opaque pointer * \param cmp a function pointer to the comparison function * \return true if there was an error */ int mlt_deque_insert( mlt_deque self, void *item, mlt_deque_compare cmp ) { int error = mlt_deque_allocate( self ); if ( error == 0 ) { int n = self->count + 1; while ( --n ) if ( cmp( item, self->list[ n - 1 ].addr ) >= 0 ) break; memmove( &self->list[ n + 1 ], &self->list[ n ], ( self->count - n ) * sizeof( deque_entry ) ); self->list[ n ].addr = item; self->count++; } return error; } /** Push an integer to the end. * * \public \memberof mlt_deque_s * \param self a deque * \param item an integer * \return true if there was an error */ int mlt_deque_push_back_int( mlt_deque self, int item ) { int error = mlt_deque_allocate( self ); if ( error == 0 ) self->list[ self->count ++ ].value = item; return error; } /** Pop an integer. * * \public \memberof mlt_deque_s * \param self a deque * \return an integer */ int mlt_deque_pop_back_int( mlt_deque self ) { return self->count > 0 ? self->list[ -- self->count ].value : 0; } /** Queue an integer at the start. * * \public \memberof mlt_deque_s * \param self a deque * \param item an integer * \return true if there was an error */ int mlt_deque_push_front_int( mlt_deque self, int item ) { int error = mlt_deque_allocate( self ); if ( error == 0 ) { memmove( &self->list[ 1 ], self->list, ( self->count ++ ) * sizeof( deque_entry ) ); self->list[ 0 ].value = item; } return error; } /** Remove an integer from the start. * * \public \memberof mlt_deque_s * \param self a deque * \return an integer */ int mlt_deque_pop_front_int( mlt_deque self ) { int item = 0; if ( self->count > 0 ) { item = self->list[ 0 ].value; memmove( self->list, &self->list[ 1 ], ( -- self->count ) * sizeof( deque_entry ) ); } return item; } /** Inquire on an integer at back of deque but don't remove. * * \public \memberof mlt_deque_s * \param self a deque * \return an integer */ int mlt_deque_peek_back_int( mlt_deque self ) { return self->count > 0 ? self->list[ self->count - 1 ].value : 0; } /** Inquire on an integer at front of deque but don't remove. * * \public \memberof mlt_deque_s * \param self a deque * \return an integer */ int mlt_deque_peek_front_int( mlt_deque self ) { return self->count > 0 ? self->list[ 0 ].value : 0; } /** Push a double float to the end. * * \public \memberof mlt_deque_s * \param self a deque * \param item a double float * \return true if there was an error */ int mlt_deque_push_back_double( mlt_deque self, double item ) { int error = mlt_deque_allocate( self ); if ( error == 0 ) self->list[ self->count ++ ].floating = item; return error; } /** Pop a double float. * * \public \memberof mlt_deque_s * \param self a deque * \return a double float */ double mlt_deque_pop_back_double( mlt_deque self ) { return self->count > 0 ? self->list[ -- self->count ].floating : 0; } /** Queue a double float at the start. * * \public \memberof mlt_deque_s * \param self a deque * \param item a double float * \return true if there was an error */ int mlt_deque_push_front_double( mlt_deque self, double item ) { int error = mlt_deque_allocate( self ); if ( error == 0 ) { memmove( &self->list[ 1 ], self->list, ( self->count ++ ) * sizeof( deque_entry ) ); self->list[ 0 ].floating = item; } return error; } /** Remove a double float from the start. * * \public \memberof mlt_deque_s * \param self a deque * \return a double float */ double mlt_deque_pop_front_double( mlt_deque self ) { double item = 0; if ( self->count > 0 ) { item = self->list[ 0 ].floating; memmove( self->list, &self->list[ 1 ], ( -- self->count ) * sizeof( deque_entry ) ); } return item; } /** Inquire on a double float at back of deque but don't remove. * * \public \memberof mlt_deque_s * \param self a deque * \return a double float */ double mlt_deque_peek_back_double( mlt_deque self ) { return self->count > 0 ? self->list[ self->count - 1 ].floating : 0; } /** Inquire on a double float at front of deque but don't remove. * * \public \memberof mlt_deque_s * \param self a deque * \return a double float */ double mlt_deque_peek_front_double( mlt_deque self ) { return self->count > 0 ? self->list[ 0 ].floating : 0; } /** Destroy the queue. * * \public \memberof mlt_deque_s * \param self a deque */ void mlt_deque_close( mlt_deque self ) { free( self->list ); free( self ); } mlt-0.9.0/src/framework/mlt_deque.h000066400000000000000000000050571215300731300172320ustar00rootroot00000000000000/** * \file mlt_deque.h * \brief double ended queue * \see mlt_deque_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_DEQUE_H_ #define _MLT_DEQUE_H_ #include "mlt_types.h" /** The callback function used to compare items for insert sort. * * \public \memberof mlt_deque_s * \param a the first object * \param b the second object * \returns 0 if equal, < 0 if a < b, or > 0 if a > b */ typedef int ( *mlt_deque_compare )( void *a, void *b ); extern mlt_deque mlt_deque_init( ); extern int mlt_deque_count( mlt_deque self ); extern int mlt_deque_push_back( mlt_deque self, void *item ); extern void *mlt_deque_pop_back( mlt_deque self ); extern int mlt_deque_push_front( mlt_deque self, void *item ); extern void *mlt_deque_pop_front( mlt_deque self ); extern void *mlt_deque_peek_back( mlt_deque self ); extern void *mlt_deque_peek_front( mlt_deque self ); extern void *mlt_deque_peek( mlt_deque self, int index ); extern int mlt_deque_insert( mlt_deque self, void *item, mlt_deque_compare ); extern int mlt_deque_push_back_int( mlt_deque self, int item ); extern int mlt_deque_pop_back_int( mlt_deque self ); extern int mlt_deque_push_front_int( mlt_deque self, int item ); extern int mlt_deque_pop_front_int( mlt_deque self ); extern int mlt_deque_peek_back_int( mlt_deque self ); extern int mlt_deque_peek_front_int( mlt_deque self ); extern int mlt_deque_push_back_double( mlt_deque self, double item ); extern double mlt_deque_pop_back_double( mlt_deque self ); extern int mlt_deque_push_front_double( mlt_deque self, double item ); extern double mlt_deque_pop_front_double( mlt_deque self ); extern double mlt_deque_peek_back_double( mlt_deque self ); extern double mlt_deque_peek_front_double( mlt_deque self ); extern void mlt_deque_close( mlt_deque self ); #endif mlt-0.9.0/src/framework/mlt_events.c000066400000000000000000000304561215300731300174270ustar00rootroot00000000000000/** * \file mlt_events.c * \brief event handling * \see mlt_events_struct * * Copyright (C) 2004-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include "mlt_properties.h" #include "mlt_events.h" /* Memory leak checks. */ #undef _MLT_EVENT_CHECKS_ #ifdef _MLT_EVENT_CHECKS_ static int events_created = 0; static int events_destroyed = 0; #endif /** \brief Events class * * Events provide messages and notifications between services and the application. * A service can register an event and fire/send it upon certain conditions or times. * Likewise, a service or an application can listen/receive specific events on specific * services. */ struct mlt_events_struct { mlt_properties owner; mlt_properties list; }; typedef struct mlt_events_struct *mlt_events; /** \brief Event class * */ struct mlt_event_struct { mlt_events owner; int ref_count; int block_count; mlt_listener listener; void *service; }; /** Increment the reference count on self event. * * \public \memberof mlt_event_struct * \param self an event */ void mlt_event_inc_ref( mlt_event self ) { if ( self != NULL ) self->ref_count ++; } /** Increment the block count on self event. * * \public \memberof mlt_event_struct * \param self an event */ void mlt_event_block( mlt_event self ) { if ( self != NULL && self->owner != NULL ) self->block_count ++; } /** Decrement the block count on self event. * * \public \memberof mlt_event_struct * \param self an event */ void mlt_event_unblock( mlt_event self ) { if ( self != NULL && self->owner != NULL ) self->block_count --; } /** Close self event. * * \public \memberof mlt_event_struct * \param self an event */ void mlt_event_close( mlt_event self ) { if ( self != NULL ) { if ( -- self->ref_count == 1 ) self->owner = NULL; if ( self->ref_count <= 0 ) { #ifdef _MLT_EVENT_CHECKS_ mlt_log( NULL, MLT_LOG_DEBUG, "Events created %d, destroyed %d\n", events_created, ++events_destroyed ); #endif free( self ); } } } /* Forward declaration to private functions. */ static mlt_events mlt_events_fetch( mlt_properties ); static void mlt_events_store( mlt_properties, mlt_events ); static void mlt_events_close( mlt_events ); /** Initialise the events structure. * * \public \memberof mlt_events_struct * \param self a properties list */ void mlt_events_init( mlt_properties self ) { mlt_events events = mlt_events_fetch( self ); if ( events == NULL ) { events = calloc( 1, sizeof( struct mlt_events_struct ) ); events->list = mlt_properties_new( ); mlt_events_store( self, events ); } } /** Register an event and transmitter. * * \public \memberof mlt_events_struct * \param self a properties list * \param id the name of an event * \param transmitter the callback function to send an event message * \return true if there was an error */ int mlt_events_register( mlt_properties self, const char *id, mlt_transmitter transmitter ) { int error = 1; mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { mlt_properties list = events->list; char temp[ 128 ]; error = mlt_properties_set_data( list, id, transmitter, 0, NULL, NULL ); sprintf( temp, "list:%s", id ); if ( mlt_properties_get_data( list, temp, NULL ) == NULL ) mlt_properties_set_data( list, temp, mlt_properties_new( ), 0, ( mlt_destructor )mlt_properties_close, NULL ); } return error; } /** Fire an event. * * This takes a variable number of arguments to supply to the listener. * \public \memberof mlt_events_struct * \param self a properties list * \param id the name of an event */ void mlt_events_fire( mlt_properties self, const char *id, ... ) { mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { int i = 0; va_list alist; void *args[ 10 ]; mlt_properties list = events->list; mlt_properties listeners = NULL; char temp[ 128 ]; mlt_transmitter transmitter = mlt_properties_get_data( list, id, NULL ); sprintf( temp, "list:%s", id ); listeners = mlt_properties_get_data( list, temp, NULL ); va_start( alist, id ); do args[ i ] = va_arg( alist, void * ); while( args[ i ++ ] != NULL ); va_end( alist ); if ( listeners != NULL ) { for ( i = 0; i < mlt_properties_count( listeners ); i ++ ) { mlt_event event = mlt_properties_get_data_at( listeners, i, NULL ); if ( event != NULL && event->owner != NULL && event->block_count == 0 ) { if ( transmitter != NULL ) transmitter( event->listener, event->owner, event->service, args ); else event->listener( event->owner, event->service ); } } } } } /** Register a listener. * * \public \memberof mlt_events_struct * \param self a properties list * \param service an opaque pointer * \param id the name of the event to listen for * \param listener the callback to receive an event message * \return */ mlt_event mlt_events_listen( mlt_properties self, void *service, const char *id, mlt_listener listener ) { mlt_event event = NULL; mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { mlt_properties list = events->list; mlt_properties listeners = NULL; char temp[ 128 ]; sprintf( temp, "list:%s", id ); listeners = mlt_properties_get_data( list, temp, NULL ); if ( listeners != NULL ) { int first_null = -1; int i = 0; for ( i = 0; event == NULL && i < mlt_properties_count( listeners ); i ++ ) { mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL ); if ( entry != NULL && entry->owner != NULL ) { if ( entry->service == service && entry->listener == listener ) event = entry; } else if ( ( entry == NULL || entry->owner == NULL ) && first_null == -1 ) { first_null = i; } } if ( event == NULL ) { event = malloc( sizeof( struct mlt_event_struct ) ); if ( event != NULL ) { #ifdef _MLT_EVENT_CHECKS_ events_created ++; #endif sprintf( temp, "%d", first_null == -1 ? mlt_properties_count( listeners ) : first_null ); event->owner = events; event->ref_count = 0; event->block_count = 0; event->listener = listener; event->service = service; mlt_properties_set_data( listeners, temp, event, 0, ( mlt_destructor )mlt_event_close, NULL ); mlt_event_inc_ref( event ); } } } } return event; } /** Block all events for a given service. * * \public \memberof mlt_events_struct * \param self a properties list * \param service an opaque pointer */ void mlt_events_block( mlt_properties self, void *service ) { mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { int i = 0, j = 0; mlt_properties list = events->list; for ( j = 0; j < mlt_properties_count( list ); j ++ ) { char *temp = mlt_properties_get_name( list, j ); if ( !strncmp( temp, "list:", 5 ) ) { mlt_properties listeners = mlt_properties_get_data( list, temp, NULL ); for ( i = 0; i < mlt_properties_count( listeners ); i ++ ) { mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL ); if ( entry != NULL && entry->service == service ) mlt_event_block( entry ); } } } } } /** Unblock all events for a given service. * * \public \memberof mlt_events_struct * \param self a properties list * \param service an opaque pointer */ void mlt_events_unblock( mlt_properties self, void *service ) { mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { int i = 0, j = 0; mlt_properties list = events->list; for ( j = 0; j < mlt_properties_count( list ); j ++ ) { char *temp = mlt_properties_get_name( list, j ); if ( !strncmp( temp, "list:", 5 ) ) { mlt_properties listeners = mlt_properties_get_data( list, temp, NULL ); for ( i = 0; i < mlt_properties_count( listeners ); i ++ ) { mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL ); if ( entry != NULL && entry->service == service ) mlt_event_unblock( entry ); } } } } } /** Disconnect all events for a given service. * * \public \memberof mlt_events_struct * \param self a properties list * \param service an opaque pointer */ void mlt_events_disconnect( mlt_properties self, void *service ) { mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { int i = 0, j = 0; mlt_properties list = events->list; for ( j = 0; j < mlt_properties_count( list ); j ++ ) { char *temp = mlt_properties_get_name( list, j ); if ( !strncmp( temp, "list:", 5 ) ) { mlt_properties listeners = mlt_properties_get_data( list, temp, NULL ); for ( i = 0; i < mlt_properties_count( listeners ); i ++ ) { mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL ); char *name = mlt_properties_get_name( listeners, i ); if ( entry != NULL && entry->service == service ) mlt_properties_set_data( listeners, name, NULL, 0, NULL, NULL ); } } } } } /** \brief private to mlt_events_struct, used by mlt_events_wait_for() */ typedef struct { pthread_cond_t cond; pthread_mutex_t mutex; } condition_pair; /** The event listener callback for the wait functions. * * \private \memberof mlt_events_struct * \param self a properties list * \param pair a condition pair */ static void mlt_events_listen_for( mlt_properties self, condition_pair *pair ) { pthread_mutex_lock( &pair->mutex ); pthread_cond_signal( &pair->cond ); pthread_mutex_unlock( &pair->mutex ); } /** Prepare to wait for an event. * * \public \memberof mlt_events_struct * \param self a properties list * \param id the name of the event to wait for * \return an event */ mlt_event mlt_events_setup_wait_for( mlt_properties self, const char *id ) { condition_pair *pair = malloc( sizeof( condition_pair ) ); pthread_cond_init( &pair->cond, NULL ); pthread_mutex_init( &pair->mutex, NULL ); pthread_mutex_lock( &pair->mutex ); return mlt_events_listen( self, pair, id, ( mlt_listener )mlt_events_listen_for ); } /** Wait for an event. * * \public \memberof mlt_events_struct * \param self a properties list * \param event an event */ void mlt_events_wait_for( mlt_properties self, mlt_event event ) { if ( event != NULL ) { condition_pair *pair = event->service; pthread_cond_wait( &pair->cond, &pair->mutex ); } } /** Cleanup after waiting for an event. * * \public \memberof mlt_events_struct * \param self a properties list * \param event an event */ void mlt_events_close_wait_for( mlt_properties self, mlt_event event ) { if ( event != NULL ) { condition_pair *pair = event->service; event->owner = NULL; pthread_mutex_unlock( &pair->mutex ); pthread_mutex_destroy( &pair->mutex ); pthread_cond_destroy( &pair->cond ); free( pair ); } } /** Fetch the events object. * * \private \memberof mlt_events_struct * \param self a properties list * \return an events object */ static mlt_events mlt_events_fetch( mlt_properties self ) { mlt_events events = NULL; if ( self != NULL ) events = mlt_properties_get_data( self, "_events", NULL ); return events; } /** Store the events object. * * \private \memberof mlt_events_struct * \param self a properties list * \param events an events object */ static void mlt_events_store( mlt_properties self, mlt_events events ) { if ( self != NULL && events != NULL ) mlt_properties_set_data( self, "_events", events, 0, ( mlt_destructor )mlt_events_close, NULL ); } /** Close the events object. * * \private \memberof mlt_events_struct * \param events an events object */ static void mlt_events_close( mlt_events events ) { if ( events != NULL ) { mlt_properties_close( events->list ); free( events ); } } mlt-0.9.0/src/framework/mlt_events.h000066400000000000000000000046661215300731300174400ustar00rootroot00000000000000/** * \file mlt_events.h * \brief event handling * \see mlt_events_struct * * Copyright (C) 2004-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_EVENTS_H_ #define _MLT_EVENTS_H_ #include "mlt_types.h" #if GCC_VERSION >= 40000 typedef void ( *mlt_transmitter )( void *, ... ); typedef void ( *mlt_listener )( void *, ... ); #else /** callback function to send an event message * */ typedef void ( *mlt_transmitter )( ); /** event handler when receiving an event message * \param the properties object on which the event was registered * \param an opaque pointer to a service or really an object * \param variable args supplied by the transmitter */ typedef void ( *mlt_listener )( ); #endif extern void mlt_events_init( mlt_properties self ); extern int mlt_events_register( mlt_properties self, const char *id, mlt_transmitter transmitter ); extern void mlt_events_fire( mlt_properties self, const char *id, ... ); extern mlt_event mlt_events_listen( mlt_properties self, void *service, const char *id, mlt_listener listener ); extern void mlt_events_block( mlt_properties self, void *service ); extern void mlt_events_unblock( mlt_properties self, void *service ); extern void mlt_events_disconnect( mlt_properties self, void *service ); extern mlt_event mlt_events_setup_wait_for( mlt_properties self, const char *id ); extern void mlt_events_wait_for( mlt_properties self, mlt_event event ); extern void mlt_events_close_wait_for( mlt_properties self, mlt_event event ); extern void mlt_event_inc_ref( mlt_event self ); extern void mlt_event_block( mlt_event self ); extern void mlt_event_unblock( mlt_event self ); extern void mlt_event_close( mlt_event self ); #endif mlt-0.9.0/src/framework/mlt_factory.c000066400000000000000000000335301215300731300175660ustar00rootroot00000000000000/** * \file mlt_factory.c * \brief the factory method interfaces * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt.h" #include "mlt_repository.h" #include #include #include #include #include #ifdef WIN32 #include /** the default subdirectory of the libdir for holding modules (plugins) */ #define PREFIX_LIB "\\lib\\mlt" /** the default subdirectory of the install prefix for holding module (plugin) data */ #define PREFIX_DATA "\\share\\mlt" #elif defined(__DARWIN__) && defined(RELOCATABLE) #include /** the default subdirectory of the libdir for holding modules (plugins) */ #define PREFIX_LIB "/lib/mlt" /** the default subdirectory of the install prefix for holding module (plugin) data */ #define PREFIX_DATA "/share/mlt" #endif /** holds the full path to the modules directory - initialized and retained for the entire session */ static char *mlt_directory = NULL; /** a global properties list for holding environment config data and things needing session-oriented cleanup */ static mlt_properties global_properties = NULL; /** the global repository singleton */ static mlt_repository repository = NULL; /** the events object for the factory events */ static mlt_properties event_object = NULL; /** for tracking the unique_id set on each constructed service */ static int unique_id = 0; /* Event transmitters. */ /** the -create-request event transmitter * * \param listener * \param owner * \param self * \param args */ static void mlt_factory_create_request( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) { if ( listener != NULL ) listener( owner, self, ( char * )args[ 0 ], ( char * )args[ 1 ], ( mlt_service * )args[ 2 ] ); } /** the -create-done event transmitter * * \param listener * \param owner * \param self * \param args */ static void mlt_factory_create_done( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) { if ( listener != NULL ) listener( owner, self, ( char * )args[ 0 ], ( char * )args[ 1 ], ( mlt_service )args[ 2 ] ); } /** Construct the repository and factories. * * The environment variable MLT_PRODUCER is the name of a default producer often used by other services, defaults to "loader". * * The environment variable MLT_CONSUMER is the name of a default consumer, defaults to "sdl". * * The environment variable MLT_TEST_CARD is the name of a producer or file to be played when nothing is available (all tracks blank). * * The environment variable MLT_DATA overrides the default full path to the MLT and module supplemental data files, defaults to \p PREFIX_DATA. * * The environment variable MLT_PROFILE defaults to "dv_pal." * * The environment variable MLT_REPOSITORY overrides the default location of the plugin modules, defaults to \p PREFIX_LIB. * * \param directory an optional full path to a directory containing the modules that overrides the default and * the MLT_REPOSITORY environment variable * \return the repository */ mlt_repository mlt_factory_init( const char *directory ) { // Load the system locales setlocale( LC_ALL, "" ); if ( ! global_properties ) global_properties = mlt_properties_new( ); // Allow property refresh on a subsequent initialisation if ( global_properties ) { mlt_properties_set_or_default( global_properties, "MLT_NORMALISATION", getenv( "MLT_NORMALISATION" ), "PAL" ); mlt_properties_set_or_default( global_properties, "MLT_PRODUCER", getenv( "MLT_PRODUCER" ), "loader" ); mlt_properties_set_or_default( global_properties, "MLT_CONSUMER", getenv( "MLT_CONSUMER" ), "sdl" ); mlt_properties_set( global_properties, "MLT_TEST_CARD", getenv( "MLT_TEST_CARD" ) ); mlt_properties_set_or_default( global_properties, "MLT_PROFILE", getenv( "MLT_PROFILE" ), "dv_pal" ); mlt_properties_set_or_default( global_properties, "MLT_DATA", getenv( "MLT_DATA" ), PREFIX_DATA ); #if defined(WIN32) char path[1024]; DWORD size = sizeof( path ); GetModuleFileName( NULL, path, size ); #elif defined(__DARWIN__) && defined(RELOCATABLE) char path[1024]; uint32_t size = sizeof( path ); _NSGetExecutablePath( path, &size ); #endif #if defined(WIN32) || (defined(__DARWIN__) && defined(RELOCATABLE)) char *path2 = strdup( path ); char *appdir = dirname( path2 ); mlt_properties_set( global_properties, "MLT_APPDIR", appdir ); free( path2 ); #endif } // Only initialise once if ( mlt_directory == NULL ) { // Allow user over rides if ( directory == NULL || !strcmp( directory, "" ) ) directory = getenv( "MLT_REPOSITORY" ); // If no directory is specified, default to install directory if ( directory == NULL ) directory = PREFIX_LIB; // Store the prefix for later retrieval #if defined(WIN32) || (defined(__DARWIN__) && defined(RELOCATABLE)) char *exedir = mlt_environment( "MLT_APPDIR" ); size_t size = strlen( exedir ); if ( global_properties && !getenv( "MLT_DATA" ) ) { mlt_directory = calloc( 1, size + strlen( PREFIX_DATA ) + 1 ); strcpy( mlt_directory, exedir ); strcat( mlt_directory, PREFIX_DATA ); mlt_properties_set( global_properties, "MLT_DATA", mlt_directory ); free( mlt_directory ); } mlt_directory = calloc( 1, size + strlen( directory ) + 1 ); strcpy( mlt_directory, exedir ); strcat( mlt_directory, directory ); #else mlt_directory = strdup( directory ); #endif // Initialise the pool mlt_pool_init( ); // Create and set up the events object event_object = mlt_properties_new( ); mlt_events_init( event_object ); mlt_events_register( event_object, "producer-create-request", ( mlt_transmitter )mlt_factory_create_request ); mlt_events_register( event_object, "producer-create-done", ( mlt_transmitter )mlt_factory_create_done ); mlt_events_register( event_object, "filter-create-request", ( mlt_transmitter )mlt_factory_create_request ); mlt_events_register( event_object, "filter-create-done", ( mlt_transmitter )mlt_factory_create_done ); mlt_events_register( event_object, "transition-create-request", ( mlt_transmitter )mlt_factory_create_request ); mlt_events_register( event_object, "transition-create-done", ( mlt_transmitter )mlt_factory_create_done ); mlt_events_register( event_object, "consumer-create-request", ( mlt_transmitter )mlt_factory_create_request ); mlt_events_register( event_object, "consumer-create-done", ( mlt_transmitter )mlt_factory_create_done ); // Create the repository of services repository = mlt_repository_init( mlt_directory ); // Force a clean up when app closes atexit( mlt_factory_close ); } return repository; } /** Fetch the events object. * * \return the global factory event object */ mlt_properties mlt_factory_event_object( ) { return event_object; } /** Fetch the module directory used in this instance. * * \return the full path to the module directory that this session is using */ const char *mlt_factory_directory( ) { return mlt_directory; } /** Get a value from the environment. * * \param name the name of a MLT (runtime configuration) environment variable * \return the value of the variable */ char *mlt_environment( const char *name ) { if ( global_properties ) return mlt_properties_get( global_properties, name ); else return NULL; } /** Set a value in the environment. * * \param name the name of a MLT environment variable * \param value the value of the variable * \return true on error */ int mlt_environment_set( const char *name, const char *value ) { if ( global_properties ) return mlt_properties_set( global_properties, name, value ); else return -1; } /** Set some properties common to all services. * * This sets _unique_id, \p mlt_type, \p mlt_service (unless _mlt_service_hidden), and _profile. * * \param properties a service's properties list * \param profile the \p mlt_profile supplied to the factory function * \param type the MLT service class * \param service the name of the service */ static void set_common_properties( mlt_properties properties, mlt_profile profile, const char *type, const char *service ) { mlt_properties_set_int( properties, "_unique_id", ++ unique_id ); mlt_properties_set( properties, "mlt_type", type ); if ( mlt_properties_get_int( properties, "_mlt_service_hidden" ) == 0 ) mlt_properties_set( properties, "mlt_service", service ); if ( profile != NULL ) mlt_properties_set_data( properties, "_profile", profile, 0, NULL, NULL ); } /** Fetch a producer from the repository. * * \param profile the \p mlt_profile to use * \param service the name of the producer (optional, defaults to MLT_PRODUCER) * \param input an optional argument to the producer constructor, typically a string * \return a new producer */ mlt_producer mlt_factory_producer( mlt_profile profile, const char *service, const void *input ) { mlt_producer obj = NULL; // Pick up the default normalising producer if necessary if ( service == NULL ) service = mlt_environment( "MLT_PRODUCER" ); // Offer the application the chance to 'create' mlt_events_fire( event_object, "producer-create-request", service, input, &obj, NULL ); // Try to instantiate via the specified service if ( obj == NULL ) { obj = mlt_repository_create( repository, profile, producer_type, service, input ); mlt_events_fire( event_object, "producer-create-done", service, input, obj, NULL ); if ( obj != NULL ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( obj ); set_common_properties( properties, profile, "producer", service ); } } return obj; } /** Fetch a filter from the repository. * * \param profile the \p mlt_profile to use * \param service the name of the filter * \param input an optional argument to the filter constructor, typically a string * \return a new filter */ mlt_filter mlt_factory_filter( mlt_profile profile, const char *service, const void *input ) { mlt_filter obj = NULL; // Offer the application the chance to 'create' mlt_events_fire( event_object, "filter-create-request", service, input, &obj, NULL ); if ( obj == NULL ) { obj = mlt_repository_create( repository, profile, filter_type, service, input ); mlt_events_fire( event_object, "filter-create-done", service, input, obj, NULL ); } if ( obj != NULL ) { mlt_properties properties = MLT_FILTER_PROPERTIES( obj ); set_common_properties( properties, profile, "filter", service ); } return obj; } /** Fetch a transition from the repository. * * \param profile the \p mlt_profile to use * \param service the name of the transition * \param input an optional argument to the transition constructor, typically a string * \return a new transition */ mlt_transition mlt_factory_transition( mlt_profile profile, const char *service, const void *input ) { mlt_transition obj = NULL; // Offer the application the chance to 'create' mlt_events_fire( event_object, "transition-create-request", service, input, &obj, NULL ); if ( obj == NULL ) { obj = mlt_repository_create( repository, profile, transition_type, service, input ); mlt_events_fire( event_object, "transition-create-done", service, input, obj, NULL ); } if ( obj != NULL ) { mlt_properties properties = MLT_TRANSITION_PROPERTIES( obj ); set_common_properties( properties, profile, "transition", service ); } return obj; } /** Fetch a consumer from the repository. * * \param profile the \p mlt_profile to use * \param service the name of the consumer (optional, defaults to MLT_CONSUMER) * \param input an optional argument to the consumer constructor, typically a string * \return a new consumer */ mlt_consumer mlt_factory_consumer( mlt_profile profile, const char *service, const void *input ) { mlt_consumer obj = NULL; if ( service == NULL ) service = mlt_environment( "MLT_CONSUMER" ); // Offer the application the chance to 'create' mlt_events_fire( event_object, "consumer-create-request", service, input, &obj, NULL ); if ( obj == NULL ) { obj = mlt_repository_create( repository, profile, consumer_type, service, input ); mlt_events_fire( event_object, "consumer-create-done", service, input, obj, NULL ); } if ( obj != NULL ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( obj ); set_common_properties( properties, profile, "consumer", service ); } return obj; } /** Register an object for clean up. * * \param ptr an opaque pointer to anything allocated on the heap * \param destructor the function pointer of the deallocation subroutine (e.g., free or \p mlt_pool_release) */ void mlt_factory_register_for_clean_up( void *ptr, mlt_destructor destructor ) { char unique[ 256 ]; sprintf( unique, "%08d", mlt_properties_count( global_properties ) ); mlt_properties_set_data( global_properties, unique, ptr, 0, destructor, NULL ); } /** Close the factory. * * Cleanup all resources for the session. */ void mlt_factory_close( ) { if ( mlt_directory != NULL ) { mlt_properties_close( event_object ); event_object = NULL; mlt_properties_close( global_properties ); global_properties = NULL; if ( repository ) { mlt_repository_close( repository ); repository = NULL; } free( mlt_directory ); mlt_directory = NULL; mlt_pool_close( ); } } mlt_properties mlt_global_properties( ) { return global_properties; } mlt-0.9.0/src/framework/mlt_factory.h000066400000000000000000000047521215300731300175770ustar00rootroot00000000000000/** * \file mlt_factory.h * \brief the factory method interfaces * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_FACTORY_H #define _MLT_FACTORY_H #include "mlt_types.h" #include "mlt_profile.h" #include "mlt_repository.h" /** * \event \em producer-create-request fired when mlt_factory_producer is called * \event \em producer-create-done fired when a producer registers itself * \event \em filter-create-request fired when mlt_factory_filter is called * \event \em filter-create-done fired when a filter registers itself * \event \em transition-create-request fired when mlt_factory_transition is called * \event \em transition-create-done fired when a transition registers itself * \event \em consumer-create-request fired when mlt_factory_consumer is called * \event \em consumer-create-done fired when a consumer registers itself */ extern mlt_repository mlt_factory_init( const char *directory ); extern const char *mlt_factory_directory( ); extern char *mlt_environment( const char *name ); extern int mlt_environment_set( const char *name, const char *value ); extern mlt_properties mlt_factory_event_object( ); extern mlt_producer mlt_factory_producer( mlt_profile profile, const char *name, const void *input ); extern mlt_filter mlt_factory_filter( mlt_profile profile, const char *name, const void *input ); extern mlt_transition mlt_factory_transition( mlt_profile profile, const char *name, const void *input ); extern mlt_consumer mlt_factory_consumer( mlt_profile profile, const char *name, const void *input ); extern void mlt_factory_register_for_clean_up( void *ptr, mlt_destructor destructor ); extern void mlt_factory_close( ); extern mlt_properties mlt_global_properties( ); #endif mlt-0.9.0/src/framework/mlt_field.c000066400000000000000000000147751215300731300172140ustar00rootroot00000000000000/** * \file mlt_field.c * \brief a field for planting multiple transitions and filters * \see mlt_field_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_field.h" #include "mlt_service.h" #include "mlt_filter.h" #include "mlt_transition.h" #include "mlt_multitrack.h" #include "mlt_tractor.h" #include #include /** \brief Field class * * The field is a convenience class that works with the tractor and multitrack classes to manage track filters and transitions. */ struct mlt_field_s { /// This is the producer we're connected to mlt_service producer; /// Multitrack mlt_multitrack multitrack; /// Tractor mlt_tractor tractor; }; /** Construct a field, mulitrack, and tractor. * * \public \memberof mlt_field_s * \return a new field */ mlt_field mlt_field_init( ) { // Initialise the field mlt_field self = calloc( 1, sizeof( struct mlt_field_s ) ); // Initialise it if ( self != NULL ) { // Construct a multitrack self->multitrack = mlt_multitrack_init( ); // Construct a tractor self->tractor = mlt_tractor_init( ); // The first plant will be connected to the mulitrack self->producer = MLT_MULTITRACK_SERVICE( self->multitrack ); // Connect the tractor to the multitrack mlt_tractor_connect( self->tractor, self->producer ); } // Return self return self; } /** Construct a field and initialize with supplied multitrack and tractor. * * \public \memberof mlt_field_s * \param multitrack a multitrack * \param tractor a tractor * \return a new field */ mlt_field mlt_field_new( mlt_multitrack multitrack, mlt_tractor tractor ) { // Initialise the field mlt_field self = calloc( 1, sizeof( struct mlt_field_s ) ); // Initialise it if ( self != NULL ) { // Construct a multitrack self->multitrack = multitrack; // Construct a tractor self->tractor = tractor; // The first plant will be connected to the mulitrack self->producer = MLT_MULTITRACK_SERVICE( self->multitrack ); // Connect the tractor to the multitrack mlt_tractor_connect( self->tractor, self->producer ); } // Return self return self; } /** Get the service associated to this field. * * \public \memberof mlt_field_s * \param self a field * \return the tractor as a service */ mlt_service mlt_field_service( mlt_field self ) { return MLT_TRACTOR_SERVICE( self->tractor ); } /** Get the multitrack. * * \public \memberof mlt_field_s * \param self a field * \return the multitrack */ mlt_multitrack mlt_field_multitrack( mlt_field self ) { return self != NULL ? self->multitrack : NULL; } /** Get the tractor. * * \public \memberof mlt_field_s * \param self a field * \return the tractor */ mlt_tractor mlt_field_tractor( mlt_field self ) { return self != NULL ? self->tractor : NULL; } /** Get the properties associated to this field. * * \public \memberof mlt_field_s * \param self a field * \return a properties list */ mlt_properties mlt_field_properties( mlt_field self ) { return MLT_SERVICE_PROPERTIES( mlt_field_service( self ) ); } /** Plant a filter. * * \public \memberof mlt_field_s * \param self a field * \param that a filter * \param track the track index * \return true if there was an error */ int mlt_field_plant_filter( mlt_field self, mlt_filter that, int track ) { // Connect the filter to the last producer int result = mlt_filter_connect( that, self->producer, track ); // If sucessful, then we'll use this for connecting in the future if ( result == 0 ) { // This is now the new producer self->producer = MLT_FILTER_SERVICE( that ); // Reconnect tractor to new producer mlt_tractor_connect( self->tractor, self->producer ); // Fire an event mlt_events_fire( mlt_field_properties( self ), "service-changed", NULL ); } return result; } /** Plant a transition. * * \public \memberof mlt_field_s * \param self a field * \param that a transition * \param a_track input A's track index * \param b_track input B's track index * \return true if there was an error */ int mlt_field_plant_transition( mlt_field self, mlt_transition that, int a_track, int b_track ) { // Connect the transition to the last producer int result = mlt_transition_connect( that, self->producer, a_track, b_track ); // If sucessful, then we'll use self for connecting in the future if ( result == 0 ) { // This is now the new producer self->producer = MLT_TRANSITION_SERVICE( that ); // Reconnect tractor to new producer mlt_tractor_connect( self->tractor, self->producer ); // Fire an event mlt_events_fire( mlt_field_properties( self ), "service-changed", NULL ); } return 0; } /** Close the field. * * \public \memberof mlt_field_s * \param self a field */ void mlt_field_close( mlt_field self ) { if ( self != NULL && mlt_properties_dec_ref( mlt_field_properties( self ) ) <= 0 ) { //mlt_tractor_close( self->tractor ); //mlt_multitrack_close( self->multitrack ); free( self ); } } /** Remove a filter or transition from the field. * * \public \memberof mlt_field_s * \param self a field * \param service the filter or transition to remove */ void mlt_field_disconnect_service( mlt_field self, mlt_service service ) { mlt_service p = mlt_service_producer( service ); mlt_service c = mlt_service_consumer( service); int i; switch ( mlt_service_identify(c) ) { case filter_type: i = mlt_filter_get_track( MLT_FILTER(c) ); mlt_service_connect_producer( c, p, i ); break; case transition_type: i = mlt_transition_get_a_track ( MLT_TRANSITION(c) ); mlt_service_connect_producer( c, p, i ); MLT_TRANSITION(c)->producer = p; break; case tractor_type: self->producer = p; mlt_tractor_connect( MLT_TRACTOR(c), p ); default: break; } mlt_events_fire( mlt_field_properties( self ), "service-changed", NULL ); } mlt-0.9.0/src/framework/mlt_field.h000066400000000000000000000032561215300731300172110ustar00rootroot00000000000000/** * \file mlt_field.h * \brief a field for planting multiple transitions and services * \see mlt_field_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_FIELD_H_ #define _MLT_FIELD_H_ #include "mlt_types.h" extern mlt_field mlt_field_init( ); extern mlt_field mlt_field_new( mlt_multitrack multitrack, mlt_tractor tractor ); extern mlt_service mlt_field_service( mlt_field self ); extern mlt_tractor mlt_field_tractor( mlt_field self ); extern mlt_multitrack mlt_field_multitrack( mlt_field self ); extern mlt_properties mlt_field_properties( mlt_field self ); extern int mlt_field_plant_filter( mlt_field self, mlt_filter that, int track ); extern int mlt_field_plant_transition( mlt_field self, mlt_transition that, int a_track, int b_track ); extern void mlt_field_close( mlt_field self ); extern void mlt_field_disconnect_service( mlt_field self, mlt_service service ); #endif mlt-0.9.0/src/framework/mlt_filter.c000066400000000000000000000242771215300731300174140ustar00rootroot00000000000000/** * \file mlt_filter.c * \brief abstraction for all filter services * \see mlt_filter_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_filter.h" #include "mlt_frame.h" #include "mlt_producer.h" #include #include #include static int filter_get_frame( mlt_service self, mlt_frame_ptr frame, int index ); /** Initialize a new filter. * * \public \memberof mlt_filter_s * \param self a filter * \param child the object of a subclass * \return true if there was an error */ int mlt_filter_init( mlt_filter self, void *child ) { mlt_service service = &self->parent; memset( self, 0, sizeof( struct mlt_filter_s ) ); self->child = child; if ( mlt_service_init( service, self ) == 0 ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); // Override the get_frame method service->get_frame = filter_get_frame; // Define the destructor service->close = ( mlt_destructor )mlt_filter_close; service->close_object = self; // Default in, out, track properties mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", 0 ); mlt_properties_set_int( properties, "track", 0 ); return 0; } return 1; } /** Create a new filter and initialize it. * * \public \memberof mlt_filter_s * \return a new filter */ mlt_filter mlt_filter_new( ) { mlt_filter self = calloc( 1, sizeof( struct mlt_filter_s ) ); if ( self != NULL && mlt_filter_init( self, NULL ) == 0 ) { return self; } else { free(self); return NULL; } } /** Get the service class interface. * * \public \memberof mlt_filter_s * \param self a filter * \return the service parent class * \see MLT_FILTER_SERVICE */ mlt_service mlt_filter_service( mlt_filter self ) { return self != NULL ? &self->parent : NULL; } /** Get the filter properties. * * \public \memberof mlt_filter_s * \param self a filter * \return the properties list for the filter * \see MLT_FILTER_PROPERTIES */ mlt_properties mlt_filter_properties( mlt_filter self ) { return MLT_SERVICE_PROPERTIES( MLT_FILTER_SERVICE( self ) ); } /** Connect this filter to a producers track. Note that a filter only operates * on a single track, and by default it operates on the entirety of that track. * * \public \memberof mlt_filter_s * \param self a filter * \param producer the producer to which to connect this filter * \param index which of potentially multiple producers to this service (0 based) */ int mlt_filter_connect( mlt_filter self, mlt_service producer, int index ) { int ret = mlt_service_connect_producer( &self->parent, producer, index ); // If the connection was successful, grab the producer, track and reset in/out if ( ret == 0 ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", 0 ); mlt_properties_set_int( properties, "track", index ); } return ret; } /** Set the starting and ending time. * * \public \memberof mlt_filter_s * \param self a filter * \param in the time relative to the producer at which start applying the filter * \param out the time relative to the producer at which to stop applying the filter */ void mlt_filter_set_in_and_out( mlt_filter self, mlt_position in, mlt_position out ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); mlt_properties_set_position( properties, "in", in ); mlt_properties_set_position( properties, "out", out ); } /** Return the track that this filter is operating on. * * \public \memberof mlt_filter_s * \param self a filter * \return true on error */ int mlt_filter_get_track( mlt_filter self ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); return mlt_properties_get_int( properties, "track" ); } /** Get the in point. * * \public \memberof mlt_filter_s * \param self a filter * \return the start time for the filter relative to the producer */ mlt_position mlt_filter_get_in( mlt_filter self ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); return mlt_properties_get_position( properties, "in" ); } /** Get the out point. * * \public \memberof mlt_filter_s * \param self a filter * \return the ending time for the filter relative to the producer */ mlt_position mlt_filter_get_out( mlt_filter self ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); return mlt_properties_get_position( properties, "out" ); } /** Get the duration. * * \public \memberof mlt_filter_s * \param self a filter * \return the duration or zero if unlimited */ mlt_position mlt_filter_get_length( mlt_filter self ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); mlt_position in = mlt_properties_get_position( properties, "in" ); mlt_position out = mlt_properties_get_position( properties, "out" ); return ( out > 0 ) ? ( out - in + 1 ) : 0; } /** Get the duration. * * This version works with filters with no explicit in and out by getting the * length of the frame's producer. * * \public \memberof mlt_filter_s * \param self a filter * \param frame a frame from which to get its producer * \return the duration or zero if unlimited */ mlt_position mlt_filter_get_length2( mlt_filter self, mlt_frame frame ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); mlt_position in = mlt_properties_get_position( properties, "in" ); mlt_position out = mlt_properties_get_position( properties, "out" ); if ( out == 0 && frame ) { // If always active, use the frame's producer mlt_producer producer = mlt_frame_get_original_producer( frame ); if ( producer ) { producer = mlt_producer_cut_parent( producer ); in = mlt_producer_get_in( producer ); out = mlt_producer_get_out( producer ); } } return ( out > 0 ) ? ( out - in + 1 ) : 0; } /** Get the position within the filter. * * The position is relative to the in point. * This will only be valid once mlt_filter_process is called. * * \public \memberof mlt_filter_s * \param self a filter * \param frame a frame * \return the position */ mlt_position mlt_filter_get_position( mlt_filter self, mlt_frame frame ) { mlt_properties properties = MLT_FILTER_PROPERTIES( self ); mlt_position in = mlt_properties_get_position( properties, "in" ); const char *unique_id = mlt_properties_get( properties, "_unique_id" ); char name[20]; // Make the properties key from unique id snprintf( name, 20, "pos.%s", unique_id ); name[20 - 1] = '\0'; return mlt_properties_get_position( MLT_FRAME_PROPERTIES( frame ), name ) - in; } /** Get the percent complete. * * This will only be valid once mlt_filter_process is called. * * \public \memberof mlt_filter_s * \param self a filter * \param frame a frame * \return the progress in the range 0.0 to 1.0 */ double mlt_filter_get_progress( mlt_filter self, mlt_frame frame ) { double position = mlt_filter_get_position( self, frame ); double length = mlt_filter_get_length2( self, frame ); return position / length; } /** Process the frame. * * When fetching the frame position in a subclass process method, the frame's * position is relative to the filter's producer - not the filter's in point * or timeline. * * \public \memberof mlt_filter_s * \param self a filter * \param frame a frame * \return a frame */ mlt_frame mlt_filter_process( mlt_filter self, mlt_frame frame ) { mlt_properties properties = MLT_FILTER_PROPERTIES( self ); int disable = mlt_properties_get_int( properties, "disable" ); const char *unique_id = mlt_properties_get( properties, "_unique_id" ); mlt_position position = mlt_frame_get_position( frame ); char name[20]; // Make the properties key from unique id snprintf( name, 20, "pos.%s", unique_id ); name[20 -1] = '\0'; // Save the position on the frame mlt_properties_set_position( MLT_FRAME_PROPERTIES( frame ), name, position ); if ( disable || self->process == NULL ) return frame; else return self->process( self, frame ); } /** Get a frame from this filter. * * \private \memberof mlt_filter_s * \param service a service * \param[out] frame a frame by reference * \param index as determined by the producer * \return true on error */ static int filter_get_frame( mlt_service service, mlt_frame_ptr frame, int index ) { mlt_filter self = service->child; // Get coords in/out/track int track = mlt_filter_get_track( self ); int in = mlt_filter_get_in( self ); int out = mlt_filter_get_out( self ); // Get the producer this is connected to mlt_service producer = mlt_service_producer( &self->parent ); // If the frame request is for this filters track, we need to process it if ( index == track || track == -1 ) { int ret = mlt_service_get_frame( producer, frame, index ); if ( ret == 0 ) { mlt_position position = mlt_frame_get_position( *frame ); if ( position >= in && ( out == 0 || position <= out ) ) *frame = mlt_filter_process( self, *frame ); return 0; } else { *frame = mlt_frame_init( service ); return 0; } } else { return mlt_service_get_frame( producer, frame, index ); } } /** Close and destroy the filter. * * \public \memberof mlt_filter_s * \param self a filter */ void mlt_filter_close( mlt_filter self ) { if ( self != NULL && mlt_properties_dec_ref( MLT_FILTER_PROPERTIES( self ) ) <= 0 ) { if ( self->close != NULL ) { self->close( self ); } else { self->parent.close = NULL; mlt_service_close( &self->parent ); } free( self ); } } mlt-0.9.0/src/framework/mlt_filter.h000066400000000000000000000054171215300731300174140ustar00rootroot00000000000000/** * \file mlt_filter.h * \brief abstraction for all filter services * \see mlt_filter_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_FILTER_H_ #define _MLT_FILTER_H_ #include "mlt_service.h" /** \brief Filter abstract service class * * A filter is a service that may modify the output of a single producer. * * \extends mlt_service_s * \properties \em track the index of the track of a multitrack on which the filter is applied * \properties \em service a reference to the service to which this filter is attached. * Currently this is not cleared when the filter is detached. */ struct mlt_filter_s { /** We're implementing service here */ struct mlt_service_s parent; /** public virtual */ void ( *close )( mlt_filter ); /** protected filter method */ mlt_frame ( *process )( mlt_filter, mlt_frame ); /** Protected */ void *child; }; #define MLT_FILTER_SERVICE( filter ) ( &( filter )->parent ) #define MLT_FILTER_PROPERTIES( filter ) MLT_SERVICE_PROPERTIES( MLT_FILTER_SERVICE( filter ) ) extern int mlt_filter_init( mlt_filter self, void *child ); extern mlt_filter mlt_filter_new( ); extern mlt_service mlt_filter_service( mlt_filter self ); extern mlt_properties mlt_filter_properties( mlt_filter self ); extern mlt_frame mlt_filter_process( mlt_filter self, mlt_frame that ); extern int mlt_filter_connect( mlt_filter self, mlt_service producer, int index ); extern void mlt_filter_set_in_and_out( mlt_filter self, mlt_position in, mlt_position out ); extern int mlt_filter_get_track( mlt_filter self ); extern mlt_position mlt_filter_get_in( mlt_filter self ); extern mlt_position mlt_filter_get_out( mlt_filter self ); extern mlt_position mlt_filter_get_length( mlt_filter self ); extern mlt_position mlt_filter_get_length2( mlt_filter self, mlt_frame frame ); extern mlt_position mlt_filter_get_position( mlt_filter self, mlt_frame frame ); extern double mlt_filter_get_progress( mlt_filter self, mlt_frame frame ); extern void mlt_filter_close( mlt_filter ); #endif mlt-0.9.0/src/framework/mlt_frame.c000066400000000000000000001043521215300731300172120ustar00rootroot00000000000000/** * \file mlt_frame.c * \brief interface for all frame classes * \see mlt_frame_s * * Copyright (C) 2003-2013 Ushodaya Enterprises Limited * \author Charles Yates * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_frame.h" #include "mlt_producer.h" #include "mlt_factory.h" #include "mlt_profile.h" #include "mlt_log.h" #include #include #include /** Construct a frame object. * * \public \memberof mlt_frame_s * \param service the pointer to any service that can provide access to the profile * \return a frame object on success or NULL if there was an allocation error */ mlt_frame mlt_frame_init( mlt_service service ) { // Allocate a frame mlt_frame self = calloc( 1, sizeof( struct mlt_frame_s ) ); if ( self != NULL ) { mlt_profile profile = mlt_service_profile( service ); // Initialise the properties mlt_properties properties = &self->parent; mlt_properties_init( properties, self ); // Set default properties on the frame mlt_properties_set_position( properties, "_position", 0.0 ); mlt_properties_set_data( properties, "image", NULL, 0, NULL, NULL ); mlt_properties_set_int( properties, "width", profile? profile->width : 720 ); mlt_properties_set_int( properties, "height", profile? profile->height : 576 ); mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( NULL ) ); mlt_properties_set_data( properties, "audio", NULL, 0, NULL, NULL ); mlt_properties_set_data( properties, "alpha", NULL, 0, NULL, NULL ); // Construct stacks for frames and methods self->stack_image = mlt_deque_init( ); self->stack_audio = mlt_deque_init( ); self->stack_service = mlt_deque_init( ); } return self; } /** Get a frame's properties. * * \public \memberof mlt_frame_s * \param self a frame * \return the frame's properties or NULL if an invalid frame is supplied */ mlt_properties mlt_frame_properties( mlt_frame self ) { return self != NULL ? &self->parent : NULL; } /** Determine if the frame will produce a test card image. * * \public \memberof mlt_frame_s * \param self a frame * \return true (non-zero) if this will produce from a test card */ int mlt_frame_is_test_card( mlt_frame self ) { return mlt_deque_count( self->stack_image ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( self ), "test_image" ); } /** Determine if the frame will produce audio from a test card. * * \public \memberof mlt_frame_s * \param self a frame * \return true (non-zero) if this will produce from a test card */ int mlt_frame_is_test_audio( mlt_frame self ) { return mlt_deque_count( self->stack_audio ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( self ), "test_audio" ); } /** Get the sample aspect ratio of the frame. * * \public \memberof mlt_frame_s * \param self a frame * \return the aspect ratio */ double mlt_frame_get_aspect_ratio( mlt_frame self ) { return mlt_properties_get_double( MLT_FRAME_PROPERTIES( self ), "aspect_ratio" ); } /** Set the sample aspect ratio of the frame. * * \public \memberof mlt_frame_s * \param self a frame * \param value the new image sample aspect ratio * \return true if error */ int mlt_frame_set_aspect_ratio( mlt_frame self, double value ) { return mlt_properties_set_double( MLT_FRAME_PROPERTIES( self ), "aspect_ratio", value ); } /** Get the time position of this frame. * * This position is not necessarily the position as the original * producer knows it. It could be the position that the playlist, * multitrack, or tractor producer set. * * \public \memberof mlt_frame_s * \param self a frame * \return the position * \see mlt_frame_original_position */ mlt_position mlt_frame_get_position( mlt_frame self ) { int pos = mlt_properties_get_position( MLT_FRAME_PROPERTIES( self ), "_position" ); return pos < 0 ? 0 : pos; } /** Get the original time position of this frame. * * This is the position that the original producer set on the frame. * * \public \memberof mlt_frame_s * \param self a frame * \return the position */ mlt_position mlt_frame_original_position( mlt_frame self ) { int pos = mlt_properties_get_position( MLT_FRAME_PROPERTIES( self ), "original_position" ); return pos < 0 ? 0 : pos; } /** Set the time position of this frame. * * \public \memberof mlt_frame_s * \param self a frame * \param value the position * \return true if error */ int mlt_frame_set_position( mlt_frame self, mlt_position value ) { // Only set the original_position the first time. if ( ! mlt_properties_get( MLT_FRAME_PROPERTIES( self ), "original_position" ) ) mlt_properties_set_position( MLT_FRAME_PROPERTIES( self ), "original_position", value ); return mlt_properties_set_position( MLT_FRAME_PROPERTIES( self ), "_position", value ); } /** Stack a get_image callback. * * \public \memberof mlt_frame_s * \param self a frame * \param get_image the get_image callback * \return true if error */ int mlt_frame_push_get_image( mlt_frame self, mlt_get_image get_image ) { return mlt_deque_push_back( self->stack_image, get_image ); } /** Pop a get_image callback. * * \public \memberof mlt_frame_s * \param self a frame * \return the get_image callback */ mlt_get_image mlt_frame_pop_get_image( mlt_frame self ) { return mlt_deque_pop_back( self->stack_image ); } /** Push a frame. * * \public \memberof mlt_frame_s * \param self a frame * \param that the frame to push onto \p self * \return true if error */ int mlt_frame_push_frame( mlt_frame self, mlt_frame that ) { return mlt_deque_push_back( self->stack_image, that ); } /** Pop a frame. * * \public \memberof mlt_frame_s * \param self a frame * \return a frame that was previously pushed */ mlt_frame mlt_frame_pop_frame( mlt_frame self ) { return mlt_deque_pop_back( self->stack_image ); } /** Push a service. * * \public \memberof mlt_frame_s * \param self a frame * \param that an opaque pointer * \return true if error */ int mlt_frame_push_service( mlt_frame self, void *that ) { return mlt_deque_push_back( self->stack_image, that ); } /** Pop a service. * * \public \memberof mlt_frame_s * \param self a frame * \return an opaque pointer to something previously pushed */ void *mlt_frame_pop_service( mlt_frame self ) { return mlt_deque_pop_back( self->stack_image ); } /** Push a number. * * \public \memberof mlt_frame_s * \param self a frame * \param that an integer * \return true if error */ int mlt_frame_push_service_int( mlt_frame self, int that ) { return mlt_deque_push_back_int( self->stack_image, that ); } /** Pop a number. * * \public \memberof mlt_frame_s * \param self a frame * \return an integer that was previously pushed */ int mlt_frame_pop_service_int( mlt_frame self ) { return mlt_deque_pop_back_int( self->stack_image ); } /** Push an audio item on the stack. * * \public \memberof mlt_frame_s * \param self a frame * \param that an opaque pointer * \return true if error */ int mlt_frame_push_audio( mlt_frame self, void *that ) { return mlt_deque_push_back( self->stack_audio, that ); } /** Pop an audio item from the stack * * \public \memberof mlt_frame_s * \param self a frame * \return an opaque pointer to something that was pushed onto the frame's audio stack */ void *mlt_frame_pop_audio( mlt_frame self ) { return mlt_deque_pop_back( self->stack_audio ); } /** Return the service stack * * \public \memberof mlt_frame_s * \param self a frame * \return the service stack */ mlt_deque mlt_frame_service_stack( mlt_frame self ) { return self->stack_service; } /** Set a new image on the frame. * * \public \memberof mlt_frame_s * \param self a frame * \param image a pointer to the raw image data * \param size the size of the image data in bytes (optional) * \param destroy a function to deallocate \p image when the frame is closed (optional) * \return true if error */ int mlt_frame_set_image( mlt_frame self, uint8_t *image, int size, mlt_destructor destroy ) { return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "image", image, size, destroy, NULL ); } /** Set a new alpha channel on the frame. * * \public \memberof mlt_frame_s * \param self a frame * \param alpha a pointer to the alpha channel * \param size the size of the alpha channel in bytes (optional) * \param destroy a function to deallocate \p alpha when the frame is closed (optional) * \return true if error */ int mlt_frame_set_alpha( mlt_frame self, uint8_t *alpha, int size, mlt_destructor destroy ) { self->get_alpha_mask = NULL; return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "alpha", alpha, size, destroy, NULL ); } /** Replace image stack with the information provided. * * This might prove to be unreliable and restrictive - the idea is that a transition * which normally uses two images may decide to only use the b frame (ie: in the case * of a composite where the b frame completely obscures the a frame). * * The image must be writable and the destructor for the image itself must be taken * care of on another frame and that frame cannot have a replace applied to it... * Further it assumes that no alpha mask is in use. * * For these reasons, it can only be used in a specific situation - when you have * multiple tracks each with their own transition and these transitions are applied * in a strictly reversed order (ie: highest numbered [lowest track] is processed * first). * * More reliable approach - the cases should be detected during the process phase * and the upper tracks should simply not be invited to stack... * * \public \memberof mlt_frame_s * \param self a frame * \param image a new image * \param format the image format * \param width the width of the new image * \param height the height of the new image */ void mlt_frame_replace_image( mlt_frame self, uint8_t *image, mlt_image_format format, int width, int height ) { // Remove all items from the stack while( mlt_deque_pop_back( self->stack_image ) ) ; // Update the information mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "image", image, 0, NULL, NULL ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "width", width ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "height", height ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "format", format ); self->get_alpha_mask = NULL; } /** Get the short name for an image format. * * \public \memberof mlt_frame_s * \param format the image format * \return a string */ const char * mlt_image_format_name( mlt_image_format format ) { switch ( format ) { case mlt_image_none: return "none"; case mlt_image_rgb24: return "rgb24"; case mlt_image_rgb24a: return "rgb24a"; case mlt_image_yuv422: return "yuv422"; case mlt_image_yuv420p: return "yuv420p"; case mlt_image_opengl: return "opengl"; case mlt_image_glsl: return "glsl"; case mlt_image_glsl_texture: return "glsl_texture"; } return "invalid"; } /** Get the number of bytes needed for an image. * * \public \memberof mlt_frame_s * \param format the image format * \param width width of the image in pixels * \param height height of the image in pixels * \param[out] bpp the number of bytes per pixel (optional) * \return the number of bytes */ int mlt_image_format_size( mlt_image_format format, int width, int height, int *bpp ) { height += 1; switch ( format ) { case mlt_image_rgb24: if ( bpp ) *bpp = 3; return width * height * 3; case mlt_image_opengl: case mlt_image_rgb24a: if ( bpp ) *bpp = 4; return width * height * 4; case mlt_image_yuv422: if ( bpp ) *bpp = 2; return width * height * 2; case mlt_image_yuv420p: if ( bpp ) *bpp = 3 / 2; return width * height * 3 / 2; default: if ( bpp ) *bpp = 0; return 0; } return 0; } static int generate_test_image( mlt_properties properties, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { mlt_producer producer = mlt_properties_get_data( properties, "test_card_producer", NULL ); mlt_image_format requested_format = *format; int error = 1; if ( producer ) { mlt_frame test_frame = NULL; mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &test_frame, 0 ); if ( test_frame ) { mlt_properties test_properties = MLT_FRAME_PROPERTIES( test_frame ); mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); mlt_properties_set( test_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) ); error = mlt_frame_get_image( test_frame, buffer, format, width, height, writable ); if ( !error && buffer && *buffer ) { mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( test_frame ) ); mlt_properties_set_int( properties, "width", *width ); mlt_properties_set_int( properties, "height", *height ); if ( test_frame->convert_image && requested_format != mlt_image_none ) test_frame->convert_image( test_frame, buffer, format, requested_format ); mlt_properties_set_int( properties, "format", *format ); } } else { mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL ); } } if ( error && buffer && *format != mlt_image_none ) { int size = 0; *width = *width == 0 ? 720 : *width; *height = *height == 0 ? 576 : *height; size = *width * *height; mlt_properties_set_int( properties, "format", *format ); mlt_properties_set_int( properties, "width", *width ); mlt_properties_set_int( properties, "height", *height ); mlt_properties_set_double( properties, "aspect_ratio", 1.0 ); switch( *format ) { case mlt_image_rgb24: size *= 3; size += *width * 3; *buffer = mlt_pool_alloc( size ); if ( *buffer ) memset( *buffer, 255, size ); break; case mlt_image_rgb24a: case mlt_image_opengl: size *= 4; size += *width * 4; *buffer = mlt_pool_alloc( size ); if ( *buffer ) memset( *buffer, 255, size ); break; case mlt_image_yuv422: size *= 2; size += *width * 2; *buffer = mlt_pool_alloc( size ); if ( *buffer ) { register uint8_t *p = *buffer; register uint8_t *q = p + size; while ( p != NULL && p != q ) { *p ++ = 235; *p ++ = 128; } } break; case mlt_image_yuv420p: *buffer = mlt_pool_alloc( size * 3 / 2 ); if ( *buffer ) { memset( *buffer, 235, size ); memset( *buffer + size, 128, size / 2 ); } break; default: size = 0; break; } mlt_properties_set_data( properties, "image", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL ); mlt_properties_set_int( properties, "test_image", 1 ); error = 0; } return error; } /** Get the image associated to the frame. * * You should express the desired format, width, and height as inputs. As long * as the loader producer was used to generate this or the imageconvert filter * was attached, then you will get the image back in the format you desire. * However, you do not always get the width and height you request depending * on properties and filters. You do not need to supply a pre-allocated * buffer, but you should always supply the desired image format. * * \public \memberof mlt_frame_s * \param self a frame * \param[out] buffer an image buffer * \param[in,out] format the image format * \param[in,out] width the horizontal size in pixels * \param[in,out] height the vertical size in pixels * \param writable whether or not you will need to be able to write to the memory returned in \p buffer * \return true if error * \todo Better describe the width and height as inputs. */ int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { mlt_properties properties = MLT_FRAME_PROPERTIES( self ); mlt_get_image get_image = mlt_frame_pop_get_image( self ); mlt_image_format requested_format = *format; int error = 0; if ( get_image ) { mlt_properties_set_int( properties, "image_count", mlt_properties_get_int( properties, "image_count" ) - 1 ); error = get_image( self, buffer, format, width, height, writable ); if ( !error && buffer && *buffer ) { mlt_properties_set_int( properties, "width", *width ); mlt_properties_set_int( properties, "height", *height ); if ( self->convert_image && requested_format != mlt_image_none ) self->convert_image( self, buffer, format, requested_format ); mlt_properties_set_int( properties, "format", *format ); } else { error = generate_test_image( properties, buffer, format, width, height, writable ); } } else if ( mlt_properties_get_data( properties, "image", NULL ) && buffer ) { *format = mlt_properties_get_int( properties, "format" ); *buffer = mlt_properties_get_data( properties, "image", NULL ); *width = mlt_properties_get_int( properties, "width" ); *height = mlt_properties_get_int( properties, "height" ); if ( self->convert_image && *buffer && requested_format != mlt_image_none ) { self->convert_image( self, buffer, format, requested_format ); mlt_properties_set_int( properties, "format", *format ); } } else { error = generate_test_image( properties, buffer, format, width, height, writable ); } return error; } /** Get the alpha channel associated to the frame. * * \public \memberof mlt_frame_s * \param self a frame * \return the alpha channel */ uint8_t *mlt_frame_get_alpha_mask( mlt_frame self ) { uint8_t *alpha = NULL; if ( self != NULL ) { if ( self->get_alpha_mask != NULL ) alpha = self->get_alpha_mask( self ); if ( alpha == NULL ) alpha = mlt_properties_get_data( &self->parent, "alpha", NULL ); if ( alpha == NULL ) { int size = mlt_properties_get_int( &self->parent, "width" ) * mlt_properties_get_int( &self->parent, "height" ); alpha = mlt_pool_alloc( size ); memset( alpha, 255, size ); mlt_properties_set_data( &self->parent, "alpha", alpha, size, mlt_pool_release, NULL ); } } return alpha; } /** Get the short name for an audio format. * * You do not need to deallocate the returned string. * \public \memberof mlt_frame_s * \param format an audio format enum * \return a string for the name of the image format */ const char * mlt_audio_format_name( mlt_audio_format format ) { switch ( format ) { case mlt_audio_none: return "none"; case mlt_audio_s16: return "s16"; case mlt_audio_s32: return "s32"; case mlt_audio_s32le: return "s32le"; case mlt_audio_float: return "float"; case mlt_audio_f32le: return "f32le"; case mlt_audio_u8: return "u8"; } return "invalid"; } /** Get the amount of bytes needed for a block of audio. * * \public \memberof mlt_frame_s * \param format an audio format enum * \param samples the number of samples per channel * \param channels the number of channels * \return the number of bytes */ int mlt_audio_format_size( mlt_audio_format format, int samples, int channels ) { switch ( format ) { case mlt_audio_none: return 0; case mlt_audio_s16: return samples * channels * sizeof( int16_t ); case mlt_audio_s32le: case mlt_audio_s32: return samples * channels * sizeof( int32_t ); case mlt_audio_f32le: case mlt_audio_float: return samples * channels * sizeof( float ); case mlt_audio_u8: return samples * channels; } return 0; } /** Get the audio associated to the frame. * * You should express the desired format, frequency, channels, and samples as inputs. As long * as the loader producer was used to generate this or the audioconvert filter * was attached, then you will get the audio back in the format you desire. * However, you do not always get the channels and samples you request depending * on properties and filters. You do not need to supply a pre-allocated * buffer, but you should always supply the desired audio format. * The audio is always in interleaved format. * You should use the \p mlt_sample_calculator to determine the number of samples you want. * * \public \memberof mlt_frame_s * \param self a frame * \param[out] buffer an audio buffer * \param[in,out] format the audio format * \param[in,out] frequency the sample rate * \param[in,out] channels * \param[in,out] samples the number of samples per frame * \return true if error */ int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { mlt_get_audio get_audio = mlt_frame_pop_audio( self ); mlt_properties properties = MLT_FRAME_PROPERTIES( self ); int hide = mlt_properties_get_int( properties, "test_audio" ); mlt_audio_format requested_format = *format; if ( hide == 0 && get_audio != NULL ) { get_audio( self, buffer, format, frequency, channels, samples ); mlt_properties_set_int( properties, "audio_frequency", *frequency ); mlt_properties_set_int( properties, "audio_channels", *channels ); mlt_properties_set_int( properties, "audio_samples", *samples ); mlt_properties_set_int( properties, "audio_format", *format ); if ( self->convert_audio && *buffer && requested_format != mlt_audio_none ) self->convert_audio( self, buffer, format, requested_format ); } else if ( mlt_properties_get_data( properties, "audio", NULL ) ) { *buffer = mlt_properties_get_data( properties, "audio", NULL ); *format = mlt_properties_get_int( properties, "audio_format" ); *frequency = mlt_properties_get_int( properties, "audio_frequency" ); *channels = mlt_properties_get_int( properties, "audio_channels" ); *samples = mlt_properties_get_int( properties, "audio_samples" ); if ( self->convert_audio && *buffer && requested_format != mlt_audio_none ) self->convert_audio( self, buffer, format, requested_format ); } else { int size = 0; *samples = *samples <= 0 ? 1920 : *samples; *channels = *channels <= 0 ? 2 : *channels; *frequency = *frequency <= 0 ? 48000 : *frequency; mlt_properties_set_int( properties, "audio_frequency", *frequency ); mlt_properties_set_int( properties, "audio_channels", *channels ); mlt_properties_set_int( properties, "audio_samples", *samples ); mlt_properties_set_int( properties, "audio_format", *format ); switch( *format ) { case mlt_image_none: size = 0; *buffer = NULL; break; case mlt_audio_s16: size = *samples * *channels * sizeof( int16_t ); break; case mlt_audio_s32: size = *samples * *channels * sizeof( int32_t ); break; case mlt_audio_float: size = *samples * *channels * sizeof( float ); break; default: break; } if ( size ) *buffer = mlt_pool_alloc( size ); if ( *buffer ) memset( *buffer, 0, size ); mlt_properties_set_data( properties, "audio", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL ); mlt_properties_set_int( properties, "test_audio", 1 ); } // TODO: This does not belong here if ( *format == mlt_audio_s16 && mlt_properties_get( properties, "meta.volume" ) ) { double value = mlt_properties_get_double( properties, "meta.volume" ); if ( value == 0.0 ) { memset( *buffer, 0, *samples * *channels * 2 ); } else if ( value != 1.0 ) { int total = *samples * *channels; int16_t *p = *buffer; while ( total -- ) { *p = *p * value; p ++; } } mlt_properties_set( properties, "meta.volume", NULL ); } return 0; } /** Set the audio on a frame. * * \public \memberof mlt_frame_s * \param self a frame * \param buffer an buffer containing audio samples * \param format the format of the audio in the \p buffer * \param size the total size of the buffer (optional) * \param destructor a function that releases or deallocates the \p buffer * \return true if error */ int mlt_frame_set_audio( mlt_frame self, void *buffer, mlt_audio_format format, int size, mlt_destructor destructor ) { mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "audio_format", format ); return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "audio", buffer, size, destructor, NULL ); } /** Get audio on a frame as a waveform image. * * This generates an 8-bit grayscale image representation of the audio in a * frame. Currently, this only really works for 2 channels. * This allocates the bitmap using mlt_pool so you should release the return * value with \p mlt_pool_release. * * \public \memberof mlt_frame_s * \param self a frame * \param w the width of the image * \param h the height of the image to create * \return a pointer to a new bitmap */ unsigned char *mlt_frame_get_waveform( mlt_frame self, int w, int h ) { int16_t *pcm = NULL; mlt_properties properties = MLT_FRAME_PROPERTIES( self ); mlt_audio_format format = mlt_audio_s16; int frequency = 16000; int channels = 2; mlt_producer producer = mlt_frame_get_original_producer( self ); double fps = mlt_producer_get_fps( mlt_producer_cut_parent( producer ) ); int samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) ); // Increase audio resolution proportional to requested image size while ( samples < w ) { frequency += 16000; samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) ); } // Get the pcm data mlt_frame_get_audio( self, (void**)&pcm, &format, &frequency, &channels, &samples ); // Make an 8-bit buffer large enough to hold rendering int size = w * h; if ( size <= 0 ) return NULL; unsigned char *bitmap = ( unsigned char* )mlt_pool_alloc( size ); if ( bitmap != NULL ) memset( bitmap, 0, size ); else return NULL; mlt_properties_set_data( properties, "waveform", bitmap, size, ( mlt_destructor )mlt_pool_release, NULL ); // Render vertical lines int16_t *ubound = pcm + samples * channels; int skip = samples / w; skip = !skip ? 1 : skip; unsigned char gray = 0xFF / skip; int i, j, k; // Iterate sample stream and along x coordinate for ( i = 0; pcm < ubound; i++ ) { // pcm data has channels interleaved for ( j = 0; j < channels; j++, pcm++ ) { // Determine sample's magnitude from 2s complement; int pcm_magnitude = *pcm < 0 ? ~(*pcm) + 1 : *pcm; // The height of a line is the ratio of the magnitude multiplied by // the vertical resolution of a single channel int height = h * pcm_magnitude / channels / 2 / 32768; // Determine the starting y coordinate - left top, right bottom int displacement = h * (j * 2 + 1) / channels / 2 - ( *pcm < 0 ? 0 : height ); // Position buffer pointer using y coordinate, stride, and x coordinate unsigned char *p = bitmap + i / skip + displacement * w; // Draw vertical line for ( k = 0; k < height + 1; k++ ) if ( *pcm < 0 ) p[ w * k ] = ( k == 0 ) ? 0xFF : p[ w * k ] + gray; else p[ w * k ] = ( k == height ) ? 0xFF : p[ w * k ] + gray; } } return bitmap; } /** Get the end service that produced self frame. * * This fetches the first producer of the frame and not any producers that * encapsulate it. * * \public \memberof mlt_frame_s * \param self a frame * \return a producer */ mlt_producer mlt_frame_get_original_producer( mlt_frame self ) { if ( self != NULL ) return mlt_properties_get_data( MLT_FRAME_PROPERTIES( self ), "_producer", NULL ); return NULL; } /** Destroy the frame. * * \public \memberof mlt_frame_s * \param self a frame */ void mlt_frame_close( mlt_frame self ) { if ( self != NULL && mlt_properties_dec_ref( MLT_FRAME_PROPERTIES( self ) ) <= 0 ) { mlt_deque_close( self->stack_image ); mlt_deque_close( self->stack_audio ); while( mlt_deque_peek_back( self->stack_service ) ) mlt_service_close( mlt_deque_pop_back( self->stack_service ) ); mlt_deque_close( self->stack_service ); mlt_properties_close( &self->parent ); free( self ); } } /***** convenience functions *****/ /** Determine the number of samples that belong in a frame at a time position. * * \public \memberof mlt_frame_s * \param fps the frame rate * \param frequency the sample rate * \param position the time position * \return the number of samples per channel */ int mlt_sample_calculator( float fps, int frequency, int64_t position ) { /* Compute the cumulative number of samples until the start of this frame and the cumulative number of samples until the start of the next frame. Round each to the nearest integer and take the difference to determine the number of samples in this frame. This approach should prevent rounding errors that can accumulate over a large number of frames causing A/V sync problems. */ return mlt_sample_calculator_to_now( fps, frequency, position + 1 ) - mlt_sample_calculator_to_now( fps, frequency, position ); } /** Determine the number of samples that belong before a time position. * * \public \memberof mlt_frame_s * \param fps the frame rate * \param frequency the sample rate * \param position the time position * \return the number of samples per channel * \bug Will this break when mlt_position is converted to double? */ int64_t mlt_sample_calculator_to_now( float fps, int frequency, int64_t position ) { int64_t samples = 0; if ( fps ) { samples = (int64_t)( (double) position * (double) frequency / (double) fps + ( position < 0 ? -0.5 : 0.5 ) ); } return samples; } void mlt_frame_write_ppm( mlt_frame frame ) { int width = 0; int height = 0; mlt_image_format format = mlt_image_rgb24; uint8_t *image; if ( mlt_frame_get_image( frame, &image, &format, &width, &height, 0 ) == 0 ) { FILE *file; char filename[16]; sprintf( filename, "frame-%05d.ppm", (int)mlt_frame_get_position( frame ) ); file = fopen( filename, "wb" ); if ( !file ) return; fprintf( file, "P6\n%d %d\n255\n", width, height); fwrite( image, width * height * 3, 1, file ); fclose( file ); } } /** Get or create a properties object unique to this service instance. * * Use this function to hold a service's processing parameters for this * particular frame. Set the parameters in the service's process function. * Then, get the parameters in the function it pushes to the frame's audio * or image stack. This makes the service more parallel by reducing race * conditions and less sensitive to multiple instances (by not setting a * non-unique property on the frame). Creation and destruction of the * properties object is handled automatically. * * \public \memberof mlt_frame_s * \param self a frame * \param service a service * \return a properties object */ mlt_properties mlt_frame_unique_properties( mlt_frame self, mlt_service service ) { mlt_properties frame_props = MLT_FRAME_PROPERTIES( self ); mlt_properties service_props = MLT_SERVICE_PROPERTIES( service ); char *unique = mlt_properties_get( service_props, "_unique_id" ); mlt_properties instance_props = mlt_properties_get_data( frame_props, unique, NULL ); if ( !instance_props ) { instance_props = mlt_properties_new(); mlt_properties_set_data( frame_props, unique, instance_props, 0, (mlt_destructor) mlt_properties_close, NULL ); } return instance_props; } /** Make a copy of a frame. * * This does not copy the get_image/get_audio processing stacks or any * data properties other than the audio and image. * * \public \memberof mlt_frame_s * \param self the frame to clone * \param is_deep a boolean to indicate whether to make a deep copy of the audio * and video data chunks or to make a shallow copy by pointing to the supplied frame * \return a almost-complete copy of the frame * \todo copy the processing deques */ mlt_frame mlt_frame_clone( mlt_frame self, int is_deep ) { mlt_frame new_frame = mlt_frame_init( NULL ); mlt_properties properties = MLT_FRAME_PROPERTIES( self ); mlt_properties new_props = MLT_FRAME_PROPERTIES( new_frame ); void *data, *copy; int size; mlt_properties_inherit( new_props, properties ); // Carry over some special data properties for the multi consumer. mlt_properties_set_data( new_props, "_producer", mlt_frame_get_original_producer( self ), 0, NULL, NULL ); mlt_properties_set_data( new_props, "movit.convert", mlt_properties_get_data( properties, "movit.convert", NULL), 0, NULL, NULL ); if ( is_deep ) { data = mlt_properties_get_data( properties, "audio", &size ); if ( data ) { if ( !size ) size = mlt_audio_format_size( mlt_properties_get_int( properties, "audio_format" ), mlt_properties_get_int( properties, "audio_samples" ), mlt_properties_get_int( properties, "audio_channels" ) ); copy = mlt_pool_alloc( size ); memcpy( copy, data, size ); mlt_properties_set_data( new_props, "audio", copy, size, mlt_pool_release, NULL ); } data = mlt_properties_get_data( properties, "image", &size ); if ( data ) { if ( ! size ) size = mlt_image_format_size( mlt_properties_get_int( properties, "format" ), mlt_properties_get_int( properties, "width" ), mlt_properties_get_int( properties, "height" ), NULL ); copy = mlt_pool_alloc( size ); memcpy( copy, data, size ); mlt_properties_set_data( new_props, "image", copy, size, mlt_pool_release, NULL ); data = mlt_properties_get_data( properties, "alpha", &size ); if ( data ) { if ( ! size ) size = mlt_properties_get_int( properties, "width" ) * mlt_properties_get_int( properties, "height" ); copy = mlt_pool_alloc( size ); memcpy( copy, data, size ); mlt_properties_set_data( new_props, "alpha", copy, size, mlt_pool_release, NULL ); }; } } else { // This frame takes a reference on the original frame since the data is a shallow copy. mlt_properties_inc_ref( properties ); mlt_properties_set_data( new_props, "_cloned_frame", self, 0, (mlt_destructor) mlt_frame_close, NULL ); // Copy properties data = mlt_properties_get_data( properties, "audio", &size ); mlt_properties_set_data( new_props, "audio", data, size, NULL, NULL ); data = mlt_properties_get_data( properties, "image", &size ); mlt_properties_set_data( new_props, "image", data, size, NULL, NULL ); data = mlt_properties_get_data( properties, "alpha", &size ); mlt_properties_set_data( new_props, "alpha", data, size, NULL, NULL ); } return new_frame; } mlt-0.9.0/src/framework/mlt_frame.h000066400000000000000000000176631215300731300172270ustar00rootroot00000000000000/** * \file mlt_frame.h * \brief interface for all frame classes * \see mlt_frame_s * * Copyright (C) 2003-2013 Ushodaya Enterprises Limited * \author Charles Yates * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_FRAME_H_ #define _MLT_FRAME_H_ #include "mlt_properties.h" #include "mlt_deque.h" #include "mlt_service.h" /** Callback function to get video data. * */ typedef int ( *mlt_get_image )( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ); /** Callback function to get audio data. * */ typedef int ( *mlt_get_audio )( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ); /** \brief Frame class * * The frame is the primary data object that gets passed around to and through services. * * \extends mlt_properties * \properties \em test_image set if the frame holds a "test card" image * \properties \em test_audio set if the frame holds "test card" audio * \properties \em _producer holds a reference to the frame's end producer * \properties \em _speed the current speed of the producer that generated the frame * \properties \em _position the position of the frame * \properties \em meta.* holds metadata * \properties \em hide set to 1 to hide the video, 2 to mute the audio * \properties \em last_track a flag to indicate an end-of-tracks frame * \properties \em previous \em frame a reference to the unfiltered preceding frame * (no speed factor applied, only available when \em _need_previous_next is set on the producer) * \properties \em next \em frame a reference to the unfiltered following frame * (no speed factor applied, only available when \em _need_previous_next is set on the producer) * \properties \em colorspace the standard for luma coefficients * \properties \em force_full_luma luma range handling, set to -1 for pass-through, 1 for full range, 0 for scaling * \properties \em audio_frequency the sample rate of the audio * \properties \em audio_channels the number of audio channels * \properties \em audio_samples the number of audio samples * \properties \em audio_format the mlt_audio_format for the audio on this frame * \properties \em format the mlt_image_format of the image on this frame * \properties \em width the horizontal resolution of the image * \properties \em height the vertical resolution of the image * \properties \em aspect_ratio the sample aspect ratio of the image */ struct mlt_frame_s { struct mlt_properties_s parent; /**< \private A frame extends properties. */ /** Get the alpha channel (callback function). * \param self a frame * \return the 8-bit alpha channel */ uint8_t * ( *get_alpha_mask )( mlt_frame self ); /** Convert the image format (callback function). * \param self a frame * \param[in,out] image a buffer of image data * \param[in,out] input the image format of supplied image data * \param output the image format to which to convert * \return true if error */ int ( *convert_image )( mlt_frame self, uint8_t **image, mlt_image_format *input, mlt_image_format output ); /** Convert the audio format (callback function). * \param self a frame * \param[in,out] audio a buffer of audio data * \param[in,out] input the audio format of supplied data * \param output the audio format to which to convert * \return true if error */ int ( *convert_audio )( mlt_frame self, void **audio, mlt_audio_format *input, mlt_audio_format output ); mlt_deque stack_image; /**< \private the image processing stack of operations and data */ mlt_deque stack_audio; /**< \private the audio processing stack of operations and data */ mlt_deque stack_service; /**< \private a general purpose data stack */ int is_processing; /**< \private indicates if a frame is or was processed by the parallel consumer */ }; #define MLT_FRAME_PROPERTIES( frame ) ( &( frame )->parent ) #define MLT_FRAME_SERVICE_STACK( frame ) ( ( frame )->stack_service ) #define MLT_FRAME_IMAGE_STACK( frame ) ( ( frame )->stack_image ) #define MLT_FRAME_AUDIO_STACK( frame ) ( ( frame )->stack_audio ) extern mlt_frame mlt_frame_init( mlt_service service ); extern mlt_properties mlt_frame_properties( mlt_frame self ); extern int mlt_frame_is_test_card( mlt_frame self ); extern int mlt_frame_is_test_audio( mlt_frame self ); extern double mlt_frame_get_aspect_ratio( mlt_frame self ); extern int mlt_frame_set_aspect_ratio( mlt_frame self, double value ); extern mlt_position mlt_frame_get_position( mlt_frame self ); extern mlt_position mlt_frame_original_position( mlt_frame self ); extern int mlt_frame_set_position( mlt_frame self, mlt_position value ); extern int mlt_frame_set_image( mlt_frame self, uint8_t *image, int size, mlt_destructor destroy ); extern int mlt_frame_set_alpha( mlt_frame self, uint8_t *alpha, int size, mlt_destructor destroy ); extern void mlt_frame_replace_image( mlt_frame self, uint8_t *image, mlt_image_format format, int width, int height ); extern int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ); extern uint8_t *mlt_frame_get_alpha_mask( mlt_frame self ); extern int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ); extern int mlt_frame_set_audio( mlt_frame self, void *buffer, mlt_audio_format, int size, mlt_destructor ); extern unsigned char *mlt_frame_get_waveform( mlt_frame self, int w, int h ); extern int mlt_frame_push_get_image( mlt_frame self, mlt_get_image get_image ); extern mlt_get_image mlt_frame_pop_get_image( mlt_frame self ); extern int mlt_frame_push_frame( mlt_frame self, mlt_frame that ); extern mlt_frame mlt_frame_pop_frame( mlt_frame self ); extern int mlt_frame_push_service( mlt_frame self, void *that ); extern void *mlt_frame_pop_service( mlt_frame self ); extern int mlt_frame_push_service_int( mlt_frame self, int that ); extern int mlt_frame_pop_service_int( mlt_frame self ); extern int mlt_frame_push_audio( mlt_frame self, void *that ); extern void *mlt_frame_pop_audio( mlt_frame self ); extern mlt_deque mlt_frame_service_stack( mlt_frame self ); extern mlt_producer mlt_frame_get_original_producer( mlt_frame self ); extern void mlt_frame_close( mlt_frame self ); extern mlt_properties mlt_frame_unique_properties( mlt_frame self, mlt_service service ); extern mlt_frame mlt_frame_clone( mlt_frame self, int is_deep ); /* convenience functions */ extern int mlt_sample_calculator( float fps, int frequency, int64_t position ); extern int64_t mlt_sample_calculator_to_now( float fps, int frequency, int64_t position ); extern const char * mlt_image_format_name( mlt_image_format format ); extern int mlt_image_format_size( mlt_image_format format, int width, int height, int *bpp ); extern const char * mlt_audio_format_name( mlt_audio_format format ); extern int mlt_audio_format_size( mlt_audio_format format, int samples, int channels ); extern void mlt_frame_write_ppm( mlt_frame frame ); /** This macro scales RGB into the YUV gamut - y is scaled by 219/255 and uv by 224/255. */ #define RGB2YUV_601_SCALED(r, g, b, y, u, v)\ y = ((263*r + 516*g + 100*b) >> 10) + 16;\ u = ((-152*r - 300*g + 450*b) >> 10) + 128;\ v = ((450*r - 377*g - 73*b) >> 10) + 128; #endif mlt-0.9.0/src/framework/mlt_geometry.c000066400000000000000000000411741215300731300177550ustar00rootroot00000000000000/** * \file mlt_geometry.c * \brief geometry animation API (deprecated) * \deprecated use mlt_animation_s instead * * Copyright (C) 2004-2005 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_geometry.h" #include "mlt_tokeniser.h" #include "mlt_factory.h" #include "mlt_profile.h" #include #include #include /** private part of geometry animation item (deprecated) * \deprecated use mlt_animation_s instead */ typedef struct geometry_item_s { struct mlt_geometry_item_s data; struct geometry_item_s *next, *prev; } *geometry_item; /** private part of geometry object (deprecated) * \deprecated use mlt_animation_s instead */ typedef struct { char *data; int length; int nw; int nh; geometry_item item; } geometry_s, *geometry; // Create a new geometry structure mlt_geometry mlt_geometry_init( ) { mlt_geometry self = calloc( 1, sizeof( struct mlt_geometry_s ) ); if ( self != NULL ) { self->local = calloc( 1, sizeof( geometry_s ) ); if ( self->local != NULL ) { geometry g = self->local; g->nw = 720; g->nh = 576; } else { free( self ); self = NULL; } } return self; } /** A linear step */ static inline double linearstep( double start, double end, double position, int length ) { double o = ( end - start ) / length; return start + position * o; } void mlt_geometry_interpolate( mlt_geometry self ) { geometry g = self->local; // Parse of all items to ensure unspecified keys are calculated correctly if ( g->item != NULL ) { int i = 0; for ( i = 0; i < 5; i ++ ) { geometry_item current = g->item; while( current != NULL ) { int fixed = current->data.f[ i ]; if ( !fixed ) { geometry_item prev = current->prev; geometry_item next = current->next; double prev_value = 0; double next_value = 0; double value = 0; while( prev != NULL && !prev->data.f[ i ] ) prev = prev->prev; while( next != NULL && !next->data.f[ i ] ) next = next->next; switch( i ) { case 0: if ( prev ) prev_value = prev->data.x; if ( next ) next_value = next->data.x; break; case 1: if ( prev ) prev_value = prev->data.y; if ( next ) next_value = next->data.y; break; case 2: if ( prev ) prev_value = prev->data.w; if ( next ) next_value = next->data.w; break; case 3: if ( prev ) prev_value = prev->data.h; if ( next ) next_value = next->data.h; break; case 4: if ( prev ) prev_value = prev->data.mix; if ( next ) next_value = next->data.mix; break; } // This should never happen if ( prev == NULL ) current->data.f[ i ] = 1; else if ( next == NULL ) value = prev_value; else value = linearstep( prev_value, next_value, current->data.frame - prev->data.frame, next->data.frame - prev->data.frame ); switch( i ) { case 0: current->data.x = value; break; case 1: current->data.y = value; break; case 2: current->data.w = value; break; case 3: current->data.h = value; break; case 4: current->data.mix = value; break; } } // Move to the next item current = current->next; } } } } static int mlt_geometry_drop( mlt_geometry self, geometry_item item ) { geometry g = self->local; if ( item == g->item ) { g->item = item->next; if ( g->item != NULL ) g->item->prev = NULL; // To ensure correct seeding, ensure all values are fixed if ( g->item != NULL ) { g->item->data.f[0] = 1; g->item->data.f[1] = 1; g->item->data.f[2] = 1; g->item->data.f[3] = 1; g->item->data.f[4] = 1; } } else if ( item->next != NULL && item->prev != NULL ) { item->prev->next = item->next; item->next->prev = item->prev; } else if ( item->next != NULL ) { item->next->prev = item->prev; } else if ( item->prev != NULL ) { item->prev->next = item->next; } free( item ); return 0; } static void mlt_geometry_clean( mlt_geometry self ) { geometry g = self->local; if ( g->data ) free( g->data ); g->data = NULL; while( g->item ) mlt_geometry_drop( self, g->item ); } // Parse the geometry specification for a given length and normalised width/height (-1 for default) // data is constructed as: [frame=]X/Y:WxH[:mix][!][;[frame=]X/Y:WxH[:mix][!]]* // and X, Y, W and H can have trailing % chars to indicate percentage of normalised size // Append a pair's value with ! to enable distort. int mlt_geometry_parse( mlt_geometry self, char *data, int length, int nw, int nh ) { int i = 0; // Create a tokeniser mlt_tokeniser tokens = mlt_tokeniser_init( ); // Get the local/private structure geometry g = self->local; // Clean the existing geometry mlt_geometry_clean( self ); // Update the info on the data if ( length != -1 ) g->length = length; if ( nw != -1 ) g->nw = nw; if ( nh != -1 ) g->nh = nh; if ( data != NULL ) g->data = strdup( data ); // Tokenise if ( data != NULL ) mlt_tokeniser_parse_new( tokens, data, ";" ); // Iterate through each token for ( i = 0; i < mlt_tokeniser_count( tokens ); i ++ ) { struct mlt_geometry_item_s item; char *value = mlt_tokeniser_get_string( tokens, i ); // If no data in keyframe, drop it (trailing semicolon) if ( value == NULL || !strcmp( value, "" ) ) continue; // Set item to 0 memset( &item, 0, sizeof( struct mlt_geometry_item_s ) ); // Now parse the item mlt_geometry_parse_item( self, &item, value ); // Now insert into place mlt_geometry_insert( self, &item ); } mlt_geometry_interpolate( self ); // Remove the tokeniser mlt_tokeniser_close( tokens ); // ??? return 0; } // Conditionally refresh in case of a change int mlt_geometry_refresh( mlt_geometry self, char *data, int length, int nw, int nh ) { geometry g = self->local; int changed = ( length != -1 && length != g->length ); changed = changed || ( nw != -1 && nw != g->nw ); changed = changed || ( nh != -1 && nh != g->nh ); changed = changed || ( data != NULL && ( g->data == NULL || strcmp( data, g->data ) ) ); if ( changed ) return mlt_geometry_parse( self, data, length, nw, nh ); return -1; } int mlt_geometry_get_length( mlt_geometry self ) { // Get the local/private structure geometry g = self->local; // return the length return g->length; } void mlt_geometry_set_length( mlt_geometry self, int length ) { // Get the local/private structure geometry g = self->local; // set the length g->length = length; } int mlt_geometry_parse_item( mlt_geometry self, mlt_geometry_item item, char *value ) { int ret = 0; // Get the local/private structure geometry g = self->local; if ( value != NULL && strcmp( value, "" ) ) { char *p = strchr( value, '=' ); int count = 0; double temp; // Determine if a position has been specified if ( p != NULL ) { temp = atof( value ); if ( temp > -1 && temp < 1 ) item->frame = temp * g->length; else item->frame = temp; value = p + 1; } // Special case - frame < 0 if ( item->frame < 0 ) item->frame += g->length; // Obtain the current value at this position - self allows new // frames to be created which don't specify all values mlt_geometry_fetch( self, item, item->frame ); // Special case - when an empty string is specified, all values are fixed // TODO: Check if this is logical - it's convenient, but it's also odd... if ( !*value ) { item->f[0] = 1; item->f[1] = 1; item->f[2] = 1; item->f[3] = 1; item->f[4] = 1; } // Iterate through the remainder of value while( *value ) { // Get the value temp = strtod( value, &p ); // Check if a value was specified if ( p != value ) { // Handle the % case if ( *p == '%' ) { if ( count == 0 || count == 2 ) temp *= g->nw / 100.0; else if ( count == 1 || count == 3 ) temp *= g->nh / 100.0; p ++; } // Special case - distort token if ( *p == '!' || *p == '*' ) { p ++; item->distort = 1; } // Actually, we don't care about the delimiter at all.. if ( *p ) p ++; // Assign to the item switch( count ) { case 0: item->x = temp; item->f[0] = 1; break; case 1: item->y = temp; item->f[1] = 1; break; case 2: item->w = temp; item->f[2] = 1; break; case 3: item->h = temp; item->f[3] = 1; break; case 4: item->mix = temp; item->f[4] = 1; break; } } else { p ++; } // Update the value pointer value = p; count ++; } } else { ret = 1; } return ret; } // Fetch a geometry item for an absolute position int mlt_geometry_fetch( mlt_geometry self, mlt_geometry_item item, float position ) { // Get the local geometry geometry g = self->local; // Need to find the nearest key to the position specifed geometry_item key = g->item; // Iterate through the keys until we reach last or have while( key != NULL && key->next != NULL && position >= key->next->data.frame ) key = key->next; if ( key != NULL ) { // Position is situated before the first key - all zeroes if ( position < key->data.frame ) { memset( item, 0, sizeof( struct mlt_geometry_item_s ) ); item->mix = 100; } // Position is a key itself - no iterpolation need else if ( position == key->data.frame ) { memcpy( item, &key->data, sizeof( struct mlt_geometry_item_s ) ); } // Position is after the last key - no interpolation, but not a key frame else if ( key->next == NULL ) { memcpy( item, &key->data, sizeof( struct mlt_geometry_item_s ) ); item->key = 0; item->f[ 0 ] = 0; item->f[ 1 ] = 0; item->f[ 2 ] = 0; item->f[ 3 ] = 0; item->f[ 4 ] = 0; } // Interpolation is needed - position > key and there is a following key else { item->key = 0; item->frame = position; position -= key->data.frame; item->x = linearstep( key->data.x, key->next->data.x, position, key->next->data.frame - key->data.frame ); item->y = linearstep( key->data.y, key->next->data.y, position, key->next->data.frame - key->data.frame ); item->w = linearstep( key->data.w, key->next->data.w, position, key->next->data.frame - key->data.frame ); item->h = linearstep( key->data.h, key->next->data.h, position, key->next->data.frame - key->data.frame ); item->mix = linearstep( key->data.mix, key->next->data.mix, position, key->next->data.frame - key->data.frame ); item->distort = key->data.distort; position += key->data.frame; } item->frame = position; } else { memset( item, 0, sizeof( struct mlt_geometry_item_s ) ); item->frame = position; item->mix = 100; } return key == NULL; } // Specify a geometry item at an absolute position int mlt_geometry_insert( mlt_geometry self, mlt_geometry_item item ) { // Get the local/private geometry structure geometry g = self->local; // Create a new local item (this may be removed if a key already exists at self position) geometry_item gi = calloc( 1, sizeof( struct geometry_item_s ) ); memcpy( &gi->data, item, sizeof( struct mlt_geometry_item_s ) ); gi->data.key = 1; // Determine if we need to insert or append to the list, or if it's a new list if ( g->item != NULL ) { // Get the first item geometry_item place = g->item; // Locate an existing nearby item while ( place->next != NULL && item->frame > place->data.frame ) place = place->next; if ( item->frame < place->data.frame ) { if ( place == g->item ) g->item = gi; if ( place->prev ) place->prev->next = gi; gi->next = place; gi->prev = place->prev; place->prev = gi; } else if ( item->frame > place->data.frame ) { if ( place->next ) place->next->prev = gi; gi->next = place->next; gi->prev = place; place->next = gi; } else { memcpy( &place->data, &gi->data, sizeof( struct mlt_geometry_item_s ) ); free( gi ); } } else { // Set the first item g->item = gi; // To ensure correct seeding, ensure all values are fixed g->item->data.f[0] = 1; g->item->data.f[1] = 1; g->item->data.f[2] = 1; g->item->data.f[3] = 1; g->item->data.f[4] = 1; } // TODO: Error checking return 0; } // Remove the key at the specified position int mlt_geometry_remove( mlt_geometry self, int position ) { int ret = 1; // Get the local/private geometry structure geometry g = self->local; // Get the first item geometry_item place = g->item; while( place != NULL && position != place->data.frame ) place = place->next; if ( place != NULL && position == place->data.frame ) ret = mlt_geometry_drop( self, place ); return ret; } // Get the key at the position or the next following int mlt_geometry_next_key( mlt_geometry self, mlt_geometry_item item, int position ) { // Get the local/private geometry structure geometry g = self->local; // Get the first item geometry_item place = g->item; while( place != NULL && position > place->data.frame ) place = place->next; if ( place != NULL ) memcpy( item, &place->data, sizeof( struct mlt_geometry_item_s ) ); return place == NULL; } // Get the key at the position or the previous key int mlt_geometry_prev_key( mlt_geometry self, mlt_geometry_item item, int position ) { // Get the local/private geometry structure geometry g = self->local; // Get the first item geometry_item place = g->item; while( place != NULL && place->next != NULL && position >= place->next->data.frame ) place = place->next; if ( place != NULL ) memcpy( item, &place->data, sizeof( struct mlt_geometry_item_s ) ); return place == NULL; } char *mlt_geometry_serialise_cut( mlt_geometry self, int in, int out ) { geometry g = self->local; struct mlt_geometry_item_s item; char *ret = malloc( 1000 ); int used = 0; int size = 1000; if ( in == -1 ) in = 0; if ( out == -1 ) out = mlt_geometry_get_length( self ); if ( ret != NULL ) { char temp[ 100 ]; strcpy( ret, "" ); item.frame = in; while( 1 ) { strcpy( temp, "" ); // If it's the first frame, then it's not necessarily a key if ( item.frame == in ) { if ( mlt_geometry_fetch( self, &item, item.frame ) ) break; // If the first key is larger than the current position // then do nothing here if ( g->item->data.frame > item.frame ) { item.frame ++; continue; } // To ensure correct seeding, ensure all values are fixed item.f[0] = 1; item.f[1] = 1; item.f[2] = 1; item.f[3] = 1; item.f[4] = 1; } // Typically, we move from key to key else if ( item.frame < out ) { if ( mlt_geometry_next_key( self, &item, item.frame ) ) break; // Special case - crop at the out point if ( item.frame > out ) mlt_geometry_fetch( self, &item, out ); } // We've handled the last key else { break; } if ( item.frame - in != 0 ) sprintf( temp, "%d=", item.frame - in ); if ( item.f[0] ) sprintf( temp + strlen( temp ), "%g", item.x ); if ( item.f[1] ) { strcat( temp, "/" ); sprintf( temp + strlen( temp ), "%g", item.y ); } if ( item.f[2] ) { strcat( temp, ":" ); sprintf( temp + strlen( temp ), "%g", item.w ); } if ( item.f[3] ) { strcat( temp, "x" ); sprintf( temp + strlen( temp ), "%g", item.h ); } if ( item.f[4] ) { strcat( temp, ":" ); sprintf( temp + strlen( temp ), "%g", item.mix ); } if ( used + strlen( temp ) + 2 > size ) // +2 for ';' and NULL { size += 1000; ret = realloc( ret, size ); } if ( ret != NULL && used != 0 ) { used ++; strcat( ret, ";" ); } if ( ret != NULL ) { used += strlen( temp ); strcat( ret, temp ); } item.frame ++; } } return ret; } // Serialise the current geometry char *mlt_geometry_serialise( mlt_geometry self ) { geometry g = self->local; char *ret = mlt_geometry_serialise_cut( self, 0, g->length ); if ( ret ) { if ( g->data ) free( g->data ); g->data = ret; } return strdup( ret ); } // Close the geometry void mlt_geometry_close( mlt_geometry self ) { if ( self != NULL ) { mlt_geometry_clean( self ); free( self->local ); free( self ); } } mlt-0.9.0/src/framework/mlt_geometry.h000066400000000000000000000065201215300731300177560ustar00rootroot00000000000000/** * \file mlt_geometry.h * \brief geometry animation API (deprecated) * \deprecated use mlt_animation_s instead * * Copyright (C) 2004-2005 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_GEOMETRY_H #define _MLT_GEOMETRY_H #include "mlt_types.h" /** geometry animation item (deprecated) * \deprecated use mlt_animation_s instead */ struct mlt_geometry_item_s { /* Will be 1 when this is a key frame */ int key; /* The actual frame this corresponds to */ int frame; /* Distort */ int distort; /* x,y are upper left */ float x, y, w, h, mix; /* Indicates which values are fixed */ int f[ 5 ]; }; /** geometry object (deprecated) * \deprecated use mlt_animation_s instead */ struct mlt_geometry_s { void *local; }; /* Create a new geometry structure */ extern mlt_geometry mlt_geometry_init( ); /* Parse the geometry specification for a given length and normalised width/height (-1 for default) */ extern int mlt_geometry_parse( mlt_geometry self, char *data, int length, int nw, int nh ); /* Conditionally refresh the geometry if it's modified */ extern int mlt_geometry_refresh( mlt_geometry self, char *data, int length, int nw, int nh ); /* Get and set the length */ extern int mlt_geometry_get_length( mlt_geometry self ); extern void mlt_geometry_set_length( mlt_geometry self, int length ); /* Parse an item - doesn't affect the geometry itself but uses current information for evaluation */ /* (item->frame should be specified if not included in the data itself) */ extern int mlt_geometry_parse_item( mlt_geometry self, mlt_geometry_item item, char *data ); /* Fetch a geometry item for an absolute position */ extern int mlt_geometry_fetch( mlt_geometry self, mlt_geometry_item item, float position ); /* Specify a geometry item at an absolute position */ extern int mlt_geometry_insert( mlt_geometry self, mlt_geometry_item item ); /* Remove the key at the specified position */ extern int mlt_geometry_remove( mlt_geometry self, int position ); /* Typically, re-interpolate after a series of insertions or removals. */ extern void mlt_geometry_interpolate( mlt_geometry self ); /* Get the key at the position or the next following */ extern int mlt_geometry_next_key( mlt_geometry self, mlt_geometry_item item, int position ); extern int mlt_geometry_prev_key( mlt_geometry self, mlt_geometry_item item, int position ); /* Serialise the current geometry */ extern char *mlt_geometry_serialise_cut( mlt_geometry self, int in, int out ); extern char *mlt_geometry_serialise( mlt_geometry self ); /* Close the geometry */ extern void mlt_geometry_close( mlt_geometry self ); #endif mlt-0.9.0/src/framework/mlt_log.c000066400000000000000000000046611215300731300167030ustar00rootroot00000000000000/** * \file mlt_log.c * \brief logging functions * * Copyright (c) 2003 Michel Bardiaux * * This file was a 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 (at your option) 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 */ #include "mlt_log.h" #include "mlt_service.h" #include static int log_level = MLT_LOG_WARNING; void default_callback( void* ptr, int level, const char* fmt, va_list vl ) { static int print_prefix = 1; mlt_properties properties = ptr ? MLT_SERVICE_PROPERTIES( ( mlt_service )ptr ) : NULL; if ( level > log_level ) return; if ( print_prefix && properties ) { char *mlt_type = mlt_properties_get( properties, "mlt_type" ); char *mlt_service = mlt_properties_get( properties, "mlt_service" ); char *resource = mlt_properties_get( properties, "resource" ); if ( !( resource && *resource && resource[0] == '<' && resource[ strlen(resource) - 1 ] == '>' ) ) mlt_type = mlt_properties_get( properties, "mlt_type" ); if ( mlt_service ) fprintf( stderr, "[%s %s] ", mlt_type, mlt_service ); else fprintf( stderr, "[%s %p] ", mlt_type, ptr ); if ( resource ) fprintf( stderr, "%s\n ", resource ); } print_prefix = strstr( fmt, "\n" ) != NULL; vfprintf( stderr, fmt, vl ); } static void ( *callback )( void*, int, const char*, va_list ) = default_callback; void mlt_log( void* service, int level, const char *fmt, ...) { va_list vl; va_start( vl, fmt ); mlt_vlog( service, level, fmt, vl ); va_end( vl ); } void mlt_vlog( void* service, int level, const char *fmt, va_list vl ) { if ( callback ) callback( service, level, fmt, vl ); } int mlt_log_get_level( void ) { return log_level; } void mlt_log_set_level( int level ) { log_level = level; } void mlt_log_set_callback( void (*new_callback)( void*, int, const char*, va_list ) ) { callback = new_callback; } mlt-0.9.0/src/framework/mlt_log.h000066400000000000000000000064611215300731300167100ustar00rootroot00000000000000/** * \file mlt_log.h * \brief logging functions * * copyright (c) 2006 Michael Niedermayer * * This file was a 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 (at your option) 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 MLT_LOG_H #define MLT_LOG_H #include #define MLT_LOG_QUIET -8 /** * something went really wrong and we will crash now */ #define MLT_LOG_PANIC 0 /** * something went wrong and recovery is not possible * like no header in a format which depends on it or a combination * of parameters which are not allowed */ #define MLT_LOG_FATAL 8 /** * something went wrong and cannot losslessly be recovered * but not all future data is affected */ #define MLT_LOG_ERROR 16 /** * something somehow does not look correct / something which may or may not * lead to some problems */ #define MLT_LOG_WARNING 24 #define MLT_LOG_INFO 32 #define MLT_LOG_VERBOSE 40 /** * stuff which is only useful for MLT developers */ #define MLT_LOG_DEBUG 48 /** * Send the specified message to the log if the level is less than or equal to * the current logging level. By default, all logging messages are sent to * stderr. This behavior can be altered by setting a different mlt_vlog callback * function. * * \param service An optional pointer to a \p mlt_service_s. * \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 mlt_vlog */ #ifdef __GNUC__ void mlt_log( void *service, int level, const char *fmt, ... ) __attribute__ ((__format__ (__printf__, 3, 4))); #else void mlt_log( void *service, int level, const char *fmt, ... ); #endif #define mlt_log_panic(service, format, args...) mlt_log((service), MLT_LOG_PANIC, (format), ## args) #define mlt_log_fatal(service, format, args...) mlt_log((service), MLT_LOG_FATAL, (format), ## args) #define mlt_log_error(service, format, args...) mlt_log((service), MLT_LOG_ERROR, (format), ## args) #define mlt_log_warning(service, format, args...) mlt_log((service), MLT_LOG_WARNING, (format), ## args) #define mlt_log_info(service, format, args...) mlt_log((service), MLT_LOG_INFO, (format), ## args) #define mlt_log_verbose(service, format, args...) mlt_log((service), MLT_LOG_VERBOSE, (format), ## args) #define mlt_log_debug(service, format, args...) mlt_log((service), MLT_LOG_DEBUG, (format), ## args) void mlt_vlog( void *service, int level, const char *fmt, va_list ); int mlt_log_get_level( void ); void mlt_log_set_level( int ); void mlt_log_set_callback( void (*)( void*, int, const char*, va_list ) ); #endif /* MLT_LOG_H */ mlt-0.9.0/src/framework/mlt_multitrack.c000066400000000000000000000353611215300731300203020ustar00rootroot00000000000000/** * \file mlt_multitrack.c * \brief multitrack service class * \see mlt_multitrack_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_multitrack.h" #include "mlt_playlist.h" #include "mlt_frame.h" #include #include /* Forward reference. */ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ); /** Construct and initialize a new multitrack. * * Sets the resource property to "". * * \public \memberof mlt_multitrack_s * \return a new multitrack */ mlt_multitrack mlt_multitrack_init( ) { // Allocate the multitrack object mlt_multitrack self = calloc( 1, sizeof( struct mlt_multitrack_s ) ); if ( self != NULL ) { mlt_producer producer = &self->parent; if ( mlt_producer_init( producer, self ) == 0 ) { mlt_properties properties = MLT_MULTITRACK_PROPERTIES( self ); producer->get_frame = producer_get_frame; mlt_properties_set_data( properties, "multitrack", self, 0, NULL, NULL ); mlt_properties_set( properties, "log_id", "multitrack" ); mlt_properties_set( properties, "resource", "" ); mlt_properties_set_int( properties, "in", 0 ); mlt_properties_set_int( properties, "out", -1 ); mlt_properties_set_int( properties, "length", 0 ); producer->close = ( mlt_destructor )mlt_multitrack_close; } else { free( self ); self = NULL; } } return self; } /** Get the producer associated to this multitrack. * * \public \memberof mlt_multitrack_s * \param self a multitrack * \return the producer object * \see MLT_MULTITRACK_PRODUCER */ mlt_producer mlt_multitrack_producer( mlt_multitrack self ) { return self != NULL ? &self->parent : NULL; } /** Get the service associated this multitrack. * * \public \memberof mlt_multitrack_s * \param self a multitrack * \return the service object * \see MLT_MULTITRACK_SERVICE */ mlt_service mlt_multitrack_service( mlt_multitrack self ) { return MLT_MULTITRACK_SERVICE( self ); } /** Get the properties associated this multitrack. * * \public \memberof mlt_multitrack_s * \param self a multitrack * \return the multitrack's property list * \see MLT_MULTITRACK_PROPERTIES */ mlt_properties mlt_multitrack_properties( mlt_multitrack self ) { return MLT_MULTITRACK_PROPERTIES( self ); } /** Initialize position related information. * * \public \memberof mlt_multitrack_s * \param self a multitrack */ void mlt_multitrack_refresh( mlt_multitrack self ) { int i = 0; // Obtain the properties of this multitrack mlt_properties properties = MLT_MULTITRACK_PROPERTIES( self ); // We need to ensure that the multitrack reports the longest track as its length mlt_position length = 0; // Obtain stats on all connected services for ( i = 0; i < self->count; i ++ ) { // Get the producer from this index mlt_track track = self->list[ i ]; mlt_producer producer = track->producer; // If it's allocated then, update our stats if ( producer != NULL ) { // If we have more than 1 track, we must be in continue mode if ( self->count > 1 ) mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "continue" ); // Determine the longest length //if ( !mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( producer ), "hide" ) ) length = mlt_producer_get_playtime( producer ) > length ? mlt_producer_get_playtime( producer ) : length; } } // Update multitrack properties now - we'll not destroy the in point here mlt_events_block( properties, properties ); mlt_properties_set_position( properties, "length", length ); mlt_events_unblock( properties, properties ); mlt_properties_set_position( properties, "out", length - 1 ); } /** Listener for producers on the playlist. * * \private \memberof mlt_multitrack_s * \param producer a producer * \param self a multitrack */ static void mlt_multitrack_listener( mlt_producer producer, mlt_multitrack self ) { mlt_multitrack_refresh( self ); } /** Connect a producer to a given track. * * Note that any producer can be connected here, but see special case treatment * of playlist in clip point determination below. * * \public \memberof mlt_multitrack_s * \param self a multitrack * \param producer the producer to connect to the multitrack producer * \param track the 0-based index of the track on which to connect the multitrack * \return true on error */ int mlt_multitrack_connect( mlt_multitrack self, mlt_producer producer, int track ) { // Connect to the producer to ourselves at the specified track int result = mlt_service_connect_producer( MLT_MULTITRACK_SERVICE( self ), MLT_PRODUCER_SERVICE( producer ), track ); if ( result == 0 ) { // Resize the producer list if need be if ( track >= self->size ) { int i; self->list = realloc( self->list, ( track + 10 ) * sizeof( mlt_track ) ); for ( i = self->size; i < track + 10; i ++ ) self->list[ i ] = NULL; self->size = track + 10; } if ( self->list[ track ] != NULL ) { mlt_event_close( self->list[ track ]->event ); mlt_producer_close( self->list[ track ]->producer ); } else { self->list[ track ] = malloc( sizeof( struct mlt_track_s ) ); } // Assign the track in our list here self->list[ track ]->producer = producer; self->list[ track ]->event = mlt_events_listen( MLT_PRODUCER_PROPERTIES( producer ), self, "producer-changed", ( mlt_listener )mlt_multitrack_listener ); mlt_properties_inc_ref( MLT_PRODUCER_PROPERTIES( producer ) ); mlt_event_inc_ref( self->list[ track ]->event ); // Increment the track count if need be if ( track >= self->count ) { self->count = track + 1; // TODO: Move this into producer_avformat.c when mlt_events broadcasting is available. if ( self->count > mlt_service_cache_get_size( MLT_MULTITRACK_SERVICE( self ), "producer_avformat" ) ) mlt_service_cache_set_size( MLT_MULTITRACK_SERVICE( self ), "producer_avformat", self->count + 1 ); } // Refresh our stats mlt_multitrack_refresh( self ); } return result; } /** Get the number of tracks. * * \public \memberof mlt_multitrack_s * \param self a multitrack * \return the number of tracks */ int mlt_multitrack_count( mlt_multitrack self ) { return self->count; } /** Get an individual track as a producer. * * \public \memberof mlt_multitrack_s * \param self a multitrack * \param track the 0-based index of the producer to get * \return the producer or NULL if not valid */ mlt_producer mlt_multitrack_track( mlt_multitrack self, int track ) { mlt_producer producer = NULL; if ( self->list != NULL && track < self->count ) producer = self->list[ track ]->producer; return producer; } /** Position comparison function for sorting. * * \private \memberof mlt_multitrack_s * \param p1 a position * \param p2 another position * \return <0 if \p p1 is less than \p p2, 0 if equal, >0 if greater */ static int position_compare( const void *p1, const void *p2 ) { return *( const mlt_position * )p1 - *( const mlt_position * )p2; } /** Add a position to a set. * * \private \memberof mlt_multitrack_s * \param array an array of positions (the set) * \param size the current number of positions in the array (not the capacity of the array) * \param position the position to add * \return the new size of the array */ static int add_unique( mlt_position *array, int size, mlt_position position ) { int i = 0; for ( i = 0; i < size; i ++ ) if ( array[ i ] == position ) break; if ( i == size ) array[ size ++ ] = position; return size; } /** Determine the clip point. * *
 * Special case here: a 'producer' has no concept of multiple clips - only the
 * playlist and multitrack producers have clip functionality. Further to that a
 * multitrack determines clip information from any connected tracks that happen
 * to be playlists.
 *
 * Additionally, it must locate clips in the correct order, for example, consider
 * the following track arrangement:
 *
 * playlist1 |0.0     |b0.0      |0.1          |0.1         |0.2           |
 * playlist2 |b1.0  |1.0           |b1.1     |1.1             |
 *
 * Note - b clips represent blanks. They are also reported as clip positions.
 *
 * When extracting clip positions from these playlists, we should get a sequence of:
 *
 * 0.0, 1.0, b0.0, 0.1, b1.1, 1.1, 0.1, 0.2, [out of playlist2], [out of playlist1]
 * 
* * \public \memberof mlt_multitrack_s * \param self a multitrack * \param whence from where to extract * \param index the 0-based index of which clip to extract * \return the position of clip \p index relative to \p whence */ mlt_position mlt_multitrack_clip( mlt_multitrack self, mlt_whence whence, int index ) { mlt_position position = 0; int i = 0; int j = 0; mlt_position *map = calloc( 1000, sizeof( mlt_position ) ); int count = 0; for ( i = 0; i < self->count; i ++ ) { // Get the producer for this track mlt_producer producer = self->list[ i ]->producer; // If it's assigned and not a hidden track if ( producer != NULL ) { // Get the properties of this producer mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); // Determine if it's a playlist mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL ); // Special case consideration of playlists if ( playlist != NULL ) { for ( j = 0; j < mlt_playlist_count( playlist ); j ++ ) count = add_unique( map, count, mlt_playlist_clip( playlist, mlt_whence_relative_start, j ) ); count = add_unique( map, count, mlt_producer_get_out( producer ) + 1 ); } else { count = add_unique( map, count, 0 ); count = add_unique( map, count, mlt_producer_get_out( producer ) + 1 ); } } } // Now sort the map qsort( map, count, sizeof( mlt_position ), position_compare ); // Now locate the requested index switch( whence ) { case mlt_whence_relative_start: if ( index < count ) position = map[ index ]; else position = map[ count - 1 ]; break; case mlt_whence_relative_current: position = mlt_producer_position( MLT_MULTITRACK_PRODUCER( self ) ); for ( i = 0; i < count - 2; i ++ ) if ( position >= map[ i ] && position < map[ i + 1 ] ) break; index += i; if ( index >= 0 && index < count ) position = map[ index ]; else if ( index < 0 ) position = map[ 0 ]; else position = map[ count - 1 ]; break; case mlt_whence_relative_end: if ( index < count ) position = map[ count - index - 1 ]; else position = map[ 0 ]; break; } // Free the map free( map ); return position; } /** Get frame method. * *
 * Special case here: The multitrack must be used in a conjunction with a downstream
 * tractor-type service, ie:
 *
 * Producer1 \
 * Producer2 - multitrack - { filters/transitions } - tractor - consumer
 * Producer3 /
 *
 * The get_frame of a tractor pulls frames from it's connected service on all tracks and
 * will terminate as soon as it receives a test card with a last_track property. The
 * important case here is that the mulitrack does not move to the next frame until all
 * tracks have been pulled.
 *
 * Reasoning: In order to seek on a network such as above, the multitrack needs to ensure
 * that all producers are positioned on the same frame. It uses the 'last track' logic
 * to determine when to move to the next frame.
 *
 * Flaw: if a transition is configured to read from a b-track which happens to trigger
 * the last frame logic (ie: it's configured incorrectly), then things are going to go
 * out of sync.
 *
 * See playlist logic too.
 * 
* * \private \memberof mlt_multitrack_s * \param parent the producer interface to a mulitrack * \param[out] frame a frame by reference * \param index the 0-based track index * \return true if there was an error */ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ) { // Get the mutiltrack object mlt_multitrack self = parent->child; // Check if we have a track for this index if ( index < self->count && self->list[ index ] != NULL ) { // Get the producer for this track mlt_producer producer = self->list[ index ]->producer; // Get the track hide property int hide = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( producer ) ), "hide" ); // Obtain the current position mlt_position position = mlt_producer_frame( parent ); // Get the parent properties mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( parent ); // Get the speed double speed = mlt_properties_get_double( producer_properties, "_speed" ); // Make sure we're at the same point mlt_producer_seek( producer, position ); // Get the frame from the producer mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), frame, 0 ); // Indicate speed of this producer mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); mlt_properties_set_double( properties, "_speed", speed ); mlt_frame_set_position( *frame, position ); mlt_properties_set_int( properties, "hide", hide ); } else { // Generate a test frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( parent ) ); // Update position on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( parent ) ); // Move on to the next frame if ( index >= self->count ) { // Let tractor know if we've reached the end mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "last_track", 1 ); // Move to the next frame mlt_producer_prepare_next( parent ); } } return 0; } /** Close this instance and free its resources. * * \public \memberof mlt_multitrack_s * \param self a multitrack */ void mlt_multitrack_close( mlt_multitrack self ) { if ( self != NULL && mlt_properties_dec_ref( MLT_MULTITRACK_PROPERTIES( self ) ) <= 0 ) { int i = 0; for ( i = 0; i < self->count; i ++ ) { if ( self->list[ i ] != NULL ) { mlt_event_close( self->list[ i ]->event ); mlt_producer_close( self->list[ i ]->producer ); free( self->list[ i ] ); } } // Close the producer self->parent.close = NULL; mlt_producer_close( &self->parent ); // Free the list free( self->list ); // Free the object free( self ); } } mlt-0.9.0/src/framework/mlt_multitrack.h000066400000000000000000000047461215300731300203120ustar00rootroot00000000000000/** * \file mlt_multitrack.h * \brief multitrack service class * \see mlt_multitrack_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_MULITRACK_H_ #define _MLT_MULITRACK_H_ #include "mlt_producer.h" /** \brief Track class used by mlt_multitrack_s */ struct mlt_track_s { mlt_producer producer; mlt_event event; }; typedef struct mlt_track_s *mlt_track; /** \brief Multitrack class * * A multitrack is a parallel container of producers that acts a single producer. * * \extends mlt_producer_s * \properties \em log_id not currently used, but sets it to "mulitrack" */ struct mlt_multitrack_s { /** We're extending producer here */ struct mlt_producer_s parent; mlt_track *list; int size; int count; }; #define MLT_MULTITRACK_PRODUCER( multitrack ) ( &( multitrack )->parent ) #define MLT_MULTITRACK_SERVICE( multitrack ) MLT_PRODUCER_SERVICE( MLT_MULTITRACK_PRODUCER( multitrack ) ) #define MLT_MULTITRACK_PROPERTIES( multitrack ) MLT_SERVICE_PROPERTIES( MLT_MULTITRACK_SERVICE( multitrack ) ) extern mlt_multitrack mlt_multitrack_init( ); extern mlt_producer mlt_multitrack_producer( mlt_multitrack self ); extern mlt_service mlt_multitrack_service( mlt_multitrack self ); extern mlt_properties mlt_multitrack_properties( mlt_multitrack self ); extern int mlt_multitrack_connect( mlt_multitrack self, mlt_producer producer, int track ); extern mlt_position mlt_multitrack_clip( mlt_multitrack self, mlt_whence whence, int index ); extern void mlt_multitrack_close( mlt_multitrack self ); extern int mlt_multitrack_count( mlt_multitrack self ); extern void mlt_multitrack_refresh( mlt_multitrack self ); extern mlt_producer mlt_multitrack_track( mlt_multitrack self, int track ); #endif mlt-0.9.0/src/framework/mlt_parser.c000066400000000000000000000157061215300731300174200ustar00rootroot00000000000000/** * \file mlt_parser.c * \brief service parsing functionality * \see mlt_parser_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt.h" #include static int on_invalid( mlt_parser self, mlt_service object ) { return 0; } static int on_unknown( mlt_parser self, mlt_service object ) { return 0; } static int on_start_producer( mlt_parser self, mlt_producer object ) { return 0; } static int on_end_producer( mlt_parser self, mlt_producer object ) { return 0; } static int on_start_playlist( mlt_parser self, mlt_playlist object ) { return 0; } static int on_end_playlist( mlt_parser self, mlt_playlist object ) { return 0; } static int on_start_tractor( mlt_parser self, mlt_tractor object ) { return 0; } static int on_end_tractor( mlt_parser self, mlt_tractor object ) { return 0; } static int on_start_multitrack( mlt_parser self, mlt_multitrack object ) { return 0; } static int on_end_multitrack( mlt_parser self, mlt_multitrack object ) { return 0; } static int on_start_track( mlt_parser self ) { return 0; } static int on_end_track( mlt_parser self ) { return 0; } static int on_start_filter( mlt_parser self, mlt_filter object ) { return 0; } static int on_end_filter( mlt_parser self, mlt_filter object ) { return 0; } static int on_start_transition( mlt_parser self, mlt_transition object ) { return 0; } static int on_end_transition( mlt_parser self, mlt_transition object ) { return 0; } mlt_parser mlt_parser_new( ) { mlt_parser self = calloc( 1, sizeof( struct mlt_parser_s ) ); if ( self != NULL && mlt_properties_init( &self->parent, self ) == 0 ) { self->on_invalid = on_invalid; self->on_unknown = on_unknown; self->on_start_producer = on_start_producer; self->on_end_producer = on_end_producer; self->on_start_playlist = on_start_playlist; self->on_end_playlist = on_end_playlist; self->on_start_tractor = on_start_tractor; self->on_end_tractor = on_end_tractor; self->on_start_multitrack = on_start_multitrack; self->on_end_multitrack = on_end_multitrack; self->on_start_track = on_start_track; self->on_end_track = on_end_track; self->on_start_filter = on_start_filter; self->on_end_filter = on_end_filter; self->on_start_transition = on_start_transition; self->on_end_transition = on_end_transition; } return self; } mlt_properties mlt_parser_properties( mlt_parser self ) { return &self->parent; } int mlt_parser_start( mlt_parser self, mlt_service object ) { int error = 0; mlt_service_type type = mlt_service_identify( object ); switch( type ) { case invalid_type: error = self->on_invalid( self, object ); break; case unknown_type: error = self->on_unknown( self, object ); break; case producer_type: if ( mlt_producer_is_cut( ( mlt_producer )object ) ) error = mlt_parser_start( self, ( mlt_service )mlt_producer_cut_parent( ( mlt_producer )object ) ); error = self->on_start_producer( self, ( mlt_producer )object ); if ( error == 0 ) { int i = 0; while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } error = self->on_end_producer( self, ( mlt_producer )object ); break; case playlist_type: error = self->on_start_playlist( self, ( mlt_playlist )object ); if ( error == 0 ) { int i = 0; while ( error == 0 && i < mlt_playlist_count( ( mlt_playlist )object ) ) mlt_parser_start( self, ( mlt_service )mlt_playlist_get_clip( ( mlt_playlist )object, i ++ ) ); i = 0; while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } error = self->on_end_playlist( self, ( mlt_playlist )object ); break; case tractor_type: error = self->on_start_tractor( self, ( mlt_tractor )object ); if ( error == 0 ) { int i = 0; mlt_service next = mlt_service_producer( object ); mlt_parser_start( self, ( mlt_service )mlt_tractor_multitrack( ( mlt_tractor )object ) ); while ( next != ( mlt_service )mlt_tractor_multitrack( ( mlt_tractor )object ) ) { mlt_parser_start( self, next ); next = mlt_service_producer( next ); } while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } error = self->on_end_tractor( self, ( mlt_tractor )object ); break; case multitrack_type: error = self->on_start_multitrack( self, ( mlt_multitrack )object ); if ( error == 0 ) { int i = 0; while ( i < mlt_multitrack_count( ( mlt_multitrack )object ) ) { self->on_start_track( self ); mlt_parser_start( self, ( mlt_service )mlt_multitrack_track( ( mlt_multitrack )object , i ++ ) ); self->on_end_track( self ); } i = 0; while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } error = self->on_end_multitrack( self, ( mlt_multitrack )object ); break; case filter_type: error = self->on_start_filter( self, ( mlt_filter )object ); if ( error == 0 ) { int i = 0; while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } error = self->on_end_filter( self, ( mlt_filter )object ); break; case transition_type: error = self->on_start_transition( self, ( mlt_transition )object ); if ( error == 0 ) { int i = 0; while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } error = self->on_end_transition( self, ( mlt_transition )object ); break; case field_type: break; case consumer_type: break; } return error; } void mlt_parser_close( mlt_parser self ) { if ( self != NULL ) { mlt_properties_close( &self->parent ); free( self ); } } mlt-0.9.0/src/framework/mlt_parser.h000066400000000000000000000045251215300731300174220ustar00rootroot00000000000000/** * \file mlt_parser.h * \brief service parsing functionality * \see mlt_parser_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_PARSER_H_ #define _MLT_PARSER_H_ #include "mlt_types.h" /** \brief Parser class * * \extends mlt_properties_s */ struct mlt_parser_s { struct mlt_properties_s parent; int ( *on_invalid )( mlt_parser self, mlt_service object ); int ( *on_unknown )( mlt_parser self, mlt_service object ); int ( *on_start_producer )( mlt_parser self, mlt_producer object ); int ( *on_end_producer )( mlt_parser self, mlt_producer object ); int ( *on_start_playlist )( mlt_parser self, mlt_playlist object ); int ( *on_end_playlist )( mlt_parser self, mlt_playlist object ); int ( *on_start_tractor )( mlt_parser self, mlt_tractor object ); int ( *on_end_tractor )( mlt_parser self, mlt_tractor object ); int ( *on_start_multitrack )( mlt_parser self, mlt_multitrack object ); int ( *on_end_multitrack )( mlt_parser self, mlt_multitrack object ); int ( *on_start_track )( mlt_parser self ); int ( *on_end_track )( mlt_parser self ); int ( *on_start_filter )( mlt_parser self, mlt_filter object ); int ( *on_end_filter )( mlt_parser self, mlt_filter object ); int ( *on_start_transition )( mlt_parser self, mlt_transition object ); int ( *on_end_transition )( mlt_parser self, mlt_transition object ); }; extern mlt_parser mlt_parser_new( ); extern mlt_properties mlt_parser_properties( mlt_parser self ); extern int mlt_parser_start( mlt_parser self, mlt_service object ); extern void mlt_parser_close( mlt_parser self ); #endif mlt-0.9.0/src/framework/mlt_playlist.c000066400000000000000000001625241215300731300177660ustar00rootroot00000000000000/** * \file mlt_playlist.c * \brief playlist service class * \see mlt_playlist_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_playlist.h" #include "mlt_tractor.h" #include "mlt_multitrack.h" #include "mlt_field.h" #include "mlt_frame.h" #include "mlt_transition.h" #include #include #include /** \brief Virtual playlist entry used by mlt_playlist_s */ struct playlist_entry_s { mlt_producer producer; mlt_position frame_in; mlt_position frame_out; mlt_position frame_count; int repeat; mlt_position producer_length; mlt_event event; int preservation_hack; }; /* Forward declarations */ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ); static int mlt_playlist_unmix( mlt_playlist self, int clip ); static int mlt_playlist_resize_mix( mlt_playlist self, int clip, int in, int out ); static void mlt_playlist_next( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ); /** Construct a playlist. * * Sets the resource property to "". * Set the mlt_type to property to "mlt_producer". * \public \memberof mlt_playlist_s * \return a new playlist */ mlt_playlist mlt_playlist_init( ) { mlt_playlist self = calloc( 1, sizeof( struct mlt_playlist_s ) ); if ( self != NULL ) { mlt_producer producer = &self->parent; // Construct the producer if ( mlt_producer_init( producer, self ) != 0 ) goto error1; // Override the producer get_frame producer->get_frame = producer_get_frame; // Define the destructor producer->close = ( mlt_destructor )mlt_playlist_close; producer->close_object = self; // Initialise blank if ( mlt_producer_init( &self->blank, NULL ) != 0 ) goto error1; mlt_properties_set( MLT_PRODUCER_PROPERTIES( &self->blank ), "mlt_service", "blank" ); mlt_properties_set( MLT_PRODUCER_PROPERTIES( &self->blank ), "resource", "blank" ); // Indicate that this producer is a playlist mlt_properties_set_data( MLT_PLAYLIST_PROPERTIES( self ), "playlist", self, 0, NULL, NULL ); // Specify the eof condition mlt_properties_set( MLT_PLAYLIST_PROPERTIES( self ), "eof", "pause" ); mlt_properties_set( MLT_PLAYLIST_PROPERTIES( self ), "resource", "" ); mlt_properties_set( MLT_PLAYLIST_PROPERTIES( self ), "mlt_type", "mlt_producer" ); mlt_properties_set_position( MLT_PLAYLIST_PROPERTIES( self ), "in", 0 ); mlt_properties_set_position( MLT_PLAYLIST_PROPERTIES( self ), "out", -1 ); mlt_properties_set_position( MLT_PLAYLIST_PROPERTIES( self ), "length", 0 ); self->size = 10; self->list = calloc( self->size, sizeof( playlist_entry * ) ); if ( self->list == NULL ) goto error2; mlt_events_register( MLT_PLAYLIST_PROPERTIES( self ), "playlist-next", (mlt_transmitter) mlt_playlist_next ); } return self; error2: free( self->list ); error1: free( self ); return NULL; } /** Construct a playlist with a profile. * * Sets the resource property to "". * Set the mlt_type to property to "mlt_producer". * \public \memberof mlt_playlist_s * \param profile the profile to use with the profile * \return a new playlist */ mlt_playlist mlt_playlist_new( mlt_profile profile ) { mlt_playlist self = mlt_playlist_init(); if ( self ) mlt_properties_set_data( MLT_PLAYLIST_PROPERTIES( self ), "_profile", profile, 0, NULL, NULL ); return self; } /** Get the producer associated to this playlist. * * \public \memberof mlt_playlist_s * \param self a playlist * \return the producer interface * \see MLT_PLAYLIST_PRODUCER */ mlt_producer mlt_playlist_producer( mlt_playlist self ) { return self != NULL ? &self->parent : NULL; } /** Get the service associated to this playlist. * * \public \memberof mlt_playlist_s * \param self a playlist * \return the service interface * \see MLT_PLAYLIST_SERVICE */ mlt_service mlt_playlist_service( mlt_playlist self ) { return MLT_PRODUCER_SERVICE( &self->parent ); } /** Get the properties associated to this playlist. * * \public \memberof mlt_playlist_s * \param self a playlist * \return the playlist's properties list * \see MLT_PLAYLIST_PROPERTIES */ mlt_properties mlt_playlist_properties( mlt_playlist self ) { return MLT_PRODUCER_PROPERTIES( &self->parent ); } /** Refresh the playlist after a clip has been changed. * * \private \memberof mlt_playlist_s * \param self a playlist * \return false */ static int mlt_playlist_virtual_refresh( mlt_playlist self ) { // Obtain the properties mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); int i = 0; mlt_position frame_count = 0; for ( i = 0; i < self->count; i ++ ) { // Get the producer mlt_producer producer = self->list[ i ]->producer; if ( producer ) { int current_length = mlt_producer_get_playtime( producer ); // Check if the length of the producer has changed if ( self->list[ i ]->frame_in != mlt_producer_get_in( producer ) || self->list[ i ]->frame_out != mlt_producer_get_out( producer ) ) { // This clip should be removed... if ( current_length < 1 ) { self->list[ i ]->frame_in = 0; self->list[ i ]->frame_out = -1; self->list[ i ]->frame_count = 0; } else { self->list[ i ]->frame_in = mlt_producer_get_in( producer ); self->list[ i ]->frame_out = mlt_producer_get_out( producer ); self->list[ i ]->frame_count = current_length; } // Update the producer_length self->list[ i ]->producer_length = current_length; } } // Calculate the frame_count self->list[ i ]->frame_count = ( self->list[ i ]->frame_out - self->list[ i ]->frame_in + 1 ) * self->list[ i ]->repeat; // Update the frame_count for self clip frame_count += self->list[ i ]->frame_count; } // Refresh all properties mlt_events_block( properties, properties ); mlt_properties_set_position( properties, "length", frame_count ); mlt_events_unblock( properties, properties ); mlt_properties_set_position( properties, "out", frame_count - 1 ); return 0; } /** Listener for producers on the playlist. * * Refreshes the playlist whenever an entry receives producer-changed. * \private \memberof mlt_playlist_s * \param producer a producer * \param self a playlist */ static void mlt_playlist_listener( mlt_producer producer, mlt_playlist self ) { mlt_playlist_virtual_refresh( self ); } /** Append to the virtual playlist. * * \private \memberof mlt_playlist_s * \param self a playlist * \param source a producer * \param in the producer's starting time * \param out the producer's ending time * \return true if there was an error */ static int mlt_playlist_virtual_append( mlt_playlist self, mlt_producer source, mlt_position in, mlt_position out ) { mlt_producer producer = NULL; mlt_properties properties = NULL; mlt_properties parent = NULL; // If we have a cut, then use the in/out points from the cut if ( mlt_producer_is_blank( source ) ) { mlt_position length = out - in + 1; // Make sure the blank is long enough to accomodate the length specified if ( length > mlt_producer_get_length( &self->blank ) ) { mlt_properties blank_props = MLT_PRODUCER_PROPERTIES( &self->blank ); mlt_events_block( blank_props, blank_props ); mlt_producer_set_in_and_out( &self->blank, in, out ); mlt_events_unblock( blank_props, blank_props ); } // Now make sure the cut comes from this self->blank if ( source == NULL ) { producer = mlt_producer_cut( &self->blank, in, out ); } else if ( !mlt_producer_is_cut( source ) || mlt_producer_cut_parent( source ) != &self->blank ) { producer = mlt_producer_cut( &self->blank, in, out ); } else { producer = source; mlt_properties_inc_ref( MLT_PRODUCER_PROPERTIES( producer ) ); } properties = MLT_PRODUCER_PROPERTIES( producer ); // Make sure this cut of blank is long enough if ( length > mlt_producer_get_length( producer ) ) mlt_properties_set_int( properties, "length", length ); } else if ( mlt_producer_is_cut( source ) ) { producer = source; if ( in < 0 ) in = mlt_producer_get_in( producer ); if ( out < 0 || out > mlt_producer_get_out( producer ) ) out = mlt_producer_get_out( producer ); properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_properties_inc_ref( properties ); } else { producer = mlt_producer_cut( source, in, out ); if ( in < 0 || in < mlt_producer_get_in( producer ) ) in = mlt_producer_get_in( producer ); if ( out < 0 || out > mlt_producer_get_out( producer ) ) out = mlt_producer_get_out( producer ); properties = MLT_PRODUCER_PROPERTIES( producer ); } // Fetch the cuts parent properties parent = MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( producer ) ); // Remove loader normalisers for fx cuts if ( mlt_properties_get_int( parent, "meta.fx_cut" ) ) { mlt_service service = MLT_PRODUCER_SERVICE( mlt_producer_cut_parent( producer ) ); mlt_filter filter = mlt_service_filter( service, 0 ); while ( filter != NULL && mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "_loader" ) ) { mlt_service_detach( service, filter ); filter = mlt_service_filter( service, 0 ); } mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( producer ), "meta.fx_cut", 1 ); } // Check that we have room if ( self->count >= self->size ) { int i; self->list = realloc( self->list, ( self->size + 10 ) * sizeof( playlist_entry * ) ); for ( i = self->size; i < self->size + 10; i ++ ) self->list[ i ] = NULL; self->size += 10; } // Create the entry self->list[ self->count ] = calloc( 1, sizeof( playlist_entry ) ); if ( self->list[ self->count ] != NULL ) { self->list[ self->count ]->producer = producer; self->list[ self->count ]->frame_in = in; self->list[ self->count ]->frame_out = out; self->list[ self->count ]->frame_count = out - in + 1; self->list[ self->count ]->repeat = 1; self->list[ self->count ]->producer_length = mlt_producer_get_playtime( producer ); self->list[ self->count ]->event = mlt_events_listen( parent, self, "producer-changed", ( mlt_listener )mlt_playlist_listener ); mlt_event_inc_ref( self->list[ self->count ]->event ); mlt_properties_set( properties, "eof", "pause" ); mlt_producer_set_speed( producer, 0 ); self->count ++; } return mlt_playlist_virtual_refresh( self ); } /** Locate a producer by index. * * \private \memberof mlt_playlist_s * \param self a playlist * \param[in, out] position the time at which to locate the producer, returns the time relative to the producer's starting point * \param[out] clip the index of the playlist entry * \param[out] total the duration of the playlist up to and including this producer * \return a producer or NULL if not found */ static mlt_producer mlt_playlist_locate( mlt_playlist self, mlt_position *position, int *clip, int *total ) { // Default producer to NULL mlt_producer producer = NULL; // Loop for each producer until found for ( *clip = 0; *clip < self->count; *clip += 1 ) { // Increment the total *total += self->list[ *clip ]->frame_count; // Check if the position indicates that we have found the clip // Note that 0 length clips get skipped automatically if ( *position < self->list[ *clip ]->frame_count ) { // Found it, now break producer = self->list[ *clip ]->producer; break; } else { // Decrement position by length of self entry *position -= self->list[ *clip ]->frame_count; } } return producer; } /** The transmitter for the producer-next event * * Invokes the listener. * * \private \memberof mlt_playlist_s * \param listener a function pointer that will be invoked * \param owner the events object that will be passed to \p listener * \param self a service that will be passed to \p listener * \param args an array of pointers. */ static void mlt_playlist_next( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) { if ( listener ) listener( owner, self, args[ 0 ] ); } /** Seek in the virtual playlist. * * This gets the producer at the current position and seeks on the producer * while doing repeat and end-of-file handling. This is also responsible for * closing producers previous to the preceding playlist if the autoclose * property is set. * \private \memberof mlt_playlist_s * \param self a playlist * \param[out] progressive true if the producer should be displayed progressively * \return the service interface of the producer at the play head * \see producer_get_frame */ static mlt_service mlt_playlist_virtual_seek( mlt_playlist self, int *progressive ) { // Map playlist position to real producer in virtual playlist mlt_position position = mlt_producer_frame( &self->parent ); // Keep the original position since we change it while iterating through the list mlt_position original = position; // Clip index and total int i = 0; int total = 0; // Locate the producer for the position mlt_producer producer = mlt_playlist_locate( self, &position, &i, &total ); // Get the properties mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); // Automatically close previous producers if requested if ( i > 1 // keep immediate previous in case app wants to get info about what just finished && position < 2 // tolerate off-by-one error on going to next clip && mlt_properties_get_int( properties, "autoclose" ) ) { int j; // They might have jumped ahead! for ( j = 0; j < i - 1; j++ ) { mlt_service_lock( MLT_PRODUCER_SERVICE( self->list[ j ]->producer ) ); mlt_producer p = self->list[ j ]->producer; if ( p ) { self->list[ j ]->producer = NULL; mlt_service_unlock( MLT_PRODUCER_SERVICE( p ) ); mlt_producer_close( p ); } // If p is null, the lock will not have been "taken" } } // Get the eof handling char *eof = mlt_properties_get( properties, "eof" ); // Seek in real producer to relative position if ( producer != NULL ) { int count = self->list[ i ]->frame_count / self->list[ i ]->repeat; *progressive = count == 1; mlt_producer_seek( producer, (int)position % count ); } else if ( !strcmp( eof, "pause" ) && total > 0 ) { playlist_entry *entry = self->list[ self->count - 1 ]; int count = entry->frame_count / entry->repeat; mlt_producer self_producer = MLT_PLAYLIST_PRODUCER( self ); mlt_producer_seek( self_producer, original - 1 ); producer = entry->producer; mlt_producer_seek( producer, (int)entry->frame_out % count ); mlt_producer_set_speed( self_producer, 0 ); mlt_producer_set_speed( producer, 0 ); *progressive = count == 1; } else if ( !strcmp( eof, "loop" ) && total > 0 ) { playlist_entry *entry = self->list[ 0 ]; mlt_producer self_producer = MLT_PLAYLIST_PRODUCER( self ); mlt_producer_seek( self_producer, 0 ); producer = entry->producer; mlt_producer_seek( producer, 0 ); } else { producer = &self->blank; } // Determine if we have moved to the next entry in the playlist. if ( original == total - 2 ) mlt_events_fire( properties, "playlist-next", i, NULL ); return MLT_PRODUCER_SERVICE( producer ); } /** Invoked when a producer indicates that it has prematurely reached its end. * * \private \memberof mlt_playlist_s * \param self a playlist * \return a producer * \see producer_get_frame */ static mlt_producer mlt_playlist_virtual_set_out( mlt_playlist self ) { // Default producer to blank mlt_producer producer = &self->blank; // Map playlist position to real producer in virtual playlist mlt_position position = mlt_producer_frame( &self->parent ); // Loop through the virtual playlist int i = 0; for ( i = 0; i < self->count; i ++ ) { if ( position < self->list[ i ]->frame_count ) { // Found it, now break producer = self->list[ i ]->producer; break; } else { // Decrement position by length of this entry position -= self->list[ i ]->frame_count; } } // Seek in real producer to relative position if ( i < self->count && self->list[ i ]->frame_out != position ) { // Update the frame_count for the changed clip (hmmm) self->list[ i ]->frame_out = position; self->list[ i ]->frame_count = self->list[ i ]->frame_out - self->list[ i ]->frame_in + 1; // Refresh the playlist mlt_playlist_virtual_refresh( self ); } return producer; } /** Obtain the current clips index. * * \public \memberof mlt_playlist_s * \param self a playlist * \return the index of the playlist entry at the current position */ int mlt_playlist_current_clip( mlt_playlist self ) { // Map playlist position to real producer in virtual playlist mlt_position position = mlt_producer_frame( &self->parent ); // Loop through the virtual playlist int i = 0; for ( i = 0; i < self->count; i ++ ) { if ( position < self->list[ i ]->frame_count ) { // Found it, now break break; } else { // Decrement position by length of this entry position -= self->list[ i ]->frame_count; } } return i; } /** Obtain the current clips producer. * * \public \memberof mlt_playlist_s * \param self a playlist * \return the producer at the current position */ mlt_producer mlt_playlist_current( mlt_playlist self ) { int i = mlt_playlist_current_clip( self ); if ( i < self->count ) return self->list[ i ]->producer; else return &self->blank; } /** Get the position which corresponds to the start of the next clip. * * \public \memberof mlt_playlist_s * \param self a playlist * \param whence the location from which to make the index relative: * start of playlist, end of playlist, or current position * \param index the playlist entry index relative to whence * \return the time at which the referenced clip starts */ mlt_position mlt_playlist_clip( mlt_playlist self, mlt_whence whence, int index ) { mlt_position position = 0; int absolute_clip = index; int i = 0; // Determine the absolute clip switch ( whence ) { case mlt_whence_relative_start: absolute_clip = index; break; case mlt_whence_relative_current: absolute_clip = mlt_playlist_current_clip( self ) + index; break; case mlt_whence_relative_end: absolute_clip = self->count - index; break; } // Check that we're in a valid range if ( absolute_clip < 0 ) absolute_clip = 0; else if ( absolute_clip > self->count ) absolute_clip = self->count; // Now determine the position for ( i = 0; i < absolute_clip; i ++ ) position += self->list[ i ]->frame_count; return position; } /** Get all the info about the clip specified. * * \public \memberof mlt_playlist_s * \param self a playlist * \param info a clip info struct * \param index a playlist entry index * \return true if there was an error */ int mlt_playlist_get_clip_info( mlt_playlist self, mlt_playlist_clip_info *info, int index ) { int error = index < 0 || index >= self->count || self->list[ index ]->producer == NULL; memset( info, 0, sizeof( mlt_playlist_clip_info ) ); if ( !error ) { mlt_producer producer = mlt_producer_cut_parent( self->list[ index ]->producer ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); info->clip = index; info->producer = producer; info->cut = self->list[ index ]->producer; info->start = mlt_playlist_clip( self, mlt_whence_relative_start, index ); info->resource = mlt_properties_get( properties, "resource" ); info->frame_in = self->list[ index ]->frame_in; info->frame_out = self->list[ index ]->frame_out; info->frame_count = self->list[ index ]->frame_count; info->repeat = self->list[ index ]->repeat; info->length = mlt_producer_get_length( producer ); info->fps = mlt_producer_get_fps( producer ); } return error; } /** Get number of clips in the playlist. * * \public \memberof mlt_playlist_s * \param self a playlist * \return the number of playlist entries */ int mlt_playlist_count( mlt_playlist self ) { return self->count; } /** Clear the playlist. * * \public \memberof mlt_playlist_s * \param self a playlist * \return true if there was an error */ int mlt_playlist_clear( mlt_playlist self ) { int i; for ( i = 0; i < self->count; i ++ ) { mlt_event_close( self->list[ i ]->event ); mlt_producer_close( self->list[ i ]->producer ); } self->count = 0; return mlt_playlist_virtual_refresh( self ); } /** Append a producer to the playlist. * * \public \memberof mlt_playlist_s * \param self a playlist * \param producer the producer to append * \return true if there was an error */ int mlt_playlist_append( mlt_playlist self, mlt_producer producer ) { // Append to virtual list return mlt_playlist_virtual_append( self, producer, 0, mlt_producer_get_playtime( producer ) - 1 ); } /** Append a producer to the playlist with in/out points. * * \public \memberof mlt_playlist_s * \param self a playlist * \param producer the producer to append * \param in the starting point on the producer; a negative value is the same as 0 * \param out the ending point on the producer; a negative value is the same as producer length - 1 * \return true if there was an error */ int mlt_playlist_append_io( mlt_playlist self, mlt_producer producer, mlt_position in, mlt_position out ) { // Append to virtual list if ( in < 0 && out < 0 ) return mlt_playlist_append( self, producer ); else return mlt_playlist_virtual_append( self, producer, in, out ); } /** Append a blank to the playlist of a given length. * * \public \memberof mlt_playlist_s * \param self a playlist * \param out the ending time of the blank entry, not its duration * \return true if there was an error */ int mlt_playlist_blank( mlt_playlist self, mlt_position out ) { // Append to the virtual list if ( out >= 0 ) return mlt_playlist_virtual_append( self, &self->blank, 0, out ); else return 1; } /** Append a blank item to the playlist with duration as a time string. * * \public \memberof mlt_playlist_s * \param self a playlist * \param length the duration of the blank entry as a time string * \return true if there was an error */ int mlt_playlist_blank_time( mlt_playlist self, const char* length ) { if ( self && length ) { mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); mlt_properties_set( properties , "_blank_time", length ); mlt_position duration = mlt_properties_get_position( properties, "_blank_time" ); return mlt_playlist_blank( self, duration - 1 ); } else return 1; } /** Insert a producer into the playlist. * * \public \memberof mlt_playlist_s * \param self a playlist * \param producer the producer to insert * \param where the producer's playlist entry index * \param in the starting point on the producer * \param out the ending point on the producer * \return true if there was an error */ int mlt_playlist_insert( mlt_playlist self, mlt_producer producer, int where, mlt_position in, mlt_position out ) { // Append to end mlt_events_block( MLT_PLAYLIST_PROPERTIES( self ), self ); mlt_playlist_append_io( self, producer, in, out ); // Move to the position specified mlt_playlist_move( self, self->count - 1, where ); mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( self ), self ); return mlt_playlist_virtual_refresh( self ); } /** Remove an entry in the playlist. * * \public \memberof mlt_playlist_s * \param self a playlist * \param where the playlist entry index * \return true if there was an error */ int mlt_playlist_remove( mlt_playlist self, int where ) { int error = where < 0 || where >= self->count; if ( error == 0 && mlt_playlist_unmix( self, where ) != 0 ) { // We need to know the current clip and the position within the playlist int current = mlt_playlist_current_clip( self ); mlt_position position = mlt_producer_position( MLT_PLAYLIST_PRODUCER( self ) ); // We need all the details about the clip we're removing mlt_playlist_clip_info where_info; playlist_entry *entry = self->list[ where ]; mlt_properties properties = MLT_PRODUCER_PROPERTIES( entry->producer ); // Loop variable int i = 0; // Get the clip info mlt_playlist_get_clip_info( self, &where_info, where ); // Reorganise the list for ( i = where + 1; i < self->count; i ++ ) self->list[ i - 1 ] = self->list[ i ]; self->count --; if ( entry->preservation_hack == 0 ) { // Decouple from mix_in/out if necessary if ( mlt_properties_get_data( properties, "mix_in", NULL ) != NULL ) { mlt_properties mix = mlt_properties_get_data( properties, "mix_in", NULL ); mlt_properties_set_data( mix, "mix_out", NULL, 0, NULL, NULL ); } if ( mlt_properties_get_data( properties, "mix_out", NULL ) != NULL ) { mlt_properties mix = mlt_properties_get_data( properties, "mix_out", NULL ); mlt_properties_set_data( mix, "mix_in", NULL, 0, NULL, NULL ); } if ( mlt_properties_ref_count( MLT_PRODUCER_PROPERTIES( entry->producer ) ) == 1 ) mlt_producer_clear( entry->producer ); } // Close the producer associated to the clip info mlt_event_close( entry->event ); mlt_producer_close( entry->producer ); // Correct position if ( where == current ) mlt_producer_seek( MLT_PLAYLIST_PRODUCER( self ), where_info.start ); else if ( where < current && self->count > 0 ) mlt_producer_seek( MLT_PLAYLIST_PRODUCER( self ), position - where_info.frame_count ); else if ( self->count == 0 ) mlt_producer_seek( MLT_PLAYLIST_PRODUCER( self ), 0 ); // Free the entry free( entry ); // Refresh the playlist mlt_playlist_virtual_refresh( self ); } return error; } /** Move an entry in the playlist. * * \public \memberof mlt_playlist_s * \param self a playlist * \param src an entry index * \param dest an entry index * \return false */ int mlt_playlist_move( mlt_playlist self, int src, int dest ) { int i; /* We need to ensure that the requested indexes are valid and correct it as necessary */ if ( src < 0 ) src = 0; if ( src >= self->count ) src = self->count - 1; if ( dest < 0 ) dest = 0; if ( dest >= self->count ) dest = self->count - 1; if ( src != dest && self->count > 1 ) { int current = mlt_playlist_current_clip( self ); mlt_position position = mlt_producer_position( MLT_PLAYLIST_PRODUCER( self ) ); playlist_entry *src_entry = NULL; // We need all the details about the current clip mlt_playlist_clip_info current_info; mlt_playlist_get_clip_info( self, ¤t_info, current ); position -= current_info.start; if ( current == src ) current = dest; else if ( current > src && current < dest ) current ++; else if ( current == dest ) current = src; src_entry = self->list[ src ]; if ( src > dest ) { for ( i = src; i > dest; i -- ) self->list[ i ] = self->list[ i - 1 ]; } else { for ( i = src; i < dest; i ++ ) self->list[ i ] = self->list[ i + 1 ]; } self->list[ dest ] = src_entry; mlt_playlist_get_clip_info( self, ¤t_info, current ); mlt_producer_seek( MLT_PLAYLIST_PRODUCER( self ), current_info.start + position ); mlt_playlist_virtual_refresh( self ); } return 0; } /** Repeat the specified clip n times. * * \public \memberof mlt_playlist_s * \param self a playlist * \param clip a playlist entry index * \param repeat the number of times to repeat the clip * \return true if there was an error */ int mlt_playlist_repeat_clip( mlt_playlist self, int clip, int repeat ) { int error = repeat < 1 || clip < 0 || clip >= self->count; if ( error == 0 ) { playlist_entry *entry = self->list[ clip ]; entry->repeat = repeat; mlt_playlist_virtual_refresh( self ); } return error; } /** Resize the specified clip. * * \public \memberof mlt_playlist_s * \param self a playlist * \param clip the index of the playlist entry * \param in the new starting time on the clip's producer; a negative value is the same as 0 * \param out the new ending time on the clip's producer; a negative value is the same as length - 1 * \return true if there was an error */ int mlt_playlist_resize_clip( mlt_playlist self, int clip, mlt_position in, mlt_position out ) { int error = clip < 0 || clip >= self->count; if ( error == 0 && mlt_playlist_resize_mix( self, clip, in, out ) != 0 ) { playlist_entry *entry = self->list[ clip ]; mlt_producer producer = entry->producer; mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); mlt_events_block( properties, properties ); if ( mlt_producer_is_blank( producer ) ) { mlt_position length = out - in + 1; // Make sure the parent blank is long enough to accomodate the length specified if ( length > mlt_producer_get_length( &self->blank ) ) { mlt_properties blank_props = MLT_PRODUCER_PROPERTIES( &self->blank ); mlt_properties_set_int( blank_props, "length", length ); mlt_producer_set_in_and_out( &self->blank, 0, out - in ); } // Make sure this cut of blank is long enough if ( length > mlt_producer_get_length( producer ) ) mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( producer ), "length", length ); } if ( in < 0 ) in = 0; if ( out < 0 || out >= mlt_producer_get_length( producer ) ) out = mlt_producer_get_length( producer ) - 1; if ( out < in ) { mlt_position t = in; in = out; out = t; } mlt_producer_set_in_and_out( producer, in, out ); mlt_events_unblock( properties, properties ); mlt_playlist_virtual_refresh( self ); } return error; } /** Split a clip on the playlist at the given position. * * This splits after the specified frame. * \public \memberof mlt_playlist_s * \param self a playlist * \param clip the index of the playlist entry * \param position the time at which to split relative to the beginning of the clip or its end if negative * \return true if there was an error */ int mlt_playlist_split( mlt_playlist self, int clip, mlt_position position ) { int error = clip < 0 || clip >= self->count; if ( error == 0 ) { playlist_entry *entry = self->list[ clip ]; position = position < 0 ? entry->frame_count + position - 1 : position; if ( position >= 0 && position < entry->frame_count - 1 ) { int in = entry->frame_in; int out = entry->frame_out; mlt_events_block( MLT_PLAYLIST_PROPERTIES( self ), self ); mlt_playlist_resize_clip( self, clip, in, in + position ); if ( !mlt_producer_is_blank( entry->producer ) ) { int i = 0; mlt_properties entry_properties = MLT_PRODUCER_PROPERTIES( entry->producer ); mlt_producer split = mlt_producer_cut( entry->producer, in + position + 1, out ); mlt_properties split_properties = MLT_PRODUCER_PROPERTIES( split ); mlt_playlist_insert( self, split, clip + 1, 0, -1 ); mlt_properties_lock( entry_properties ); for ( i = 0; i < mlt_properties_count( entry_properties ); i ++ ) { char *name = mlt_properties_get_name( entry_properties, i ); if ( name != NULL && !strncmp( name, "meta.", 5 ) ) mlt_properties_set( split_properties, name, mlt_properties_get_value( entry_properties, i ) ); } mlt_properties_unlock( entry_properties ); mlt_producer_close( split ); } else { mlt_playlist_insert( self, &self->blank, clip + 1, 0, out - position - 1 ); } mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( self ), self ); mlt_playlist_virtual_refresh( self ); } else { error = 1; } } return error; } /** Split the playlist at the absolute position. * * \public \memberof mlt_playlist_s * \param self a playlist * \param position the time at which to split relative to the beginning of the clip * \param left true to split before the frame starting at position * \return true if there was an error */ int mlt_playlist_split_at( mlt_playlist self, mlt_position position, int left ) { int result = self == NULL ? -1 : 0; if ( !result ) { if ( position >= 0 && position < mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( self ) ) ) { int clip = mlt_playlist_get_clip_index_at( self, position ); mlt_playlist_clip_info info; mlt_playlist_get_clip_info( self, &info, clip ); if ( left && position != info.start ) mlt_playlist_split( self, clip, position - info.start - 1 ); else if ( !left ) mlt_playlist_split( self, clip, position - info.start ); result = position; } else if ( position <= 0 ) { result = 0; } else { result = mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( self ) ); } } return result; } /** Join 1 or more consecutive clips. * * \public \memberof mlt_playlist_s * \param self a playlist * \param clip the starting playlist entry index * \param count the number of entries to merge * \param merge ignored * \return true if there was an error */ int mlt_playlist_join( mlt_playlist self, int clip, int count, int merge ) { int error = clip < 0 || clip >= self->count; if ( error == 0 ) { int i = clip; mlt_playlist new_clip = mlt_playlist_new( mlt_service_profile( MLT_PLAYLIST_SERVICE(self) ) ); mlt_events_block( MLT_PLAYLIST_PROPERTIES( self ), self ); if ( clip + count >= self->count ) count = self->count - clip - 1; for ( i = 0; i <= count; i ++ ) { playlist_entry *entry = self->list[ clip ]; mlt_playlist_append( new_clip, entry->producer ); mlt_playlist_repeat_clip( new_clip, i, entry->repeat ); entry->preservation_hack = 1; mlt_playlist_remove( self, clip ); } mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( self ), self ); mlt_playlist_insert( self, MLT_PLAYLIST_PRODUCER( new_clip ), clip, 0, -1 ); mlt_playlist_close( new_clip ); } return error; } /** Mix consecutive clips for a specified length and apply transition if specified. * * \public \memberof mlt_playlist_s * \param self a playlist * \param clip the index of the playlist entry * \param length the number of frames over which to create the mix * \param transition the transition to use for the mix * \return true if there was an error */ int mlt_playlist_mix( mlt_playlist self, int clip, int length, mlt_transition transition ) { int error = ( clip < 0 || clip + 1 >= self->count ); if ( error == 0 ) { playlist_entry *clip_a = self->list[ clip ]; playlist_entry *clip_b = self->list[ clip + 1 ]; mlt_producer track_a = NULL; mlt_producer track_b = NULL; mlt_tractor tractor = mlt_tractor_new( ); mlt_events_block( MLT_PLAYLIST_PROPERTIES( self ), self ); // Check length is valid for both clips and resize if necessary. int max_size = clip_a->frame_count > clip_b->frame_count ? clip_a->frame_count : clip_b->frame_count; length = length > max_size ? max_size : length; // Create the a and b tracks/cuts if necessary - note that no cuts are required if the length matches if ( length != clip_a->frame_count ) track_a = mlt_producer_cut( clip_a->producer, clip_a->frame_out - length + 1, clip_a->frame_out ); else track_a = clip_a->producer; if ( length != clip_b->frame_count ) track_b = mlt_producer_cut( clip_b->producer, clip_b->frame_in, clip_b->frame_in + length - 1 ); else track_b = clip_b->producer; // Set the tracks on the tractor mlt_tractor_set_track( tractor, track_a, 0 ); mlt_tractor_set_track( tractor, track_b, 1 ); // Insert the mix object into the playlist mlt_playlist_insert( self, MLT_TRACTOR_PRODUCER( tractor ), clip + 1, -1, -1 ); mlt_properties_set_data( MLT_TRACTOR_PROPERTIES( tractor ), "mlt_mix", tractor, 0, NULL, NULL ); // Attach the transition if ( transition != NULL ) { mlt_field field = mlt_tractor_field( tractor ); mlt_field_plant_transition( field, transition, 0, 1 ); mlt_transition_set_in_and_out( transition, 0, length - 1 ); } // Close our references to the tracks if we created new cuts above (the tracks can still be used here) if ( track_a != clip_a->producer ) mlt_producer_close( track_a ); if ( track_b != clip_b->producer ) mlt_producer_close( track_b ); // Check if we have anything left on the right hand clip if ( track_b == clip_b->producer ) { clip_b->preservation_hack = 1; mlt_playlist_remove( self, clip + 2 ); } else if ( clip_b->frame_out - clip_b->frame_in > length ) { mlt_playlist_resize_clip( self, clip + 2, clip_b->frame_in + length, clip_b->frame_out ); mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( clip_b->producer ), "mix_in", tractor, 0, NULL, NULL ); mlt_properties_set_data( MLT_TRACTOR_PROPERTIES( tractor ), "mix_out", clip_b->producer, 0, NULL, NULL ); } else { mlt_producer_clear( clip_b->producer ); mlt_playlist_remove( self, clip + 2 ); } // Check if we have anything left on the left hand clip if ( track_a == clip_a->producer ) { clip_a->preservation_hack = 1; mlt_playlist_remove( self, clip ); } else if ( clip_a->frame_out - clip_a->frame_in > length ) { mlt_playlist_resize_clip( self, clip, clip_a->frame_in, clip_a->frame_out - length ); mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( clip_a->producer ), "mix_out", tractor, 0, NULL, NULL ); mlt_properties_set_data( MLT_TRACTOR_PROPERTIES( tractor ), "mix_in", clip_a->producer, 0, NULL, NULL ); } else { mlt_producer_clear( clip_a->producer ); mlt_playlist_remove( self, clip ); } // Unblock and force a fire off of change events to listeners mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( self ), self ); mlt_playlist_virtual_refresh( self ); mlt_tractor_close( tractor ); } return error; } /** Add a transition to an existing mix. * * \public \memberof mlt_playlist_s * \param self a playlist * \param clip the index of the playlist entry * \param transition a transition * \return true if there was an error */ int mlt_playlist_mix_add( mlt_playlist self, int clip, mlt_transition transition ) { mlt_producer producer = mlt_producer_cut_parent( mlt_playlist_get_clip( self, clip ) ); mlt_properties properties = producer != NULL ? MLT_PRODUCER_PROPERTIES( producer ) : NULL; mlt_tractor tractor = properties != NULL ? mlt_properties_get_data( properties, "mlt_mix", NULL ) : NULL; int error = transition == NULL || tractor == NULL; if ( error == 0 ) { mlt_field field = mlt_tractor_field( tractor ); mlt_field_plant_transition( field, transition, 0, 1 ); mlt_transition_set_in_and_out( transition, 0, self->list[ clip ]->frame_count - 1 ); } return error; } /** Return the clip at the clip index. * * \public \memberof mlt_playlist_s * \param self a playlist * \param clip the index of a playlist entry * \return a producer or NULL if there was an error */ mlt_producer mlt_playlist_get_clip( mlt_playlist self, int clip ) { if ( clip >= 0 && clip < self->count ) return self->list[ clip ]->producer; return NULL; } /** Return the clip at the specified position. * * \public \memberof mlt_playlist_s * \param self a playlist * \param position a time relative to the beginning of the playlist * \return a producer or NULL if not found */ mlt_producer mlt_playlist_get_clip_at( mlt_playlist self, mlt_position position ) { int index = 0, total = 0; return mlt_playlist_locate( self, &position, &index, &total ); } /** Return the clip index of the specified position. * * \public \memberof mlt_playlist_s * \param self a playlist * \param position a time relative to the beginning of the playlist * \return the index of the playlist entry */ int mlt_playlist_get_clip_index_at( mlt_playlist self, mlt_position position ) { int index = 0, total = 0; mlt_playlist_locate( self, &position, &index, &total ); return index; } /** Determine if the clip is a mix. * * \public \memberof mlt_playlist_s * \param self a playlist * \param clip the index of the playlist entry * \return true if the producer is a mix */ int mlt_playlist_clip_is_mix( mlt_playlist self, int clip ) { mlt_producer producer = mlt_producer_cut_parent( mlt_playlist_get_clip( self, clip ) ); mlt_properties properties = producer != NULL ? MLT_PRODUCER_PROPERTIES( producer ) : NULL; mlt_tractor tractor = properties != NULL ? mlt_properties_get_data( properties, "mlt_mix", NULL ) : NULL; return tractor != NULL; } /** Remove a mixed clip - ensure that the cuts included in the mix find their way * back correctly on to the playlist. * * \private \memberof mlt_playlist_s * \param self a playlist * \param clip the index of the playlist entry * \return true if there was an error */ static int mlt_playlist_unmix( mlt_playlist self, int clip ) { int error = ( clip < 0 || clip >= self->count ); // Ensure that the clip request is actually a mix if ( error == 0 ) { mlt_producer producer = mlt_producer_cut_parent( self->list[ clip ]->producer ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); error = mlt_properties_get_data( properties, "mlt_mix", NULL ) == NULL || self->list[ clip ]->preservation_hack; } if ( error == 0 ) { playlist_entry *mix = self->list[ clip ]; mlt_tractor tractor = ( mlt_tractor )mlt_producer_cut_parent( mix->producer ); mlt_properties properties = MLT_TRACTOR_PROPERTIES( tractor ); mlt_producer clip_a = mlt_properties_get_data( properties, "mix_in", NULL ); mlt_producer clip_b = mlt_properties_get_data( properties, "mix_out", NULL ); int length = mlt_producer_get_playtime( MLT_TRACTOR_PRODUCER( tractor ) ); mlt_events_block( MLT_PLAYLIST_PROPERTIES( self ), self ); if ( clip_a != NULL ) { mlt_producer_set_in_and_out( clip_a, mlt_producer_get_in( clip_a ), mlt_producer_get_out( clip_a ) + length ); } else { mlt_producer cut = mlt_tractor_get_track( tractor, 0 ); mlt_playlist_insert( self, cut, clip, -1, -1 ); clip ++; } if ( clip_b != NULL ) { mlt_producer_set_in_and_out( clip_b, mlt_producer_get_in( clip_b ) - length, mlt_producer_get_out( clip_b ) ); } else { mlt_producer cut = mlt_tractor_get_track( tractor, 1 ); mlt_playlist_insert( self, cut, clip + 1, -1, -1 ); } mlt_properties_set_data( properties, "mlt_mix", NULL, 0, NULL, NULL ); mlt_playlist_remove( self, clip ); mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( self ), self ); mlt_playlist_virtual_refresh( self ); } return error; } /** Resize a mix clip. * * \private \memberof mlt_playlist_s * \param self a playlist * \param clip the index of the playlist entry * \param in the new starting point * \param out the new ending point * \return true if there was an error */ static int mlt_playlist_resize_mix( mlt_playlist self, int clip, int in, int out ) { int error = ( clip < 0 || clip >= self->count ); // Ensure that the clip request is actually a mix if ( error == 0 ) { mlt_producer producer = mlt_producer_cut_parent( self->list[ clip ]->producer ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); error = mlt_properties_get_data( properties, "mlt_mix", NULL ) == NULL; } if ( error == 0 ) { playlist_entry *mix = self->list[ clip ]; mlt_tractor tractor = ( mlt_tractor )mlt_producer_cut_parent( mix->producer ); mlt_properties properties = MLT_TRACTOR_PROPERTIES( tractor ); mlt_producer clip_a = mlt_properties_get_data( properties, "mix_in", NULL ); mlt_producer clip_b = mlt_properties_get_data( properties, "mix_out", NULL ); mlt_producer track_a = mlt_tractor_get_track( tractor, 0 ); mlt_producer track_b = mlt_tractor_get_track( tractor, 1 ); int length = out - in + 1; int length_diff = length - mlt_producer_get_playtime( MLT_TRACTOR_PRODUCER( tractor ) ); mlt_events_block( MLT_PLAYLIST_PROPERTIES( self ), self ); if ( clip_a != NULL ) mlt_producer_set_in_and_out( clip_a, mlt_producer_get_in( clip_a ), mlt_producer_get_out( clip_a ) - length_diff ); if ( clip_b != NULL ) mlt_producer_set_in_and_out( clip_b, mlt_producer_get_in( clip_b ) + length_diff, mlt_producer_get_out( clip_b ) ); mlt_producer_set_in_and_out( track_a, mlt_producer_get_in( track_a ) - length_diff, mlt_producer_get_out( track_a ) ); mlt_producer_set_in_and_out( track_b, mlt_producer_get_in( track_b ), mlt_producer_get_out( track_b ) + length_diff ); mlt_producer_set_in_and_out( MLT_MULTITRACK_PRODUCER( mlt_tractor_multitrack( tractor ) ), in, out ); mlt_producer_set_in_and_out( MLT_TRACTOR_PRODUCER( tractor ), in, out ); mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( mix->producer ), "length", out - in + 1 ); mlt_producer_set_in_and_out( mix->producer, in, out ); mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( self ), self ); mlt_playlist_virtual_refresh( self ); } return error; } /** Consolidate adjacent blank producers. * * \public \memberof mlt_playlist_s * \param self a playlist * \param keep_length set false to remove the last entry if it is blank */ void mlt_playlist_consolidate_blanks( mlt_playlist self, int keep_length ) { if ( self != NULL ) { int i = 0; mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); mlt_events_block( properties, properties ); for ( i = 1; i < self->count; i ++ ) { playlist_entry *left = self->list[ i - 1 ]; playlist_entry *right = self->list[ i ]; if ( mlt_producer_is_blank( left->producer ) && mlt_producer_is_blank( right->producer ) ) { mlt_playlist_resize_clip( self, i - 1, 0, left->frame_count + right->frame_count - 1 ); mlt_playlist_remove( self, i -- ); } } if ( !keep_length && self->count > 0 ) { playlist_entry *last = self->list[ self->count - 1 ]; if ( mlt_producer_is_blank( last->producer ) ) mlt_playlist_remove( self, self->count - 1 ); } mlt_events_unblock( properties, properties ); mlt_playlist_virtual_refresh( self ); } } /** Determine if the specified clip index is a blank. * * \public \memberof mlt_playlist_s * \param self a playlist * \param clip the index of the playlist entry * \return true if there was an error */ int mlt_playlist_is_blank( mlt_playlist self, int clip ) { return self == NULL || mlt_producer_is_blank( mlt_playlist_get_clip( self, clip ) ); } /** Determine if the specified position is a blank. * * \public \memberof mlt_playlist_s * \param self a playlist * \param position a time relative to the start or end (negative) of the playlist * \return true if there was an error */ int mlt_playlist_is_blank_at( mlt_playlist self, mlt_position position ) { return self == NULL || mlt_producer_is_blank( mlt_playlist_get_clip_at( self, position ) ); } /** Replace the specified clip with a blank and return the clip. * * \public \memberof mlt_playlist_s * \param self a playlist * \param clip the index of the playlist entry * \return a producer or NULL if there was an error */ mlt_producer mlt_playlist_replace_with_blank( mlt_playlist self, int clip ) { mlt_producer producer = NULL; if ( !mlt_playlist_is_blank( self, clip ) ) { playlist_entry *entry = self->list[ clip ]; int in = entry->frame_in; int out = entry->frame_out; mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); producer = entry->producer; mlt_properties_inc_ref( MLT_PRODUCER_PROPERTIES( producer ) ); mlt_events_block( properties, properties ); mlt_playlist_remove( self, clip ); mlt_playlist_blank( self, out - in ); mlt_playlist_move( self, self->count - 1, clip ); mlt_events_unblock( properties, properties ); mlt_playlist_virtual_refresh( self ); mlt_producer_set_in_and_out( producer, in, out ); } return producer; } /** Insert blank space. * * \public \memberof mlt_playlist_s * \param self a playlist * \param clip the index of the new blank section * \param length the ending time of the new blank section (duration - 1) */ void mlt_playlist_insert_blank( mlt_playlist self, int clip, int length ) { if ( self != NULL && length >= 0 ) { mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); mlt_events_block( properties, properties ); mlt_playlist_blank( self, length ); mlt_playlist_move( self, self->count - 1, clip ); mlt_events_unblock( properties, properties ); mlt_playlist_virtual_refresh( self ); } } /** Resize a blank entry. * * \public \memberof mlt_playlist_s * \param self a playlist * \param position the time at which the blank entry exists relative to the start or end (negative) of the playlist. * \param length the additional amount of blank frames to add * \param find true to fist locate the blank after the clip at position */ void mlt_playlist_pad_blanks( mlt_playlist self, mlt_position position, int length, int find ) { if ( self != NULL && length != 0 ) { int clip = mlt_playlist_get_clip_index_at( self, position ); mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); mlt_events_block( properties, properties ); if ( find && clip < self->count && !mlt_playlist_is_blank( self, clip ) ) clip ++; if ( clip < self->count && mlt_playlist_is_blank( self, clip ) ) { mlt_playlist_clip_info info; mlt_playlist_get_clip_info( self, &info, clip ); if ( info.frame_out + length > info.frame_in ) mlt_playlist_resize_clip( self, clip, info.frame_in, info.frame_out + length ); else mlt_playlist_remove( self, clip ); } else if ( find && clip < self->count && length > 0 ) { mlt_playlist_insert_blank( self, clip, length ); } mlt_events_unblock( properties, properties ); mlt_playlist_virtual_refresh( self ); } } /** Insert a clip at a specific time. * * \public \memberof mlt_playlist_s * \param self a playlist * \param position the time at which to insert * \param producer the producer to insert * \param mode true if you want to overwrite any blank section * \return true if there was an error */ int mlt_playlist_insert_at( mlt_playlist self, mlt_position position, mlt_producer producer, int mode ) { int ret = self == NULL || position < 0 || producer == NULL; if ( ret == 0 ) { mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); int length = mlt_producer_get_playtime( producer ); int clip = mlt_playlist_get_clip_index_at( self, position ); mlt_playlist_clip_info info; mlt_playlist_get_clip_info( self, &info, clip ); mlt_events_block( properties, self ); if ( clip < self->count && mlt_playlist_is_blank( self, clip ) ) { // Split and move to new clip if need be if ( position != info.start && mlt_playlist_split( self, clip, position - info.start - 1 ) == 0 ) mlt_playlist_get_clip_info( self, &info, ++ clip ); // Split again if need be if ( length < info.frame_count ) mlt_playlist_split( self, clip, length - 1 ); // Remove mlt_playlist_remove( self, clip ); // Insert mlt_playlist_insert( self, producer, clip, -1, -1 ); ret = clip; } else if ( clip < self->count ) { if ( position > info.start + info.frame_count / 2 ) clip ++; if ( mode == 1 && clip < self->count && mlt_playlist_is_blank( self, clip ) ) { mlt_playlist_get_clip_info( self, &info, clip ); if ( length < info.frame_count ) mlt_playlist_split( self, clip, length ); mlt_playlist_remove( self, clip ); } mlt_playlist_insert( self, producer, clip, -1, -1 ); ret = clip; } else { if ( mode == 1 ) { if ( position == info.start ) mlt_playlist_remove( self, clip ); else mlt_playlist_blank( self, position - mlt_properties_get_int( properties, "length" ) - 1 ); } mlt_playlist_append( self, producer ); ret = self->count - 1; } mlt_events_unblock( properties, self ); mlt_playlist_virtual_refresh( self ); } else { ret = -1; } return ret; } /** Get the time at which the clip starts relative to the playlist. * * \public \memberof mlt_playlist_s * \param self a playlist * \param clip the index of the playlist entry * \return the starting time */ int mlt_playlist_clip_start( mlt_playlist self, int clip ) { mlt_playlist_clip_info info; if ( mlt_playlist_get_clip_info( self, &info, clip ) == 0 ) return info.start; return clip < 0 ? 0 : mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( self ) ); } /** Get the playable duration of the clip. * * \public \memberof mlt_playlist_s * \param self a playlist * \param clip the index of the playlist entry * \return the duration of the playlist entry */ int mlt_playlist_clip_length( mlt_playlist self, int clip ) { mlt_playlist_clip_info info; if ( mlt_playlist_get_clip_info( self, &info, clip ) == 0 ) return info.frame_count; return 0; } /** Get the duration of a blank space. * * \public \memberof mlt_playlist_s * \param self a playlist * \param clip the index of the playlist entry * \param bounded the maximum number of blank entries or 0 for all * \return the duration of a blank section */ int mlt_playlist_blanks_from( mlt_playlist self, int clip, int bounded ) { int count = 0; mlt_playlist_clip_info info; if ( self != NULL && clip < self->count ) { mlt_playlist_get_clip_info( self, &info, clip ); if ( mlt_playlist_is_blank( self, clip ) ) count += info.frame_count; if ( bounded == 0 ) bounded = self->count; for ( clip ++; clip < self->count && bounded >= 0; clip ++ ) { mlt_playlist_get_clip_info( self, &info, clip ); if ( mlt_playlist_is_blank( self, clip ) ) count += info.frame_count; else bounded --; } } return count; } /** Remove a portion of the playlist by time. * * \public \memberof mlt_playlist_s * \param self a playlist * \param position the starting time * \param length the duration of time to remove * \return the new entry index at the position */ int mlt_playlist_remove_region( mlt_playlist self, mlt_position position, int length ) { int index = mlt_playlist_get_clip_index_at( self, position ); if ( index >= 0 && index < self->count ) { mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); int clip_start = mlt_playlist_clip_start( self, index ); int list_length = mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( self ) ); mlt_events_block( properties, self ); if ( position + length > list_length ) length -= ( position + length - list_length ); if ( clip_start < position ) { mlt_playlist_split( self, index ++, position - clip_start - 1 ); } while( length > 0 ) { if ( mlt_playlist_clip_length( self, index ) > length ) mlt_playlist_split( self, index, length - 1 ); length -= mlt_playlist_clip_length( self, index ); mlt_playlist_remove( self, index ); } mlt_playlist_consolidate_blanks( self, 0 ); mlt_events_unblock( properties, self ); mlt_playlist_virtual_refresh( self ); // Just to be sure, we'll get the clip index again... index = mlt_playlist_get_clip_index_at( self, position ); } return index; } /** Not implemented * * \deprecated not implemented * \public \memberof mlt_playlist_s * \param self * \param position * \param length * \param new_position * \return */ int mlt_playlist_move_region( mlt_playlist self, mlt_position position, int length, int new_position ) { if ( self != NULL ) { } return 0; } /** Get the current frame. * * The implementation of the get_frame virtual function. * \private \memberof mlt_playlist_s * \param producer a producer * \param frame a frame by reference * \param index the time at which to get the frame * \return false */ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Check that we have a producer if ( producer == NULL ) { *frame = NULL; return -1; } // Get this mlt_playlist mlt_playlist self = producer->child; // Need to ensure the frame is deinterlaced when repeating 1 frame int progressive = 0; // Get the real producer mlt_service real = mlt_playlist_virtual_seek( self, &progressive ); // Check that we have a producer if ( real == NULL ) { *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); return 0; } // Get the frame if ( !mlt_properties_get_int( MLT_SERVICE_PROPERTIES( real ), "meta.fx_cut" ) ) { mlt_service_get_frame( real, frame, index ); } else { mlt_producer parent = mlt_producer_cut_parent( ( mlt_producer )real ); *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( parent ) ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "fx_cut", 1 ); mlt_frame_push_service( *frame, NULL ); mlt_frame_push_audio( *frame, NULL ); mlt_service_apply_filters( MLT_PRODUCER_SERVICE( parent ), *frame, 0 ); mlt_service_apply_filters( real, *frame, 0 ); mlt_deque_pop_front( MLT_FRAME_IMAGE_STACK( *frame ) ); mlt_deque_pop_front( MLT_FRAME_AUDIO_STACK( *frame ) ); } // Check if we're at the end of the clip mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); if ( mlt_properties_get_int( properties, "end_of_clip" ) ) mlt_playlist_virtual_set_out( self ); // Set the consumer progressive property if ( progressive ) { mlt_properties_set_int( properties, "consumer_deinterlace", progressive ); mlt_properties_set_int( properties, "test_audio", 1 ); } // Check for notifier and call with appropriate argument mlt_properties playlist_properties = MLT_PRODUCER_PROPERTIES( producer ); void ( *notifier )( void * ) = mlt_properties_get_data( playlist_properties, "notifier", NULL ); if ( notifier != NULL ) { void *argument = mlt_properties_get_data( playlist_properties, "notifier_arg", NULL ); notifier( argument ); } // Update position on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_frame( producer ) ); // Position ourselves on the next frame mlt_producer_prepare_next( producer ); return 0; } /** Close the playlist. * * \public \memberof mlt_playlist_s * \param self a playlist */ void mlt_playlist_close( mlt_playlist self ) { if ( self != NULL && mlt_properties_dec_ref( MLT_PLAYLIST_PROPERTIES( self ) ) <= 0 ) { int i = 0; self->parent.close = NULL; for ( i = 0; i < self->count; i ++ ) { mlt_event_close( self->list[ i ]->event ); mlt_producer_close( self->list[ i ]->producer ); free( self->list[ i ] ); } mlt_producer_close( &self->blank ); mlt_producer_close( &self->parent ); free( self->list ); free( self ); } } mlt-0.9.0/src/framework/mlt_playlist.h000066400000000000000000000147341215300731300177720ustar00rootroot00000000000000/** * \file mlt_playlist.h * \brief playlist service class * \see mlt_playlist_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_PLAYLIST_H_ #define _MLT_PLAYLIST_H_ #include "mlt_producer.h" /** \brief structure for returning clip information from a playlist entry */ typedef struct { int clip; /**< the index of the clip within the playlist */ mlt_producer producer; /**< the clip's producer (or parent producer of a cut) */ mlt_producer cut; /**< the clips' cut producer */ mlt_position start; /**< the time this begins relative to the beginning of the playlist */ char *resource; /**< the file name or address of the clip */ mlt_position frame_in; /**< the clip's in point */ mlt_position frame_out; /**< the clip's out point */ mlt_position frame_count; /**< the duration of the clip */ mlt_position length; /**< the unedited duration of the clip */ float fps; /**< the frame rate of the clip */ int repeat; /**< the number of times the clip is repeated */ } mlt_playlist_clip_info; /** Playlist Entry */ typedef struct playlist_entry_s playlist_entry; /** \brief Playlist class * * A playlist is a sequential container of producers and blank spaces. The class provides all * sorts of playlist assembly and manipulation routines. A playlist is also a producer within * the framework. * * \extends mlt_producer_s * \properties \em autoclose Set this true if you are doing sequential processing and want to * automatically close producers as they are finished being used to free resources. * \properties \em meta.fx_cut Set true on a producer to indicate that it is a "fx_cut," * which is a way to add filters as a playlist entry - useful only in a multitrack. See FxCut on the wiki. * \properties \em mix_in * \properties \em mix_out * \event \em playlist-next The playlist fires this when it moves to the next item in the list. * The listener receives one argument that is the index of the entry that just completed. */ struct mlt_playlist_s { struct mlt_producer_s parent; struct mlt_producer_s blank; int size; int count; playlist_entry **list; }; #define MLT_PLAYLIST_PRODUCER( playlist ) ( &( playlist )->parent ) #define MLT_PLAYLIST_SERVICE( playlist ) MLT_PRODUCER_SERVICE( MLT_PLAYLIST_PRODUCER( playlist ) ) #define MLT_PLAYLIST_PROPERTIES( playlist ) MLT_SERVICE_PROPERTIES( MLT_PLAYLIST_SERVICE( playlist ) ) extern mlt_playlist mlt_playlist_init( ); extern mlt_playlist mlt_playlist_new( mlt_profile profile ); extern mlt_producer mlt_playlist_producer( mlt_playlist self ); extern mlt_service mlt_playlist_service( mlt_playlist self ); extern mlt_properties mlt_playlist_properties( mlt_playlist self ); extern int mlt_playlist_count( mlt_playlist self ); extern int mlt_playlist_clear( mlt_playlist self ); extern int mlt_playlist_append( mlt_playlist self, mlt_producer producer ); extern int mlt_playlist_append_io( mlt_playlist self, mlt_producer producer, mlt_position in, mlt_position out ); extern int mlt_playlist_blank( mlt_playlist self, mlt_position out ); extern int mlt_playlist_blank_time( mlt_playlist self, const char *length ); extern mlt_position mlt_playlist_clip( mlt_playlist self, mlt_whence whence, int index ); extern int mlt_playlist_current_clip( mlt_playlist self ); extern mlt_producer mlt_playlist_current( mlt_playlist self ); extern int mlt_playlist_get_clip_info( mlt_playlist self, mlt_playlist_clip_info *info, int index ); extern int mlt_playlist_insert( mlt_playlist self, mlt_producer producer, int where, mlt_position in, mlt_position out ); extern int mlt_playlist_remove( mlt_playlist self, int where ); extern int mlt_playlist_move( mlt_playlist self, int from, int to ); extern int mlt_playlist_resize_clip( mlt_playlist self, int clip, mlt_position in, mlt_position out ); extern int mlt_playlist_repeat_clip( mlt_playlist self, int clip, int repeat ); extern int mlt_playlist_split( mlt_playlist self, int clip, mlt_position position ); extern int mlt_playlist_split_at( mlt_playlist self, mlt_position position, int left ); extern int mlt_playlist_join( mlt_playlist self, int clip, int count, int merge ); extern int mlt_playlist_mix( mlt_playlist self, int clip, int length, mlt_transition transition ); extern int mlt_playlist_mix_add( mlt_playlist self, int clip, mlt_transition transition ); extern mlt_producer mlt_playlist_get_clip( mlt_playlist self, int clip ); extern mlt_producer mlt_playlist_get_clip_at( mlt_playlist self, mlt_position position ); extern int mlt_playlist_get_clip_index_at( mlt_playlist self, mlt_position position ); extern int mlt_playlist_clip_is_mix( mlt_playlist self, int clip ); extern void mlt_playlist_consolidate_blanks( mlt_playlist self, int keep_length ); extern int mlt_playlist_is_blank( mlt_playlist self, int clip ); extern int mlt_playlist_is_blank_at( mlt_playlist self, mlt_position position ); extern void mlt_playlist_insert_blank( mlt_playlist self, int clip, int length ); extern void mlt_playlist_pad_blanks( mlt_playlist self, mlt_position position, int length, int find ); extern mlt_producer mlt_playlist_replace_with_blank( mlt_playlist self, int clip ); extern int mlt_playlist_insert_at( mlt_playlist self, mlt_position position, mlt_producer producer, int mode ); extern int mlt_playlist_clip_start( mlt_playlist self, int clip ); extern int mlt_playlist_clip_length( mlt_playlist self, int clip ); extern int mlt_playlist_blanks_from( mlt_playlist self, int clip, int bounded ); extern int mlt_playlist_remove_region( mlt_playlist self, mlt_position position, int length ); extern int mlt_playlist_move_region( mlt_playlist self, mlt_position position, int length, int new_position ); extern void mlt_playlist_close( mlt_playlist self ); #endif mlt-0.9.0/src/framework/mlt_pool.c000066400000000000000000000204651215300731300170730ustar00rootroot00000000000000/** * \file mlt_pool.c * \brief memory pooling functionality * \see mlt_pool_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_properties.h" #include "mlt_deque.h" #include #include #include // Not nice - memalign is defined here apparently? #ifdef linux #include #endif /** global singleton for tracking pools */ static mlt_properties pools = NULL; /** \brief Pool (memory) class */ typedef struct mlt_pool_s { pthread_mutex_t lock; ///< lock to prevent race conditions mlt_deque stack; ///< a stack of addresses to memory blocks int size; ///< the size of the memory block as a power of 2 int count; ///< the number of blocks in the pool } *mlt_pool; /** \brief private to mlt_pool_s, for tracking items to release * * Aligned to 16 byte in case we toss buffers to external assembly * optimized libraries (sse/altivec). */ typedef struct __attribute__ ((aligned (16))) mlt_release_s { mlt_pool pool; int references; } *mlt_release; /** Create a pool. * * \private \memberof mlt_pool_s * \param size the size of the memory blocks to hold as some power of two * \return a new pool object */ static mlt_pool pool_init( int size ) { // Create the pool mlt_pool self = calloc( 1, sizeof( struct mlt_pool_s ) ); // Initialise it if ( self != NULL ) { // Initialise the mutex pthread_mutex_init( &self->lock, NULL ); // Create the stack self->stack = mlt_deque_init( ); // Assign the size self->size = size; } // Return it return self; } /** Get an item from the pool. * * \private \memberof mlt_pool_s * \param self a pool * \return an opaque pointer */ static void *pool_fetch( mlt_pool self ) { // We will generate a release object void *ptr = NULL; // Sanity check if ( self != NULL ) { // Lock the pool pthread_mutex_lock( &self->lock ); // Check if the stack is empty if ( mlt_deque_count( self->stack ) != 0 ) { // Pop the top of the stack ptr = mlt_deque_pop_back( self->stack ); // Assign the reference ( ( mlt_release )ptr )->references = 1; } else { // We need to generate a release item #ifdef linux mlt_release release = memalign( 16, self->size ); #else mlt_release release = malloc( self->size ); #endif // Initialise it if ( release != NULL ) { // Increment the number of items allocated to this pool self->count ++; // Assign the pool release->pool = self; // Assign the reference release->references = 1; // Determine the ptr ptr = ( char * )release + sizeof( struct mlt_release_s ); } } // Unlock the pool pthread_mutex_unlock( &self->lock ); } // Return the generated release object return ptr; } /** Return an item to the pool. * * \private \memberof mlt_pool_s * \param ptr an opaque pointer */ static void pool_return( void *ptr ) { // Sanity checks if ( ptr != NULL ) { // Get the release pointer mlt_release that = ( void * )(( char * )ptr - sizeof( struct mlt_release_s )); // Get the pool mlt_pool self = that->pool; if ( self != NULL ) { // Lock the pool pthread_mutex_lock( &self->lock ); // Push the that back back on to the stack mlt_deque_push_back( self->stack, ptr ); // Unlock the pool pthread_mutex_unlock( &self->lock ); // Ensure that we don't clean up ptr = NULL; } } // Tidy up - this will only occur if the returned item is incorrect if ( ptr != NULL ) { // Free the release itself free( ( char * )ptr - sizeof( struct mlt_release_s ) ); } } /** Destroy a pool. * * \private \memberof mlt_pool_s * \param self a pool */ static void pool_close( mlt_pool self ) { if ( self != NULL ) { // We need to free up all items in the pool void *release = NULL; // Iterate through the stack until depleted while ( ( release = mlt_deque_pop_back( self->stack ) ) != NULL ) { // We'll free this item now free( ( char * )release - sizeof( struct mlt_release_s ) ); } // We can now close the stack mlt_deque_close( self->stack ); // Destroy the mutex pthread_mutex_destroy( &self->lock ); // Close the pool free( self ); } } /** Initialise the global pool. * * \public \memberof mlt_pool_s */ void mlt_pool_init( ) { // Loop variable used to create the pools int i = 0; // Create the pools pools = mlt_properties_new( ); // Create the pools for ( i = 8; i < 31; i ++ ) { // Each properties item needs a name char name[ 32 ]; // Construct a pool mlt_pool pool = pool_init( 1 << i ); // Generate a name sprintf( name, "%d", i ); // Register with properties mlt_properties_set_data( pools, name, pool, 0, ( mlt_destructor )pool_close, NULL ); } } /** Allocate size bytes from the pool. * * \public \memberof mlt_pool_s * \param size the number of bytes */ void *mlt_pool_alloc( int size ) { // This will be used to obtain the pool to use mlt_pool pool = NULL; // Determines the index of the pool to use int index = 8; // Minimum size pooled is 256 bytes size += sizeof( struct mlt_release_s ); while ( ( 1 << index ) < size ) index ++; // Now get the pool at the index pool = mlt_properties_get_data_at( pools, index - 8, NULL ); // Now get the real item return pool_fetch( pool ); } /** Allocate size bytes from the pool. * * \public \memberof mlt_pool_s * \param ptr an opaque pointer - can be in the pool or a new block to allocate * \param size the number of bytes */ void *mlt_pool_realloc( void *ptr, int size ) { // Result to return void *result = NULL; // Check if we actually have an address if ( ptr != NULL ) { // Get the release pointer mlt_release that = ( void * )(( char * )ptr - sizeof( struct mlt_release_s )); // If the current pool this ptr belongs to is big enough if ( size > that->pool->size - sizeof( struct mlt_release_s ) ) { // Allocate result = mlt_pool_alloc( size ); // Copy memcpy( result, ptr, that->pool->size - sizeof( struct mlt_release_s ) ); // Release mlt_pool_release( ptr ); } else { // Nothing to do result = ptr; } } else { // Simply allocate result = mlt_pool_alloc( size ); } return result; } /** Purge unused items in the pool. * * A form of garbage collection. * \public \memberof mlt_pool_s */ void mlt_pool_purge( ) { int i = 0; // For each pool for ( i = 0; i < mlt_properties_count( pools ); i ++ ) { // Get the pool mlt_pool self = mlt_properties_get_data_at( pools, i, NULL ); // Pointer to unused memory void *release = NULL; // Lock the pool pthread_mutex_lock( &self->lock ); // We'll free all unused items now while ( ( release = mlt_deque_pop_back( self->stack ) ) != NULL ) free( ( char * )release - sizeof( struct mlt_release_s ) ); // Unlock the pool pthread_mutex_unlock( &self->lock ); } } /** Release the allocated memory. * * \public \memberof mlt_pool_s * \param release an opaque pointer of a block in the pool */ void mlt_pool_release( void *release ) { // Return to the pool pool_return( release ); } /** Close the pool. * * \public \memberof mlt_pool_s */ void mlt_pool_close( ) { #ifdef _MLT_POOL_CHECKS_ // Stats dump on close int i = 0; for ( i = 0; i < mlt_properties_count( pools ); i ++ ) { mlt_pool pool = mlt_properties_get_data_at( pools, i, NULL ); if ( pool->count ) mlt_log( NULL, MLT_LOG_DEBUG, "%s: size %d allocated %d returned %d %c\n", __FUNCTION__, pool->size, pool->count, mlt_deque_count( pool->stack ), pool->count != mlt_deque_count( pool->stack ) ? '*' : ' ' ); } #endif // Close the properties mlt_properties_close( pools ); } mlt-0.9.0/src/framework/mlt_pool.h000066400000000000000000000023041215300731300170700ustar00rootroot00000000000000/** * \file mlt_pool.h * \brief memory pooling functionality * \see mlt_pool_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_POOL_H #define _MLT_POOL_H extern void mlt_pool_init( ); extern void *mlt_pool_alloc( int size ); extern void *mlt_pool_realloc( void *ptr, int size ); extern void mlt_pool_release( void *release ); extern void mlt_pool_purge( ); extern void mlt_pool_close( ); #endif mlt-0.9.0/src/framework/mlt_producer.c000066400000000000000000001012321215300731300177350ustar00rootroot00000000000000/** * \file mlt_producer.c * \brief abstraction for all producer services * \see mlt_producer_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_producer.h" #include "mlt_factory.h" #include "mlt_frame.h" #include "mlt_parser.h" #include "mlt_profile.h" #include "mlt_log.h" #include #include #include /* Forward references. */ static int producer_get_frame( mlt_service self, mlt_frame_ptr frame, int index ); static void mlt_producer_property_changed( mlt_service owner, mlt_producer self, char *name ); static void mlt_producer_service_changed( mlt_service owner, mlt_producer self ); /* for debugging */ //#define _MLT_PRODUCER_CHECKS_ 1 #ifdef _MLT_PRODUCER_CHECKS_ static int producers_created = 0; static int producers_destroyed = 0; #endif /** Initialize a producer service. * * \public \memberof mlt_producer_s * \param self the producer structure to initialize * \param child a pointer to the child object for the subclass * \return true if there was an error */ int mlt_producer_init( mlt_producer self, void *child ) { // Check that we haven't received NULL int error = self == NULL; // Continue if no error if ( error == 0 ) { #ifdef _MLT_PRODUCER_CHECKS_ producers_created ++; #endif // Initialise the producer memset( self, 0, sizeof( struct mlt_producer_s ) ); // Associate with the child self->child = child; // Initialise the service if ( mlt_service_init( &self->parent, self ) == 0 ) { // The parent is the service mlt_service parent = &self->parent; // Define the parent close parent->close = ( mlt_destructor )mlt_producer_close; parent->close_object = self; // For convenience, we'll assume the close_object is self self->close_object = self; // Get the properties of the parent mlt_properties properties = MLT_SERVICE_PROPERTIES( parent ); // Set the default properties mlt_properties_set( properties, "mlt_type", "mlt_producer" ); mlt_properties_set_position( properties, "_position", 0.0 ); mlt_properties_set_double( properties, "_frame", 0 ); mlt_properties_set_double( properties, "_speed", 1.0 ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", 14999 ); mlt_properties_set_position( properties, "length", 15000 ); mlt_properties_set( properties, "eof", "pause" ); mlt_properties_set( properties, "resource", "" ); // Override service get_frame parent->get_frame = producer_get_frame; mlt_events_listen( properties, self, "service-changed", ( mlt_listener )mlt_producer_service_changed ); mlt_events_listen( properties, self, "property-changed", ( mlt_listener )mlt_producer_property_changed ); mlt_events_register( properties, "producer-changed", NULL ); } } return error; } /** Listener for property changes. * * If the in, out, or length properties changed, fire a "producer-changed" event. * * \private \memberof mlt_producer_s * \param owner a service (ignored) * \param self the producer * \param name the property that changed */ static void mlt_producer_property_changed( mlt_service owner, mlt_producer self, char *name ) { if ( !strcmp( name, "in" ) || !strcmp( name, "out" ) || !strcmp( name, "length" ) ) mlt_events_fire( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), "producer-changed", NULL ); } /** Listener for service changes. * * Fires the "producer-changed" event. * * \private \memberof mlt_producer_s * \param owner a service (ignored) * \param self the producer */ static void mlt_producer_service_changed( mlt_service owner, mlt_producer self ) { mlt_events_fire( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), "producer-changed", NULL ); } /** Create and initialize a new producer. * * \public \memberof mlt_producer_s * \return the new producer */ mlt_producer mlt_producer_new( mlt_profile profile ) { mlt_producer self = malloc( sizeof( struct mlt_producer_s ) ); if ( self ) { if ( mlt_producer_init( self, NULL ) == 0 ) { mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( self ), "_profile", profile, 0, NULL, NULL ); mlt_properties_set_double( MLT_PRODUCER_PROPERTIES( self ), "aspect_ratio", mlt_profile_sar( profile ) ); } else { free( self ); return NULL; } } return self; } /** Determine if producer is a cut. * * \public \memberof mlt_producer_s * \param self a producer * \return true if \p self is a "cut" producer * \see mlt_producer_cut */ int mlt_producer_is_cut( mlt_producer self ) { return mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( self ), "_cut" ); } /** Determine if producer is a mix. * * \public \memberof mlt_producer_s * \param self a producer * \return true if \p self is a "mix" producer * \todo Define a mix producer. */ int mlt_producer_is_mix( mlt_producer self ) { mlt_properties properties = self != NULL ? MLT_PRODUCER_PROPERTIES( self ) : NULL; mlt_tractor tractor = properties != NULL ? mlt_properties_get_data( properties, "mlt_mix", NULL ) : NULL; return tractor != NULL; } /** Determine if the producer is a blank. * * Blank producers should only appear as an item in a playlist. * \public \memberof mlt_producer_s * \param self a producer * \return true if \p self is a "blank" producer * \see mlt_playlist_insert_blank */ int mlt_producer_is_blank( mlt_producer self ) { return self == NULL || !strcmp( mlt_properties_get( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), "resource" ), "blank" ); } /** Obtain the parent producer. * * \public \memberof mlt_producer_s * \param self a producer * \return either the parent producer if \p self is a "cut" producer or \p self otherwise. */ mlt_producer mlt_producer_cut_parent( mlt_producer self ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); if ( mlt_producer_is_cut( self ) ) return mlt_properties_get_data( properties, "_cut_parent", NULL ); else return self; } /** Create a cut of this producer. * * A "cut" is a portion of another (parent) producer. * * \public \memberof mlt_producer_s * \param self a producer * \param in the beginning * \param out the end * \return the new producer * \todo Expand on the value of a cut. */ mlt_producer mlt_producer_cut( mlt_producer self, int in, int out ) { mlt_producer result = mlt_producer_new( mlt_service_profile( MLT_PRODUCER_SERVICE( self ) ) ); mlt_producer parent = mlt_producer_cut_parent( self ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( result ); mlt_properties parent_props = MLT_PRODUCER_PROPERTIES( parent ); mlt_events_block( MLT_PRODUCER_PROPERTIES( result ), MLT_PRODUCER_PROPERTIES( result ) ); // Special case - allow for a cut of the entire producer (this will squeeze all other cuts to 0) if ( in <= 0 ) in = 0; if ( ( out < 0 || out >= mlt_producer_get_length( parent ) ) && !mlt_producer_is_blank( self ) ) out = mlt_producer_get_length( parent ) - 1; mlt_properties_inc_ref( parent_props ); mlt_properties_set_int( properties, "_cut", 1 ); mlt_properties_set_data( properties, "_cut_parent", parent, 0, ( mlt_destructor )mlt_producer_close, NULL ); mlt_properties_set_position( properties, "length", mlt_properties_get_position( parent_props, "length" ) ); mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( parent_props, "aspect_ratio" ) ); mlt_producer_set_in_and_out( result, in, out ); return result; } /** Get the parent service object. * * \public \memberof mlt_producer_s * \param self a producer * \return the service parent class * \see MLT_PRODUCER_SERVICE */ mlt_service mlt_producer_service( mlt_producer self ) { return self != NULL ? &self->parent : NULL; } /** Get the producer properties. * * \public \memberof mlt_producer_s * \param self a producer * \return the producer's property list * \see MLT_PRODUCER_PROPERTIES */ mlt_properties mlt_producer_properties( mlt_producer self ) { return MLT_SERVICE_PROPERTIES( &self->parent ); } /** Seek to a specified position. * * \public \memberof mlt_producer_s * \param self a producer * \param position set the "play head" position of the producer * \return false * \todo Document how the properties affect behavior. * \see mlt_producer_seek_time */ int mlt_producer_seek( mlt_producer self, mlt_position position ) { // Determine eof handling mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); char *eof = mlt_properties_get( properties, "eof" ); int use_points = 1 - mlt_properties_get_int( properties, "ignore_points" ); // Recursive behaviour for cuts - repositions parent and then repositions cut // hence no return on this condition if ( mlt_producer_is_cut( self ) ) mlt_producer_seek( mlt_producer_cut_parent( self ), position + mlt_producer_get_in( self ) ); // Check bounds if ( position < 0 || mlt_producer_get_playtime( self ) == 0 ) { position = 0; } else if ( use_points && ( eof == NULL || !strcmp( eof, "pause" ) ) && position >= mlt_producer_get_playtime( self ) ) { mlt_producer_set_speed( self, 0 ); position = mlt_producer_get_playtime( self ) - 1; } else if ( use_points && eof && !strcmp( eof, "loop" ) && position >= mlt_producer_get_playtime( self ) ) { position = (int)position % (int)mlt_producer_get_playtime( self ); } // Set the position mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( self ), "_position", position ); // Calculate the absolute frame mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( self ), "_frame", use_points * mlt_producer_get_in( self ) + position ); return 0; } /** Seek to a specified time string. * * \public \memberof mlt_producer_s * \param self a producer * \param time set the "play head" position of the producer to the time string * \return false * \see mlt_producer_seek */ int mlt_producer_seek_time( mlt_producer self, const char* time ) { mlt_properties_set( MLT_PRODUCER_PROPERTIES(self), "_seek_time", time ); mlt_position position = mlt_properties_get_position( MLT_PRODUCER_PROPERTIES(self), "_seek_time" ); return mlt_producer_seek( self, position ); } /** Get the current position (relative to in point). * * \public \memberof mlt_producer_s * \param self a producer * \return the position of the "play head" relative to its beginning */ mlt_position mlt_producer_position( mlt_producer self ) { return mlt_properties_get_position( MLT_PRODUCER_PROPERTIES( self ), "_position" ); } /** Get the current position (relative to start of producer). * * \public \memberof mlt_producer_s * \param self a producer * \return the position of the "play head" regardless of the in point */ mlt_position mlt_producer_frame( mlt_producer self ) { return mlt_properties_get_position( MLT_PRODUCER_PROPERTIES( self ), "_frame" ); } /** Get the current position (relative to start of producer) as a time string. * * \public \memberof mlt_producer_s * \param self a producer * \param format the time value format * \return the position of the "play head" regardless of the in point */ char* mlt_producer_frame_time( mlt_producer self, mlt_time_format format ) { return mlt_properties_get_time( MLT_PRODUCER_PROPERTIES( self ), "_frame", format ); } /** Set the playing speed. * * \public \memberof mlt_producer_s * \param self a producer * \param speed the new speed as a relative factor (1.0 = normal) * \return true if error */ int mlt_producer_set_speed( mlt_producer self, double speed ) { return mlt_properties_set_double( MLT_PRODUCER_PROPERTIES( self ), "_speed", speed ); } /** Get the playing speed. * * \public \memberof mlt_producer_s * \param self a producer * \return the speed as a relative factor (1.0 = normal) */ double mlt_producer_get_speed( mlt_producer self ) { return mlt_properties_get_double( MLT_PRODUCER_PROPERTIES( self ), "_speed" ); } /** Get the frames per second. * * This is determined by the producer's profile. * * \public \memberof mlt_producer_s * \param self a producer * \return the video refresh rate */ double mlt_producer_get_fps( mlt_producer self ) { mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( self ) ); return mlt_profile_fps( profile ); } /** Set the in and out points. * * The in point is where play out should start relative to the natural start * of the underlying file. The out point is where play out should end, also * relative to the start of the underlying file. If the underlying resource is * a live stream, then the in point is an offset relative to first usable * sample. * * \public \memberof mlt_producer_s * \param self a producer * \param in the relative starting time; a negative value is the same as 0 * \param out the relative ending time; a negative value is the same as length - 1 * \return false */ int mlt_producer_set_in_and_out( mlt_producer self, mlt_position in, mlt_position out ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); // Correct ins and outs if necessary if ( in < 0 ) in = 0; else if ( in >= mlt_producer_get_length( self ) ) in = mlt_producer_get_length( self ) - 1; if ( ( out < 0 || out >= mlt_producer_get_length( self ) ) && !mlt_producer_is_blank( self ) ) out = mlt_producer_get_length( self ) - 1; else if ( ( out < 0 || out >= mlt_producer_get_length( self ) ) && mlt_producer_is_blank( self ) ) mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( self ), "length", out + 1 ); else if ( out < 0 ) out = 0; // Swap ins and outs if wrong if ( out < in ) { mlt_position t = in; in = out; out = t; } // Set the values mlt_events_block( properties, properties ); mlt_properties_set_position( properties, "in", in ); mlt_events_unblock( properties, properties ); mlt_properties_set_position( properties, "out", out ); return 0; } /** Physically reduce the producer (typically a cut) to a 0 length. * Essentially, all 0 length cuts should be immediately removed by containers. * * \public \memberof mlt_producer_s * \param self a producer * \return false */ int mlt_producer_clear( mlt_producer self ) { if ( self != NULL ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); mlt_events_block( properties, properties ); mlt_properties_set_position( properties, "in", 0 ); mlt_events_unblock( properties, properties ); mlt_properties_set_position( properties, "out", -1 ); } return 0; } /** Get the in point. * * \public \memberof mlt_producer_s * \param self a producer * \return the in point */ mlt_position mlt_producer_get_in( mlt_producer self ) { return mlt_properties_get_position( MLT_PRODUCER_PROPERTIES( self ), "in" ); } /** Get the out point. * * \public \memberof mlt_producer_s * \param self a producer * \return the out point */ mlt_position mlt_producer_get_out( mlt_producer self ) { return mlt_properties_get_position( MLT_PRODUCER_PROPERTIES( self ), "out" ); } /** Get the total play time. * * \public \memberof mlt_producer_s * \param self a producer * \return the playable (based on in and out points) duration */ mlt_position mlt_producer_get_playtime( mlt_producer self ) { return mlt_producer_get_out( self ) - mlt_producer_get_in( self ) + 1; } /** Get the total, unedited length of the producer. * * The value returned by a live streaming producer is unknown. * * \public \memberof mlt_producer_s * \param self a producer * \return the duration of the producer regardless of in and out points */ mlt_position mlt_producer_get_length( mlt_producer self ) { return mlt_properties_get_position( MLT_PRODUCER_PROPERTIES( self ), "length" ); } /** Get the total, unedited length of the producer as a time string. * * The value returned by a live streaming producer is unknown. * * \public \memberof mlt_producer_s * \param self a producer * \param format the time value format * \return the duration of the producer regardless of in and out points */ char* mlt_producer_get_length_time( mlt_producer self, mlt_time_format format ) { return mlt_properties_get_time( MLT_PRODUCER_PROPERTIES( self ), "length", format ); } /** Prepare for next frame. * * Advance the play out position. If the speed is less than zero, it will * move the play out position in the reverse direction. * * \public \memberof mlt_producer_s * \param self a producer */ void mlt_producer_prepare_next( mlt_producer self ) { if ( mlt_producer_get_speed( self ) != 0 ) mlt_producer_seek( self, mlt_producer_position( self ) + mlt_producer_get_speed( self ) ); } /** Get a frame. * * This is the implementation of the \p get_frame virtual function. * It requests a new frame object from the actual producer for the current * play out position. The producer and its filters can add information and * operations to the frame object in their get_frame handlers. * * \private \memberof mlt_producer_s * \param service a service * \param[out] frame a frame by reference * \param index as determined by the actual producer * \return true if there was an error * \todo Learn more about the details and document how certain properties affect * its behavior. */ static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int index ) { int result = 1; mlt_producer self = service != NULL ? service->child : NULL; if ( self != NULL && !mlt_producer_is_cut( self ) ) { // Get the properties of this producer mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); // Determine eof handling char *eof = mlt_properties_get( MLT_PRODUCER_PROPERTIES( self ), "eof" ); // Get the speed of the producer double speed = mlt_producer_get_speed( self ); // We need to use the clone if it's specified mlt_producer clone = mlt_properties_get_data( properties, "use_clone", NULL ); // If no clone is specified, use self clone = clone == NULL ? self : clone; // A properly instatiated producer will have a get_frame method... if ( self->get_frame == NULL || ( !strcmp( eof, "continue" ) && mlt_producer_position( self ) > mlt_producer_get_out( self ) ) ) { // Generate a test frame *frame = mlt_frame_init( service ); // Set the position result = mlt_frame_set_position( *frame, mlt_producer_position( self ) ); // Mark as a test card mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_image", 1 ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_audio", 1 ); // Calculate the next position mlt_producer_prepare_next( self ); } else { // Get the frame from the implementation result = self->get_frame( clone, frame, index ); } // Copy the fps and speed of the producer onto the frame properties = MLT_FRAME_PROPERTIES( *frame ); mlt_properties_set_double( properties, "_speed", speed ); mlt_properties_set_int( properties, "test_audio", mlt_frame_is_test_audio( *frame ) ); mlt_properties_set_int( properties, "test_image", mlt_frame_is_test_card( *frame ) ); if ( mlt_properties_get_data( properties, "_producer", NULL ) == NULL ) mlt_properties_set_data( properties, "_producer", service, 0, NULL, NULL ); } else if ( self != NULL ) { // Get the speed of the cut double speed = mlt_producer_get_speed( self ); // Get the parent of the cut mlt_producer parent = mlt_producer_cut_parent( self ); // Get the properties of the parent mlt_properties parent_properties = MLT_PRODUCER_PROPERTIES( parent ); // Get the properties of the cut mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); // Determine the clone index int clone_index = mlt_properties_get_int( properties, "_clone" ); // Determine the clone to use mlt_producer clone = self; if ( clone_index > 0 ) { char key[ 25 ]; sprintf( key, "_clone.%d", clone_index - 1 ); clone = mlt_properties_get_data( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), key, NULL ); if ( clone == NULL ) mlt_log( service, MLT_LOG_ERROR, "requested clone doesn't exist %d\n", clone_index ); clone = clone == NULL ? self : clone; } else { clone = parent; } // We need to seek to the correct position in the clone mlt_producer_seek( clone, mlt_producer_get_in( self ) + mlt_properties_get_int( properties, "_position" ) ); // Assign the clone property to the parent mlt_properties_set_data( parent_properties, "use_clone", clone, 0, NULL, NULL ); // Now get the frame from the parents service result = mlt_service_get_frame( MLT_PRODUCER_SERVICE( parent ), frame, index ); // We're done with the clone now mlt_properties_set_data( parent_properties, "use_clone", NULL, 0, NULL, NULL ); // This is useful and required by always_active transitions to determine in/out points of the cut if ( mlt_properties_get_data( MLT_FRAME_PROPERTIES( *frame ), "_producer", NULL ) == MLT_PRODUCER_SERVICE( parent ) ) mlt_properties_set_data( MLT_FRAME_PROPERTIES( *frame ), "_producer", self, 0, NULL, NULL ); mlt_properties_set_double( MLT_FRAME_PROPERTIES( *frame ), "_speed", speed ); mlt_producer_prepare_next( self ); } else { *frame = mlt_frame_init( service ); result = 0; } // Pass on all meta properties from the producer/cut on to the frame if ( *frame != NULL && self != NULL ) { int i = 0; mlt_properties p_props = MLT_PRODUCER_PROPERTIES( self ); mlt_properties f_props = MLT_FRAME_PROPERTIES( *frame ); mlt_properties_lock( p_props ); int count = mlt_properties_count( p_props ); for ( i = 0; i < count; i ++ ) { char *name = mlt_properties_get_name( p_props, i ); if ( !strncmp( name, "meta.", 5 ) ) mlt_properties_set( f_props, name, mlt_properties_get_value( p_props, i ) ); else if ( !strncmp( name, "set.", 4 ) ) mlt_properties_set( f_props, name + 4, mlt_properties_get_value( p_props, i ) ); } mlt_properties_unlock( p_props ); } return result; } /** Attach a filter. * * \public \memberof mlt_producer_s * \param self a producer * \param filter the filter to attach * \return true if there was an error */ int mlt_producer_attach( mlt_producer self, mlt_filter filter ) { return mlt_service_attach( MLT_PRODUCER_SERVICE( self ), filter ); } /** Detach a filter. * * \public \memberof mlt_producer_s * \param self a service * \param filter the filter to detach * \return true if there was an error */ int mlt_producer_detach( mlt_producer self, mlt_filter filter ) { return mlt_service_detach( MLT_PRODUCER_SERVICE( self ), filter ); } /** Retrieve a filter. * * \public \memberof mlt_producer_s * \param self a service * \param index which filter to retrieve * \return the filter or null if there was an error */ mlt_filter mlt_producer_filter( mlt_producer self, int index ) { return mlt_service_filter( MLT_PRODUCER_SERVICE( self ), index ); } /** Clone a producer. * * \private \memberof mlt_producer_s * \param self a producer * \return a new producer that is a copy of \p self * \see mlt_producer_set_clones */ static mlt_producer mlt_producer_clone( mlt_producer self ) { mlt_producer clone = NULL; mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); char *resource = mlt_properties_get( properties, "resource" ); char *service = mlt_properties_get( properties, "mlt_service" ); mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( self ) ); mlt_events_block( mlt_factory_event_object( ), mlt_factory_event_object( ) ); if ( service != NULL ) clone = mlt_factory_producer( profile, service, resource ); if ( clone == NULL && resource != NULL ) clone = mlt_factory_producer( profile, NULL, resource ); if ( clone != NULL ) mlt_properties_inherit( MLT_PRODUCER_PROPERTIES( clone ), properties ); mlt_events_unblock( mlt_factory_event_object( ), mlt_factory_event_object( ) ); return clone; } /** Create clones. * * \private \memberof mlt_producer_s * \param self a producer * \param clones the number of copies to make * \see mlt_producer_optimise */ static void mlt_producer_set_clones( mlt_producer self, int clones ) { mlt_producer parent = mlt_producer_cut_parent( self ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( parent ); int existing = mlt_properties_get_int( properties, "_clones" ); int i = 0; char key[ 25 ]; // If the number of existing clones is different, then create/remove as necessary if ( existing != clones ) { if ( existing < clones ) { for ( i = existing; i < clones; i ++ ) { mlt_producer clone = mlt_producer_clone( parent ); sprintf( key, "_clone.%d", i ); mlt_properties_set_data( properties, key, clone, 0, ( mlt_destructor )mlt_producer_close, NULL ); } } else { for ( i = clones; i < existing; i ++ ) { sprintf( key, "_clone.%d", i ); mlt_properties_set_data( properties, key, NULL, 0, NULL, NULL ); } } } // Ensure all properties on the parent are passed to the clones for ( i = 0; i < clones; i ++ ) { mlt_producer clone = NULL; sprintf( key, "_clone.%d", i ); clone = mlt_properties_get_data( properties, key, NULL ); if ( clone != NULL ) mlt_properties_pass( MLT_PRODUCER_PROPERTIES( clone ), properties, "" ); } // Update the number of clones on the properties mlt_properties_set_int( properties, "_clones", clones ); } /** \brief private to mlt_producer_s, used by mlt_producer_optimise() */ typedef struct { int multitrack; int track; int position; int length; int offset; } track_info; /** \brief private to mlt_producer_s, used by mlt_producer_optimise() */ typedef struct { mlt_producer cut; int start; int end; } clip_references; static int intersect( clip_references *a, clip_references *b ) { int diff = ( a->start - b->start ) + ( a->end - b->end ); return diff >= 0 && diff < ( a->end - a->start + 1 ); } static int push( mlt_parser self, int multitrack, int track, int position ) { mlt_properties properties = mlt_parser_properties( self ); mlt_deque stack = mlt_properties_get_data( properties, "stack", NULL ); track_info *info = malloc( sizeof( track_info ) ); info->multitrack = multitrack; info->track = track; info->position = position; info->length = 0; info->offset = 0; return mlt_deque_push_back( stack, info ); } static track_info *pop( mlt_parser self ) { mlt_properties properties = mlt_parser_properties( self ); mlt_deque stack = mlt_properties_get_data( properties, "stack", NULL ); return mlt_deque_pop_back( stack ); } static track_info *peek( mlt_parser self ) { mlt_properties properties = mlt_parser_properties( self ); mlt_deque stack = mlt_properties_get_data( properties, "stack", NULL ); return mlt_deque_peek_back( stack ); } static int on_start_multitrack( mlt_parser self, mlt_multitrack object ) { track_info *info = peek( self ); return push( self, info->multitrack ++, info->track, info->position ); } static int on_start_track( mlt_parser self ) { track_info *info = peek( self ); info->position -= info->offset; info->length -= info->offset; return push( self, info->multitrack, info->track ++, info->position ); } static int on_start_producer( mlt_parser self, mlt_producer object ) { mlt_properties properties = mlt_parser_properties( self ); mlt_properties producers = mlt_properties_get_data( properties, "producers", NULL ); mlt_producer parent = mlt_producer_cut_parent( object ); if ( mlt_service_identify( ( mlt_service )mlt_producer_cut_parent( object ) ) == producer_type && mlt_producer_is_cut( object ) ) { int ref_count = 0; clip_references *old_refs = NULL; clip_references *refs = NULL; char key[ 50 ]; int count = 0; track_info *info = peek( self ); sprintf( key, "%p", parent ); mlt_properties_get_data( producers, key, &count ); mlt_properties_set_data( producers, key, parent, ++ count, NULL, NULL ); old_refs = mlt_properties_get_data( properties, key, &ref_count ); refs = malloc( ( ref_count + 1 ) * sizeof( clip_references ) ); if ( old_refs != NULL ) memcpy( refs, old_refs, ref_count * sizeof( clip_references ) ); mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( object ), "_clone", -1 ); refs[ ref_count ].cut = object; refs[ ref_count ].start = info->position; refs[ ref_count ].end = info->position + mlt_producer_get_playtime( object ) - 1; mlt_properties_set_data( properties, key, refs, ++ ref_count, free, NULL ); info->position += mlt_producer_get_playtime( object ); info->length += mlt_producer_get_playtime( object ); } return 0; } static int on_end_track( mlt_parser self ) { track_info *track = pop( self ); track_info *multi = peek( self ); multi->length += track->length; multi->position += track->length; multi->offset = track->length; free( track ); return 0; } static int on_end_multitrack( mlt_parser self, mlt_multitrack object ) { track_info *multi = pop( self ); track_info *track = peek( self ); track->position += multi->length; track->length += multi->length; free( multi ); return 0; } /** Optimise for overlapping cuts from the same clip. * * \todo learn more about this * \public \memberof mlt_producer_s * \param self a producer * \return true if there was an error */ int mlt_producer_optimise( mlt_producer self ) { int error = 1; mlt_parser parser = mlt_parser_new( ); if ( parser != NULL ) { int i = 0, j = 0, k = 0; mlt_properties properties = mlt_parser_properties( parser ); mlt_properties producers = mlt_properties_new( ); mlt_deque stack = mlt_deque_init( ); mlt_properties_set_data( properties, "producers", producers, 0, ( mlt_destructor )mlt_properties_close, NULL ); mlt_properties_set_data( properties, "stack", stack, 0, ( mlt_destructor )mlt_deque_close, NULL ); parser->on_start_producer = on_start_producer; parser->on_start_track = on_start_track; parser->on_end_track = on_end_track; parser->on_start_multitrack = on_start_multitrack; parser->on_end_multitrack = on_end_multitrack; push( parser, 0, 0, 0 ); mlt_parser_start( parser, MLT_PRODUCER_SERVICE( self ) ); free( pop( parser ) ); for ( k = 0; k < mlt_properties_count( producers ); k ++ ) { char *name = mlt_properties_get_name( producers, k ); int count = 0; int clones = 0; int max_clones = 0; mlt_producer producer = mlt_properties_get_data_at( producers, k, &count ); if ( producer != NULL && count > 1 ) { clip_references *refs = mlt_properties_get_data( properties, name, &count ); for ( i = 0; i < count; i ++ ) { clones = 0; for ( j = i + 1; j < count; j ++ ) { if ( intersect( &refs[ i ], &refs[ j ] ) ) { clones ++; mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( refs[ j ].cut ), "_clone", clones ); } } if ( clones > max_clones ) max_clones = clones; } for ( i = 0; i < count; i ++ ) { mlt_producer cut = refs[ i ].cut; if ( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( cut ), "_clone" ) == -1 ) mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( cut ), "_clone", 0 ); } mlt_producer_set_clones( producer, max_clones ); } else if ( producer != NULL ) { clip_references *refs = mlt_properties_get_data( properties, name, &count ); for ( i = 0; i < count; i ++ ) { mlt_producer cut = refs[ i ].cut; mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( cut ), "_clone", 0 ); } mlt_producer_set_clones( producer, 0 ); } } mlt_parser_close( parser ); } return error; } /** Close the producer. * * Destroys the producer and deallocates its resources managed by its * properties list. This will call the close virtual function. Therefore, a * subclass that defines its own close function should set its virtual close * function to NULL prior to calling this to avoid circular calls. * * \public \memberof mlt_producer_s * \param self a producer */ void mlt_producer_close( mlt_producer self ) { if ( self != NULL && mlt_properties_dec_ref( MLT_PRODUCER_PROPERTIES( self ) ) <= 0 ) { self->parent.close = NULL; if ( self->close != NULL ) { self->close( self->close_object ); } else { int destroy = mlt_producer_is_cut( self ); #if _MLT_PRODUCER_CHECKS_ == 1 // Show debug info mlt_properties_debug( MLT_PRODUCER_PROPERTIES( self ), "Producer closing", stderr ); #endif #ifdef _MLT_PRODUCER_CHECKS_ // Show current stats - these should match when the app is closed mlt_log( MLT_PRODUCER_SERVICE( self ), MLT_LOG_DEBUG, "Producers created %d, destroyed %d\n", producers_created, ++producers_destroyed ); #endif mlt_service_close( &self->parent ); if ( destroy ) free( self ); } } } mlt-0.9.0/src/framework/mlt_producer.h000066400000000000000000000134601215300731300177470ustar00rootroot00000000000000/** * \file mlt_producer.h * \brief abstraction for all producer services * \see mlt_producer_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_PRODUCER_H_ #define _MLT_PRODUCER_H_ #include "mlt_service.h" #include "mlt_filter.h" #include "mlt_profile.h" /** \brief Producer abstract service class * * A producer is a service that generates audio, video, and metadata. * Some day it may also generate text (subtitles). This is not to say * a producer "synthesizes," rather that is an origin of data within the * service network - that could be through synthesis or reading a stream. * * \extends mlt_service * \event \em producer-changed either service-changed was fired or the timing of the producer changed * \properties \em mlt_type the name of the service subclass, e.g. mlt_producer * \properties \em mlt_service the name of a producer subclass * \properties \em _position the current position of the play head, relative to the in point * \properties \em _frame the current position of the play head, relative to the beginning of the resource * \properties \em _speed the current speed factor, where 1.0 is normal * \properties \em aspect_ratio sample aspect ratio * \properties \em length the duration of the cut in frames * \properties \em eof the end-of-file behavior, one of: pause, continue, loop * \properties \em resource the file name, stream address, or the class name in angle brackets * \properties \em _cut set if this producer is a "cut" producer * \properties \em mlt_mix stores the data for a "mix" producer * \properties \em _cut_parent holds a reference to the cut's parent producer * \properties \em ignore_points Set this to temporarily disable the in and out points. * \properties \em use_clone holds a reference to a clone's producer, as created by mlt_producer_optimise * \properties \em _clone is the index of the clone in the list of clones stored on the clone's producer * \properties \em _clones is the number of clones of the producer, as created by mlt_producer_optimise * \properties \em _clone.{N} holds a reference to the N'th clone of the producer, as created by mlt_producer_optimise * \properties \em meta.* holds metadata - there is a loose taxonomy to be defined * \properties \em set.* holds properties to set on a frame produced * \todo define the media metadata taxonomy */ struct mlt_producer_s { /** A producer is a service. */ struct mlt_service_s parent; /** Get a frame of data (virtual function). * * \param mlt_producer a producer * \param mlt_frame_ptr a frame pointer by reference * \param int an index * \return true if there was an error */ int ( *get_frame )( mlt_producer, mlt_frame_ptr, int ); /** the destructor virtual function */ mlt_destructor close; void *close_object; /**< the object supplied to the close virtual function */ void *local; /**< \private instance object */ void *child; /**< \private the object of a subclass */ }; /* * Public final methods */ #define MLT_PRODUCER_SERVICE( producer ) ( &( producer )->parent ) #define MLT_PRODUCER_PROPERTIES( producer ) MLT_SERVICE_PROPERTIES( MLT_PRODUCER_SERVICE( producer ) ) extern int mlt_producer_init( mlt_producer self, void *child ); extern mlt_producer mlt_producer_new( mlt_profile ); extern mlt_service mlt_producer_service( mlt_producer self ); extern mlt_properties mlt_producer_properties( mlt_producer self ); extern int mlt_producer_seek( mlt_producer self, mlt_position position ); extern int mlt_producer_seek_time( mlt_producer self, const char* time ); extern mlt_position mlt_producer_position( mlt_producer self ); extern mlt_position mlt_producer_frame( mlt_producer self ); char* mlt_producer_frame_time( mlt_producer self, mlt_time_format ); extern int mlt_producer_set_speed( mlt_producer self, double speed ); extern double mlt_producer_get_speed( mlt_producer self ); extern double mlt_producer_get_fps( mlt_producer self ); extern int mlt_producer_set_in_and_out( mlt_producer self, mlt_position in, mlt_position out ); extern int mlt_producer_clear( mlt_producer self ); extern mlt_position mlt_producer_get_in( mlt_producer self ); extern mlt_position mlt_producer_get_out( mlt_producer self ); extern mlt_position mlt_producer_get_playtime( mlt_producer self ); extern mlt_position mlt_producer_get_length( mlt_producer self ); extern char* mlt_producer_get_length_time( mlt_producer self, mlt_time_format ); extern void mlt_producer_prepare_next( mlt_producer self ); extern int mlt_producer_attach( mlt_producer self, mlt_filter filter ); extern int mlt_producer_detach( mlt_producer self, mlt_filter filter ); extern mlt_filter mlt_producer_filter( mlt_producer self, int index ); extern mlt_producer mlt_producer_cut( mlt_producer self, int in, int out ); extern int mlt_producer_is_cut( mlt_producer self ); extern int mlt_producer_is_mix( mlt_producer self ); extern int mlt_producer_is_blank( mlt_producer self ); extern mlt_producer mlt_producer_cut_parent( mlt_producer self ); extern int mlt_producer_optimise( mlt_producer self ); extern void mlt_producer_close( mlt_producer self ); #endif mlt-0.9.0/src/framework/mlt_profile.c000066400000000000000000000322661215300731300175640ustar00rootroot00000000000000/** * \file mlt_profile.c * \brief video output definition * \see mlt_profile_s * * Copyright (C) 2007-2009 Ushodaya Enterprises Limited * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt.h" #include #include #include #include /** the default subdirectory of the datadir for holding profiles */ #define PROFILES_DIR "/profiles/" /** Load a profile from the system folder. * * The environment variable MLT_PROFILES_PATH overrides the default \p PROFILES_DIR. * * \private \memberof mlt_profile_s * \param name the name of a profile settings file located in the standard location or * the full path name to a profile settings file * \return a profile or NULL on error */ static mlt_profile mlt_profile_select( const char *name ) { char *filename = NULL; const char *prefix = getenv( "MLT_PROFILES_PATH" ); mlt_properties properties = mlt_properties_load( name ); mlt_profile profile = NULL; // Try to load from file specification if ( properties && mlt_properties_get_int( properties, "width" ) ) { filename = calloc( 1, strlen( name ) + 1 ); } // Load from $datadir/mlt/profiles else if ( prefix == NULL ) { prefix = mlt_environment( "MLT_DATA" ); filename = calloc( 1, strlen( prefix ) + strlen( PROFILES_DIR ) + strlen( name ) + 1 ); strcpy( filename, prefix ); strcat( filename, PROFILES_DIR ); } // Use environment variable instead else { filename = calloc( 1, strlen( prefix ) + strlen( name ) + 2 ); strcpy( filename, prefix ); if ( filename[ strlen( filename ) - 1 ] != '/' ) filename[ strlen( filename ) ] = '/'; } // Finish loading strcat( filename, name ); profile = mlt_profile_load_file( filename ); // Cleanup mlt_properties_close( properties ); free( filename ); return profile; } /** Construct a profile. * * This will never return NULL as it uses the dv_pal settings as hard-coded fallback default. * * \public \memberof mlt_profile_s * \param name the name of a profile settings file located in the standard location or * the full path name to a profile settings file * \return a profile */ mlt_profile mlt_profile_init( const char *name ) { mlt_profile profile = NULL; // Explicit profile by name gets priority over environment variables if ( name ) profile = mlt_profile_select( name ); // Try to load by environment variable if ( profile == NULL ) { // MLT_PROFILE is preferred environment variable if ( getenv( "MLT_PROFILE" ) ) profile = mlt_profile_select( getenv( "MLT_PROFILE" ) ); // MLT_NORMALISATION backwards compatibility else if ( getenv( "MLT_NORMALISATION" ) && strcmp( getenv( "MLT_NORMALISATION" ), "PAL" ) ) profile = mlt_profile_select( "dv_ntsc" ); else profile = mlt_profile_select( "dv_pal" ); // If still not loaded (no profile files), default to PAL if ( profile == NULL ) { profile = calloc( 1, sizeof( struct mlt_profile_s ) ); if ( profile ) { mlt_environment_set( "MLT_PROFILE", "dv_pal" ); profile->description = strdup( "PAL 4:3 DV or DVD" ); profile->frame_rate_num = 25; profile->frame_rate_den = 1; profile->width = 720; profile->height = 576; profile->progressive = 0; profile->sample_aspect_num = 16; profile->sample_aspect_den = 15; profile->display_aspect_num = 4; profile->display_aspect_den = 3; profile->colorspace = 601; } } } return profile; } static void set_mlt_normalisation( const char *profile_name ) { if ( profile_name ) { if ( strstr( profile_name, "_ntsc" ) || strstr( profile_name, "_60" ) || strstr( profile_name, "_5994" ) || strstr( profile_name, "_2997" ) || strstr( profile_name, "_30" ) ) { mlt_environment_set( "MLT_NORMALISATION", "NTSC" ); } else if ( strstr( profile_name, "_pal" ) || strstr( profile_name, "_50" ) || strstr( profile_name, "_25" ) ) { mlt_environment_set( "MLT_NORMALISATION", "PAL" ); } } } /** Load a profile from specific file. * * \public \memberof mlt_profile_s * \param file the full path name to a properties file * \return a profile or NULL on error */ mlt_profile mlt_profile_load_file( const char *file ) { mlt_profile profile = NULL; // Load the profile as properties mlt_properties properties = mlt_properties_load( file ); if ( properties ) { // Simple check if the profile is valid if ( mlt_properties_get_int( properties, "width" ) ) { profile = mlt_profile_load_properties( properties ); // Set MLT_PROFILE to basename char *filename = strdup( file ); mlt_environment_set( "MLT_PROFILE", basename( filename ) ); set_mlt_normalisation( basename( filename ) ); free( filename ); } mlt_properties_close( properties ); } // Set MLT_NORMALISATION to appease legacy modules char *profile_name = mlt_environment( "MLT_PROFILE" ); set_mlt_normalisation( profile_name ); return profile; } /** Load a profile from a properties object. * * \public \memberof mlt_profile_s * \param properties a properties list * \return a profile or NULL if out of memory */ mlt_profile mlt_profile_load_properties( mlt_properties properties ) { mlt_profile profile = calloc( 1, sizeof( struct mlt_profile_s ) ); if ( profile ) { if ( mlt_properties_get( properties, "name" ) ) mlt_environment_set( "MLT_PROFILE", mlt_properties_get( properties, "name" ) ); if ( mlt_properties_get( properties, "description" ) ) profile->description = strdup( mlt_properties_get( properties, "description" ) ); profile->frame_rate_num = mlt_properties_get_int( properties, "frame_rate_num" ); profile->frame_rate_den = mlt_properties_get_int( properties, "frame_rate_den" ); profile->width = mlt_properties_get_int( properties, "width" ); profile->height = mlt_properties_get_int( properties, "height" ); profile->progressive = mlt_properties_get_int( properties, "progressive" ); profile->sample_aspect_num = mlt_properties_get_int( properties, "sample_aspect_num" ); profile->sample_aspect_den = mlt_properties_get_int( properties, "sample_aspect_den" ); profile->display_aspect_num = mlt_properties_get_int( properties, "display_aspect_num" ); profile->display_aspect_den = mlt_properties_get_int( properties, "display_aspect_den" ); profile->colorspace = mlt_properties_get_int( properties, "colorspace" ); } return profile; } /** Load an anonymous profile from string. * * \public \memberof mlt_profile_s * \param string a newline-delimited list of properties as name=value pairs * \return a profile or NULL if out of memory */ mlt_profile mlt_profile_load_string( const char *string ) { mlt_properties properties = mlt_properties_new(); mlt_profile profile = NULL; if ( properties ) { const char *p = string; while ( p ) { if ( strcmp( p, "" ) && p[ 0 ] != '#' ) mlt_properties_parse( properties, p ); p = strchr( p, '\n' ); if ( p ) p++; } profile = mlt_profile_load_properties( properties ); mlt_properties_close( properties ); } return profile; } /** Get the video frame rate as a floating point value. * * \public \memberof mlt_profile_s * @param profile a profile * @return the frame rate */ double mlt_profile_fps( mlt_profile profile ) { if ( profile ) return ( double ) profile->frame_rate_num / profile->frame_rate_den; else return 0; } /** Get the sample aspect ratio as a floating point value. * * \public \memberof mlt_profile_s * \param profile a profile * \return the pixel aspect ratio */ double mlt_profile_sar( mlt_profile profile ) { if ( profile ) return ( double ) profile->sample_aspect_num / profile->sample_aspect_den; else return 0; } /** Get the display aspect ratio as floating point value. * * \public \memberof mlt_profile_s * \param profile a profile * \return the image aspect ratio */ double mlt_profile_dar( mlt_profile profile ) { if ( profile ) return ( double ) profile->display_aspect_num / profile->display_aspect_den; else return 0; } /** Free up the global profile resources. * * \public \memberof mlt_profile_s * \param profile a profile */ void mlt_profile_close( mlt_profile profile ) { if ( profile ) { if ( profile->description ) free( profile->description ); profile->description = NULL; free( profile ); profile = NULL; } } /** Make a copy of a profile. * * \public \memberof mlt_profile_s * \param profile the profile to clone * \return a copy of the profile */ mlt_profile mlt_profile_clone( mlt_profile profile ) { mlt_profile clone = NULL; if ( profile ) { clone = calloc( 1, sizeof( *profile ) ); if ( clone ) { memcpy( clone, profile, sizeof( *profile ) ); clone->description = strdup( profile->description ); } } return clone; } /** Get the list of profiles. * * The caller MUST close the returned properties object! * Each entry in the list is keyed on its name, and its value is another * properties object that contains the attributes of the profile. * \public \memberof mlt_profile_s * \return a list of profiles */ mlt_properties mlt_profile_list( ) { char *filename = NULL; const char *prefix = getenv( "MLT_PROFILES_PATH" ); mlt_properties properties = mlt_properties_new(); mlt_properties dir = mlt_properties_new(); int sort = 1; const char *wildcard = NULL; int i; // Load from $datadir/mlt/profiles if no env var if ( prefix == NULL ) { prefix = mlt_environment( "MLT_DATA" ); filename = calloc( 1, strlen( prefix ) + strlen( PROFILES_DIR ) + 1 ); strcpy( filename, prefix ); strcat( filename, PROFILES_DIR ); prefix = filename; } mlt_properties_dir_list( dir, prefix, wildcard, sort ); for ( i = 0; i < mlt_properties_count( dir ); i++ ) { char *filename = mlt_properties_get_value( dir, i ); char *profile_name = basename( filename ); if ( profile_name[0] != '.' && strcmp( profile_name, "Makefile" ) && profile_name[ strlen( profile_name ) - 1 ] != '~' ) { mlt_properties profile = mlt_properties_load( filename ); if ( profile ) { mlt_properties_set_data( properties, profile_name, profile, 0, (mlt_destructor) mlt_properties_close, NULL ); } } } mlt_properties_close( dir ); if ( filename ) free( filename ); return properties; } /** Update the profile using the attributes of a producer. * * Use this to make an "auto-profile." Typically, you need to re-open the producer * after you use this because some producers (e.g. avformat) adjust their framerate * to that of the profile used when you created it. * \public \memberof mlt_profile_s * \param profile the profile to update * \param producer the producer to inspect */ void mlt_profile_from_producer( mlt_profile profile, mlt_producer producer ) { mlt_frame fr = NULL; uint8_t *buffer = NULL; mlt_image_format fmt = mlt_image_none; mlt_properties p; int w = profile->width; int h = profile->height; if ( ! mlt_service_get_frame( MLT_PRODUCER_SERVICE(producer), &fr, 0 ) && fr ) { if ( ! mlt_frame_get_image( fr, &buffer, &fmt, &w, &h, 0 ) ) { // Some source properties are not exposed until after the first get_image call. mlt_frame_close( fr ); mlt_service_get_frame( MLT_PRODUCER_SERVICE(producer), &fr, 0 ); p = MLT_FRAME_PROPERTIES( fr ); // mlt_properties_dump(p, stderr); if ( mlt_properties_get_int( p, "meta.media.frame_rate_den" ) && mlt_properties_get_int( p, "meta.media.sample_aspect_den" ) ) { profile->width = mlt_properties_get_int( p, "meta.media.width" ); profile->height = mlt_properties_get_int( p, "meta.media.height" ); profile->progressive = mlt_properties_get_int( p, "meta.media.progressive" ); profile->frame_rate_num = mlt_properties_get_int( p, "meta.media.frame_rate_num" ); profile->frame_rate_den = mlt_properties_get_int( p, "meta.media.frame_rate_den" ); // AVCHD is mis-reported as double frame rate. if ( profile->progressive == 0 && ( profile->frame_rate_num / profile->frame_rate_den == 50 || profile->frame_rate_num / profile->frame_rate_den == 59 ) ) profile->frame_rate_num /= 2; profile->sample_aspect_num = mlt_properties_get_int( p, "meta.media.sample_aspect_num" ); profile->sample_aspect_den = mlt_properties_get_int( p, "meta.media.sample_aspect_den" ); profile->colorspace = mlt_properties_get_int( p, "meta.media.colorspace" ); profile->display_aspect_num = lrint( (double) profile->sample_aspect_num * profile->width / profile->sample_aspect_den ); profile->display_aspect_den = profile->height; free( profile->description ); profile->description = strdup( "automatic" ); profile->is_explicit = 0; } } } mlt_frame_close( fr ); mlt_producer_seek( producer, 0 ); } mlt-0.9.0/src/framework/mlt_profile.h000066400000000000000000000054621215300731300175670ustar00rootroot00000000000000/** * \file mlt_profile.h * \brief video output definition * \see mlt_profile_s * * Copyright (C) 2007-2009 Ushodaya Enterprises Limited * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_PROFILE_H #define _MLT_PROFILE_H #include "mlt_types.h" /** \brief Profile class * */ struct mlt_profile_s { char* description; /**< a brief description suitable as a label in UI menu */ int frame_rate_num; /**< the numerator of the video frame rate */ int frame_rate_den; /**< the denominator of the video frame rate */ int width; /**< the horizontal resolution of the video */ int height; /**< the vertical resolution of the video */ int progressive; /**< a flag to indicate if the video is progressive scan, interlace if not set */ int sample_aspect_num; /**< the numerator of the pixel aspect ratio */ int sample_aspect_den; /**< the denominator of the pixel aspect ratio */ int display_aspect_num; /**< the numerator of the image aspect ratio in case it can not be simply derived (e.g. ITU-R 601) */ int display_aspect_den; /**< the denominator of the image aspect ratio in case it can not be simply derived (e.g. ITU-R 601) */ int colorspace; /**< the Y'CbCr colorspace standard: =601 for ITU-R 601, =709 for ITU-R 709, or =240 for SMPTE240M */ int is_explicit; /**< used internally to indicate if the profile was requested explicitly or computed or defaulted */ }; extern mlt_profile mlt_profile_init( const char *name ); extern mlt_profile mlt_profile_load_file( const char *file ); extern mlt_profile mlt_profile_load_properties( mlt_properties properties ); extern mlt_profile mlt_profile_load_string( const char *string ); extern double mlt_profile_fps( mlt_profile profile ); extern double mlt_profile_sar( mlt_profile profile ); extern double mlt_profile_dar( mlt_profile profile ); extern void mlt_profile_close( mlt_profile profile ); extern mlt_profile mlt_profile_clone( mlt_profile profile ); extern mlt_properties mlt_profile_list( ); extern void mlt_profile_from_producer( mlt_profile profile, mlt_producer producer ); #endif mlt-0.9.0/src/framework/mlt_properties.c000066400000000000000000002016511215300731300203140ustar00rootroot00000000000000/** * \file mlt_properties.c * \brief Properties class definition * \see mlt_properties_s * * Copyright (C) 2003-2013 Ushodaya Enterprises Limited * \author Charles Yates * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // For strtod_l #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include "mlt_properties.h" #include "mlt_property.h" #include "mlt_deque.h" #include "mlt_log.h" #include "mlt_factory.h" #include #include #include #include #include #include #include #include #include #include #include #include #define PRESETS_DIR "/presets" /** \brief private implementation of the property list */ typedef struct { int hash[ 199 ]; char **name; mlt_property *value; int count; int size; mlt_properties mirror; int ref_count; pthread_mutex_t mutex; locale_t locale; } property_list; /* Memory leak checks */ //#define _MLT_PROPERTY_CHECKS_ 2 #ifdef _MLT_PROPERTY_CHECKS_ static int properties_created = 0; static int properties_destroyed = 0; #endif /** Initialize a properties object that was already allocated. * * This does allocate its ::property_list, and it adds a reference count. * \public \memberof mlt_properties_s * \param self the properties structure to initialize * \param child an opaque pointer to a subclass object * \return true if failed */ int mlt_properties_init( mlt_properties self, void *child ) { if ( self != NULL ) { #ifdef _MLT_PROPERTY_CHECKS_ // Increment number of properties created properties_created ++; #endif // NULL all methods memset( self, 0, sizeof( struct mlt_properties_s ) ); // Assign the child of the object self->child = child; // Allocate the local structure self->local = calloc( 1, sizeof( property_list ) ); // Increment the ref count ( ( property_list * )self->local )->ref_count = 1; pthread_mutex_init( &( ( property_list * )self->local )->mutex, NULL );; } // Check that initialisation was successful return self != NULL && self->local == NULL; } /** Create a properties object. * * This allocates the properties structure and calls mlt_properties_init() on it. * Free the properties object with mlt_properties_close(). * \public \memberof mlt_properties_s * \return a new properties object */ mlt_properties mlt_properties_new( ) { // Construct a standalone properties object mlt_properties self = calloc( 1, sizeof( struct mlt_properties_s ) ); // Initialise self mlt_properties_init( self, NULL ); // Return the pointer return self; } /** Set the numeric locale used for string/double conversions. * * \public \memberof mlt_properties_s * \param self a properties list * \param locale the locale name * \return true if error */ int mlt_properties_set_lcnumeric( mlt_properties self, const char *locale ) { int error = 0; if ( self && locale ) { property_list *list = self->local; #if defined(__linux__) || defined(__DARWIN__) if ( list->locale ) freelocale( list->locale ); list->locale = newlocale( LC_NUMERIC_MASK, locale, NULL ); #endif error = list->locale == NULL; } else error = 1; return error; } /** Get the numeric locale for this properties object. * * Do not free the result. * \public \memberof mlt_properties_s * \param self a properties list * \return the locale name if this properties has a specific locale it is using, NULL otherwise */ const char* mlt_properties_get_lcnumeric( mlt_properties self ) { property_list *list = self->local; const char *result = NULL; if ( list->locale ) { #if defined(__DARWIN__) result = querylocale( LC_NUMERIC, list->locale ); #elif defined(__linux__) result = list->locale->__names[ LC_NUMERIC ]; #else // TODO: not yet sure what to do on other platforms #endif } return result; } static int load_properties( mlt_properties self, const char *filename ) { // Open the file FILE *file = fopen( filename, "r" ); // Load contents of file if ( file != NULL ) { // Temp string char temp[ 1024 ]; char last[ 1024 ] = ""; // Read each string from the file while( fgets( temp, 1024, file ) ) { // Chomp the new line character from the string int x = strlen( temp ) - 1; if ( temp[x] == '\n' || temp[x] == '\r' ) temp[x] = '\0'; // Check if the line starts with a . if ( temp[ 0 ] == '.' ) { char temp2[ 1024 ]; sprintf( temp2, "%s%s", last, temp ); strcpy( temp, temp2 ); } else if ( strchr( temp, '=' ) ) { strcpy( last, temp ); *( strchr( last, '=' ) ) = '\0'; } // Parse and set the property if ( strcmp( temp, "" ) && temp[ 0 ] != '#' ) mlt_properties_parse( self, temp ); } // Close the file fclose( file ); } return file? 0 : errno; } /** Create a properties object by reading a .properties text file. * * Free the properties object with mlt_properties_close(). * \deprecated Please start using mlt_properties_parse_yaml(). * \public \memberof mlt_properties_s * \param filename the absolute file name * \return a new properties object */ mlt_properties mlt_properties_load( const char *filename ) { // Construct a standalone properties object mlt_properties self = mlt_properties_new( ); if ( self != NULL ) load_properties( self, filename ); // Return the pointer return self; } /** Set properties from a preset. * * Presets are typically installed to $prefix/share/mlt/presets/{type}/{service}/[{profile}/]{name}. * For example, "/usr/share/mlt/presets/consumer/avformat/dv_ntsc_wide/DVD" * could be an encoding preset for a widescreen NTSC DVD Video. * Do not specify the type and service in the preset name parameter; these are * inferred automatically from the service to which you are applying the preset. * Using the example above and assuming you are calling this function on the * avformat consumer, the name passed to the function should simply be DVD. * Note that the profile portion of the path is optional, but a profile-specific * preset with the same name as a more generic one is given a higher priority. * \todo Look in a user-specific location - somewhere in the home directory. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the name of a preset in a well-known location or the explicit path * \return true if error */ int mlt_properties_preset( mlt_properties self, const char *name ) { struct stat stat_buff; // validate input if ( !( self && name && strlen( name ) ) ) return 1; // See if name is an explicit file if ( ! stat( name, &stat_buff ) ) { return load_properties( self, name ); } else { // Look for profile-specific preset before a generic one. char *data = getenv( "MLT_PRESETS_PATH" ); const char *type = mlt_properties_get( self, "mlt_type" ); const char *service = mlt_properties_get( self, "mlt_service" ); const char *profile = mlt_environment( "MLT_PROFILE" ); int error = 0; if ( data ) { data = strdup( data ); } else { data = malloc( strlen( mlt_environment( "MLT_DATA" ) ) + strlen( PRESETS_DIR ) + 1 ); strcpy( data, mlt_environment( "MLT_DATA" ) ); strcat( data, PRESETS_DIR ); } if ( data && type && service ) { char *path = malloc( 5 + strlen(name) + strlen(data) + strlen(type) + strlen(service) + ( profile? strlen(profile) : 0 ) ); sprintf( path, "%s/%s/%s/%s/%s", data, type, service, profile, name ); if ( load_properties( self, path ) ) { sprintf( path, "%s/%s/%s/%s", data, type, service, name ); error = load_properties( self, path ); } free( path ); } else { error = 1; } free( data ); return error; } } /** Generate a hash key. * * \private \memberof mlt_properties_s * \param name a string * \return an integer */ static inline int generate_hash( const char *name ) { int hash = 0; int i = 1; while ( *name ) hash = ( hash + ( i ++ * ( *name ++ & 31 ) ) ) % 199; return hash; } /** Copy a serializable property to a properties list that is mirroring this one. * * Special case - when a container (such as loader) is protecting another * producer, we need to ensure that properties are passed through to the * real producer. * \private \memberof mlt_properties_s * \param self a properties list * \param name the name of the property to copy */ static inline void mlt_properties_do_mirror( mlt_properties self, const char *name ) { if ( !self ) return; property_list *list = self->local; if ( list->mirror != NULL ) { char *value = mlt_properties_get( self, name ); if ( value != NULL ) mlt_properties_set( list->mirror, name, value ); } } /** Increment the reference count. * * \public \memberof mlt_properties_s * \param self a properties list * \return the new reference count */ int mlt_properties_inc_ref( mlt_properties self ) { int result = 0; if ( self != NULL ) { property_list *list = self->local; pthread_mutex_lock( &list->mutex ); result = ++ list->ref_count; pthread_mutex_unlock( &list->mutex ); } return result; } /** Decrement the reference count. * * \public \memberof mlt_properties_s * \param self a properties list * \return the new reference count */ int mlt_properties_dec_ref( mlt_properties self ) { int result = 0; if ( self != NULL ) { property_list *list = self->local; pthread_mutex_lock( &list->mutex ); result = -- list->ref_count; pthread_mutex_unlock( &list->mutex ); } return result; } /** Get the reference count. * * \public \memberof mlt_properties_s * \param self a properties list * \return the current reference count */ int mlt_properties_ref_count( mlt_properties self ) { if ( self != NULL ) { property_list *list = self->local; return list->ref_count; } return 0; } /** Set a properties list to be a mirror copy of another. * * Note that this does not copy all existing properties. Rather, you must * call this before setting the properties that you wish to copy. * \public \memberof mlt_properties_s * \param that the properties which will receive copies of the properties as they are set. * \param self the properties to mirror */ void mlt_properties_mirror( mlt_properties self, mlt_properties that ) { if ( !self ) return; property_list *list = self->local; list->mirror = that; } /** Copy all serializable properties to another properties list. * * \public \memberof mlt_properties_s * \param self The properties to copy to * \param that The properties to copy from * \return true if error */ int mlt_properties_inherit( mlt_properties self, mlt_properties that ) { if ( !self || !that ) return 1; int count = mlt_properties_count( that ); int i = 0; for ( i = 0; i < count; i ++ ) { char *value = mlt_properties_get_value( that, i ); if ( value != NULL ) { char *name = mlt_properties_get_name( that, i ); mlt_properties_set( self, name, value ); } } return 0; } /** Pass all serializable properties that match a prefix to another properties object * * \warning The prefix is stripped from the name when it is set on the \p self properties list! * For example a property named "foo.bar" will match prefix "foo.", but the property * will be named simply "bar" on the receiving properties object. * \public \memberof mlt_properties_s * \param self the properties to copy to * \param that The properties to copy from * \param prefix the property names to match (required) * \return true if error */ int mlt_properties_pass( mlt_properties self, mlt_properties that, const char *prefix ) { if ( !self || !that ) return 1; int count = mlt_properties_count( that ); int length = strlen( prefix ); int i = 0; for ( i = 0; i < count; i ++ ) { char *name = mlt_properties_get_name( that, i ); if ( !strncmp( name, prefix, length ) ) { char *value = mlt_properties_get_value( that, i ); if ( value != NULL ) mlt_properties_set( self, name + length, value ); } } return 0; } /** Locate a property by name. * * \private \memberof mlt_properties_s * \param self a properties list * \param name the property to lookup by name * \return the property or NULL for failure */ static inline mlt_property mlt_properties_find( mlt_properties self, const char *name ) { if ( !self || !name ) return NULL; property_list *list = self->local; mlt_property value = NULL; int key = generate_hash( name ); mlt_properties_lock( self ); int i = list->hash[ key ] - 1; if ( i >= 0 ) { // Check if we're hashed if ( list->count > 0 && name[ 0 ] == list->name[ i ][ 0 ] && !strcmp( list->name[ i ], name ) ) value = list->value[ i ]; // Locate the item for ( i = list->count - 1; value == NULL && i >= 0; i -- ) if ( name[ 0 ] == list->name[ i ][ 0 ] && !strcmp( list->name[ i ], name ) ) value = list->value[ i ]; } mlt_properties_unlock( self ); return value; } /** Add a new property. * * \private \memberof mlt_properties_s * \param self a properties list * \param name the name of the new property * \return the new property */ static mlt_property mlt_properties_add( mlt_properties self, const char *name ) { property_list *list = self->local; int key = generate_hash( name ); mlt_property result; mlt_properties_lock( self ); // Check that we have space and resize if necessary if ( list->count == list->size ) { list->size += 50; list->name = realloc( list->name, list->size * sizeof( const char * ) ); list->value = realloc( list->value, list->size * sizeof( mlt_property ) ); } // Assign name/value pair list->name[ list->count ] = strdup( name ); list->value[ list->count ] = mlt_property_init( ); // Assign to hash table if ( list->hash[ key ] == 0 ) list->hash[ key ] = list->count + 1; // Return and increment count accordingly result = list->value[ list->count ++ ]; mlt_properties_unlock( self ); return result; } /** Fetch a property by name and add one if not found. * * \private \memberof mlt_properties_s * \param self a properties list * \param name the property to lookup or add * \return the property */ static mlt_property mlt_properties_fetch( mlt_properties self, const char *name ) { // Try to find an existing property first mlt_property property = mlt_properties_find( self, name ); // If it wasn't found, create one if ( property == NULL ) property = mlt_properties_add( self, name ); // Return the property return property; } /** Copy a property to another properties list. * * \public \memberof mlt_properties_s * \author Zach * \param self the properties to copy to * \param that the properties to copy from * \param name the name of the property to copy */ void mlt_properties_pass_property( mlt_properties self, mlt_properties that, const char *name ) { // Make sure the source property isn't null. mlt_property that_prop = mlt_properties_find( that, name ); if( that_prop == NULL ) return; mlt_property_pass( mlt_properties_fetch( self, name ), that_prop ); } /** Copy all properties specified in a comma-separated list to another properties list. * * White space is also a delimiter. * \public \memberof mlt_properties_s * \author Zach * \param self the properties to copy to * \param that the properties to copy from * \param list a delimited list of property names * \return true if error */ int mlt_properties_pass_list( mlt_properties self, mlt_properties that, const char *list ) { if ( !self || !that || !list ) return 1; char *props = strdup( list ); char *ptr = props; const char *delim = " ,\t\n"; // Any combination of spaces, commas, tabs, and newlines int count, done = 0; while( !done ) { count = strcspn( ptr, delim ); if( ptr[count] == '\0' ) done = 1; else ptr[count] = '\0'; // Make it a real string mlt_properties_pass_property( self, that, ptr ); ptr += count + 1; if ( !done ) ptr += strspn( ptr, delim ); } free( props ); return 0; } /** Set a property to a string. * * The property name "properties" is reserved to load the preset in \p value. * When the value begins with '@' then it is interpreted as a very simple math * expression containing only the +, -, *, and / operators. * The event "property-changed" is fired after the property has been set. * * This makes a copy of the string value you supply. * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to set * \param value the property's new value * \return true if error */ int mlt_properties_set( mlt_properties self, const char *name, const char *value ) { int error = 1; if ( !self || !name ) return error; // Fetch the property to work with mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property == NULL ) { mlt_log( NULL, MLT_LOG_FATAL, "Whoops - %s not found (should never occur)\n", name ); } else if ( value == NULL ) { error = mlt_property_set_string( property, value ); mlt_properties_do_mirror( self, name ); } else if ( *value != '@' ) { error = mlt_property_set_string( property, value ); mlt_properties_do_mirror( self, name ); if ( !strcmp( name, "properties" ) ) mlt_properties_preset( self, value ); } else if ( value[ 0 ] == '@' ) { double total = 0; double current = 0; char id[ 255 ]; char op = '+'; value ++; while ( *value != '\0' ) { int length = strcspn( value, "+-*/" ); // Get the identifier strncpy( id, value, length ); id[ length ] = '\0'; value += length; // Determine the value if ( isdigit( id[ 0 ] ) ) { #if defined(__GLIBC__) || defined(__DARWIN__) property_list *list = self->local; if ( list->locale ) current = strtod_l( id, NULL, list->locale ); else #endif current = strtod( id, NULL ); } else { current = mlt_properties_get_double( self, id ); } // Apply the operation switch( op ) { case '+': total += current; break; case '-': total -= current; break; case '*': total *= current; break; case '/': total = total / current; break; } // Get the next op op = *value != '\0' ? *value ++ : ' '; } error = mlt_property_set_double( property, total ); mlt_properties_do_mirror( self, name ); } mlt_events_fire( self, "property-changed", name, NULL ); return error; } /** Set or default a property to a string. * * This makes a copy of the string value you supply. * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to set * \param value the string value to set or NULL to use the default * \param def the default string if value is NULL * \return true if error */ int mlt_properties_set_or_default( mlt_properties self, const char *name, const char *value, const char *def ) { return mlt_properties_set( self, name, value == NULL ? def : value ); } /** Get a string value by name. * * Do not free the returned string. It's lifetime is controlled by the property * and this properties object. * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to get * \return the property's string value or NULL if it does not exist */ char *mlt_properties_get( mlt_properties self, const char *name ) { char *result = NULL; mlt_property value = mlt_properties_find( self, name ); if ( value ) { property_list *list = self->local; result = mlt_property_get_string_l( value, list->locale ); } return result; } /** Get a property name by index. * * Do not free the returned string. * \public \memberof mlt_properties_s * \param self a properties list * \param index the numeric index of the property * \return the name of the property or NULL if index is out of range */ char *mlt_properties_get_name( mlt_properties self, int index ) { if ( !self ) return NULL; property_list *list = self->local; if ( index >= 0 && index < list->count ) return list->name[ index ]; return NULL; } /** Get a property's string value by index. * * Do not free the returned string. * \public \memberof mlt_properties_s * \param self a properties list * \param index the numeric index of the property * \return the property value as a string or NULL if the index is out of range */ char *mlt_properties_get_value( mlt_properties self, int index ) { if ( !self ) return NULL; property_list *list = self->local; if ( index >= 0 && index < list->count ) return mlt_property_get_string_l( list->value[ index ], list->locale ); return NULL; } /** Get a data value by index. * * Do not free the returned pointer if you supplied a destructor function when you * set this property. * \public \memberof mlt_properties_s * \param self a properties list * \param index the numeric index of the property * \param[out] size the size of the binary data in bytes or NULL if the index is out of range */ void *mlt_properties_get_data_at( mlt_properties self, int index, int *size ) { if ( !self ) return NULL; property_list *list = self->local; if ( index >= 0 && index < list->count ) return mlt_property_get_data( list->value[ index ], size ); return NULL; } /** Return the number of items in the list. * * \public \memberof mlt_properties_s * \param self a properties list * \return the number of property objects or -1 if error */ int mlt_properties_count( mlt_properties self ) { if ( !self ) return -1; property_list *list = self->local; return list->count; } /** Set a value by parsing a name=value string. * * \public \memberof mlt_properties_s * \param self a properties list * \param namevalue a string containing name and value delimited by '=' * \return true if there was an error */ int mlt_properties_parse( mlt_properties self, const char *namevalue ) { if ( !self ) return 1; char *name = strdup( namevalue ); char *value = NULL; int error = 0; char *ptr = strchr( name, '=' ); if ( ptr ) { *( ptr ++ ) = '\0'; if ( *ptr != '\"' ) { value = strdup( ptr ); } else { ptr ++; value = strdup( ptr ); if ( value != NULL && value[ strlen( value ) - 1 ] == '\"' ) value[ strlen( value ) - 1 ] = '\0'; } } else { value = strdup( "" ); } error = mlt_properties_set( self, name, value ); free( name ); free( value ); return error; } /** Get an integer associated to the name. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to get * \return The integer value, 0 if not found (which may also be a legitimate value) */ int mlt_properties_get_int( mlt_properties self, const char *name ) { int result = 0; mlt_property value = mlt_properties_find( self, name ); if ( value ) { mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); double fps = mlt_profile_fps( profile ); property_list *list = self->local; result = mlt_property_get_int( value, fps, list->locale ); } return result; } /** Set a property to an integer value. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to set * \param value the integer * \return true if error */ int mlt_properties_set_int( mlt_properties self, const char *name, int value ) { int error = 1; if ( !self || !name ) return error; // Fetch the property to work with mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { error = mlt_property_set_int( property, value ); mlt_properties_do_mirror( self, name ); } mlt_events_fire( self, "property-changed", name, NULL ); return error; } /** Get a 64-bit integer associated to the name. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to get * \return the integer value, 0 if not found (which may also be a legitimate value) */ int64_t mlt_properties_get_int64( mlt_properties self, const char *name ) { mlt_property value = mlt_properties_find( self, name ); return value == NULL ? 0 : mlt_property_get_int64( value ); } /** Set a property to a 64-bit integer value. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to set * \param value the integer * \return true if error */ int mlt_properties_set_int64( mlt_properties self, const char *name, int64_t value ) { int error = 1; if ( !self || !name ) return error; // Fetch the property to work with mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { error = mlt_property_set_int64( property, value ); mlt_properties_do_mirror( self, name ); } mlt_events_fire( self, "property-changed", name, NULL ); return error; } /** Get a floating point value associated to the name. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to get * \return the floating point, 0 if not found (which may also be a legitimate value) */ double mlt_properties_get_double( mlt_properties self, const char *name ) { double result = 0; mlt_property value = mlt_properties_find( self, name ); if ( value ) { mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); double fps = mlt_profile_fps( profile ); property_list *list = self->local; result = mlt_property_get_double( value, fps, list->locale ); } return result; } /** Set a property to a floating point value. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to set * \param value the floating point value * \return true if error */ int mlt_properties_set_double( mlt_properties self, const char *name, double value ) { int error = 1; if ( !self || !name ) return error; // Fetch the property to work with mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { error = mlt_property_set_double( property, value ); mlt_properties_do_mirror( self, name ); } mlt_events_fire( self, "property-changed", name, NULL ); return error; } /** Get a position value associated to the name. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to get * \return the position, 0 if not found (which may also be a legitimate value) */ mlt_position mlt_properties_get_position( mlt_properties self, const char *name ) { mlt_position result = 0; mlt_property value = mlt_properties_find( self, name ); if ( value ) { mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); double fps = mlt_profile_fps( profile ); property_list *list = self->local; result = mlt_property_get_position( value, fps, list->locale ); } return result; } /** Set a property to a position value. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to get * \param value the position * \return true if error */ int mlt_properties_set_position( mlt_properties self, const char *name, mlt_position value ) { int error = 1; if ( !self || !name ) return error; // Fetch the property to work with mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { error = mlt_property_set_position( property, value ); mlt_properties_do_mirror( self, name ); } mlt_events_fire( self, "property-changed", name, NULL ); return error; } /** Get a binary data value associated to the name. * * Do not free the returned pointer if you supplied a destructor function * when you set this property. * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to get * \param[out] length The size of the binary data in bytes, if available (often it is not, you should know) */ void *mlt_properties_get_data( mlt_properties self, const char *name, int *length ) { mlt_property value = mlt_properties_find( self, name ); return value == NULL ? NULL : mlt_property_get_data( value, length ); } /** Store binary data as a property. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to set * \param value an opaque pointer to binary data * \param length the size of the binary data in bytes (optional) * \param destroy a function to deallocate the binary data when the property is closed (optional) * \param serialise a function that can serialize the binary data as text (optional) * \return true if error */ int mlt_properties_set_data( mlt_properties self, const char *name, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise ) { int error = 1; if ( !self || !name ) return error; // Fetch the property to work with mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) error = mlt_property_set_data( property, value, length, destroy, serialise ); mlt_events_fire( self, "property-changed", name, NULL ); return error; } /** Rename a property. * * \public \memberof mlt_properties_s * \param self a properties list * \param source the property to rename * \param dest the new name * \return true if the name is already in use */ int mlt_properties_rename( mlt_properties self, const char *source, const char *dest ) { mlt_property value = mlt_properties_find( self, dest ); if ( value == NULL ) { property_list *list = self->local; int i = 0; // Locate the item mlt_properties_lock( self ); for ( i = 0; i < list->count; i ++ ) { if ( !strcmp( list->name[ i ], source ) ) { free( list->name[ i ] ); list->name[ i ] = strdup( dest ); list->hash[ generate_hash( dest ) ] = i + 1; break; } } mlt_properties_unlock( self ); } return value != NULL; } /** Dump the properties to a file handle. * * \public \memberof mlt_properties_s * \param self a properties list * \param output a file handle */ void mlt_properties_dump( mlt_properties self, FILE *output ) { if ( !self || !output ) return; property_list *list = self->local; int i = 0; for ( i = 0; i < list->count; i ++ ) if ( mlt_properties_get( self, list->name[ i ] ) != NULL ) fprintf( output, "%s=%s\n", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) ); } /** Output the properties to a file handle. * * This version includes reference counts and does not put each property on a new line. * \public \memberof mlt_properties_s * \param self a properties pointer * \param title a string to preface the output * \param output a file handle */ void mlt_properties_debug( mlt_properties self, const char *title, FILE *output ) { if ( !self || !output ) return; if ( output == NULL ) output = stderr; fprintf( output, "%s: ", title ); if ( self != NULL ) { property_list *list = self->local; int i = 0; fprintf( output, "[ ref=%d", list->ref_count ); for ( i = 0; i < list->count; i ++ ) if ( mlt_properties_get( self, list->name[ i ] ) != NULL ) fprintf( output, ", %s=%s", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) ); else fprintf( output, ", %s=%p", list->name[ i ], mlt_properties_get_data( self, list->name[ i ], NULL ) ); fprintf( output, " ]" ); } fprintf( output, "\n" ); } /** Save the properties to a file by name. * * This uses the dump format - one line per property. * \public \memberof mlt_properties_s * \param self a properties list * \param filename the name of a file to create or overwrite * \return true if there was an error */ int mlt_properties_save( mlt_properties self, const char *filename ) { int error = 1; if ( !self || !filename ) return error; FILE *f = fopen( filename, "w" ); if ( f != NULL ) { mlt_properties_dump( self, f ); fclose( f ); error = 0; } return error; } /* This is a very basic cross platform fnmatch replacement - it will fail in * many cases, but for the basic *.XXX and YYY*.XXX, it will work ok. */ /** Test whether a filename or pathname matches a shell-style pattern. * * \private \memberof mlt_properties_s * \param wild a string containing a wildcard pattern * \param file the name of a file to test against * \return true if the file name matches the wildcard pattern */ static int mlt_fnmatch( const char *wild, const char *file ) { int f = 0; int w = 0; while( f < strlen( file ) && w < strlen( wild ) ) { if ( wild[ w ] == '*' ) { w ++; if ( w == strlen( wild ) ) f = strlen( file ); while ( f != strlen( file ) && tolower( file[ f ] ) != tolower( wild[ w ] ) ) f ++; } else if ( wild[ w ] == '?' || tolower( file[ f ] ) == tolower( wild[ w ] ) ) { f ++; w ++; } else if ( wild[ 0 ] == '*' ) { w = 0; } else { return 0; } } return strlen( file ) == f && strlen( wild ) == w; } /** Compare the string or serialized value of two properties. * * \private \memberof mlt_properties_s * \param self a property * \param that a property * \return < 0 if \p self less than \p that, 0 if equal, or > 0 if \p self is greater than \p that */ static int mlt_compare( const void *self, const void *that ) { return strcmp( mlt_property_get_string( *( const mlt_property * )self ), mlt_property_get_string( *( const mlt_property * )that ) ); } /** Get the contents of a directory. * * Obtains an optionally sorted list of the files found in a directory with a specific wild card. * Entries in the list have a numeric name (running from 0 to count - 1). Only values change * position if sort is enabled. Designed to be posix compatible (linux, os/x, mingw etc). * \public \memberof mlt_properties_s * \param self a properties list * \param dirname the name of the directory * \param pattern a wildcard pattern to filter the directory listing * \param sort Do you want to sort the directory listing? * \return the number of items in the directory listing */ int mlt_properties_dir_list( mlt_properties self, const char *dirname, const char *pattern, int sort ) { DIR *dir = opendir( dirname ); if ( dir ) { char key[ 20 ]; struct dirent *de = readdir( dir ); char fullname[ 1024 ]; while( de != NULL ) { sprintf( key, "%d", mlt_properties_count( self ) ); snprintf( fullname, 1024, "%s/%s", dirname, de->d_name ); if ( pattern == NULL ) mlt_properties_set( self, key, fullname ); else if ( de->d_name[ 0 ] != '.' && mlt_fnmatch( pattern, de->d_name ) ) mlt_properties_set( self, key, fullname ); de = readdir( dir ); } closedir( dir ); } if ( sort && mlt_properties_count( self ) ) { property_list *list = self->local; mlt_properties_lock( self ); qsort( list->value, mlt_properties_count( self ), sizeof( mlt_property ), mlt_compare ); mlt_properties_unlock( self ); } return mlt_properties_count( self ); } /** Close a properties object. * * Deallocates the properties object and everything it contains. * \public \memberof mlt_properties_s * \param self a properties object */ void mlt_properties_close( mlt_properties self ) { if ( self != NULL && mlt_properties_dec_ref( self ) <= 0 ) { if ( self->close != NULL ) { self->close( self->close_object ); } else { property_list *list = self->local; int index = 0; #if _MLT_PROPERTY_CHECKS_ == 1 // Show debug info mlt_properties_debug( self, "Closing", stderr ); #endif #ifdef _MLT_PROPERTY_CHECKS_ // Increment destroyed count properties_destroyed ++; // Show current stats - these should match when the app is closed mlt_log( NULL, MLT_LOG_DEBUG, "Created %d, destroyed %d\n", properties_created, properties_destroyed ); #endif // Clean up names and values for ( index = list->count - 1; index >= 0; index -- ) { mlt_property_close( list->value[ index ] ); free( list->name[ index ] ); } #if defined(__linux__) || defined(__DARWIN__) // Cleanup locale if ( list->locale ) freelocale( list->locale ); #endif // Clear up the list pthread_mutex_destroy( &list->mutex ); free( list->name ); free( list->value ); free( list ); // Free self now if self has no child if ( self->child == NULL ) free( self ); } } } /** Determine if the properties list is really just a sequence or ordered list. * * \public \memberof mlt_properties_s * \param properties a properties list * \return true if all of the property names are numeric (a sequence) */ int mlt_properties_is_sequence( mlt_properties properties ) { int i; int n = mlt_properties_count( properties ); for ( i = 0; i < n; i++ ) if ( ! isdigit( mlt_properties_get_name( properties, i )[0] ) ) return 0; return 1; } /** \brief YAML Tiny Parser context structure * * YAML is a nifty text format popular in the Ruby world as a cleaner, * less verbose alternative to XML. See this Wikipedia topic for an overview: * http://en.wikipedia.org/wiki/YAML * The YAML specification is at: * http://yaml.org/ * YAML::Tiny is a Perl module that specifies a subset of YAML that we are * using here (for the same reasons): * http://search.cpan.org/~adamk/YAML-Tiny-1.25/lib/YAML/Tiny.pm * \private */ struct yaml_parser_context { mlt_deque stack; unsigned int level; int index; mlt_deque index_stack; char block; char *block_name; unsigned int block_indent; }; typedef struct yaml_parser_context *yaml_parser; /** Remove spaces from the left side of a string. * * \param s the string to trim * \return the number of characters removed */ static unsigned int ltrim( char **s ) { unsigned int i = 0; char *c = *s; int n = strlen( c ); for ( i = 0; i < n && *c == ' '; i++, c++ ); *s = c; return i; } /** Remove spaces from the right side of a string. * * \param s the string to trim * \return the number of characters removed */ static unsigned int rtrim( char *s ) { int n = strlen( s ); int i; for ( i = n; i > 0 && s[i - 1] == ' '; --i ) s[i - 1] = 0; return n - i; } /** Parse a line of YAML Tiny. * * Adds a property if needed. * \private \memberof yaml_parser_context * \param context a YAML Tiny Parser context * \param namevalue a line of YAML Tiny * \return true if there was an error */ static int parse_yaml( yaml_parser context, const char *namevalue ) { char *name_ = strdup( namevalue ); char *name = name_; char *value = NULL; int error = 0; char *ptr = strchr( name, ':' ); unsigned int indent = ltrim( &name ); mlt_properties properties = mlt_deque_peek_back( context->stack ); // Ascending one more levels in the tree if ( indent < context->level ) { unsigned int i; unsigned int n = ( context->level - indent ) / 2; for ( i = 0; i < n; i++ ) { mlt_deque_pop_back( context->stack ); context->index = mlt_deque_pop_back_int( context->index_stack ); } properties = mlt_deque_peek_back( context->stack ); context->level = indent; } // Descending a level in the tree else if ( indent > context->level && context->block == 0 ) { context->level = indent; } // If there is a colon that is not part of a block if ( ptr && ( indent == context->level ) ) { // Reset block processing if ( context->block_name ) { free( context->block_name ); context->block_name = NULL; context->block = 0; } // Terminate the name and setup the value pointer *( ptr ++ ) = 0; // Trim comment char *comment = strchr( ptr, '#' ); if ( comment ) { *comment = 0; } // Trim leading and trailing spaces from bare value ltrim( &ptr ); rtrim( ptr ); // No value means a child if ( strcmp( ptr, "" ) == 0 ) { mlt_properties child = mlt_properties_new(); mlt_properties_set_lcnumeric( child, mlt_properties_get_lcnumeric( properties ) ); mlt_properties_set_data( properties, name, child, 0, ( mlt_destructor )mlt_properties_close, NULL ); mlt_deque_push_back( context->stack, child ); mlt_deque_push_back_int( context->index_stack, context->index ); context->index = 0; free( name_ ); return error; } // A dash indicates a sequence item if ( name[0] == '-' ) { mlt_properties child = mlt_properties_new(); char key[20]; mlt_properties_set_lcnumeric( child, mlt_properties_get_lcnumeric( properties ) ); snprintf( key, sizeof(key), "%d", context->index++ ); mlt_properties_set_data( properties, key, child, 0, ( mlt_destructor )mlt_properties_close, NULL ); mlt_deque_push_back( context->stack, child ); mlt_deque_push_back_int( context->index_stack, context->index ); name ++; context->level += ltrim( &name ) + 1; properties = child; } // Value is quoted if ( *ptr == '\"' ) { ptr ++; value = strdup( ptr ); if ( value && value[ strlen( value ) - 1 ] == '\"' ) value[ strlen( value ) - 1 ] = 0; } // Value is folded or unfolded block else if ( *ptr == '|' || *ptr == '>' ) { context->block = *ptr; context->block_name = strdup( name ); context->block_indent = 0; value = strdup( "" ); } // Bare value else { value = strdup( ptr ); } } // A list of scalars else if ( name[0] == '-' ) { // Reset block processing if ( context->block_name ) { free( context->block_name ); context->block_name = NULL; context->block = 0; } char key[20]; snprintf( key, sizeof(key), "%d", context->index++ ); ptr = name + 1; // Trim comment char *comment = strchr( ptr, '#' ); if ( comment ) *comment = 0; // Trim leading and trailing spaces from bare value ltrim( &ptr ); rtrim( ptr ); // Value is quoted if ( *ptr == '\"' ) { ptr ++; value = strdup( ptr ); if ( value && value[ strlen( value ) - 1 ] == '\"' ) value[ strlen( value ) - 1 ] = 0; } // Value is folded or unfolded block else if ( *ptr == '|' || *ptr == '>' ) { context->block = *ptr; context->block_name = strdup( key ); context->block_indent = 0; value = strdup( "" ); } // Bare value else { value = strdup( ptr ); } free( name_ ); name = name_ = strdup( key ); } // Non-folded block else if ( context->block == '|' ) { if ( context->block_indent == 0 ) context->block_indent = indent; if ( indent > context->block_indent ) name = &name_[ context->block_indent ]; rtrim( name ); char *old_value = mlt_properties_get( properties, context->block_name ); value = calloc( 1, strlen( old_value ) + strlen( name ) + 2 ); strcpy( value, old_value ); if ( strcmp( old_value, "" ) ) strcat( value, "\n" ); strcat( value, name ); name = context->block_name; } // Folded block else if ( context->block == '>' ) { ltrim( &name ); rtrim( name ); char *old_value = mlt_properties_get( properties, context->block_name ); // Blank line (prepended with spaces) is new line if ( strcmp( name, "" ) == 0 ) { value = calloc( 1, strlen( old_value ) + 2 ); strcat( value, old_value ); strcat( value, "\n" ); } // Concatenate with space else { value = calloc( 1, strlen( old_value ) + strlen( name ) + 2 ); strcat( value, old_value ); if ( strcmp( old_value, "" ) && old_value[ strlen( old_value ) - 1 ] != '\n' ) strcat( value, " " ); strcat( value, name ); } name = context->block_name; } else { value = strdup( "" ); } error = mlt_properties_set( properties, name, value ); if ( !strcmp( name, "LC_NUMERIC" ) ) mlt_properties_set_lcnumeric( properties, value ); free( name_ ); free( value ); return error; } /** Parse a YAML Tiny file by name. * * \public \memberof mlt_properties_s * \param filename the name of a text file containing YAML Tiny * \return a new properties list */ mlt_properties mlt_properties_parse_yaml( const char *filename ) { // Construct a standalone properties object mlt_properties self = mlt_properties_new( ); if ( self ) { // Open the file FILE *file = fopen( filename, "r" ); // Load contents of file if ( file ) { // Temp string char temp[ 1024 ]; char *ptemp = &temp[ 0 ]; // Default to LC_NUMERIC = C mlt_properties_set_lcnumeric( self, "C" ); // Parser context yaml_parser context = calloc( 1, sizeof( struct yaml_parser_context ) ); context->stack = mlt_deque_init(); context->index_stack = mlt_deque_init(); mlt_deque_push_back( context->stack, self ); mlt_deque_push_back_int( context->index_stack, 0 ); // Read each string from the file while( fgets( temp, 1024, file ) ) { // Check for end-of-stream if ( strncmp( ptemp, "...", 3 ) == 0 ) break; // Chomp the string temp[ strlen( temp ) - 1 ] = '\0'; // Skip blank lines, comment lines, and document separator if ( strcmp( ptemp, "" ) && ptemp[ 0 ] != '#' && strncmp( ptemp, "---", 3 ) && strncmp( ptemp, "%YAML", 5 ) && strncmp( ptemp, "% YAML", 6 ) ) parse_yaml( context, temp ); } // Close the file fclose( file ); mlt_deque_close( context->stack ); mlt_deque_close( context->index_stack ); if ( context->block_name ) free( context->block_name ); free( context ); } } // Return the pointer return self; } /* * YAML Tiny Serializer */ /** How many bytes to grow at a time */ #define STRBUF_GROWTH (1024) /** \brief Private to mlt_properties_s, a self-growing buffer for building strings * \private */ struct strbuf_s { size_t size; char *string; }; typedef struct strbuf_s *strbuf; /** Create a new string buffer * * \private \memberof strbuf_s * \return a new string buffer */ static strbuf strbuf_new( ) { strbuf buffer = calloc( 1, sizeof( struct strbuf_s ) ); buffer->size = STRBUF_GROWTH; buffer->string = calloc( 1, buffer->size ); return buffer; } /** Destroy a string buffer * * \private \memberof strbuf_s * \param buffer the string buffer to close */ static void strbuf_close( strbuf buffer ) { // We do not free buffer->string; strbuf user must save that pointer // and free it. if ( buffer ) free( buffer ); } /** Format a string into a string buffer * * A variable number of arguments follows the format string - one for each * format specifier. * \private \memberof strbuf_s * \param buffer the string buffer to write into * \param format a string that contains text and formatting instructions * \return the formatted string */ static char *strbuf_printf( strbuf buffer, const char *format, ... ) { while ( buffer->string ) { va_list ap; va_start( ap, format ); size_t len = strlen( buffer->string ); size_t remain = buffer->size - len - 1; int need = vsnprintf( buffer->string + len, remain, format, ap ); va_end( ap ); if ( need > -1 && need < remain ) break; buffer->string[ len ] = 0; buffer->size += need + STRBUF_GROWTH; buffer->string = realloc( buffer->string, buffer->size ); } return buffer->string; } /** Indent a line of YAML Tiny. * * \private \memberof strbuf_s * \param output a string buffer * \param indent the number of spaces to indent */ static inline void indent_yaml( strbuf output, int indent ) { int j; for ( j = 0; j < indent; j++ ) strbuf_printf( output, " " ); } static void strbuf_escape( strbuf output, const char *value, char c ) { char *v = strdup( value ); char *s = v; char *found = strchr( s, c ); while ( found ) { *found = '\0'; strbuf_printf( output, "%s\\%c", s, c ); s = found + 1; found = strchr( s, c ); } strbuf_printf( output, "%s", s ); free( v ); } /** Convert a line string into a YAML block literal. * * \private \memberof strbuf_s * \param output a string buffer * \param value the string to format as a block literal * \param indent the number of spaces to indent */ static void output_yaml_block_literal( strbuf output, const char *value, int indent ) { char *v = strdup( value ); char *sol = v; char *eol = strchr( sol, '\n' ); while ( eol ) { indent_yaml( output, indent ); *eol = '\0'; strbuf_printf( output, "%s\n", sol ); sol = eol + 1; eol = strchr( sol, '\n' ); } indent_yaml( output, indent ); strbuf_printf( output, "%s\n", sol ); free( v ); } /** Recursively serialize a properties list into a string buffer as YAML Tiny. * * \private \memberof mlt_properties_s * \param self a properties list * \param output a string buffer to hold the serialized YAML Tiny * \param indent the number of spaces to indent (for recursion, initialize to 0) * \param is_parent_sequence Is this properties list really just a sequence (for recursion, initialize to 0)? */ static void serialise_yaml( mlt_properties self, strbuf output, int indent, int is_parent_sequence ) { property_list *list = self->local; int i = 0; for ( i = 0; i < list->count; i ++ ) { // This implementation assumes that all data elements are property lists. // Unfortunately, we do not have run time type identification. mlt_properties child = mlt_property_get_data( list->value[ i ], NULL ); if ( mlt_properties_is_sequence( self ) ) { // Ignore hidden/non-serialisable items if ( list->name[ i ][ 0 ] != '_' ) { // Indicate a sequence item indent_yaml( output, indent ); strbuf_printf( output, "- " ); // If the value can be represented as a string const char *value = mlt_properties_get( self, list->name[ i ] ); if ( value && strcmp( value, "" ) ) { // Determine if this is an unfolded block literal if ( strchr( value, '\n' ) ) { strbuf_printf( output, "|\n" ); output_yaml_block_literal( output, value, indent + strlen( list->name[ i ] ) + strlen( "|" ) ); } else if ( strchr( value, ':' ) || strchr( value, '[' ) ) { strbuf_printf( output, "\"" ); strbuf_escape( output, value, '"' ); strbuf_printf( output, "\"\n", value ); } else { strbuf_printf( output, "%s\n", value ); } } } // Recurse on child if ( child ) serialise_yaml( child, output, indent + 2, 1 ); } else { // Assume this is a normal map-oriented properties list const char *value = mlt_properties_get( self, list->name[ i ] ); // Ignore hidden/non-serialisable items // If the value can be represented as a string if ( list->name[ i ][ 0 ] != '_' && value && strcmp( value, "" ) ) { if ( is_parent_sequence == 0 ) indent_yaml( output, indent ); else is_parent_sequence = 0; // Determine if this is an unfolded block literal if ( strchr( value, '\n' ) ) { strbuf_printf( output, "%s: |\n", list->name[ i ] ); output_yaml_block_literal( output, value, indent + strlen( list->name[ i ] ) + strlen( ": " ) ); } else if ( strchr( value, ':' ) || strchr( value, '[' ) ) { strbuf_printf( output, "%s: \"", list->name[ i ] ); strbuf_escape( output, value, '"' ); strbuf_printf( output, "\"\n" ); } else { strbuf_printf( output, "%s: %s\n", list->name[ i ], value ); } } // Output a child as a map item if ( child ) { indent_yaml( output, indent ); strbuf_printf( output, "%s:\n", list->name[ i ] ); // Recurse on child serialise_yaml( child, output, indent + 2, 0 ); } } } } /** Serialize a properties list as a string of YAML Tiny. * * The caller MUST free the returned string! * This operates on properties containing properties as a hierarchical data * structure. * \public \memberof mlt_properties_s * \param self a properties list * \return a string containing YAML Tiny that represents the properties list */ char *mlt_properties_serialise_yaml( mlt_properties self ) { if ( !self ) return NULL; const char *lc_numeric = mlt_properties_get_lcnumeric( self ); strbuf b = strbuf_new(); strbuf_printf( b, "---\n" ); mlt_properties_set_lcnumeric( self, "C" ); serialise_yaml( self, b, 0, 0 ); mlt_properties_set_lcnumeric( self, lc_numeric ); strbuf_printf( b, "...\n" ); char *ret = b->string; strbuf_close( b ); return ret; } /** Protect a properties list against concurrent access. * * \public \memberof mlt_properties_s * \param self a properties list */ void mlt_properties_lock( mlt_properties self ) { if ( self ) pthread_mutex_lock( &( ( property_list* )( self->local ) )->mutex ); } /** End protecting a properties list against concurrent access. * * \public \memberof mlt_properties_s * \param self a properties list */ void mlt_properties_unlock( mlt_properties self ) { if ( self ) pthread_mutex_unlock( &( ( property_list* )( self->local ) )->mutex ); } /** Get a time string associated to the name. * * Do not free the returned string. It's lifetime is controlled by the property. * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to get * \param format the time format that you want * \return the property's time value or NULL if \p name does not exist or there is no profile */ char *mlt_properties_get_time( mlt_properties self, const char* name, mlt_time_format format ) { mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); if ( profile ) { double fps = mlt_profile_fps( profile ); mlt_property value = mlt_properties_find( self, name ); property_list *list = self->local; return value == NULL ? NULL : mlt_property_get_time( value, format, fps, list->locale ); } return NULL; } /** Convert a numeric property to a tuple of color components. * * If the property's string is red, green, blue, white, or black, then it * is converted to the corresponding opaque color tuple. Otherwise, the property * is fetched as an integer and then converted. * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to get * \return a color structure */ mlt_color mlt_properties_get_color( mlt_properties self, const char* name ) { mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); double fps = mlt_profile_fps( profile ); property_list *list = self->local; mlt_property value = mlt_properties_find( self, name ); mlt_color result = { 0xff, 0xff, 0xff, 0xff }; if ( value ) { const char *color = mlt_property_get_string_l( value, list->locale ); unsigned int color_int = mlt_property_get_int( value, fps, list->locale ); if ( !strcmp( color, "red" ) ) { result.r = 0xff; result.g = 0x00; result.b = 0x00; } else if ( !strcmp( color, "green" ) ) { result.r = 0x00; result.g = 0xff; result.b = 0x00; } else if ( !strcmp( color, "blue" ) ) { result.r = 0x00; result.g = 0x00; result.b = 0xff; } else if ( !strcmp( color, "black" ) ) { result.r = 0x00; result.g = 0x00; result.b = 0x00; } else if ( strcmp( color, "white" ) ) { result.r = ( color_int >> 24 ) & 0xff; result.g = ( color_int >> 16 ) & 0xff; result.b = ( color_int >> 8 ) & 0xff; result.a = ( color_int ) & 0xff; } } return result; } /** Set a property to an integer value by color. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to set * \param color the color * \return true if error */ int mlt_properties_set_color( mlt_properties self, const char *name, mlt_color color ) { int error = 1; if ( !self || !name ) return error; // Fetch the property to work with mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { uint32_t value = ( color.r << 24 ) | ( color.g << 16 ) | ( color.b << 8 ) | color.a; error = mlt_property_set_int( property, value ); mlt_properties_do_mirror( self, name ); } mlt_events_fire( self, "property-changed", name, NULL ); return error; } /** Get a string value by name at a frame position. * * Do not free the returned string. It's lifetime is controlled by the property * and this properties object. * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to get * \param position the frame number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \return the property's string value or NULL if it does not exist */ char* mlt_properties_anim_get( mlt_properties self, const char *name, int position, int length ) { mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); double fps = mlt_profile_fps( profile ); mlt_property value = mlt_properties_find( self, name ); property_list *list = self->local; return value == NULL ? NULL : mlt_property_anim_get_string( value, fps, list->locale, position, length ); } /** Set a property to a string at a frame position. * * The event "property-changed" is fired after the property has been set. * * This makes a copy of the string value you supply. * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to set * \param value the property's new value * \param position the frame number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \return true if error */ int mlt_properties_anim_set( mlt_properties self, const char *name, const char *value, int position, int length ) { int error = 1; if ( !self || !name ) return error; // Fetch the property to work with mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property ) { mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); double fps = mlt_profile_fps( profile ); property_list *list = self->local; error = mlt_property_anim_set_string( property, value, fps, list->locale, position, length ); mlt_properties_do_mirror( self, name ); } mlt_events_fire( self, "property-changed", name, NULL ); return error; } /** Get an integer associated to the name at a frame position. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to get * \param position the frame number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \return the integer value, 0 if not found (which may also be a legitimate value) */ int mlt_properties_anim_get_int( mlt_properties self, const char *name, int position, int length ) { mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); double fps = mlt_profile_fps( profile ); property_list *list = self->local; mlt_property value = mlt_properties_find( self, name ); return value == NULL ? 0 : mlt_property_anim_get_int( value, fps, list->locale, position, length ); } /** Set a property to an integer value at a frame position. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to set * \param value the integer * \param position the frame number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \param keyframe_type the interpolation method for this keyframe * \return true if error */ int mlt_properties_anim_set_int( mlt_properties self, const char *name, int value, int position, int length, mlt_keyframe_type keyframe_type ) { int error = 1; if ( !self || !name ) return error; // Fetch the property to work with mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); double fps = mlt_profile_fps( profile ); property_list *list = self->local; error = mlt_property_anim_set_int( property, value, fps, list->locale, position, length, keyframe_type ); mlt_properties_do_mirror( self, name ); } mlt_events_fire( self, "property-changed", name, NULL ); return error; } /** Get a real number associated to the name at a frame position. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to get * \param position the frame number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \return the real number, 0 if not found (which may also be a legitimate value) */ double mlt_properties_anim_get_double( mlt_properties self, const char *name, int position, int length ) { mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); double fps = mlt_profile_fps( profile ); property_list *list = self->local; mlt_property value = mlt_properties_find( self, name ); return value == NULL ? 0.0 : mlt_property_anim_get_double( value, fps, list->locale, position, length ); } /** Set a property to a real number at a frame position. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to set * \param value the real number * \param position the frame number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \param keyframe_type the interpolation method for this keyframe * \return true if error */ int mlt_properties_anim_set_double( mlt_properties self, const char *name, double value, int position, int length, mlt_keyframe_type keyframe_type ) { int error = 1; if ( !self || !name ) return error; // Fetch the property to work with mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); double fps = mlt_profile_fps( profile ); property_list *list = self->local; error = mlt_property_anim_set_double( property, value, fps, list->locale, position, length, keyframe_type ); mlt_properties_do_mirror( self, name ); } mlt_events_fire( self, "property-changed", name, NULL ); return error; } /** Get the animation associated to the name. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to get * \return The animation object or NULL if the property has no animation */ mlt_animation mlt_properties_get_animation( mlt_properties self, const char *name ) { mlt_property value = mlt_properties_find( self, name ); return value == NULL ? NULL : mlt_property_get_animation( value ); } /** Set a property to a rectangle value. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to set * \param value the rectangle * \return true if error */ extern int mlt_properties_set_rect( mlt_properties self, const char *name, mlt_rect value ) { int error = 1; if ( !self || !name ) return error; // Fetch the property to work with mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { error = mlt_property_set_rect( property, value ); mlt_properties_do_mirror( self, name ); } mlt_events_fire( self, "property-changed", name, NULL ); return error; } /** Get a rectangle associated to the name. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to get * \return the rectangle value, the rectangle fields will be DBL_MIN if not found */ extern mlt_rect mlt_properties_get_rect( mlt_properties self, const char* name ) { property_list *list = self->local; mlt_property value = mlt_properties_find( self, name ); mlt_rect rect = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN }; return value == NULL ? rect : mlt_property_get_rect( value, list->locale ); } /** Set a property to a rectangle value at a frame position. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to set * \param value the rectangle * \param position the frame number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \param keyframe_type the interpolation method for this keyframe * \return true if error */ extern int mlt_properties_anim_set_rect( mlt_properties self, const char *name, mlt_rect value, int position, int length , mlt_keyframe_type keyframe_type ) { int error = 1; if ( !self || !name ) return error; // Fetch the property to work with mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); double fps = mlt_profile_fps( profile ); property_list *list = self->local; error = mlt_property_anim_set_rect( property, value, fps, list->locale, position, length, keyframe_type ); mlt_properties_do_mirror( self, name ); } mlt_events_fire( self, "property-changed", name, NULL ); return error; } /** Get a rectangle associated to the name at a frame position. * * \public \memberof mlt_properties_s * \param self a properties list * \param name the property to get * \param position the frame number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \return the rectangle value, the rectangle fields will be DBL_MIN if not found */ extern mlt_rect mlt_properties_anim_get_rect( mlt_properties self, const char *name, int position, int length ) { mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); double fps = mlt_profile_fps( profile ); property_list *list = self->local; mlt_property value = mlt_properties_find( self, name ); mlt_rect rect = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN }; return value == NULL ? rect : mlt_property_anim_get_rect( value, fps, list->locale, position, length ); } mlt-0.9.0/src/framework/mlt_properties.h000066400000000000000000000145571215300731300203300ustar00rootroot00000000000000/** * \file mlt_properties.h * \brief Properties class declaration * \see mlt_properties_s * * Copyright (C) 2003-2013 Ushodaya Enterprises Limited * \author Charles Yates * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_PROPERTIES_H_ #define _MLT_PROPERTIES_H_ #include "mlt_types.h" #include "mlt_events.h" #include /** \brief Properties class * * Properties is a combination list/dictionary of name/::mlt_property pairs. * It is also a base class for many of the other MLT classes. */ struct mlt_properties_s { void *child; /**< \private the object of a subclass */ void *local; /**< \private instance object */ /** the destructor virtual function */ mlt_destructor close; void *close_object; /**< the object supplied to the close virtual function */ }; extern int mlt_properties_init( mlt_properties, void *child ); extern mlt_properties mlt_properties_new( ); extern int mlt_properties_set_lcnumeric( mlt_properties, const char *locale ); extern const char* mlt_properties_get_lcnumeric( mlt_properties self ); extern mlt_properties mlt_properties_load( const char *file ); extern int mlt_properties_preset( mlt_properties self, const char *name ); extern int mlt_properties_inc_ref( mlt_properties self ); extern int mlt_properties_dec_ref( mlt_properties self ); extern int mlt_properties_ref_count( mlt_properties self ); extern void mlt_properties_mirror( mlt_properties self, mlt_properties that ); extern int mlt_properties_inherit( mlt_properties self, mlt_properties that ); extern int mlt_properties_pass( mlt_properties self, mlt_properties that, const char *prefix ); extern void mlt_properties_pass_property( mlt_properties self, mlt_properties that, const char *name ); extern int mlt_properties_pass_list( mlt_properties self, mlt_properties that, const char *list ); extern int mlt_properties_set( mlt_properties self, const char *name, const char *value ); extern int mlt_properties_set_or_default( mlt_properties self, const char *name, const char *value, const char *def ); extern int mlt_properties_parse( mlt_properties self, const char *namevalue ); extern char *mlt_properties_get( mlt_properties self, const char *name ); extern char *mlt_properties_get_name( mlt_properties self, int index ); extern char *mlt_properties_get_value( mlt_properties self, int index ); extern void *mlt_properties_get_data_at( mlt_properties self, int index, int *size ); extern int mlt_properties_get_int( mlt_properties self, const char *name ); extern int mlt_properties_set_int( mlt_properties self, const char *name, int value ); extern int64_t mlt_properties_get_int64( mlt_properties self, const char *name ); extern int mlt_properties_set_int64( mlt_properties self, const char *name, int64_t value ); extern double mlt_properties_get_double( mlt_properties self, const char *name ); extern int mlt_properties_set_double( mlt_properties self, const char *name, double value ); extern mlt_position mlt_properties_get_position( mlt_properties self, const char *name ); extern int mlt_properties_set_position( mlt_properties self, const char *name, mlt_position value ); extern int mlt_properties_set_data( mlt_properties self, const char *name, void *value, int length, mlt_destructor, mlt_serialiser ); extern void *mlt_properties_get_data( mlt_properties self, const char *name, int *length ); extern int mlt_properties_rename( mlt_properties self, const char *source, const char *dest ); extern int mlt_properties_count( mlt_properties self ); extern void mlt_properties_dump( mlt_properties self, FILE *output ); extern void mlt_properties_debug( mlt_properties self, const char *title, FILE *output ); extern int mlt_properties_save( mlt_properties, const char * ); extern int mlt_properties_dir_list( mlt_properties, const char *, const char *, int ); extern void mlt_properties_close( mlt_properties self ); extern int mlt_properties_is_sequence( mlt_properties self ); extern mlt_properties mlt_properties_parse_yaml( const char *file ); extern char *mlt_properties_serialise_yaml( mlt_properties self ); extern void mlt_properties_lock( mlt_properties self ); extern void mlt_properties_unlock( mlt_properties self ); extern char *mlt_properties_get_time( mlt_properties, const char* name, mlt_time_format ); extern mlt_color mlt_properties_get_color( mlt_properties, const char* name ); extern int mlt_properties_set_color( mlt_properties, const char* name, mlt_color value ); extern char* mlt_properties_anim_get( mlt_properties self, const char *name, int position, int length ); extern int mlt_properties_anim_set( mlt_properties self, const char *name, const char *value, int position, int length ); extern int mlt_properties_anim_get_int( mlt_properties self, const char *name, int position, int length ); extern int mlt_properties_anim_set_int( mlt_properties self, const char *name, int value, int position, int length, mlt_keyframe_type keyframe_type ); extern double mlt_properties_anim_get_double( mlt_properties self, const char *name, int position, int length ); extern int mlt_properties_anim_set_double( mlt_properties self, const char *name, double value, int position, int length, mlt_keyframe_type keyframe_type ); extern mlt_animation mlt_properties_get_animation( mlt_properties self, const char *name ); extern int mlt_properties_set_rect( mlt_properties self, const char *name, mlt_rect value ); extern mlt_rect mlt_properties_get_rect( mlt_properties self, const char *name ); extern int mlt_properties_anim_set_rect( mlt_properties self, const char *name, mlt_rect value, int position, int length, mlt_keyframe_type keyframe_type ); extern mlt_rect mlt_properties_anim_get_rect( mlt_properties self, const char *name, int position, int length ); #endif mlt-0.9.0/src/framework/mlt_property.c000066400000000000000000001343711215300731300200100ustar00rootroot00000000000000/** * \file mlt_property.c * \brief Property class definition * \see mlt_property_s * * Copyright (C) 2003-2013 Ushodaya Enterprises Limited * \author Charles Yates * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // For strtod_l #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include "mlt_property.h" #include "mlt_animation.h" #include #include #include #include #include #include #include /** Bit pattern used internally to indicated representations available. */ typedef enum { mlt_prop_none = 0, //!< not set mlt_prop_int = 1, //!< set as an integer mlt_prop_string = 2, //!< set as string or already converted to string mlt_prop_position = 4,//!< set as a position mlt_prop_double = 8, //!< set as a floating point mlt_prop_data = 16, //!< set as opaque binary mlt_prop_int64 = 32, //!< set as a 64-bit integer mlt_prop_rect = 64 //!< set as a mlt_rect } mlt_property_type; /** \brief Property class * * A property is like a variant or dynamic type. They are used for many things * in MLT, but in particular they are the parameter mechanism for the plugins. */ struct mlt_property_s { /// Stores a bit pattern of types available for this property mlt_property_type types; /// Atomic type handling int prop_int; mlt_position prop_position; double prop_double; int64_t prop_int64; /// String handling char *prop_string; /// Generic type handling void *data; int length; mlt_destructor destructor; mlt_serialiser serialiser; pthread_mutex_t mutex; mlt_animation animation; }; /** Construct a property and initialize it * \public \memberof mlt_property_s */ mlt_property mlt_property_init( ) { mlt_property self = calloc( 1, sizeof( *self ) ); if ( self ) pthread_mutex_init( &self->mutex, NULL ); return self; } /** Clear (0/null) a property. * * Frees up any associated resources in the process. * \private \memberof mlt_property_s * \param self a property */ static inline void mlt_property_clear( mlt_property self ) { // Special case data handling if ( self->types & mlt_prop_data && self->destructor != NULL ) self->destructor( self->data ); // Special case string handling if ( self->types & mlt_prop_string ) free( self->prop_string ); if ( self->animation ) mlt_animation_close( self->animation ); // Wipe stuff self->types = 0; self->prop_int = 0; self->prop_position = 0; self->prop_double = 0; self->prop_int64 = 0; self->prop_string = NULL; self->data = NULL; self->length = 0; self->destructor = NULL; self->serialiser = NULL; self->animation = NULL; } /** Set the property to an integer value. * * \public \memberof mlt_property_s * \param self a property * \param value an integer * \return false */ int mlt_property_set_int( mlt_property self, int value ) { pthread_mutex_lock( &self->mutex ); mlt_property_clear( self ); self->types = mlt_prop_int; self->prop_int = value; pthread_mutex_unlock( &self->mutex ); return 0; } /** Set the property to a floating point value. * * \public \memberof mlt_property_s * \param self a property * \param value a double precision floating point value * \return false */ int mlt_property_set_double( mlt_property self, double value ) { pthread_mutex_lock( &self->mutex ); mlt_property_clear( self ); self->types = mlt_prop_double; self->prop_double = value; pthread_mutex_unlock( &self->mutex ); return 0; } /** Set the property to a position value. * * Position is a relative time value in frame units. * \public \memberof mlt_property_s * \param self a property * \param value a position value * \return false */ int mlt_property_set_position( mlt_property self, mlt_position value ) { pthread_mutex_lock( &self->mutex ); mlt_property_clear( self ); self->types = mlt_prop_position; self->prop_position = value; pthread_mutex_unlock( &self->mutex ); return 0; } /** Set the property to a string value. * * This makes a copy of the string you supply so you do not need to track * a new reference to it. * \public \memberof mlt_property_s * \param self a property * \param value the string to copy to the property * \return true if it failed */ int mlt_property_set_string( mlt_property self, const char *value ) { pthread_mutex_lock( &self->mutex ); if ( value != self->prop_string ) { mlt_property_clear( self ); self->types = mlt_prop_string; if ( value != NULL ) self->prop_string = strdup( value ); } else { self->types = mlt_prop_string; } pthread_mutex_unlock( &self->mutex ); return self->prop_string == NULL; } /** Set the property to a 64-bit integer value. * * \public \memberof mlt_property_s * \param self a property * \param value a 64-bit integer * \return false */ int mlt_property_set_int64( mlt_property self, int64_t value ) { pthread_mutex_lock( &self->mutex ); mlt_property_clear( self ); self->types = mlt_prop_int64; self->prop_int64 = value; pthread_mutex_unlock( &self->mutex ); return 0; } /** Set a property to an opaque binary value. * * This does not make a copy of the data. You can use a Properties object * with its reference tracking and the destructor function to control * the lifetime of the data. Otherwise, pass NULL for the destructor * function and control the lifetime yourself. * \public \memberof mlt_property_s * \param self a property * \param value an opaque pointer * \param length the number of bytes pointed to by value (optional) * \param destructor a function to use to destroy this binary data (optional, assuming you manage the resource) * \param serialiser a function to use to convert this binary data to a string (optional) * \return false */ int mlt_property_set_data( mlt_property self, void *value, int length, mlt_destructor destructor, mlt_serialiser serialiser ) { pthread_mutex_lock( &self->mutex ); if ( self->data == value ) self->destructor = NULL; mlt_property_clear( self ); self->types = mlt_prop_data; self->data = value; self->length = length; self->destructor = destructor; self->serialiser = serialiser; pthread_mutex_unlock( &self->mutex ); return 0; } /** Parse a SMIL clock value. * * \private \memberof mlt_property_s * \param s the string to parse * \param fps frames per second * \param locale the locale to use for parsing a real number value * \return position in frames */ static int time_clock_to_frames( const char *s, double fps, locale_t locale ) { char *pos, *copy = strdup( s ); int hours = 0, minutes = 0; double seconds; s = copy; pos = strrchr( s, ':' ); if ( pos ) { #if defined(__GLIBC__) || defined(__DARWIN__) if ( locale ) seconds = strtod_l( pos + 1, NULL, locale ); else #endif seconds = strtod( pos + 1, NULL ); *pos = 0; pos = strrchr( s, ':' ); if ( pos ) { minutes = atoi( pos + 1 ); *pos = 0; hours = atoi( s ); } else { minutes = atoi( s ); } } else { #if defined(__GLIBC__) || defined(__DARWIN__) if ( locale ) seconds = strtod_l( s, NULL, locale ); else #endif seconds = strtod( s, NULL ); } free( copy ); return lrint( fps * ( (hours * 3600) + (minutes * 60) + seconds ) ); } /** Parse a SMPTE timecode string. * * \private \memberof mlt_property_s * \param s the string to parse * \param fps frames per second * \return position in frames */ static int time_code_to_frames( const char *s, double fps ) { char *pos, *copy = strdup( s ); int hours = 0, minutes = 0, seconds = 0, frames; s = copy; pos = strrchr( s, ';' ); if ( !pos ) pos = strrchr( s, ':' ); if ( pos ) { frames = atoi( pos + 1 ); *pos = 0; pos = strrchr( s, ':' ); if ( pos ) { seconds = atoi( pos + 1 ); *pos = 0; pos = strrchr( s, ':' ); if ( pos ) { minutes = atoi( pos + 1 ); *pos = 0; hours = atoi( s ); } else { minutes = atoi( s ); } } else { seconds = atoi( s ); } } else { frames = atoi( s ); } free( copy ); return lrint( fps * ( (hours * 3600) + (minutes * 60) + seconds ) + frames ); } /** Convert a string to an integer. * * The string must begin with '0x' to be interpreted as hexadecimal. * Otherwise, it is interpreted as base 10. * * If the string begins with '#' it is interpreted as a hexadecimal color value * in the form RRGGBB or AARRGGBB. Color values that begin with '0x' are * always in the form RRGGBBAA where the alpha components are not optional. * Applications and services should expect the binary color value in bytes to * be in the following order: RGBA. This means they will have to cast the int * to an unsigned int. This is especially important when they need to shift * right to obtain RGB without alpha in order to make it do a logical instead * of arithmetic shift. * * If the string contains a colon it is interpreted as a time value. If it also * contains a period or comma character, the string is parsed as a clock value: * HH:MM:SS. Otherwise, the time value is parsed as a SMPTE timecode: HH:MM:SS:FF. * \private \memberof mlt_property_s * \param value a string to convert * \param fps frames per second, used when converting from time value * \param locale the locale to use when converting from time clock value * \return the resultant integer */ static int mlt_property_atoi( const char *value, double fps, locale_t locale ) { // Parse a hex color value as #RRGGBB or #AARRGGBB. if ( value[0] == '#' ) { unsigned int rgb = strtoul( value + 1, NULL, 16 ); unsigned int alpha = ( strlen( value ) > 7 ) ? ( rgb >> 24 ) : 0xff; return ( rgb << 8 ) | alpha; } // Do hex and decimal explicitly to avoid decimal value with leading zeros // interpreted as octal. else if ( value[0] == '0' && value[1] == 'x' ) { return strtoul( value + 2, NULL, 16 ); } else if ( fps > 0 && strchr( value, ':' ) ) { if ( strchr( value, '.' ) || strchr( value, ',' ) ) return time_clock_to_frames( value, fps, locale ); else return time_code_to_frames( value, fps ); } else { return strtol( value, NULL, 10 ); } } /** Get the property as an integer. * * \public \memberof mlt_property_s * \param self a property * \param fps frames per second, used when converting from time value * \param locale the locale to use when converting from time clock value * \return an integer value */ int mlt_property_get_int( mlt_property self, double fps, locale_t locale ) { if ( self->types & mlt_prop_int ) return self->prop_int; else if ( self->types & mlt_prop_double ) return ( int )self->prop_double; else if ( self->types & mlt_prop_position ) return ( int )self->prop_position; else if ( self->types & mlt_prop_int64 ) return ( int )self->prop_int64; else if ( self->types & mlt_prop_rect && self->data ) return ( int ) ( (mlt_rect*) self->data )->x; else if ( ( self->types & mlt_prop_string ) && self->prop_string ) return mlt_property_atoi( self->prop_string, fps, locale ); return 0; } /** Convert a string to a floating point number. * * If the string contains a colon it is interpreted as a time value. If it also * contains a period or comma character, the string is parsed as a clock value: * HH:MM:SS. Otherwise, the time value is parsed as a SMPTE timecode: HH:MM:SS:FF. * If the numeric string ends with '%' then the value is divided by 100 to convert * it into a ratio. * \private \memberof mlt_property_s * \param value the string to convert * \param fps frames per second, used when converting from time value * \param locale the locale to use when converting from time clock value * \return the resultant real number */ static double mlt_property_atof( const char *value, double fps, locale_t locale ) { if ( fps > 0 && strchr( value, ':' ) ) { if ( strchr( value, '.' ) || strchr( value, ',' ) ) return time_clock_to_frames( value, fps, locale ); else return time_code_to_frames( value, fps ); } else { char *end = NULL; double result; #if defined(__GLIBC__) || defined(__DARWIN__) if ( locale ) result = strtod_l( value, &end, locale ); else #endif result = strtod( value, &end ); if ( end && end[0] == '%' ) result /= 100.0; return result; } } /** Get the property as a floating point. * * \public \memberof mlt_property_s * \param self a property * \param fps frames per second, used when converting from time value * \param locale the locale to use for this conversion * \return a floating point value */ double mlt_property_get_double( mlt_property self, double fps, locale_t locale ) { if ( self->types & mlt_prop_double ) return self->prop_double; else if ( self->types & mlt_prop_int ) return ( double )self->prop_int; else if ( self->types & mlt_prop_position ) return ( double )self->prop_position; else if ( self->types & mlt_prop_int64 ) return ( double )self->prop_int64; else if ( self->types & mlt_prop_rect && self->data ) return ( (mlt_rect*) self->data )->x; else if ( ( self->types & mlt_prop_string ) && self->prop_string ) return mlt_property_atof( self->prop_string, fps, locale ); return 0; } /** Get the property as a position. * * A position is an offset time in terms of frame units. * \public \memberof mlt_property_s * \param self a property * \param fps frames per second, used when converting from time value * \param locale the locale to use when converting from time clock value * \return the position in frames */ mlt_position mlt_property_get_position( mlt_property self, double fps, locale_t locale ) { if ( self->types & mlt_prop_position ) return self->prop_position; else if ( self->types & mlt_prop_int ) return ( mlt_position )self->prop_int; else if ( self->types & mlt_prop_double ) return ( mlt_position )self->prop_double; else if ( self->types & mlt_prop_int64 ) return ( mlt_position )self->prop_int64; else if ( self->types & mlt_prop_rect && self->data ) return ( mlt_position ) ( (mlt_rect*) self->data )->x; else if ( ( self->types & mlt_prop_string ) && self->prop_string ) return ( mlt_position )mlt_property_atoi( self->prop_string, fps, locale ); return 0; } /** Convert a string to a 64-bit integer. * * If the string begins with '0x' it is interpreted as a hexadecimal value. * \private \memberof mlt_property_s * \param value a string * \return a 64-bit integer */ static inline int64_t mlt_property_atoll( const char *value ) { if ( value == NULL ) return 0; else if ( value[0] == '0' && value[1] == 'x' ) return strtoll( value + 2, NULL, 16 ); else return strtoll( value, NULL, 10 ); } /** Get the property as a signed integer. * * \public \memberof mlt_property_s * \param self a property * \return a 64-bit integer */ int64_t mlt_property_get_int64( mlt_property self ) { if ( self->types & mlt_prop_int64 ) return self->prop_int64; else if ( self->types & mlt_prop_int ) return ( int64_t )self->prop_int; else if ( self->types & mlt_prop_double ) return ( int64_t )self->prop_double; else if ( self->types & mlt_prop_position ) return ( int64_t )self->prop_position; else if ( self->types & mlt_prop_rect && self->data ) return ( int64_t ) ( (mlt_rect*) self->data )->x; else if ( ( self->types & mlt_prop_string ) && self->prop_string ) return mlt_property_atoll( self->prop_string ); return 0; } /** Get the property as a string. * * The caller is not responsible for deallocating the returned string! * The string is deallocated when the Property is closed. * This tries its hardest to convert the property to string including using * a serialization function for binary data, if supplied. * \public \memberof mlt_property_s * \param self a property * \return a string representation of the property or NULL if failed */ char *mlt_property_get_string( mlt_property self ) { // Construct a string if need be if ( ! ( self->types & mlt_prop_string ) ) { pthread_mutex_lock( &self->mutex ); if ( self->types & mlt_prop_int ) { self->types |= mlt_prop_string; self->prop_string = malloc( 32 ); sprintf( self->prop_string, "%d", self->prop_int ); } else if ( self->types & mlt_prop_double ) { self->types |= mlt_prop_string; self->prop_string = malloc( 32 ); sprintf( self->prop_string, "%g", self->prop_double ); } else if ( self->types & mlt_prop_position ) { self->types |= mlt_prop_string; self->prop_string = malloc( 32 ); sprintf( self->prop_string, "%d", (int)self->prop_position ); } else if ( self->types & mlt_prop_int64 ) { self->types |= mlt_prop_string; self->prop_string = malloc( 32 ); sprintf( self->prop_string, "%"PRId64, self->prop_int64 ); } else if ( self->types & mlt_prop_data && self->serialiser != NULL ) { self->types |= mlt_prop_string; self->prop_string = self->serialiser( self->data, self->length ); } pthread_mutex_unlock( &self->mutex ); } // Return the string (may be NULL) return self->prop_string; } /** Get the property as a string (with locale). * * The caller is not responsible for deallocating the returned string! * The string is deallocated when the Property is closed. * This tries its hardest to convert the property to string including using * a serialization function for binary data, if supplied. * \public \memberof mlt_property_s * \param self a property * \param locale the locale to use for this conversion * \return a string representation of the property or NULL if failed */ char *mlt_property_get_string_l( mlt_property self, locale_t locale ) { // Optimization for no locale if ( !locale ) return mlt_property_get_string( self ); // Construct a string if need be if ( ! ( self->types & mlt_prop_string ) ) { // TODO: when glibc gets sprintf_l, start using it! For now, hack on setlocale. // Save the current locale #if defined(__DARWIN__) const char *localename = querylocale( LC_NUMERIC, locale ); #elif defined(__GLIBC__) const char *localename = locale->__names[ LC_NUMERIC ]; #else // TODO: not yet sure what to do on other platforms const char *localename = ""; #endif // Protect damaging the global locale from a temporary locale on another thread. pthread_mutex_lock( &self->mutex ); // Get the current locale char *orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) ); // Set the new locale setlocale( LC_NUMERIC, localename ); if ( self->types & mlt_prop_int ) { self->types |= mlt_prop_string; self->prop_string = malloc( 32 ); sprintf( self->prop_string, "%d", self->prop_int ); } else if ( self->types & mlt_prop_double ) { self->types |= mlt_prop_string; self->prop_string = malloc( 32 ); sprintf( self->prop_string, "%g", self->prop_double ); } else if ( self->types & mlt_prop_position ) { self->types |= mlt_prop_string; self->prop_string = malloc( 32 ); sprintf( self->prop_string, "%d", (int)self->prop_position ); } else if ( self->types & mlt_prop_int64 ) { self->types |= mlt_prop_string; self->prop_string = malloc( 32 ); sprintf( self->prop_string, "%"PRId64, self->prop_int64 ); } else if ( self->types & mlt_prop_data && self->serialiser != NULL ) { self->types |= mlt_prop_string; self->prop_string = self->serialiser( self->data, self->length ); } // Restore the current locale setlocale( LC_NUMERIC, orig_localename ); free( orig_localename ); pthread_mutex_unlock( &self->mutex ); } // Return the string (may be NULL) return self->prop_string; } /** Get the binary data from a property. * * This only works if you previously put binary data into the property. * This does not return a copy of the data; it returns a pointer to it. * If you supplied a destructor function when setting the binary data, * the destructor is used when the Property is closed to free the memory. * Therefore, only free the returned pointer if you did not supply a * destructor function. * \public \memberof mlt_property_s * \param self a property * \param[out] length the size of the binary object in bytes (optional) * \return an opaque data pointer or NULL if not available */ void *mlt_property_get_data( mlt_property self, int *length ) { // Assign length if not NULL if ( length != NULL ) *length = self->length; // Return the data (note: there is no conversion here) return self->data; } /** Destroy a property and free all related resources. * * \public \memberof mlt_property_s * \param self a property */ void mlt_property_close( mlt_property self ) { mlt_property_clear( self ); pthread_mutex_destroy( &self->mutex ); free( self ); } /** Copy a property. * * A Property holding binary data only copies the data if a serialiser * function was supplied when you set the Property. * \public \memberof mlt_property_s * \author Zach * \param self a property * \param that another property */ void mlt_property_pass( mlt_property self, mlt_property that ) { pthread_mutex_lock( &self->mutex ); mlt_property_clear( self ); self->types = that->types; if ( self->types & mlt_prop_int64 ) self->prop_int64 = that->prop_int64; else if ( self->types & mlt_prop_int ) self->prop_int = that->prop_int; else if ( self->types & mlt_prop_double ) self->prop_double = that->prop_double; else if ( self->types & mlt_prop_position ) self->prop_position = that->prop_position; if ( self->types & mlt_prop_string ) { if ( that->prop_string != NULL ) self->prop_string = strdup( that->prop_string ); } else if ( that->types & mlt_prop_rect ) { mlt_property_clear( self ); self->types = mlt_prop_rect | mlt_prop_data; self->length = that->length; self->data = calloc( 1, self->length ); memcpy( self->data, that->data, self->length ); self->destructor = free; self->serialiser = that->serialiser; } else if ( self->types & mlt_prop_data && self->serialiser != NULL ) { self->types = mlt_prop_string; self->prop_string = self->serialiser( self->data, self->length ); } pthread_mutex_unlock( &self->mutex ); } /** Convert frame count to a SMPTE timecode string. * * \private \memberof mlt_property_s * \param frames a frame count * \param fps frames per second * \param[out] s the string to write into - must have enough space to hold largest time string */ static void time_smpte_from_frames( int frames, double fps, char *s ) { int hours, mins, secs; char frame_sep = ':'; if ( fps == 30000.0/1001.0 ) { fps = 30.0; int i, max_frames = frames; for ( i = 1800; i <= max_frames; i += 1800 ) { if ( i % 18000 ) { max_frames += 2; frames += 2; } } frame_sep = ';'; } hours = frames / ( fps * 3600 ); frames -= hours * ( fps * 3600 ); mins = frames / ( fps * 60 ); frames -= mins * ( fps * 60 ); secs = frames / fps; frames -= secs * fps; sprintf( s, "%02d:%02d:%02d%c%02d", hours, mins, secs, frame_sep, frames ); } /** Convert frame count to a SMIL clock value string. * * \private \memberof mlt_property_s * \param frames a frame count * \param fps frames per second * \param[out] s the string to write into - must have enough space to hold largest time string */ static void time_clock_from_frames( int frames, double fps, char *s ) { int hours, mins; double secs; hours = frames / ( fps * 3600 ); frames -= hours * ( fps * 3600 ); mins = frames / ( fps * 60 ); frames -= mins * ( fps * 60 ); secs = (double) frames / fps; sprintf( s, "%02d:%02d:%06.3f", hours, mins, secs ); } /** Get the property as a time string. * * The time value can be either a SMPTE timecode or SMIL clock value. * The caller is not responsible for deallocating the returned string! * The string is deallocated when the property is closed. * \public \memberof mlt_property_s * \param self a property * \param format the time format that you want * \param fps frames per second * \param locale the locale to use for this conversion * \return a string representation of the property or NULL if failed */ char *mlt_property_get_time( mlt_property self, mlt_time_format format, double fps, locale_t locale ) { char *orig_localename = NULL; const char *localename = ""; // Optimization for mlt_time_frames if ( format == mlt_time_frames ) return mlt_property_get_string_l( self, locale ); // Remove existing string if ( self->prop_string ) mlt_property_set_int( self, mlt_property_get_int( self, fps, locale ) ); // Use the specified locale if ( locale ) { // TODO: when glibc gets sprintf_l, start using it! For now, hack on setlocale. // Save the current locale #if defined(__DARWIN__) localename = querylocale( LC_NUMERIC, locale ); #elif defined(__GLIBC__) localename = locale->__names[ LC_NUMERIC ]; #else // TODO: not yet sure what to do on other platforms #endif // Protect damaging the global locale from a temporary locale on another thread. pthread_mutex_lock( &self->mutex ); // Get the current locale orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) ); // Set the new locale setlocale( LC_NUMERIC, localename ); } else { // Make sure we have a lock before accessing self->types pthread_mutex_lock( &self->mutex ); } // Convert number to string if ( self->types & mlt_prop_int ) { self->types |= mlt_prop_string; self->prop_string = malloc( 32 ); if ( format == mlt_time_clock ) time_clock_from_frames( self->prop_int, fps, self->prop_string ); else time_smpte_from_frames( self->prop_int, fps, self->prop_string ); } else if ( self->types & mlt_prop_position ) { self->types |= mlt_prop_string; self->prop_string = malloc( 32 ); if ( format == mlt_time_clock ) time_clock_from_frames( (int) self->prop_position, fps, self->prop_string ); else time_smpte_from_frames( (int) self->prop_position, fps, self->prop_string ); } else if ( self->types & mlt_prop_double ) { self->types |= mlt_prop_string; self->prop_string = malloc( 32 ); if ( format == mlt_time_clock ) time_clock_from_frames( self->prop_double, fps, self->prop_string ); else time_smpte_from_frames( self->prop_double, fps, self->prop_string ); } else if ( self->types & mlt_prop_int64 ) { self->types |= mlt_prop_string; self->prop_string = malloc( 32 ); if ( format == mlt_time_clock ) time_clock_from_frames( (int) self->prop_int64, fps, self->prop_string ); else time_smpte_from_frames( (int) self->prop_int64, fps, self->prop_string ); } // Restore the current locale if ( locale ) { setlocale( LC_NUMERIC, orig_localename ); free( orig_localename ); pthread_mutex_unlock( &self->mutex ); } else { // Make sure we have a lock before accessing self->types pthread_mutex_unlock( &self->mutex ); } // Return the string (may be NULL) return self->prop_string; } /** Determine if the property holds a numeric or numeric string value. * * \private \memberof mlt_property_s * \param self a property * \param locale the locale to use for string evaluation * \return true if it is numeric */ static int is_property_numeric( mlt_property self, locale_t locale ) { int result = ( self->types & mlt_prop_int ) || ( self->types & mlt_prop_int64 ) || ( self->types & mlt_prop_double ) || ( self->types & mlt_prop_position ) || ( self->types & mlt_prop_rect ); // If not already numeric but string is numeric. if ( ( !result && self->types & mlt_prop_string ) && self->prop_string ) { double temp; char *p = NULL; #if defined(__GLIBC__) || defined(__DARWIN__) if ( locale ) temp = strtod_l( self->prop_string, &p, locale ); else #endif temp = strtod( self->prop_string, &p ); result = ( p != self->prop_string ); } return result; } /** A linear interpolation function for animation. * * \private \memberof mlt_property_s */ static inline double linear_interpolate( double y1, double y2, double t ) { return y1 + ( y2 - y1 ) * t; } /** A smooth spline interpolation for animation. * * For non-closed curves, you need to also supply the tangent vector at the first and last control point. * This is commonly done: T(P[0]) = P[1] - P[0] and T(P[n]) = P[n] - P[n-1]. * \private \memberof mlt_property_s */ static inline double catmull_rom_interpolate( double y0, double y1, double y2, double y3, double t ) { double t2 = t * t; double a0 = -0.5 * y0 + 1.5 * y1 - 1.5 * y2 + 0.5 * y3; double a1 = y0 - 2.5 * y1 + 2 * y2 - 0.5 * y3; double a2 = -0.5 * y0 + 0.5 * y2; double a3 = y1; return a0 * t * t2 + a1 * t2 + a2 * t + a3; } /** Interpolate a new property value given a set of other properties. * * \public \memberof mlt_property_s * \param self the property onto which to set the computed value * \param p an array of at least 1 value in p[1] if \p interp is discrete, * 2 values in p[1] and p[2] if \p interp is linear, or * 4 values in p[0] - p[3] if \p interp is smooth * \param progress a ratio in the range [0, 1] to indicate how far between p[1] and p[2] * \param fps the frame rate, which may be needed for converting a time string to frame units * \param locale the locale, which may be needed for converting a string to a real number * \param interp the interpolation method to use * \return true if there was an error */ int mlt_property_interpolate( mlt_property self, mlt_property p[], double progress, double fps, locale_t locale, mlt_keyframe_type interp ) { int error = 0; if ( interp != mlt_keyframe_discrete && is_property_numeric( p[1], locale ) && is_property_numeric( p[2], locale ) ) { if ( self->types & mlt_prop_rect ) { mlt_rect value = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN }; if ( interp == mlt_keyframe_linear ) { mlt_rect points[2]; mlt_rect zero = {0, 0, 0, 0, 0}; points[0] = p[1]? mlt_property_get_rect( p[1], locale ) : zero; if ( p[2] ) { points[1] = mlt_property_get_rect( p[2], locale ); value.x = linear_interpolate( points[0].x, points[1].x, progress ); value.y = linear_interpolate( points[0].y, points[1].y, progress ); value.w = linear_interpolate( points[0].w, points[1].w, progress ); value.h = linear_interpolate( points[0].h, points[1].h, progress ); value.o = linear_interpolate( points[0].o, points[1].o, progress ); } else { value = points[0]; } } else if ( interp == mlt_keyframe_smooth ) { mlt_rect points[4]; mlt_rect zero = {0, 0, 0, 0, 0}; points[1] = p[1]? mlt_property_get_rect( p[1], locale ) : zero; if ( p[2] ) { points[0] = p[0]? mlt_property_get_rect( p[0], locale ) : zero; points[2] = p[2]? mlt_property_get_rect( p[2], locale ) : zero; points[3] = p[3]? mlt_property_get_rect( p[3], locale ) : zero; value.x = catmull_rom_interpolate( points[0].x, points[1].x, points[2].x, points[3].x, progress ); value.y = catmull_rom_interpolate( points[0].y, points[1].y, points[2].y, points[3].y, progress ); value.w = catmull_rom_interpolate( points[0].w, points[1].w, points[2].w, points[3].w, progress ); value.h = catmull_rom_interpolate( points[0].h, points[1].h, points[2].h, points[3].h, progress ); value.o = catmull_rom_interpolate( points[0].o, points[1].o, points[2].o, points[3].o, progress ); } else { value = points[1]; } } error = mlt_property_set_rect( self, value ); } else { double value; if ( interp == mlt_keyframe_linear ) { double points[2]; points[0] = p[1]? mlt_property_get_double( p[1], fps, locale ) : 0; points[1] = p[2]? mlt_property_get_double( p[2], fps, locale ) : 0; value = p[2]? linear_interpolate( points[0], points[1], progress ) : points[0]; } else if ( interp == mlt_keyframe_smooth ) { double points[4]; points[0] = p[0]? mlt_property_get_double( p[0], fps, locale ) : 0; points[1] = p[1]? mlt_property_get_double( p[1], fps, locale ) : 0; points[2] = p[2]? mlt_property_get_double( p[2], fps, locale ) : 0; points[3] = p[3]? mlt_property_get_double( p[3], fps, locale ) : 0; value = p[2]? catmull_rom_interpolate( points[0], points[1], points[2], points[3], progress ) : points[1]; } error = mlt_property_set_double( self, value ); } } else { mlt_property_pass( self, p[1] ); } return error; } /** Create a new animation or refresh an existing one. * * \private \memberof mlt_property_s * \param self a property * \param fps the frame rate, which may be needed for converting a time string to frame units * \param locale the locale, which may be needed for converting a string to a real number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that */ static void refresh_animation( mlt_property self, double fps, locale_t locale, int length ) { if ( !self->animation ) { self->animation = mlt_animation_new(); if ( self->prop_string ) { mlt_animation_parse( self->animation, self->prop_string, length, fps, locale ); } else { mlt_animation_set_length( self->animation, length ); pthread_mutex_lock( &self->mutex ); self->types |= mlt_prop_data; self->data = self->animation; self->serialiser = (mlt_serialiser) mlt_animation_serialize; pthread_mutex_unlock( &self->mutex ); } } else if ( self->prop_string ) { mlt_animation_refresh( self->animation, self->prop_string, length ); } } /** Get the real number at a frame position. * * \public \memberof mlt_property_s * \param self a property * \param fps the frame rate, which may be needed for converting a time string to frame units * \param locale the locale, which may be needed for converting a string to a real number * \param position the frame number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \return the real number */ double mlt_property_anim_get_double( mlt_property self, double fps, locale_t locale, int position, int length ) { double result; if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) ) { struct mlt_animation_item_s item; item.property = mlt_property_init(); refresh_animation( self, fps, locale, length ); mlt_animation_get_item( self->animation, &item, position ); result = mlt_property_get_double( item.property, fps, locale ); mlt_property_close( item.property ); } else { result = mlt_property_get_double( self, fps, locale ); } return result; } /** Get the property as an integer number at a frame position. * * \public \memberof mlt_property_s * \param self a property * \param fps the frame rate, which may be needed for converting a time string to frame units * \param locale the locale, which may be needed for converting a string to a real number * \param position the frame number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \return an integer value */ int mlt_property_anim_get_int( mlt_property self, double fps, locale_t locale, int position, int length ) { int result; if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) ) { struct mlt_animation_item_s item; item.property = mlt_property_init(); refresh_animation( self, fps, locale, length ); mlt_animation_get_item( self->animation, &item, position ); result = mlt_property_get_int( item.property, fps, locale ); mlt_property_close( item.property ); } else { result = mlt_property_get_int( self, fps, locale ); } return result; } /** Get the string at certain a frame position. * * \public \memberof mlt_property_s * \param self a property * \param fps the frame rate, which may be needed for converting a time string to frame units * \param locale the locale, which may be needed for converting a string to a real number * \param position the frame number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \return the string representation of the property or NULL if failed */ char* mlt_property_anim_get_string( mlt_property self, double fps, locale_t locale, int position, int length ) { char *result; if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) ) { struct mlt_animation_item_s item; item.property = mlt_property_init(); if ( !self->animation ) refresh_animation( self, fps, locale, length ); mlt_animation_get_item( self->animation, &item, position ); pthread_mutex_lock( &self->mutex ); if ( self->prop_string ) free( self->prop_string ); self->prop_string = mlt_property_get_string_l( item.property, locale ); if ( self->prop_string ) self->prop_string = strdup( self->prop_string ); self->types |= mlt_prop_string; pthread_mutex_unlock( &self->mutex ); result = self->prop_string; mlt_property_close( item.property ); } else { result = mlt_property_get_string_l( self, locale ); } return result; } /** Set a property animation keyframe to a real number. * * \public \memberof mlt_property_s * \param self a property * \param value a double precision floating point value * \param fps the frame rate, which may be needed for converting a time string to frame units * \param locale the locale, which may be needed for converting a string to a real number * \param position the frame number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \param keyframe_type the interpolation method for this keyframe * \return false if successful, true to indicate error */ int mlt_property_anim_set_double( mlt_property self, double value, double fps, locale_t locale, int position, int length, mlt_keyframe_type keyframe_type ) { int result; struct mlt_animation_item_s item; item.property = mlt_property_init(); item.frame = position; item.keyframe_type = keyframe_type; mlt_property_set_double( item.property, value ); refresh_animation( self, fps, locale, length ); result = mlt_animation_insert( self->animation, &item ); mlt_animation_interpolate( self->animation ); mlt_property_close( item.property ); return result; } /** Set a property animation keyframe to an integer value. * * \public \memberof mlt_property_s * \param self a property * \param value an integer * \param fps the frame rate, which may be needed for converting a time string to frame units * \param locale the locale, which may be needed for converting a string to a real number * \param position the frame number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \param keyframe_type the interpolation method for this keyframe * \return false if successful, true to indicate error */ int mlt_property_anim_set_int( mlt_property self, int value, double fps, locale_t locale, int position, int length, mlt_keyframe_type keyframe_type ) { int result; struct mlt_animation_item_s item; item.property = mlt_property_init(); item.frame = position; item.keyframe_type = keyframe_type; mlt_property_set_int( item.property, value ); refresh_animation( self, fps, locale, length ); result = mlt_animation_insert( self->animation, &item ); mlt_animation_interpolate( self->animation ); mlt_property_close( item.property ); return result; } /** Set a property animation keyframe to a string. * * Strings only support discrete animation. Do not use this to set a property's * animation string that contains a semicolon-delimited set of values; use * mlt_property_set() for that. * \public \memberof mlt_property_s * \param self a property * \param value a string * \param fps the frame rate, which may be needed for converting a time string to frame units * \param locale the locale, which may be needed for converting a string to a real number * \param position the frame number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \return false if successful, true to indicate error */ int mlt_property_anim_set_string( mlt_property self, const char *value, double fps, locale_t locale, int position, int length ) { int result; struct mlt_animation_item_s item; item.property = mlt_property_init(); item.frame = position; item.keyframe_type = mlt_keyframe_discrete; mlt_property_set_string( item.property, value ); refresh_animation( self, fps, locale, length ); result = mlt_animation_insert( self->animation, &item ); mlt_animation_interpolate( self->animation ); mlt_property_close( item.property ); return result; } /** Get an object's animation object. * * You might need to call another mlt_property_anim_ function to actually construct * the animation, as this is a simple accessor function. * \public \memberof mlt_property_s * \param self a property * \return the animation object or NULL if there is no animation */ mlt_animation mlt_property_get_animation( mlt_property self ) { return self->animation; } /** Convert a rectangle value into a string. * * Unlike the deprecated mlt_geometry API, the canonical form of a mlt_rect * is a space delimited "x y w h o" even though many kinds of field delimiters * may be used to convert a string to a rectangle. * \private \memberof mlt_property_s * \param rect the rectangle to convert * \param length not used * \return the string representation of a rectangle */ static char* serialise_mlt_rect( mlt_rect *rect, int length ) { char* result = calloc( 1, 100 ); if ( rect->x != DBL_MIN ) sprintf( result + strlen( result ), "%g", rect->x ); if ( rect->y != DBL_MIN ) sprintf( result + strlen( result ), " %g", rect->y ); if ( rect->w != DBL_MIN ) sprintf( result + strlen( result ), " %g", rect->w ); if ( rect->h != DBL_MIN ) sprintf( result + strlen( result ), " %g", rect->h ); if ( rect->o != DBL_MIN ) sprintf( result + strlen( result ), " %g", rect->o ); return result; } /** Set a property to a mlt_rect rectangle. * * \public \memberof mlt_property_s * \param self a property * \param value a rectangle * \return false */ int mlt_property_set_rect( mlt_property self, mlt_rect value ) { pthread_mutex_lock( &self->mutex ); mlt_property_clear( self ); self->types = mlt_prop_rect | mlt_prop_data; self->length = sizeof(value); self->data = calloc( 1, self->length ); memcpy( self->data, &value, self->length ); self->destructor = free; self->serialiser = (mlt_serialiser) serialise_mlt_rect; pthread_mutex_unlock( &self->mutex ); return 0; } /** Get the property as a rectangle. * * You can use any non-numeric character(s) as a field delimiter. * If the number has a '%' immediately following it, the number is divided by * 100 to convert it into a real number. * \public \memberof mlt_property_s * \param self a property * \param locale the locale to use for when converting from a string * \return a rectangle value */ mlt_rect mlt_property_get_rect( mlt_property self, locale_t locale ) { mlt_rect rect = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN }; if ( self->types & mlt_prop_rect ) rect = *( (mlt_rect*) self->data ); else if ( self->types & mlt_prop_double ) rect.x = self->prop_double; else if ( self->types & mlt_prop_int ) rect.x = ( double )self->prop_int; else if ( self->types & mlt_prop_position ) rect.x = ( double )self->prop_position; else if ( self->types & mlt_prop_int64 ) rect.x = ( double )self->prop_int64; else if ( ( self->types & mlt_prop_string ) && self->prop_string ) { //return mlt_property_atof( self->prop_string, fps, locale ); char *value = self->prop_string; char *p = NULL; int count = 0; while ( *value ) { double temp; #if defined(__GLIBC__) || defined(__DARWIN__) if ( locale ) temp = strtod_l( value, &p, locale ); else #endif temp = strtod( value, &p ); if ( p != value ) { if ( p[0] == '%' ) temp /= 100.0; if ( *p ) p ++; switch( count ) { case 0: rect.x = temp; break; case 1: rect.y = temp; break; case 2: rect.w = temp; break; case 3: rect.h = temp; break; case 4: rect.o = temp; break; } } else { p++; } value = p; count ++; } } return rect; } /** Set a property animation keyframe to a rectangle. * * \public \memberof mlt_property_s * \param self a property * \param value a rectangle * \param fps the frame rate, which may be needed for converting a time string to frame units * \param locale the locale, which may be needed for converting a string to a real number * \param position the frame number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \param keyframe_type the interpolation method for this keyframe * \return false if successful, true to indicate error */ int mlt_property_anim_set_rect( mlt_property self, mlt_rect value, double fps, locale_t locale, int position, int length, mlt_keyframe_type keyframe_type ) { int result; struct mlt_animation_item_s item; item.property = mlt_property_init(); item.frame = position; item.keyframe_type = keyframe_type; mlt_property_set_rect( item.property, value ); refresh_animation( self, fps, locale, length ); result = mlt_animation_insert( self->animation, &item ); mlt_animation_interpolate( self->animation ); mlt_property_close( item.property ); return result; } /** Get a rectangle at a frame position. * * \public \memberof mlt_property_s * \param self a property * \param fps the frame rate, which may be needed for converting a time string to frame units * \param locale the locale, which may be needed for converting a string to a real number * \param position the frame number * \param length the maximum number of frames when interpreting negative keyframe times, * <=0 if you don't care or need that * \return the rectangle */ mlt_rect mlt_property_anim_get_rect( mlt_property self, double fps, locale_t locale, int position, int length ) { mlt_rect result; if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) ) { struct mlt_animation_item_s item; item.property = mlt_property_init(); item.property->types = mlt_prop_rect; refresh_animation( self, fps, locale, length ); mlt_animation_get_item( self->animation, &item, position ); result = mlt_property_get_rect( item.property, locale ); mlt_property_close( item.property ); } else { result = mlt_property_get_rect( self, locale ); } return result; } mlt-0.9.0/src/framework/mlt_property.h000066400000000000000000000077511215300731300200160ustar00rootroot00000000000000/** * \file mlt_property.h * \brief Property class declaration * \see mlt_property_s * * Copyright (C) 2003-2013 Ushodaya Enterprises Limited * \author Charles Yates * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_PROPERTY_H_ #define _MLT_PROPERTY_H_ #include "mlt_types.h" #if defined(__FreeBSD__) /* This header has existed since 1994 and defines __FreeBSD_version below. */ #include #endif #if defined(__GLIBC__) || defined(__DARWIN__) || (__FreeBSD_version >= 900506) #include #else typedef void* locale_t; #endif extern mlt_property mlt_property_init( ); extern int mlt_property_set_int( mlt_property self, int value ); extern int mlt_property_set_double( mlt_property self, double value ); extern int mlt_property_set_position( mlt_property self, mlt_position value ); extern int mlt_property_set_int64( mlt_property self, int64_t value ); extern int mlt_property_set_string( mlt_property self, const char *value ); extern int mlt_property_set_data( mlt_property self, void *value, int length, mlt_destructor destructor, mlt_serialiser serialiser ); extern int mlt_property_get_int( mlt_property self, double fps, locale_t ); extern double mlt_property_get_double( mlt_property self, double fps, locale_t ); extern mlt_position mlt_property_get_position( mlt_property self, double fps, locale_t ); extern int64_t mlt_property_get_int64( mlt_property self ); extern char *mlt_property_get_string( mlt_property self ); extern char *mlt_property_get_string_l( mlt_property self, locale_t ); extern void *mlt_property_get_data( mlt_property self, int *length ); extern void mlt_property_close( mlt_property self ); extern void mlt_property_pass( mlt_property self, mlt_property that ); extern char *mlt_property_get_time( mlt_property self, mlt_time_format, double fps, locale_t ); extern int mlt_property_interpolate( mlt_property self, mlt_property points[], double progress, double fps, locale_t locale, mlt_keyframe_type interp ); extern double mlt_property_anim_get_double( mlt_property self, double fps, locale_t locale, int position, int length ); extern int mlt_property_anim_get_int( mlt_property self, double fps, locale_t locale, int position, int length ); extern char* mlt_property_anim_get_string( mlt_property self, double fps, locale_t locale, int position, int length ); extern int mlt_property_anim_set_double( mlt_property self, double value, double fps, locale_t locale, int position, int length, mlt_keyframe_type keyframe_type ); extern int mlt_property_anim_set_int( mlt_property self, int value, double fps, locale_t locale, int position, int length, mlt_keyframe_type keyframe_type ); extern int mlt_property_anim_set_string( mlt_property self, const char *value, double fps, locale_t locale, int position, int length ); extern mlt_animation mlt_property_get_animation( mlt_property self ); extern int mlt_property_set_rect( mlt_property self, mlt_rect value ); extern mlt_rect mlt_property_get_rect( mlt_property self, locale_t locale ); extern int mlt_property_anim_set_rect( mlt_property self, mlt_rect value, double fps, locale_t locale, int position, int length, mlt_keyframe_type keyframe_type ); extern mlt_rect mlt_property_anim_get_rect( mlt_property self, double fps, locale_t locale, int position, int length ); #endif mlt-0.9.0/src/framework/mlt_repository.c000066400000000000000000000350541215300731300203410ustar00rootroot00000000000000/** * \file mlt_repository.c * \brief provides a map between service and shared objects * \see mlt_repository_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_repository.h" #include "mlt_properties.h" #include "mlt_tokeniser.h" #include "mlt_log.h" #include "mlt_factory.h" #include #include #include #include #include #include #include /** the default subdirectory of the datadir for holding presets */ #define PRESETS_DIR "/presets" /** \brief Repository class * * The Repository is a collection of plugin modules and their services and service metadata. * * \extends mlt_properties_s * \properties \p language a cached list of user locales */ struct mlt_repository_s { struct mlt_properties_s parent; /// a list of object files mlt_properties consumers; /// a list of entry points for consumers mlt_properties filters; /// a list of entry points for filters mlt_properties producers; /// a list of entry points for producers mlt_properties transitions; /// a list of entry points for transitions }; /** Construct a new repository. * * \public \memberof mlt_repository_s * \param directory the full path of a directory from which to read modules * \return a new repository or NULL if failed */ mlt_repository mlt_repository_init( const char *directory ) { // Safety check if ( directory == NULL || strcmp( directory, "" ) == 0 ) return NULL; // Construct the repository mlt_repository self = calloc( 1, sizeof( struct mlt_repository_s )); mlt_properties_init( &self->parent, self ); self->consumers = mlt_properties_new(); self->filters = mlt_properties_new(); self->producers = mlt_properties_new(); self->transitions = mlt_properties_new(); // Get the directory list mlt_properties dir = mlt_properties_new(); int count = mlt_properties_dir_list( dir, directory, NULL, 0 ); int i; // Iterate over files for ( i = 0; i < count; i++ ) { int flags = RTLD_NOW; const char *object_name = mlt_properties_get_value( dir, i); // Very temporary hack to allow the quicktime plugins to work // TODO: extend repository to allow this to be used on a case by case basis if ( strstr( object_name, "libmltkino" ) ) flags |= RTLD_GLOBAL; // Open the shared object void *object = dlopen( object_name, flags ); if ( object != NULL ) { // Get the registration function mlt_repository_callback symbol_ptr = dlsym( object, "mlt_register" ); // Call the registration function if ( symbol_ptr != NULL ) { symbol_ptr( self ); // Register the object file for closure mlt_properties_set_data( &self->parent, object_name, object, 0, ( mlt_destructor )dlclose, NULL ); } else { dlclose( object ); } } else if ( strstr( object_name, "libmlt" ) ) { mlt_log( NULL, MLT_LOG_WARNING, "%s: failed to dlopen %s\n (%s)\n", __FUNCTION__, object_name, dlerror() ); } } mlt_properties_close( dir ); return self; } /** Create a properties list for a service holding a function pointer to its constructor function. * * \private \memberof mlt_repository_s * \param symbol a pointer to a function that can create the service. * \return a properties list */ static mlt_properties new_service( void *symbol ) { mlt_properties properties = mlt_properties_new(); mlt_properties_set_data( properties, "symbol", symbol, 0, NULL, NULL ); return properties; } /** Register a service with the repository. * * Typically, this is invoked by a module within its mlt_register(). * * \public \memberof mlt_repository_s * \param self a repository * \param service_type a service class * \param service the name of a service * \param symbol a pointer to a function to create the service */ void mlt_repository_register( mlt_repository self, mlt_service_type service_type, const char *service, mlt_register_callback symbol ) { // Add the entry point to the corresponding service list switch ( service_type ) { case consumer_type: mlt_properties_set_data( self->consumers, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); break; case filter_type: mlt_properties_set_data( self->filters, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); break; case producer_type: mlt_properties_set_data( self->producers, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); break; case transition_type: mlt_properties_set_data( self->transitions, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); break; default: break; } } /** Get the repository properties for particular service class. * * \private \memberof mlt_repository_s * \param self a repository * \param type a service class * \param service the name of a service * \return a properties list or NULL if error */ static mlt_properties get_service_properties( mlt_repository self, mlt_service_type type, const char *service ) { mlt_properties service_properties = NULL; // Get the entry point from the corresponding service list switch ( type ) { case consumer_type: service_properties = mlt_properties_get_data( self->consumers, service, NULL ); break; case filter_type: service_properties = mlt_properties_get_data( self->filters, service, NULL ); break; case producer_type: service_properties = mlt_properties_get_data( self->producers, service, NULL ); break; case transition_type: service_properties = mlt_properties_get_data( self->transitions, service, NULL ); break; default: break; } return service_properties; } /** Construct a new instance of a service. * * \public \memberof mlt_repository_s * \param self a repository * \param profile a \p mlt_profile to give the service * \param type a service class * \param service the name of the service * \param input an optional argument to the service constructor */ void *mlt_repository_create( mlt_repository self, mlt_profile profile, mlt_service_type type, const char *service, const void *input ) { mlt_properties properties = get_service_properties( self, type, service ); if ( properties != NULL ) { mlt_register_callback symbol_ptr = mlt_properties_get_data( properties, "symbol", NULL ); // Construct the service return ( symbol_ptr != NULL ) ? symbol_ptr( profile, type, service, input ) : NULL; } return NULL; } /** Destroy a repository and free its resources. * * \public \memberof mlt_repository_s * \param self a repository */ void mlt_repository_close( mlt_repository self ) { mlt_properties_close( self->consumers ); mlt_properties_close( self->filters ); mlt_properties_close( self->producers ); mlt_properties_close( self->transitions ); mlt_properties_close( &self->parent ); free( self ); } /** Get the list of registered consumers. * * \public \memberof mlt_repository_s * \param self a repository * \return a properties list containing all of the consumers */ mlt_properties mlt_repository_consumers( mlt_repository self ) { return self->consumers; } /** Get the list of registered filters. * * \public \memberof mlt_repository_s * \param self a repository * \return a properties list of all of the filters */ mlt_properties mlt_repository_filters( mlt_repository self ) { return self->filters; } /** Get the list of registered producers. * * \public \memberof mlt_repository_s * \param self a repository * \return a properties list of all of the producers */ mlt_properties mlt_repository_producers( mlt_repository self ) { return self->producers; } /** Get the list of registered transitions. * * \public \memberof mlt_repository_s * \param self a repository * \return a properties list of all of the transitions */ mlt_properties mlt_repository_transitions( mlt_repository self ) { return self->transitions; } /** Register the metadata for a service. * * IMPORTANT: mlt_repository will take responsibility for deallocating the metadata properties * that you supply! * * \public \memberof mlt_repository_s * \param self a repository * \param type a service class * \param service the name of a service * \param callback the pointer to a function that can supply metadata * \param callback_data an opaque user data pointer to be supplied on the callback */ void mlt_repository_register_metadata( mlt_repository self, mlt_service_type type, const char *service, mlt_metadata_callback callback, void *callback_data ) { mlt_properties service_properties = get_service_properties( self, type, service ); mlt_properties_set_data( service_properties, "metadata_cb", callback, 0, NULL, NULL ); mlt_properties_set_data( service_properties, "metadata_cb_data", callback_data, 0, NULL, NULL ); } /** Get the metadata about a service. * * Returns NULL if service or its metadata are unavailable. * * \public \memberof mlt_repository_s * \param self a repository * \param type a service class * \param service the name of a service * \return the service metadata as a structured properties list */ mlt_properties mlt_repository_metadata( mlt_repository self, mlt_service_type type, const char *service ) { mlt_properties metadata = NULL; mlt_properties properties = get_service_properties( self, type, service ); // If this is a valid service if ( properties ) { // Lookup cached metadata metadata = mlt_properties_get_data( properties, "metadata", NULL ); if ( ! metadata ) { // Not cached, so get the registered metadata callback function mlt_metadata_callback callback = mlt_properties_get_data( properties, "metadata_cb", NULL ); // If a metadata callback function is registered if ( callback ) { // Fetch the callback data arg void *data = mlt_properties_get_data( properties, "metadata_cb_data", NULL ); // Fetch the metadata through the callback metadata = callback( type, service, data ); // Cache the metadata if ( metadata ) // Include dellocation and serialisation mlt_properties_set_data( properties, "metadata", metadata, 0, ( mlt_destructor )mlt_properties_close, ( mlt_serialiser )mlt_properties_serialise_yaml ); } } } return metadata; } /** Try to determine the locale from some commonly used environment variables. * * \private \memberof mlt_repository_s * \return a string containing the locale id or NULL if unknown */ static char *getenv_locale() { char *s = getenv( "LANGUAGE" ); if ( s && s[0] ) return s; s = getenv( "LC_ALL" ); if ( s && s[0] ) return s; s = getenv( "LC_MESSAGES" ); if ( s && s[0] ) return s; s = getenv( "LANG" ); if ( s && s[0] ) return s; return NULL; } /** Return a list of user-preferred language codes taken from environment variables. * * A module should use this to locate a localized YAML Tiny file from which to build * its metadata strucutured properties. * * \public \memberof mlt_repository_s * \param self a repository * \return a properties list that is a list (not a map) of locales, defaults to "en" if not * overridden by environment variables, in order: LANGUAGE, LC_ALL, LC_MESSAGES, LANG */ mlt_properties mlt_repository_languages( mlt_repository self ) { mlt_properties languages = mlt_properties_get_data( &self->parent, "languages", NULL ); if ( languages ) return languages; languages = mlt_properties_new(); char *locale = getenv_locale(); if ( locale ) { locale = strdup( locale ); mlt_tokeniser tokeniser = mlt_tokeniser_init(); int count = mlt_tokeniser_parse_new( tokeniser, locale, ":" ); if ( count ) { int i; for ( i = 0; i < count; i++ ) { char *locale = mlt_tokeniser_get_string( tokeniser, i ); if ( strcmp( locale, "C" ) == 0 || strcmp( locale, "POSIX" ) == 0 ) locale = "en"; else if ( strlen( locale ) > 2 ) locale[2] = 0; char string[21]; snprintf( string, sizeof(string), "%d", i ); mlt_properties_set( languages, string, locale ); } } else { mlt_properties_set( languages, "0", "en" ); } free( locale ); mlt_tokeniser_close( tokeniser ); } else { mlt_properties_set( languages, "0", "en" ); } mlt_properties_set_data( &self->parent, "languages", languages, 0, ( mlt_destructor )mlt_properties_close, NULL ); return languages; } static void list_presets( mlt_properties properties, const char *path, const char *dirname ) { DIR *dir = opendir( dirname ); if ( dir ) { struct dirent *de = readdir( dir ); char fullname[ PATH_MAX ]; while ( de != NULL ) { if ( de->d_name[0] != '.' && de->d_name[strlen( de->d_name ) - 1] != '~' ) { struct stat info; snprintf( fullname, sizeof(fullname), "%s/%s", dirname, de->d_name ); stat( fullname, &info ); if ( S_ISDIR( info.st_mode ) ) { // recurse into subdirectories char sub[ PATH_MAX ]; if ( path ) snprintf( sub, sizeof(sub), "%s/%s", path, de->d_name ); else strncpy( sub, de->d_name, sizeof(sub) ); list_presets( properties, sub, fullname ); } else { // load the preset mlt_properties preset = mlt_properties_load( fullname ); if ( preset && mlt_properties_count( preset ) ) { snprintf( fullname, 1024, "%s/%s", path, de->d_name ); mlt_properties_set_data( properties, fullname, preset, 0, (mlt_destructor) mlt_properties_close, NULL ); } } } de = readdir( dir ); } closedir( dir ); } } /** Get the list of presets. * * \public \memberof mlt_repository_s * \return a properties list of all the presets */ mlt_properties mlt_repository_presets( ) { mlt_properties result = mlt_properties_new(); char *path = getenv( "MLT_PRESETS_PATH" ); if ( path ) { path = strdup( path ); } else { path = malloc( strlen( mlt_environment( "MLT_DATA" ) ) + strlen( PRESETS_DIR ) + 1 ); strcpy( path, mlt_environment( "MLT_DATA" ) ); strcat( path, PRESETS_DIR ); } list_presets( result, NULL, path ); free( path ); return result; } mlt-0.9.0/src/framework/mlt_repository.h000066400000000000000000000067161215300731300203510ustar00rootroot00000000000000/** * \file mlt_repository.h * \brief provides a map between service and shared objects * \see mlt_repository_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * \author Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_REPOSITORY_H_ #define _MLT_REPOSITORY_H_ #include "mlt_types.h" #include "mlt_profile.h" /** This callback is the main entry point into a module, which must be exported * with the symbol "mlt_register". * * Inside the callback, the module registers the additional callbacks below. */ typedef void ( *mlt_repository_callback )( mlt_repository ); /** The callback function that modules implement to construct a service. */ typedef void *( *mlt_register_callback )( mlt_profile, mlt_service_type, const char * /* service name */, const void * /* arg */ ); /** The callback function that modules implement to supply metadata as a properties list. */ typedef mlt_properties ( *mlt_metadata_callback )( mlt_service_type, const char * /* service name */, void * /* callback_data */ ); /** A convenience macro to create an entry point for service registration. */ #define MLT_REPOSITORY void mlt_register( mlt_repository repository ) /** A convenience macro to a register service in a more declarative manner. */ #define MLT_REGISTER( type, service, symbol ) ( mlt_repository_register( repository, (type), (service), ( mlt_register_callback )(symbol) ) ) /** A convenience macro to a register metadata in a more declarative manner. */ #define MLT_REGISTER_METADATA( type, service, callback, data ) ( mlt_repository_register_metadata( repository, (type), (service), ( mlt_metadata_callback )(callback), (data) ) ) extern mlt_repository mlt_repository_init( const char *directory ); extern void mlt_repository_register( mlt_repository self, mlt_service_type service_type, const char *service, mlt_register_callback ); extern void *mlt_repository_create( mlt_repository self, mlt_profile profile, mlt_service_type type, const char *service, const void *arg ); extern void mlt_repository_close( mlt_repository self ); extern mlt_properties mlt_repository_consumers( mlt_repository self ); extern mlt_properties mlt_repository_filters( mlt_repository self ); extern mlt_properties mlt_repository_producers( mlt_repository self ); extern mlt_properties mlt_repository_transitions( mlt_repository self ); extern void mlt_repository_register_metadata( mlt_repository self, mlt_service_type type, const char *service, mlt_metadata_callback, void *callback_data ); extern mlt_properties mlt_repository_metadata( mlt_repository self, mlt_service_type type, const char *service ); extern mlt_properties mlt_repository_languages( mlt_repository self ); extern mlt_properties mlt_repository_presets( ); #endif mlt-0.9.0/src/framework/mlt_service.c000066400000000000000000000571661215300731300175720ustar00rootroot00000000000000/** * \file mlt_service.c * \brief interface definition for all service classes * \see mlt_service_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_service.h" #include "mlt_filter.h" #include "mlt_frame.h" #include "mlt_cache.h" #include "mlt_factory.h" #include "mlt_log.h" #include "mlt_producer.h" #include #include #include #include /* IMPORTANT NOTES The base service implements a null frame producing service - as such, it is functional without extension and will produce test cards frames and PAL sized audio frames. PLEASE DO NOT CHANGE THIS BEHAVIOUR!!! OVERRIDE THE METHODS THAT CONTROL THIS IN EXTENDING CLASSES. */ /** \brief private service definition */ typedef struct { int size; int count; mlt_service *in; mlt_service out; int filter_count; int filter_size; mlt_filter *filters; pthread_mutex_t mutex; } mlt_service_base; /* Private methods */ static void mlt_service_disconnect( mlt_service self ); static void mlt_service_connect( mlt_service self, mlt_service that ); static int service_get_frame( mlt_service self, mlt_frame_ptr frame, int index ); static void mlt_service_property_changed( mlt_listener, mlt_properties owner, mlt_service self, void **args ); /** Initialize a service. * * \public \memberof mlt_service_s * \param self the service structure to initialize * \param child pointer to the child object for the subclass * \return true if there was an error */ int mlt_service_init( mlt_service self, void *child ) { int error = 0; // Initialise everything to NULL memset( self, 0, sizeof( struct mlt_service_s ) ); // Assign the child self->child = child; // Generate local space self->local = calloc( 1, sizeof( mlt_service_base ) ); // Associate the methods self->get_frame = service_get_frame; // Initialise the properties error = mlt_properties_init( &self->parent, self ); if ( error == 0 ) { self->parent.close = ( mlt_destructor )mlt_service_close; self->parent.close_object = self; mlt_events_init( &self->parent ); mlt_events_register( &self->parent, "service-changed", NULL ); mlt_events_register( &self->parent, "property-changed", ( mlt_transmitter )mlt_service_property_changed ); pthread_mutex_init( &( ( mlt_service_base * )self->local )->mutex, NULL ); } return error; } /** The transmitter for property changes. * * Invokes the listener. * * \private \memberof mlt_service_s * \param listener a function pointer that will be invoked * \param owner a properties list that will be passed to \p listener * \param self a service that will be passed to \p listener * \param args an array of pointers - the first entry is passed as a string to \p listener */ static void mlt_service_property_changed( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) { if ( listener != NULL ) listener( owner, self, ( char * )args[ 0 ] ); } /** Acquire a mutual exclusion lock on this service. * * \public \memberof mlt_service_s * \param self the service to lock */ void mlt_service_lock( mlt_service self ) { if ( self != NULL ) pthread_mutex_lock( &( ( mlt_service_base * )self->local )->mutex ); } /** Release a mutual exclusion lock on this service. * * \public \memberof mlt_service_s * \param self the service to unlock */ void mlt_service_unlock( mlt_service self ) { if ( self != NULL ) pthread_mutex_unlock( &( ( mlt_service_base * )self->local )->mutex ); } /** Identify the subclass of the service. * * \public \memberof mlt_service_s * \param self a service * \return the subclass */ mlt_service_type mlt_service_identify( mlt_service self ) { mlt_service_type type = invalid_type; if ( self != NULL ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( self ); char *mlt_type = mlt_properties_get( properties, "mlt_type" ); char *resource = mlt_properties_get( properties, "resource" ); if ( mlt_type == NULL ) type = unknown_type; else if (resource != NULL && !strcmp( resource, "" ) ) type = playlist_type; else if (resource != NULL && !strcmp( resource, "" ) ) type = tractor_type; else if (resource != NULL && !strcmp( resource, "" ) ) type = multitrack_type; else if ( !strcmp( mlt_type, "producer" ) ) type = producer_type; else if ( !strcmp( mlt_type, "filter" ) ) type = filter_type; else if ( !strcmp( mlt_type, "transition" ) ) type = transition_type; else if ( !strcmp( mlt_type, "consumer" ) ) type = consumer_type; else type = unknown_type; } return type; } /** Connect a producer to the service. * * \public \memberof mlt_service_s * \param self a service * \param producer a producer * \param index which of potentially multiple producers to this service (0 based) * \return > 0 warning, == 0 success, < 0 serious error, * 1 = this service does not accept input, * 2 = the producer is invalid, * 3 = the producer is already registered with self consumer */ int mlt_service_connect_producer( mlt_service self, mlt_service producer, int index ) { int i = 0; // Get the service base mlt_service_base *base = self->local; // Special case 'track' index - only works for last filter(s) in a particular chain // but allows a filter to apply to the output frame regardless of which track it comes from if ( index == -1 ) index = 0; // Check if the producer is already registered with this service for ( i = 0; i < base->count; i ++ ) if ( base->in[ i ] == producer ) return 3; // Allocate space if ( index >= base->size ) { int new_size = base->size + index + 10; base->in = realloc( base->in, new_size * sizeof( mlt_service ) ); if ( base->in != NULL ) { for ( i = base->size; i < new_size; i ++ ) base->in[ i ] = NULL; base->size = new_size; } } // If we have space, assign the input if ( base->in != NULL && index >= 0 && index < base->size ) { // Get the current service mlt_service current = base->in[ index ]; // Increment the reference count on this producer if ( producer != NULL ) mlt_properties_inc_ref( MLT_SERVICE_PROPERTIES( producer ) ); // Now we disconnect the producer service from its consumer mlt_service_disconnect( producer ); // Add the service to index specified base->in[ index ] = producer; // Determine the number of active tracks if ( index >= base->count ) base->count = index + 1; // Now we connect the producer to its connected consumer mlt_service_connect( producer, self ); // Close the current service mlt_service_close( current ); // Inform caller that all went well return 0; } else { return -1; } } /** Disconnect a service from its consumer. * * \private \memberof mlt_service_s * \param self a service */ static void mlt_service_disconnect( mlt_service self ) { if ( self != NULL ) { // Get the service base mlt_service_base *base = self->local; // Disconnect base->out = NULL; } } /** Obtain the consumer a service is connected to. * * \public \memberof mlt_service_s * \param self a service * \return the consumer */ mlt_service mlt_service_consumer( mlt_service self ) { // Get the service base mlt_service_base *base = self->local; // Return the connected consumer return base->out; } /** Obtain the producer a service is connected to. * * \public \memberof mlt_service_s * \param self a service * \return the last-most producer */ mlt_service mlt_service_producer( mlt_service self ) { // Get the service base mlt_service_base *base = self->local; // Return the connected producer return base->count > 0 ? base->in[ base->count - 1 ] : NULL; } /** Associate a service to a consumer. * * Overwrites connection to any existing consumer. * \private \memberof mlt_service_s * \param self a service * \param that a consumer */ static void mlt_service_connect( mlt_service self, mlt_service that ) { if ( self != NULL ) { // Get the service base mlt_service_base *base = self->local; // There's a bit more required here... base->out = that; } } /** Get the first connected producer. * * \public \memberof mlt_service_s * \param self a service * \return the first producer */ mlt_service mlt_service_get_producer( mlt_service self ) { mlt_service producer = NULL; // Get the service base mlt_service_base *base = self->local; if ( base->in != NULL ) producer = base->in[ 0 ]; return producer; } /** Default implementation of the get_frame virtual function. * * \private \memberof mlt_service_s * \param self a service * \param[out] frame a frame by reference * \param index as determined by the producer * \return false */ static int service_get_frame( mlt_service self, mlt_frame_ptr frame, int index ) { mlt_service_base *base = self->local; if ( index < base->count ) { mlt_service producer = base->in[ index ]; if ( producer != NULL ) return mlt_service_get_frame( producer, frame, index ); } *frame = mlt_frame_init( self ); return 0; } /** Return the properties object. * * \public \memberof mlt_service_s * \param self a service * \return the properties */ mlt_properties mlt_service_properties( mlt_service self ) { return self != NULL ? &self->parent : NULL; } /** Recursively apply attached filters. * * \public \memberof mlt_service_s * \param self a service * \param frame a frame * \param index used to track depth of recursion, top caller should supply 0 */ void mlt_service_apply_filters( mlt_service self, mlt_frame frame, int index ) { int i; mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); mlt_properties service_properties = MLT_SERVICE_PROPERTIES( self ); mlt_service_base *base = self->local; mlt_position position = mlt_frame_get_position( frame ); mlt_position self_in = mlt_properties_get_position( service_properties, "in" ); mlt_position self_out = mlt_properties_get_position( service_properties, "out" ); if ( index == 0 || mlt_properties_get_int( service_properties, "_filter_private" ) == 0 ) { // Process the frame with the attached filters for ( i = 0; i < base->filter_count; i ++ ) { if ( base->filters[ i ] != NULL ) { mlt_position in = mlt_filter_get_in( base->filters[ i ] ); mlt_position out = mlt_filter_get_out( base->filters[ i ] ); int disable = mlt_properties_get_int( MLT_FILTER_PROPERTIES( base->filters[ i ] ), "disable" ); if ( !disable && ( ( in == 0 && out == 0 ) || ( position >= in && ( position <= out || out == 0 ) ) ) ) { mlt_properties_set_position( frame_properties, "in", in == 0 ? self_in : in ); mlt_properties_set_position( frame_properties, "out", out == 0 ? self_out : out ); mlt_filter_process( base->filters[ i ], frame ); mlt_service_apply_filters( MLT_FILTER_SERVICE( base->filters[ i ] ), frame, index + 1 ); } } } } } /** Obtain a frame. * * \public \memberof mlt_service_s * \param self a service * \param[out] frame a frame by reference * \param index as determined by the producer * \return true if there was an error */ int mlt_service_get_frame( mlt_service self, mlt_frame_ptr frame, int index ) { int result = 0; // Lock the service mlt_service_lock( self ); // Ensure that the frame is NULL *frame = NULL; // Only process if we have a valid service if ( self != NULL && self->get_frame != NULL ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( self ); mlt_position in = mlt_properties_get_position( properties, "in" ); mlt_position out = mlt_properties_get_position( properties, "out" ); mlt_position position = mlt_service_identify( self ) == producer_type ? mlt_producer_position( MLT_PRODUCER( self ) ) : -1; result = self->get_frame( self, frame, index ); if ( result == 0 ) { mlt_properties_inc_ref( properties ); properties = MLT_FRAME_PROPERTIES( *frame ); if ( in >=0 && out > 0 ) { mlt_properties_set_position( properties, "in", in ); mlt_properties_set_position( properties, "out", out ); } mlt_service_apply_filters( self, *frame, 1 ); mlt_deque_push_back( MLT_FRAME_SERVICE_STACK( *frame ), self ); if ( mlt_service_identify( self ) == producer_type && mlt_properties_get_int( MLT_SERVICE_PROPERTIES( self ), "_need_previous_next" ) ) { // Save the new position from self->get_frame mlt_position new_position = mlt_producer_position( MLT_PRODUCER( self ) ); // Get the preceding frame, unfiltered mlt_frame previous_frame; mlt_producer_seek( MLT_PRODUCER(self), position - 1 ); result = self->get_frame( self, &previous_frame, index ); if ( !result ) mlt_properties_set_data( properties, "previous frame", previous_frame, 0, ( mlt_destructor ) mlt_frame_close, NULL ); // Get the following frame, unfiltered mlt_frame next_frame; mlt_producer_seek( MLT_PRODUCER(self), position + 1 ); result = self->get_frame( self, &next_frame, index ); if ( !result ) { mlt_properties_set_data( properties, "next frame", next_frame, 0, ( mlt_destructor ) mlt_frame_close, NULL ); } // Restore the new position mlt_producer_seek( MLT_PRODUCER(self), new_position ); } } } // Make sure we return a frame if ( *frame == NULL ) *frame = mlt_frame_init( self ); // Unlock the service mlt_service_unlock( self ); return result; } /** The service-changed event handler. * * \private \memberof mlt_service_s * \param owner ignored * \param self the service on which the "service-changed" event is fired */ static void mlt_service_filter_changed( mlt_service owner, mlt_service self ) { mlt_events_fire( MLT_SERVICE_PROPERTIES( self ), "service-changed", NULL ); } /** The property-changed event handler. * * \private \memberof mlt_service_s * \param owner ignored * \param self the service on which the "property-changed" event is fired * \param name the name of the property that changed */ static void mlt_service_filter_property_changed( mlt_service owner, mlt_service self, char *name ) { mlt_events_fire( MLT_SERVICE_PROPERTIES( self ), "property-changed", name, NULL ); } /** Attach a filter. * * \public \memberof mlt_service_s * \param self a service * \param filter the filter to attach * \return true if there was an error */ int mlt_service_attach( mlt_service self, mlt_filter filter ) { int error = self == NULL || filter == NULL; if ( error == 0 ) { int i = 0; mlt_properties properties = MLT_SERVICE_PROPERTIES( self ); mlt_service_base *base = self->local; for ( i = 0; error == 0 && i < base->filter_count; i ++ ) if ( base->filters[ i ] == filter ) error = 1; if ( error == 0 ) { if ( base->filter_count == base->filter_size ) { base->filter_size += 10; base->filters = realloc( base->filters, base->filter_size * sizeof( mlt_filter ) ); } if ( base->filters != NULL ) { mlt_properties props = MLT_FILTER_PROPERTIES( filter ); mlt_properties_inc_ref( MLT_FILTER_PROPERTIES( filter ) ); base->filters[ base->filter_count ++ ] = filter; mlt_properties_set_data( props, "service", self, 0, NULL, NULL ); mlt_events_fire( properties, "service-changed", NULL ); mlt_events_fire( props, "service-changed", NULL ); mlt_events_listen( props, self, "service-changed", ( mlt_listener )mlt_service_filter_changed ); mlt_events_listen( props, self, "property-changed", ( mlt_listener )mlt_service_filter_property_changed ); } else { error = 2; } } } return error; } /** Detach a filter. * * \public \memberof mlt_service_s * \param self a service * \param filter the filter to detach * \return true if there was an error */ int mlt_service_detach( mlt_service self, mlt_filter filter ) { int error = self == NULL || filter == NULL; if ( error == 0 ) { int i = 0; mlt_service_base *base = self->local; mlt_properties properties = MLT_SERVICE_PROPERTIES( self ); for ( i = 0; i < base->filter_count; i ++ ) if ( base->filters[ i ] == filter ) break; if ( i < base->filter_count ) { base->filters[ i ] = NULL; for ( i ++ ; i < base->filter_count; i ++ ) base->filters[ i - 1 ] = base->filters[ i ]; base->filter_count --; mlt_events_disconnect( MLT_FILTER_PROPERTIES( filter ), self ); mlt_filter_close( filter ); mlt_events_fire( properties, "service-changed", NULL ); } } return error; } /** Get the number of filters attached. * * \public \memberof mlt_service_s * \param self a service * \return the number of attached filters or -1 if there was an error */ int mlt_service_filter_count( mlt_service self ) { int result = -1; if ( self ) { mlt_service_base *base = self->local; result = base->filter_count; } return result; } /** Reorder the attached filters. * * \public \memberof mlt_service_s * \param self a service * \param from the current index value of the filter to move * \param to the new index value for the filter specified in \p from * \return true if there was an error */ int mlt_service_move_filter( mlt_service self, int from, int to ) { int error = -1; if ( self ) { mlt_service_base *base = self->local; if ( from < 0 ) from = 0; if ( from >= base->filter_count ) from = base->filter_count - 1; if ( to < 0 ) to = 0; if ( to >= base->filter_count ) to = base->filter_count - 1; if ( from != to && base->filter_count > 1 ) { mlt_filter filter = base->filters[from]; int i; if ( from > to ) { for ( i = from; i > to; i-- ) base->filters[i] = base->filters[i - 1]; } else { for ( i = from; i < to; i++ ) base->filters[i] = base->filters[i + 1]; } base->filters[to] = filter; mlt_events_fire( MLT_SERVICE_PROPERTIES(self), "service-changed", NULL ); error = 0; } } return error; } /** Retrieve an attached filter. * * \public \memberof mlt_service_s * \param self a service * \param index which one of potentially multiple filters * \return the filter or null if there was an error */ mlt_filter mlt_service_filter( mlt_service self, int index ) { mlt_filter filter = NULL; if ( self != NULL ) { mlt_service_base *base = self->local; if ( index >= 0 && index < base->filter_count ) filter = base->filters[ index ]; } return filter; } /** Retrieve the profile. * * \public \memberof mlt_service_s * \param self a service * \return the profile */ mlt_profile mlt_service_profile( mlt_service self ) { return self? mlt_properties_get_data( MLT_SERVICE_PROPERTIES( self ), "_profile", NULL ) : NULL; } /** Set the profile for a service. * * \public \memberof mlt_service_s * \param self a service * \param profile the profile to set onto the service */ void mlt_service_set_profile( mlt_service self, mlt_profile profile ) { mlt_properties_set_data( MLT_SERVICE_PROPERTIES( self ), "_profile", profile, 0, NULL, NULL ); } /** Destroy a service. * * \public \memberof mlt_service_s * \param self the service to destroy */ void mlt_service_close( mlt_service self ) { if ( self != NULL && mlt_properties_dec_ref( MLT_SERVICE_PROPERTIES( self ) ) <= 0 ) { if ( self->close != NULL ) { self->close( self->close_object ); } else { mlt_service_base *base = self->local; int i = 0; int count = base->filter_count; mlt_events_block( MLT_SERVICE_PROPERTIES( self ), self ); while( count -- ) mlt_service_detach( self, base->filters[ 0 ] ); free( base->filters ); for ( i = 0; i < base->count; i ++ ) if ( base->in[ i ] != NULL ) mlt_service_close( base->in[ i ] ); self->parent.close = NULL; free( base->in ); pthread_mutex_destroy( &base->mutex ); free( base ); mlt_properties_close( &self->parent ); } } } /** Release a service's cache items. * * \private \memberof mlt_service_s * \param self a service */ void mlt_service_cache_purge( mlt_service self ) { mlt_properties caches = mlt_properties_get_data( mlt_global_properties(), "caches", NULL ); if ( caches ) { int i = mlt_properties_count( caches ); while ( i-- ) { mlt_cache_purge( mlt_properties_get_data_at( caches, i, NULL ), self ); mlt_properties_set_data( mlt_global_properties(), mlt_properties_get_name( caches, i ), NULL, 0, NULL, NULL ); } } } /** Lookup the cache object for a service. * * \private \memberof mlt_service_s * \param self a service * \param name a name for the object * \return a cache */ static mlt_cache get_cache( mlt_service self, const char *name ) { mlt_cache result = NULL; mlt_properties caches = mlt_properties_get_data( mlt_global_properties(), "caches", NULL ); if ( !caches ) { caches = mlt_properties_new(); mlt_properties_set_data( mlt_global_properties(), "caches", caches, 0, ( mlt_destructor )mlt_properties_close, NULL ); } if ( caches ) { result = mlt_properties_get_data( caches, name, NULL ); if ( !result ) { result = mlt_cache_init(); mlt_properties_set_data( caches, name, result, 0, ( mlt_destructor )mlt_cache_close, NULL ); } } return result; } /** Put an object into a service's cache. * * \public \memberof mlt_service_s * \param self a service * \param name a name for the object that is unique to the service class, but not to the instance * \param data an opaque pointer to the object to put into the cache * \param size the number of bytes pointed to by data * \param destructor a function that releases the data */ void mlt_service_cache_put( mlt_service self, const char *name, void* data, int size, mlt_destructor destructor ) { mlt_log( self, MLT_LOG_DEBUG, "%s: name %s object %p data %p\n", __FUNCTION__, name, self, data ); mlt_cache cache = get_cache( self, name ); if ( cache ) mlt_cache_put( cache, self, data, size, destructor ); } /** Get an object from a service's cache. * * \public \memberof mlt_service_s * \param self a service * \param name a name for the object that is unique to the service class, but not to the instance * \return a cache item or NULL if an object is not found * \see mlt_cache_item_data */ mlt_cache_item mlt_service_cache_get( mlt_service self, const char *name ) { mlt_log( self, MLT_LOG_DEBUG, "%s: name %s object %p\n", __FUNCTION__, name, self ); mlt_cache_item result = NULL; mlt_cache cache = get_cache( self, name ); if ( cache ) result = mlt_cache_get( cache, self ); return result; } /** Set the number of items to cache for the named cache. * * \public \memberof mlt_service_s * \param self a service * \param name a name for the object that is unique to the service class, but not to the instance * \param size the number of items to cache */ void mlt_service_cache_set_size( mlt_service self, const char *name, int size ) { mlt_cache cache = get_cache( self, name ); if ( cache ) mlt_cache_set_size( cache, size ); } /** Get the current maximum size of the named cache. * * \public \memberof mlt_service_s * \param self a service * \param name a name for the object that is unique to the service class, but not to the instance * \return the current maximum number of items to cache or zero if there is an error */ int mlt_service_cache_get_size( mlt_service self, const char *name ) { mlt_cache cache = get_cache( self, name ); if ( cache ) return mlt_cache_get_size( cache ); else return 0; } mlt-0.9.0/src/framework/mlt_service.h000066400000000000000000000122121215300731300175560ustar00rootroot00000000000000/** * \file mlt_service.h * \brief interface declaration for all service classes * \see mlt_service_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_SERVICE_H_ #define _MLT_SERVICE_H_ #include "mlt_properties.h" #include "mlt_types.h" /** \brief Service abstract base class * * \extends mlt_properties * The service is the base class for all of the interesting classes and * plugins for MLT. A service can have multiple inputs connections to * other services called its "producers" but only a single output to another * service called its "consumer." A service that has both producer and * consumer connections is called a filter. Any service can have zero or more * filters "attached" to it. We call any collection of services and their * connections a "service network," which is similar to what DirectShow calls * a filter graph or what gstreamer calls an element pipeline. * * \event \em service-changed a filter was attached or detached or a transition was connected or disconnected * \event \em property-changed * \properties \em mlt_type identifies the subclass * \properties \em _mlt_service_hidden a flag that indicates whether to hide the mlt_service * \properties \em mlt_service is the name of the implementation of the service * \properties \em resource is either the stream identifier or grandchild-class * \properties \em in when to start, what is started is service-specific * \properties \em out when to stop * \properties \em _filter_private Set this on a service to ensure that attached filters are handled privately. * See modules/core/filter_region.c and modules/core/filter_watermark.c for examples. * \properties \em disable Set this on a filter to disable it while keeping it in the object model. * \properties \em _profile stores the mlt_profile for a service * \properties \em _unique_id is a unique identifier * \properties \em _need_previous_next boolean that instructs producers to get * preceding and following frames inside of \p mlt_service_get_frame */ struct mlt_service_s { struct mlt_properties_s parent; /**< \private A service extends properties. */ /** Get a frame of data (virtual function). * * \param mlt_producer a producer * \param mlt_frame_ptr a frame pointer by reference * \param int an index * \return true if there was an error */ int ( *get_frame )( mlt_service self, mlt_frame_ptr frame, int index ); /** the destructor virtual function */ mlt_destructor close; void *close_object; /**< the object supplied to the close virtual function */ void *local; /**< \private instance object */ void *child; /**< \private the object of a subclass */ }; #define MLT_SERVICE_PROPERTIES( service ) ( &( service )->parent ) extern int mlt_service_init( mlt_service self, void *child ); extern void mlt_service_lock( mlt_service self ); extern void mlt_service_unlock( mlt_service self ); extern mlt_service_type mlt_service_identify( mlt_service self ); extern int mlt_service_connect_producer( mlt_service self, mlt_service producer, int index ); extern mlt_service mlt_service_get_producer( mlt_service self ); extern int mlt_service_get_frame( mlt_service self, mlt_frame_ptr frame, int index ); extern mlt_properties mlt_service_properties( mlt_service self ); extern mlt_service mlt_service_consumer( mlt_service self ); extern mlt_service mlt_service_producer( mlt_service self ); extern int mlt_service_attach( mlt_service self, mlt_filter filter ); extern int mlt_service_detach( mlt_service self, mlt_filter filter ); extern void mlt_service_apply_filters( mlt_service self, mlt_frame frame, int index ); extern int mlt_service_filter_count( mlt_service self ); extern int mlt_service_move_filter( mlt_service self, int from, int to ); extern mlt_filter mlt_service_filter( mlt_service self, int index ); extern mlt_profile mlt_service_profile( mlt_service self ); extern void mlt_service_set_profile( mlt_service self, mlt_profile profile ); extern void mlt_service_close( mlt_service self ); extern void mlt_service_cache_put( mlt_service self, const char *name, void* data, int size, mlt_destructor destructor ); extern mlt_cache_item mlt_service_cache_get( mlt_service self, const char *name ); extern void mlt_service_cache_set_size( mlt_service self, const char *name, int size ); extern int mlt_service_cache_get_size( mlt_service self, const char *name ); extern void mlt_service_cache_purge( mlt_service self ); #endif mlt-0.9.0/src/framework/mlt_tokeniser.c000066400000000000000000000074111215300731300201210ustar00rootroot00000000000000/** * \file mlt_tokeniser.c * \brief string tokeniser * \see mlt_tokeniser_s * * Copyright (C) 2002-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* System header files */ #include #include /* Application header files */ #include "mlt_tokeniser.h" /** Initialise a tokeniser. */ mlt_tokeniser mlt_tokeniser_init( ) { return calloc( 1, sizeof( mlt_tokeniser_t ) ); } /** Clear the tokeniser. */ static void mlt_tokeniser_clear( mlt_tokeniser tokeniser ) { int index = 0; for ( index = 0; index < tokeniser->count; index ++ ) free( tokeniser->tokens[ index ] ); tokeniser->count = 0; free( tokeniser->input ); tokeniser->input = NULL; } /** Append a string to the tokeniser. */ static int mlt_tokeniser_append( mlt_tokeniser tokeniser, char *token ) { int error = 0; if ( tokeniser->count == tokeniser->size ) { tokeniser->size += 20; tokeniser->tokens = realloc( tokeniser->tokens, tokeniser->size * sizeof( char * ) ); } if ( tokeniser->tokens != NULL ) { tokeniser->tokens[ tokeniser->count ++ ] = strdup( token ); } else { tokeniser->count = 0; error = -1; } return error; } /** Parse a string by splitting on the delimiter provided. */ int mlt_tokeniser_parse_new( mlt_tokeniser tokeniser, char *string, const char *delimiter ) { int count = 0; int length = strlen( string ); int delimiter_size = strlen( delimiter ); int index = 0; char *token = strdup( string ); mlt_tokeniser_clear( tokeniser ); tokeniser->input = strdup( string ); strcpy( token, "" ); for ( index = 0; index < length; ) { char *start = string + index; char *end = strstr( start, delimiter ); if ( end == NULL ) { strcat( token, start ); mlt_tokeniser_append( tokeniser, token ); index = length; count ++; } else if ( start != end ) { strncat( token, start, end - start ); index += end - start; if ( strchr( token, '\"' ) == NULL || token[ strlen( token ) - 1 ] == '\"' ) { mlt_tokeniser_append( tokeniser, token ); strcpy( token, "" ); count ++; } else while ( strncmp( string + index, delimiter, delimiter_size ) == 0 ) { strncat( token, delimiter, delimiter_size ); index += delimiter_size; } } else { index += delimiter_size; } } /* Special case - malformed string condition */ if ( !strcmp( token, "" ) ) { count = 0 - ( count - 1 ); mlt_tokeniser_append( tokeniser, token ); } free( token ); return count; } /** Get the original input. */ char *mlt_tokeniser_get_input( mlt_tokeniser tokeniser ) { return tokeniser->input; } /** Get the number of tokens. */ int mlt_tokeniser_count( mlt_tokeniser tokeniser ) { return tokeniser->count; } /** Get a token as a string. */ char *mlt_tokeniser_get_string( mlt_tokeniser tokeniser, int index ) { if ( index < tokeniser->count ) return tokeniser->tokens[ index ]; else return NULL; } /** Close the tokeniser. */ void mlt_tokeniser_close( mlt_tokeniser tokeniser ) { mlt_tokeniser_clear( tokeniser ); free( tokeniser->tokens ); free( tokeniser ); } mlt-0.9.0/src/framework/mlt_tokeniser.h000066400000000000000000000030361215300731300201250ustar00rootroot00000000000000/** * \file mlt_tokeniser.h * \brief string tokeniser * \see mlt_tokeniser_s * * Copyright (C) 2002-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_TOKENISER_H_ #define _MLT_TOKENISER_H_ /** \brief Tokeniser class * */ typedef struct { char *input; char **tokens; int count; int size; } *mlt_tokeniser, mlt_tokeniser_t; /* Remote parser API. */ extern mlt_tokeniser mlt_tokeniser_init( ); extern int mlt_tokeniser_parse_new( mlt_tokeniser tokeniser, char *text, const char *delimiter ); extern char *mlt_tokeniser_get_input( mlt_tokeniser tokeniser ); extern int mlt_tokeniser_count( mlt_tokeniser tokeniser ); extern char *mlt_tokeniser_get_string( mlt_tokeniser tokeniser, int index ); extern void mlt_tokeniser_close( mlt_tokeniser tokeniser ); #endif mlt-0.9.0/src/framework/mlt_tractor.c000066400000000000000000000457361215300731300176100ustar00rootroot00000000000000/** * \file mlt_tractor.c * \brief tractor service class * \see mlt_tractor_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_tractor.h" #include "mlt_frame.h" #include "mlt_multitrack.h" #include "mlt_field.h" #include "mlt_log.h" #include #include #include #include /* Forward references to static methods. */ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int track ); static void mlt_tractor_listener( mlt_multitrack tracks, mlt_tractor self ); /** Construct a tractor without a field or multitrack. * * Sets the resource property to "", the mlt_type to "mlt_producer", * and mlt_service to "tractor". * * \public \memberof mlt_tractor_s * \return the new tractor */ mlt_tractor mlt_tractor_init( ) { mlt_tractor self = calloc( 1, sizeof( struct mlt_tractor_s ) ); if ( self != NULL ) { mlt_producer producer = &self->parent; if ( mlt_producer_init( producer, self ) == 0 ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_properties_set( properties, "resource", "" ); mlt_properties_set( properties, "mlt_type", "mlt_producer" ); mlt_properties_set( properties, "mlt_service", "tractor" ); mlt_properties_set_int( properties, "in", 0 ); mlt_properties_set_int( properties, "out", -1 ); mlt_properties_set_int( properties, "length", 0 ); producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )mlt_tractor_close; producer->close_object = self; } else { free( self ); self = NULL; } } return self; } /** Construct a tractor as well as a field and multitrack. * * Sets the resource property to "", the mlt_type to "mlt_producer", * and mlt_service to "tractor". * * \public \memberof mlt_tractor_s * \return the new tractor */ mlt_tractor mlt_tractor_new( ) { mlt_tractor self = calloc( 1, sizeof( struct mlt_tractor_s ) ); if ( self != NULL ) { mlt_producer producer = &self->parent; if ( mlt_producer_init( producer, self ) == 0 ) { mlt_multitrack multitrack = mlt_multitrack_init( ); mlt_field field = mlt_field_new( multitrack, self ); mlt_properties props = MLT_PRODUCER_PROPERTIES( producer ); mlt_properties_set( props, "resource", "" ); mlt_properties_set( props, "mlt_type", "mlt_producer" ); mlt_properties_set( props, "mlt_service", "tractor" ); mlt_properties_set_position( props, "in", 0 ); mlt_properties_set_position( props, "out", 0 ); mlt_properties_set_position( props, "length", 0 ); mlt_properties_set_data( props, "multitrack", multitrack, 0, ( mlt_destructor )mlt_multitrack_close, NULL ); mlt_properties_set_data( props, "field", field, 0, ( mlt_destructor )mlt_field_close, NULL ); mlt_events_listen( MLT_MULTITRACK_PROPERTIES( multitrack ), self, "producer-changed", ( mlt_listener )mlt_tractor_listener ); producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )mlt_tractor_close; producer->close_object = self; } else { free( self ); self = NULL; } } return self; } /** Get the service object associated to the tractor. * * \public \memberof mlt_tractor_s * \param self a tractor * \return the parent service object * \see MLT_TRACTOR_SERVICE */ mlt_service mlt_tractor_service( mlt_tractor self ) { return MLT_PRODUCER_SERVICE( &self->parent ); } /** Get the producer object associated to the tractor. * * \public \memberof mlt_tractor_s * \param self a tractor * \return the parent producer object * \see MLT_TRACTOR_PRODUCER */ mlt_producer mlt_tractor_producer( mlt_tractor self ) { return self != NULL ? &self->parent : NULL; } /** Get the properties object associated to the tractor. * * \public \memberof mlt_tractor_s * \param self a tractor * \return the tractor's property list * \see MLT_TRACTOR_PROPERTIES */ mlt_properties mlt_tractor_properties( mlt_tractor self ) { return MLT_PRODUCER_PROPERTIES( &self->parent ); } /** Get the field self tractor is harvesting. * * \public \memberof mlt_tractor_s * \param self a tractor * \return a field or NULL if there is no field for this tractor */ mlt_field mlt_tractor_field( mlt_tractor self ) { return mlt_properties_get_data( MLT_TRACTOR_PROPERTIES( self ), "field", NULL ); } /** Get the multitrack a tractor is pulling. * * \public \memberof mlt_tractor_s * \param self a tractor * \return a multitrack or NULL if there is none */ mlt_multitrack mlt_tractor_multitrack( mlt_tractor self ) { return mlt_properties_get_data( MLT_TRACTOR_PROPERTIES( self ), "multitrack", NULL ); } /** Ensure the tractors in/out points match the multitrack. * * \public \memberof mlt_tractor_s * \param self a tractor */ void mlt_tractor_refresh( mlt_tractor self ) { mlt_multitrack multitrack = mlt_tractor_multitrack( self ); mlt_properties multitrack_props = MLT_MULTITRACK_PROPERTIES( multitrack ); mlt_properties properties = MLT_TRACTOR_PROPERTIES( self ); mlt_events_block( multitrack_props, properties ); mlt_events_block( properties, properties ); mlt_multitrack_refresh( multitrack ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", mlt_properties_get_position( multitrack_props, "out" ) ); mlt_events_unblock( properties, properties ); mlt_events_unblock( multitrack_props, properties ); mlt_properties_set_position( properties, "length", mlt_properties_get_position( multitrack_props, "length" ) ); } static void mlt_tractor_listener( mlt_multitrack tracks, mlt_tractor self ) { mlt_tractor_refresh( self ); } /** Connect the tractor. * * \public \memberof mlt_tractor_s * \param self a tractor * \param producer a producer * \return true on error */ int mlt_tractor_connect( mlt_tractor self, mlt_service producer ) { int ret = mlt_service_connect_producer( MLT_TRACTOR_SERVICE( self ), producer, 0 ); // This is the producer we're going to connect to if ( ret == 0 ) self->producer = producer; return ret; } /** Set the producer for a specific track. * * \public \memberof mlt_tractor_s * \param self a tractor * \param producer a producer * \param index the 0-based track index * \return true on error */ int mlt_tractor_set_track( mlt_tractor self, mlt_producer producer, int index ) { return mlt_multitrack_connect( mlt_tractor_multitrack( self ), producer, index ); } /** Get the producer for a specific track. * * \public \memberof mlt_tractor_s * \param self a tractor * \param index the 0-based track index * \return the producer for track \p index */ mlt_producer mlt_tractor_get_track( mlt_tractor self, int index ) { return mlt_multitrack_track( mlt_tractor_multitrack( self ), index ); } static int producer_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { uint8_t *data = NULL; int size = 0; mlt_properties properties = MLT_FRAME_PROPERTIES( self ); mlt_frame frame = mlt_frame_pop_service( self ); mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); mlt_properties_set( frame_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) ); mlt_properties_set_int( frame_properties, "resize_alpha", mlt_properties_get_int( properties, "resize_alpha" ) ); mlt_properties_set_int( frame_properties, "distort", mlt_properties_get_int( properties, "distort" ) ); mlt_properties_set_int( frame_properties, "consumer_deinterlace", mlt_properties_get_int( properties, "consumer_deinterlace" ) ); mlt_properties_set( frame_properties, "deinterlace_method", mlt_properties_get( properties, "deinterlace_method" ) ); mlt_properties_set_int( frame_properties, "consumer_tff", mlt_properties_get_int( properties, "consumer_tff" ) ); mlt_frame_get_image( frame, buffer, format, width, height, writable ); mlt_frame_set_image( self, *buffer, 0, NULL ); mlt_properties_set_int( properties, "width", *width ); mlt_properties_set_int( properties, "height", *height ); mlt_properties_set_int( properties, "format", *format ); mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( frame ) ); mlt_properties_set_int( properties, "progressive", mlt_properties_get_int( frame_properties, "progressive" ) ); mlt_properties_set_int( properties, "distort", mlt_properties_get_int( frame_properties, "distort" ) ); mlt_properties_set_int( properties, "colorspace", mlt_properties_get_int( frame_properties, "colorspace" ) ); mlt_properties_set_int( properties, "force_full_luma", mlt_properties_get_int( frame_properties, "force_full_luma" ) ); mlt_properties_set_int( properties, "top_field_first", mlt_properties_get_int( frame_properties, "top_field_first" ) ); data = mlt_frame_get_alpha_mask( frame ); mlt_properties_get_data( frame_properties, "alpha", &size ); mlt_frame_set_alpha( self, data, size, NULL ); self->convert_image = frame->convert_image; self->convert_audio = frame->convert_audio; return 0; } static int producer_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { mlt_properties properties = MLT_FRAME_PROPERTIES( self ); mlt_frame frame = mlt_frame_pop_audio( self ); mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); mlt_frame_set_audio( self, *buffer, *format, mlt_audio_format_size( *format, *samples, *channels ), NULL ); mlt_properties_set_int( properties, "audio_frequency", *frequency ); mlt_properties_set_int( properties, "audio_channels", *channels ); mlt_properties_set_int( properties, "audio_samples", *samples ); return 0; } static void destroy_data_queue( void *arg ) { if ( arg != NULL ) { // Assign the correct type mlt_deque queue = arg; // Iterate through each item and destroy them while ( mlt_deque_peek_front( queue ) != NULL ) mlt_properties_close( mlt_deque_pop_back( queue ) ); // Close the deque mlt_deque_close( queue ); } } /** Get the next frame. * * \private \memberof mlt_tractor_s * \param parent the producer interface to the tractor * \param[out] frame a frame by reference * \param track the 0-based track index * \return true on error */ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int track ) { mlt_tractor self = parent->child; // We only respond to the first track requests if ( track == 0 && self->producer != NULL ) { int i = 0; int done = 0; mlt_frame temp = NULL; int count = 0; int image_count = 0; // Get the properties of the parent producer mlt_properties properties = MLT_PRODUCER_PROPERTIES( parent ); // Try to obtain the multitrack associated to the tractor mlt_multitrack multitrack = mlt_properties_get_data( properties, "multitrack", NULL ); // Or a specific producer mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL ); // Determine whether this tractor feeds to the consumer or stops here int global_feed = mlt_properties_get_int( properties, "global_feed" ); // If we don't have one, we're in trouble... if ( multitrack != NULL ) { // The output frame will hold the 'global' data feeds (ie: those which are targetted for the final frame) mlt_deque data_queue = mlt_deque_init( ); // Used to garbage collect all frames char label[ 30 ]; // Get the id of the tractor char *id = mlt_properties_get( properties, "_unique_id" ); // Will be used to store the frame properties object mlt_properties frame_properties = NULL; // We'll store audio and video frames to use here mlt_frame audio = NULL; mlt_frame video = NULL; mlt_frame first_video = NULL; // Temporary properties mlt_properties temp_properties = NULL; // Get the multitrack's producer mlt_producer target = MLT_MULTITRACK_PRODUCER( multitrack ); mlt_producer_seek( target, mlt_producer_frame( parent ) ); mlt_producer_set_speed( target, mlt_producer_get_speed( parent ) ); // We will create one frame and attach everything to it *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( parent ) ); // Get the properties of the frame frame_properties = MLT_FRAME_PROPERTIES( *frame ); // Loop through each of the tracks we're harvesting for ( i = 0; !done; i ++ ) { // Get a frame from the producer mlt_service_get_frame( self->producer, &temp, i ); // Get the temporary properties temp_properties = MLT_FRAME_PROPERTIES( temp ); // Pass all unique meta properties from the producer's frame to the new frame mlt_properties_lock( temp_properties ); int props_count = mlt_properties_count( temp_properties ); int j; for ( j = 0; j < props_count; j ++ ) { char *name = mlt_properties_get_name( temp_properties, j ); if ( !strncmp( name, "meta.", 5 ) && !mlt_properties_get( frame_properties, name ) ) mlt_properties_set( frame_properties, name, mlt_properties_get_value( temp_properties, j ) ); } mlt_properties_unlock( temp_properties ); // Copy the format conversion virtual functions if ( ! (*frame)->convert_image && temp->convert_image ) (*frame)->convert_image = temp->convert_image; if ( ! (*frame)->convert_audio && temp->convert_audio ) (*frame)->convert_audio = temp->convert_audio; // Check for last track done = mlt_properties_get_int( temp_properties, "last_track" ); // Handle fx only tracks if ( mlt_properties_get_int( temp_properties, "fx_cut" ) ) { int hide = ( video == NULL ? 1 : 0 ) | ( audio == NULL ? 2 : 0 ); mlt_properties_set_int( temp_properties, "hide", hide ); } // We store all frames with a destructor on the output frame sprintf( label, "_%s_%d", id, count ++ ); mlt_properties_set_data( frame_properties, label, temp, 0, ( mlt_destructor )mlt_frame_close, NULL ); // We want to append all 'final' feeds to the global queue if ( !done && mlt_properties_get_data( temp_properties, "data_queue", NULL ) != NULL ) { // Move the contents of this queue on to the output frames data queue mlt_deque sub_queue = mlt_properties_get_data( MLT_FRAME_PROPERTIES( temp ), "data_queue", NULL ); mlt_deque temp = mlt_deque_init( ); while ( global_feed && mlt_deque_count( sub_queue ) ) { mlt_properties p = mlt_deque_pop_back( sub_queue ); if ( mlt_properties_get_int( p, "final" ) ) mlt_deque_push_back( data_queue, p ); else mlt_deque_push_back( temp, p ); } while( mlt_deque_count( temp ) ) mlt_deque_push_front( sub_queue, mlt_deque_pop_back( temp ) ); mlt_deque_close( temp ); } // Now do the same with the global queue but without the conditional behaviour if ( mlt_properties_get_data( temp_properties, "global_queue", NULL ) != NULL ) { mlt_deque sub_queue = mlt_properties_get_data( MLT_FRAME_PROPERTIES( temp ), "global_queue", NULL ); while ( mlt_deque_count( sub_queue ) ) { mlt_properties p = mlt_deque_pop_back( sub_queue ); mlt_deque_push_back( data_queue, p ); } } // Pick up first video and audio frames if ( !done && !mlt_frame_is_test_audio( temp ) && !( mlt_properties_get_int( temp_properties, "hide" ) & 2 ) ) { // Order of frame creation is starting to get problematic if ( audio != NULL ) { mlt_deque_push_front( MLT_FRAME_AUDIO_STACK( temp ), producer_get_audio ); mlt_deque_push_front( MLT_FRAME_AUDIO_STACK( temp ), audio ); } audio = temp; } if ( !done && !mlt_frame_is_test_card( temp ) && !( mlt_properties_get_int( temp_properties, "hide" ) & 1 ) ) { if ( video != NULL ) { mlt_deque_push_front( MLT_FRAME_IMAGE_STACK( temp ), producer_get_image ); mlt_deque_push_front( MLT_FRAME_IMAGE_STACK( temp ), video ); } video = temp; if ( first_video == NULL ) first_video = temp; mlt_properties_set_int( MLT_FRAME_PROPERTIES( temp ), "image_count", ++ image_count ); image_count = 1; } } // Now stack callbacks if ( audio != NULL ) { mlt_frame_push_audio( *frame, audio ); mlt_frame_push_audio( *frame, producer_get_audio ); } if ( video != NULL ) { mlt_properties video_properties = MLT_FRAME_PROPERTIES( first_video ); mlt_frame_push_service( *frame, video ); mlt_frame_push_service( *frame, producer_get_image ); if ( global_feed ) mlt_properties_set_data( frame_properties, "data_queue", data_queue, 0, NULL, NULL ); mlt_properties_set_data( video_properties, "global_queue", data_queue, 0, destroy_data_queue, NULL ); mlt_properties_set_int( frame_properties, "width", mlt_properties_get_int( video_properties, "width" ) ); mlt_properties_set_int( frame_properties, "height", mlt_properties_get_int( video_properties, "height" ) ); mlt_properties_pass_list( frame_properties, video_properties, "meta.media.width, meta.media.height" ); mlt_properties_set_int( frame_properties, "progressive", mlt_properties_get_int( video_properties, "progressive" ) ); mlt_properties_set_double( frame_properties, "aspect_ratio", mlt_properties_get_double( video_properties, "aspect_ratio" ) ); mlt_properties_set_int( frame_properties, "image_count", image_count ); } else { destroy_data_queue( data_queue ); } mlt_frame_set_position( *frame, mlt_producer_frame( parent ) ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_audio", audio == NULL ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_image", video == NULL ); } else if ( producer != NULL ) { mlt_producer_seek( producer, mlt_producer_frame( parent ) ); mlt_producer_set_speed( producer, mlt_producer_get_speed( parent ) ); mlt_service_get_frame( self->producer, frame, track ); } else { mlt_log( MLT_PRODUCER_SERVICE( parent ), MLT_LOG_ERROR, "tractor without a multitrack!!\n" ); mlt_service_get_frame( self->producer, frame, track ); } // Prepare the next frame mlt_producer_prepare_next( parent ); // Indicate our found status return 0; } else { // Generate a test card *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( parent ) ); return 0; } } /** Close the tractor and free its resources. * * \public \memberof mlt_tractor_s * \param self a tractor */ void mlt_tractor_close( mlt_tractor self ) { if ( self != NULL && mlt_properties_dec_ref( MLT_TRACTOR_PROPERTIES( self ) ) <= 0 ) { self->parent.close = NULL; mlt_producer_close( &self->parent ); free( self ); } } mlt-0.9.0/src/framework/mlt_tractor.h000066400000000000000000000054231215300731300176020ustar00rootroot00000000000000/** * \file mlt_tractor.h * \brief tractor service class * \see mlt_tractor_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_TRACTOR_H_ #define _MLT_TRACTOR_H_ #include "mlt_producer.h" /** \brief Tractor class * * The tractor is a convenience class that works with the field class * to manage a multitrack, track filters, and transitions. * * \extends mlt_producer_s * \properties \em multitrack holds a reference to the mulitrack object that a tractor manages * \properties \em field holds a reference to the field object that a tractor manages * \properties \em producer holds a reference to an encapsulated producer * \properties \em global_feed a flag to indicate whether this tractor feeds to the consumer or stops here * \properties \em global_queue is something for the data_feed functionality in the core module * \properties \em data_queue is something for the data_feed functionality in the core module */ struct mlt_tractor_s { struct mlt_producer_s parent; mlt_service producer; }; #define MLT_TRACTOR_PRODUCER( tractor ) ( &( tractor )->parent ) #define MLT_TRACTOR_SERVICE( tractor ) MLT_PRODUCER_SERVICE( MLT_TRACTOR_PRODUCER( tractor ) ) #define MLT_TRACTOR_PROPERTIES( tractor ) MLT_SERVICE_PROPERTIES( MLT_TRACTOR_SERVICE( tractor ) ) extern mlt_tractor mlt_tractor_init( ); extern mlt_tractor mlt_tractor_new( ); extern mlt_service mlt_tractor_service( mlt_tractor self ); extern mlt_producer mlt_tractor_producer( mlt_tractor self ); extern mlt_properties mlt_tractor_properties( mlt_tractor self ); extern mlt_field mlt_tractor_field( mlt_tractor self ); extern mlt_multitrack mlt_tractor_multitrack( mlt_tractor self ); extern int mlt_tractor_connect( mlt_tractor self, mlt_service service ); extern void mlt_tractor_refresh( mlt_tractor self ); extern int mlt_tractor_set_track( mlt_tractor self, mlt_producer producer, int index ); extern mlt_producer mlt_tractor_get_track( mlt_tractor self, int index ); extern void mlt_tractor_close( mlt_tractor self ); #endif mlt-0.9.0/src/framework/mlt_transition.c000066400000000000000000000405341215300731300203130ustar00rootroot00000000000000/** * \file mlt_transition.c * \brief abstraction for all transition services * \see mlt_transition_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_transition.h" #include "mlt_frame.h" #include "mlt_log.h" #include "mlt_producer.h" #include #include #include /* Forward references */ static int transition_get_frame( mlt_service self, mlt_frame_ptr frame, int index ); /** Initialize a new transition. * * \public \memberof mlt_transition_s * \param self a transition * \param child the object of a subclass * \return true on error */ int mlt_transition_init( mlt_transition self, void *child ) { mlt_service service = &self->parent; memset( self, 0, sizeof( struct mlt_transition_s ) ); self->child = child; if ( mlt_service_init( service, self ) == 0 ) { mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); service->get_frame = transition_get_frame; service->close = ( mlt_destructor )mlt_transition_close; service->close_object = self; mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", 0 ); mlt_properties_set_int( properties, "a_track", 0 ); mlt_properties_set_int( properties, "b_track", 1 ); return 0; } return 1; } /** Create and initialize a new transition. * * \public \memberof mlt_transition_s * \return a new transition */ mlt_transition mlt_transition_new( ) { mlt_transition self = calloc( 1, sizeof( struct mlt_transition_s ) ); if ( self != NULL ) mlt_transition_init( self, NULL ); return self; } /** Get the service class interface. * * \public \memberof mlt_transition_s * \param self a transition * \return the service class * \see MLT_TRANSITION_SERVICE */ mlt_service mlt_transition_service( mlt_transition self ) { return self != NULL ? &self->parent : NULL; } /** Get the properties interface. * * \public \memberof mlt_transition_s * \param self a transition * \return the transition's properties * \see MLT_TRANSITION_PROPERTIES */ mlt_properties mlt_transition_properties( mlt_transition self ) { return MLT_TRANSITION_PROPERTIES( self ); } /** Connect a transition with a producer's a and b tracks. * * \public \memberof mlt_transition_s * \param self a transition * \param producer a producer * \param a_track the track index of the first input * \param b_track the track index of the second index * \return true on error */ int mlt_transition_connect( mlt_transition self, mlt_service producer, int a_track, int b_track ) { int ret = mlt_service_connect_producer( &self->parent, producer, a_track ); if ( ret == 0 ) { mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); self->producer = producer; mlt_properties_set_int( properties, "a_track", a_track ); mlt_properties_set_int( properties, "b_track", b_track ); } return ret; } /** Set the starting and ending time for when the transition is active. * * \public \memberof mlt_transition_s * \param self a transition * \param in the starting time * \param out the ending time */ void mlt_transition_set_in_and_out( mlt_transition self, mlt_position in, mlt_position out ) { mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); mlt_properties_set_position( properties, "in", in ); mlt_properties_set_position( properties, "out", out ); } /** Get the index of the a track. * * \public \memberof mlt_transition_s * \param self a transition * \return the 0-based index of the track of the first producer */ int mlt_transition_get_a_track( mlt_transition self ) { return mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( self ), "a_track" ); } /** Get the index of the b track. * * \public \memberof mlt_transition_s * \param self a transition * \return the 0-based index of the track of the second producer */ int mlt_transition_get_b_track( mlt_transition self ) { return mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( self ), "b_track" ); } /** Get the in point. * * \public \memberof mlt_transition_s * \param self a transition * \return the starting time */ mlt_position mlt_transition_get_in( mlt_transition self ) { return mlt_properties_get_position( MLT_TRANSITION_PROPERTIES( self ), "in" ); } /** Get the out point. * * \public \memberof mlt_transition_s * \param self a transition * \return the ending time */ mlt_position mlt_transition_get_out( mlt_transition self ) { return mlt_properties_get_position( MLT_TRANSITION_PROPERTIES( self ), "out" ); } /** Get the duration. * * \public \memberof mlt_transition_s * \param self a transition * \return the duration or zero if unlimited */ mlt_position mlt_transition_get_length( mlt_transition self ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); mlt_position in = mlt_properties_get_position( properties, "in" ); mlt_position out = mlt_properties_get_position( properties, "out" ); return ( out > 0 ) ? ( out - in + 1 ) : 0; } /** Get the position within the transition. * * The position is relative to the in point. * * \public \memberof mlt_transition_s * \param self a transition * \param frame a frame * \return the position */ mlt_position mlt_transition_get_position( mlt_transition self, mlt_frame frame ) { mlt_position in = mlt_transition_get_in( self ); mlt_position position = mlt_frame_get_position( frame ); return position - in; } /** Get the percent complete. * * \public \memberof mlt_transition_s * \param self a transition * \param frame a frame * \return the progress in the range 0.0 to 1.0 */ double mlt_transition_get_progress( mlt_transition self, mlt_frame frame ) { double progress = 0; mlt_position in = mlt_transition_get_in( self ); mlt_position out = mlt_transition_get_out( self ); if ( out == 0 ) { // If always active, use the frame's producer mlt_producer producer = mlt_frame_get_original_producer( frame ); if ( producer ) { in = mlt_producer_get_in( producer ); out = mlt_producer_get_out( producer ); } } if ( out != 0 ) { mlt_position position = mlt_frame_get_position( frame ); progress = ( double ) ( position - in ) / ( double ) ( out - in + 1 ); } return progress; } /** Get the second field incremental progress. * * \public \memberof mlt_transition_s * \param self a transition * \param frame a frame * \return the progress increment in the range 0.0 to 1.0 */ double mlt_transition_get_progress_delta( mlt_transition self, mlt_frame frame ) { double progress = 0; mlt_position in = mlt_transition_get_in( self ); mlt_position out = mlt_transition_get_out( self ); if ( out == 0 ) { // If always active, use the frame's producer mlt_producer producer = mlt_frame_get_original_producer( frame ); if ( producer ) { in = mlt_producer_get_in( producer ); out = mlt_producer_get_out( producer ); } } if ( out != 0 ) { mlt_position position = mlt_frame_get_position( frame ); double length = out - in + 1; double x = ( double ) ( position - in ) / length; double y = ( double ) ( position + 1 - in ) / length; progress = ( y - x ) / 2.0; } return progress; } /** Process the frame. * * If we have no process method (unlikely), we simply return the a_frame unmolested. * * \public \memberof mlt_transition_s * \param self a transition * \param a_frame a frame from the first producer * \param b_frame a frame from the second producer * \return a frame */ mlt_frame mlt_transition_process( mlt_transition self, mlt_frame a_frame, mlt_frame b_frame ) { if ( self->process == NULL ) return a_frame; else return self->process( self, a_frame, b_frame ); } static int get_image_a( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_transition self = mlt_frame_pop_service( a_frame ); mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); // All transitions get scaling const char *rescale = mlt_properties_get( a_props, "rescale.interp" ); if ( !rescale || !strcmp( rescale, "none" ) ) mlt_properties_set( a_props, "rescale.interp", "nearest" ); // Ensure sane aspect ratio if ( mlt_frame_get_aspect_ratio( a_frame ) == 0.0 ) mlt_frame_set_aspect_ratio( a_frame, mlt_profile_sar( mlt_service_profile( MLT_TRANSITION_SERVICE(self) ) ) ); return mlt_frame_get_image( a_frame, image, format, width, height, writable ); } static int get_image_b( mlt_frame b_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_transition self = mlt_frame_pop_service( b_frame ); mlt_frame a_frame = mlt_frame_pop_frame( b_frame ); mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); // Set scaling from A frame if not already provided. if ( !mlt_properties_get( b_props, "rescale.interp" ) ) { const char *rescale = mlt_properties_get( a_props, "rescale.interp" ); if ( !rescale || !strcmp( rescale, "none" ) ) rescale = "nearest"; mlt_properties_set( b_props, "rescale.interp", rescale ); } // Ensure sane aspect ratio if ( mlt_frame_get_aspect_ratio( b_frame ) == 0.0 ) mlt_frame_set_aspect_ratio( b_frame, mlt_profile_sar( mlt_service_profile( MLT_TRANSITION_SERVICE(self) ) ) ); mlt_properties_pass_list( b_props, a_props, "consumer_deinterlace, deinterlace_method, consumer_tff" ); return mlt_frame_get_image( b_frame, image, format, width, height, writable ); } /** Get a frame from a transition. The logic is complex here. A transition is typically applied to frames on the a and b tracks specified in the connect method above and only if both contain valid info for the transition type (this is either audio or image). However, the fixed a_track may not always contain data of the correct type, eg:
	+---------+                               +-------+
	|c1       |                               |c5     | <-- A(0,1) <-- B(0,2) <-- get frame
	+---------+                     +---------+-+-----+        |          |
	                                |c4         |       <------+          |
	         +----------+-----------+-+---------+                         |
	         |c2        |c3           |                 <-----------------+
	         +----------+-------------+
During the overlap of c1 and c2, there is nothing for the A transition to do, so this results in a no operation, but B is triggered. During the overlap of c2 and c3, again, the A transition is inactive and because the B transition is pointing at track 0, it too would be inactive. This isn't an ideal situation - it's better if the B transition simply treats the frames from c3 as though they're the a track. For this to work, we cache all frames coming from all tracks between the a and b tracks. Before we process, we determine that the b frame contains someting of the right type and then we determine which frame to use as the a frame (selecting a matching frame from a_track to b_track - 1). If both frames contain data of the correct type, we process the transition. This method is invoked for each track and we return the cached frames as needed. We clear the cache only when the requested frame is flagged as a 'last_track' frame. * \private \memberof mlt_transition_s * \param service a service * \param[out] frame a frame by reference * \param index 0-based track index * \return true on error */ static int transition_get_frame( mlt_service service, mlt_frame_ptr frame, int index ) { int error = 0; mlt_transition self = service->child; mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); int accepts_blanks = mlt_properties_get_int( properties, "accepts_blanks" ); int a_track = mlt_properties_get_int( properties, "a_track" ); int b_track = mlt_properties_get_int( properties, "b_track" ); mlt_position in = mlt_properties_get_position( properties, "in" ); mlt_position out = mlt_properties_get_position( properties, "out" ); int always_active = mlt_properties_get_int( properties, "always_active" ); int type = mlt_properties_get_int( properties, "_transition_type" ); int reverse_order = 0; // Ensure that we have the correct order if ( a_track > b_track ) { reverse_order = 1; a_track = b_track; b_track = mlt_properties_get_int( properties, "a_track" ); } // Only act on this operation once per multitrack iteration from the tractor if ( !self->held ) { int active = 0; int i = 0; int a_frame = a_track; int b_frame = b_track; mlt_position position; int ( *invalid )( mlt_frame ) = type == 1 ? mlt_frame_is_test_card : mlt_frame_is_test_audio; // Initialise temporary store if ( self->frames == NULL ) self->frames = calloc( sizeof( mlt_frame ), b_track + 1 ); // Get all frames between a and b for( i = a_track; i <= b_track; i ++ ) mlt_service_get_frame( self->producer, &self->frames[ i ], i ); // We're holding these frames until the last_track frame property is received self->held = 1; // When we need to locate the a_frame switch( type ) { case 1: case 2: // Some transitions (esp. audio) may accept blank frames active = accepts_blanks; // If we're not active then... if ( !active ) { // Hunt for the a_frame while( a_frame <= b_frame && invalid( self->frames[ a_frame ] ) ) a_frame ++; // Determine if we're active now active = a_frame != b_frame && !invalid( self->frames[ b_frame ] ); } break; default: mlt_log( service, MLT_LOG_ERROR, "invalid transition type\n" ); break; } // Now handle the non-always active case if ( active && !always_active ) { // For non-always-active transitions, we need the current position of the a frame position = mlt_frame_get_position( self->frames[ a_frame ] ); // If a is in range, we're active active = position >= in && ( out == 0 || position <= out ); } // Finally, process the a and b frames if ( active ) { mlt_frame a_frame_ptr = self->frames[ !reverse_order ? a_frame : b_frame ]; mlt_frame b_frame_ptr = self->frames[ !reverse_order ? b_frame : a_frame ]; int a_hide = mlt_properties_get_int( MLT_FRAME_PROPERTIES( a_frame_ptr ), "hide" ); int b_hide = mlt_properties_get_int( MLT_FRAME_PROPERTIES( b_frame_ptr ), "hide" ); if ( !( a_hide & type ) && !( b_hide & type ) ) { // Add hooks for pre-processing frames mlt_frame_push_service( a_frame_ptr, self ); mlt_frame_push_get_image( a_frame_ptr, get_image_a ); mlt_frame_push_frame( b_frame_ptr, a_frame_ptr ); mlt_frame_push_service( b_frame_ptr, self ); mlt_frame_push_get_image( b_frame_ptr, get_image_b ); // Process the transition *frame = mlt_transition_process( self, a_frame_ptr, b_frame_ptr ); // We need to ensure that the tractor doesn't consider this frame for output if ( *frame == a_frame_ptr ) b_hide |= type; else a_hide |= type; mlt_properties_set_int( MLT_FRAME_PROPERTIES( a_frame_ptr ), "hide", a_hide ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( b_frame_ptr ), "hide", b_hide ); } } } // Obtain the frame from the cache or the producer we're attached to if ( index >= a_track && index <= b_track ) *frame = self->frames[ index ]; else error = mlt_service_get_frame( self->producer, frame, index ); // Determine if that was the last track self->held = !mlt_properties_get_int( MLT_FRAME_PROPERTIES( *frame ), "last_track" ); return error; } /** Close and destroy the transition. * * \public \memberof mlt_transition_s * \param self a transition */ void mlt_transition_close( mlt_transition self ) { if ( self != NULL && mlt_properties_dec_ref( MLT_TRANSITION_PROPERTIES( self ) ) <= 0 ) { self->parent.close = NULL; if ( self->close != NULL ) { self->close( self ); } else { mlt_service_close( &self->parent ); free( self->frames ); free( self ); } } } mlt-0.9.0/src/framework/mlt_transition.h000066400000000000000000000065721215300731300203240ustar00rootroot00000000000000/** * \file mlt_transition.h * \brief abstraction for all transition services * \see mlt_transition_s * * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_TRANSITION_H_ #define _MLT_TRANSITION_H_ #include "mlt_service.h" /** \brief Transition abstract service class * * A transition may modify the output of a producer based on the output of a second producer. * * \extends mlt_service_s * \properties \em a_track the track index (0-based) of a multitrack of the first producer * \properties \em b_track the track index (0-based) of a multitrack of the second producer * \properties \em accepts_blanks a flag to indicate if the transition should accept blank frames * \properties \em always_active a flag to indicate that the in and out points do not apply * \properties \em _transition_type 1 for video, 2 for audio */ struct mlt_transition_s { /** We're implementing service here */ struct mlt_service_s parent; /** public virtual */ void ( *close )( mlt_transition ); /** protected transition method */ mlt_frame ( *process )( mlt_transition, mlt_frame, mlt_frame ); /** Protected */ void *child; /** track and in/out points */ mlt_service producer; /** Private */ mlt_frame *frames; int held; }; #define MLT_TRANSITION_SERVICE( transition ) ( &( transition )->parent ) #define MLT_TRANSITION_PROPERTIES( transition ) MLT_SERVICE_PROPERTIES( MLT_TRANSITION_SERVICE( transition ) ) extern int mlt_transition_init( mlt_transition self, void *child ); extern mlt_transition mlt_transition_new( ); extern mlt_service mlt_transition_service( mlt_transition self ); extern mlt_properties mlt_transition_properties( mlt_transition self ); extern int mlt_transition_connect( mlt_transition self, mlt_service producer, int a_track, int b_track ); extern void mlt_transition_set_in_and_out( mlt_transition self, mlt_position in, mlt_position out ); extern int mlt_transition_get_a_track( mlt_transition self ); extern int mlt_transition_get_b_track( mlt_transition self ); extern mlt_position mlt_transition_get_in( mlt_transition self ); extern mlt_position mlt_transition_get_out( mlt_transition self ); extern mlt_position mlt_transition_get_length( mlt_transition self ); extern mlt_position mlt_transition_get_position( mlt_transition self, mlt_frame frame ); extern double mlt_transition_get_progress( mlt_transition self, mlt_frame frame ); extern double mlt_transition_get_progress_delta( mlt_transition self, mlt_frame frame ); extern mlt_frame mlt_transition_process( mlt_transition self, mlt_frame a_frame, mlt_frame b_frame ); extern void mlt_transition_close( mlt_transition self ); #endif mlt-0.9.0/src/framework/mlt_types.h000066400000000000000000000172731215300731300172760ustar00rootroot00000000000000/** * \file mlt_types.h * \brief Provides forward definitions of all public types * * Copyright (C) 2003-2012 Ushodaya Enterprises Limited * \author Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_TYPES_H_ #define _MLT_TYPES_H_ #ifndef GCC_VERSION #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #endif #include #include #include "mlt_pool.h" #ifndef PATH_MAX #define PATH_MAX 4096 #endif /** The set of supported image formats */ typedef enum { mlt_image_none = 0,/**< image not available */ mlt_image_rgb24, /**< 8-bit RGB */ mlt_image_rgb24a, /**< 8-bit RGB with alpha channel */ mlt_image_yuv422, /**< 8-bit YUV 4:2:2 packed */ mlt_image_yuv420p, /**< 8-bit YUV 4:2:0 planar */ mlt_image_opengl, /**< (deprecated) suitable for OpenGL texture */ mlt_image_glsl, /**< for opengl module internal use only */ mlt_image_glsl_texture /**< an OpenGL texture name */ } mlt_image_format; /** The set of supported audio formats */ typedef enum { mlt_audio_none = 0,/**< audio not available */ mlt_audio_pcm = 1, /**< \deprecated signed 16-bit interleaved PCM */ mlt_audio_s16 = 1, /**< signed 16-bit interleaved PCM */ mlt_audio_s32, /**< signed 32-bit non-interleaved PCM */ mlt_audio_float, /**< 32-bit non-interleaved floating point */ mlt_audio_s32le, /**< signed 32-bit interleaved PCM */ mlt_audio_f32le, /**< 32-bit interleaved floating point */ mlt_audio_u8 /**< unsigned 8-bit interleaved PCM */ } mlt_audio_format; /** The time string formats */ typedef enum { mlt_time_frames = 0, /**< frame count */ mlt_time_clock, /**< SMIL clock-value as [[hh:]mm:]ss[.fraction] */ mlt_time_smpte /**< SMPTE timecode as [[[hh:]mm:]ss:]frames */ } mlt_time_format; /** Interpolation methods for animation keyframes */ typedef enum { mlt_keyframe_discrete = 0, /**< non-interpolated; value changes instantaneously at the key frame */ mlt_keyframe_linear, /**< simple, constant pace from this key frame to the next */ mlt_keyframe_smooth /**< eased pacing from this keyframe to the next using a Catmull-Rom spline */ } mlt_keyframe_type; /** The relative time qualifiers */ typedef enum { mlt_whence_relative_start = 0, /**< relative to the beginning */ mlt_whence_relative_current, /**< relative to the current position */ mlt_whence_relative_end /**< relative to the end */ } mlt_whence; /** The recognized subclasses of mlt_service */ typedef enum { invalid_type = 0, /**< invalid service */ unknown_type, /**< unknown class */ producer_type, /**< Producer class */ tractor_type, /**< Tractor class */ playlist_type, /**< Playlist class */ multitrack_type, /**< Multitrack class */ filter_type, /**< Filter class */ transition_type, /**< Transition class */ consumer_type, /**< Consumer class */ field_type /**< Field class */ } mlt_service_type; /* I don't want to break anyone's applications without warning. -Zach */ #undef DOUBLE_MLT_POSITION #ifdef DOUBLE_MLT_POSITION #define MLT_POSITION_FMT "%f" #define MLT_POSITION_MOD(A, B) (A - B * ((int)(A / B))) typedef double mlt_position; #else #define MLT_POSITION_MOD(A, B) A % B #define MLT_POSITION_FMT "%d" typedef int32_t mlt_position; #endif /** A rectangle type with coordinates, size, and opacity */ typedef struct { double x; /**< X coordinate */ double y; /**< Y coordinate */ double w; /**< width */ double h; /**< height */ double o; /**< opacity / mix-level */ } mlt_rect; /** A tuple of color components */ typedef struct { uint8_t r; /**< red */ uint8_t g; /**< green */ uint8_t b; /**< blue */ uint8_t a; /**< alpha */ } mlt_color; typedef struct mlt_frame_s *mlt_frame, **mlt_frame_ptr; /**< pointer to Frame object */ typedef struct mlt_property_s *mlt_property; /**< pointer to Property object */ typedef struct mlt_properties_s *mlt_properties; /**< pointer to Properties object */ typedef struct mlt_event_struct *mlt_event; /**< pointer to Event object */ typedef struct mlt_service_s *mlt_service; /**< pointer to Service object */ typedef struct mlt_producer_s *mlt_producer; /**< pointer to Producer object */ typedef struct mlt_playlist_s *mlt_playlist; /**< pointer to Playlist object */ typedef struct mlt_multitrack_s *mlt_multitrack; /**< pointer to Multitrack object */ typedef struct mlt_filter_s *mlt_filter; /**< pointer to Filter object */ typedef struct mlt_transition_s *mlt_transition; /**< pointer to Transition object */ typedef struct mlt_tractor_s *mlt_tractor; /**< pointer to Tractor object */ typedef struct mlt_field_s *mlt_field; /**< pointer to Field object */ typedef struct mlt_consumer_s *mlt_consumer; /**< pointer to Consumer object */ typedef struct mlt_parser_s *mlt_parser; /**< pointer to Properties object */ typedef struct mlt_deque_s *mlt_deque; /**< pointer to Deque object */ typedef struct mlt_geometry_s *mlt_geometry; /**< pointer to Geometry object */ typedef struct mlt_geometry_item_s *mlt_geometry_item; /**< pointer to Geometry Item object */ typedef struct mlt_profile_s *mlt_profile; /**< pointer to Profile object */ typedef struct mlt_repository_s *mlt_repository; /**< pointer to Repository object */ typedef struct mlt_cache_s *mlt_cache; /**< pointer to Cache object */ typedef struct mlt_cache_item_s *mlt_cache_item; /**< pointer to CacheItem object */ typedef struct mlt_animation_s *mlt_animation; /**< pointer to Property Animation object */ typedef void ( *mlt_destructor )( void * ); /**< pointer to destructor function */ typedef char *( *mlt_serialiser )( void *, int length );/**< pointer to serialization function */ #define MLT_SERVICE(x) ( ( mlt_service )( x ) ) /**< Cast to a Service pointer */ #define MLT_PRODUCER(x) ( ( mlt_producer )( x ) ) /**< Cast to a Producer pointer */ #define MLT_MULTITRACK(x) ( ( mlt_multitrack )( x ) ) /**< Cast to a Multitrack pointer */ #define MLT_PLAYLIST(x) ( ( mlt_playlist )( x ) ) /**< Cast to a Playlist pointer */ #define MLT_TRACTOR(x) ( ( mlt_tractor )( x ) ) /**< Cast to a Tractor pointer */ #define MLT_FILTER(x) ( ( mlt_filter )( x ) ) /**< Cast to a Filter pointer */ #define MLT_TRANSITION(x) ( ( mlt_transition )( x ) ) /**< Cast to a Transition pointer */ #define MLT_CONSUMER(x) ( ( mlt_consumer )( x ) ) /**< Cast to a Consumer pointer */ #define MLT_FRAME(x) ( ( mlt_frame )( x ) ) /**< Cast to a Frame pointer */ #ifdef WIN32 #include /* Win32 compatibility function declarations */ extern int usleep(unsigned int useconds); extern int nanosleep( const struct timespec * rqtp, struct timespec * rmtp ); extern int setenv(const char *name, const char *value, int overwrite); #endif #endif mlt-0.9.0/src/framework/mlt_version.c000066400000000000000000000023601215300731300176010ustar00rootroot00000000000000/** * \file mlt_version.c * \brief contains version information * * Copyright (C) 2010 Ushodaya Enterprises Limited * \author Jonathan Thomas * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mlt_version.h" int mlt_version_get_int( ) { return LIBMLT_VERSION_INT; } char *mlt_version_get_string( ) { return LIBMLT_VERSION; } int mlt_version_get_major( ) { return LIBMLT_VERSION_MAJOR; } int mlt_version_get_minor( ) { return LIBMLT_VERSION_MINOR; } int mlt_version_get_revision( ) { return LIBMLT_VERSION_REVISION; } mlt-0.9.0/src/framework/mlt_version.h000066400000000000000000000031211215300731300176020ustar00rootroot00000000000000/** * \file mlt_version.h * \brief contains version information * * Copyright (C) 2010-2013 Ushodaya Enterprises Limited * \author Jonathan Thomas * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLT_VERSION_H_ #define _MLT_VERSION_H_ // Add quotes around any #define variables #define STRINGIZE2(s) #s #define STRINGIZE(s) STRINGIZE2(s) #define LIBMLT_VERSION_MAJOR 0 #define LIBMLT_VERSION_MINOR 9 #define LIBMLT_VERSION_REVISION 0 #define LIBMLT_VERSION_INT ((LIBMLT_VERSION_MAJOR<<16)+(LIBMLT_VERSION_MINOR<<8)+LIBMLT_VERSION_REVISION) #define LIBMLT_VERSION STRINGIZE(LIBMLT_VERSION_MAJOR.LIBMLT_VERSION_MINOR.LIBMLT_VERSION_REVISION) extern int mlt_version_get_int( ); extern int mlt_version_get_major( ); extern int mlt_version_get_minor( ); extern int mlt_version_get_revision( ); extern char *mlt_version_get_string( ); #endif mlt-0.9.0/src/melt/000077500000000000000000000000001215300731300140375ustar00rootroot00000000000000mlt-0.9.0/src/melt/Makefile000066400000000000000000000017141215300731300155020ustar00rootroot00000000000000include ../../config.mak OBJS = melt.o \ io.o CFLAGS += -I.. $(RDYNAMIC) -DVERSION=\"$(version)\" LDFLAGS += -L../framework -lmlt -lpthread SRCS := $(OBJS:.o=.c) ifeq ($(targetos), MinGW) ifeq (, $(findstring MELT_NOSDL, $(CFLAGS))) CFLAGS += `sdl-config --cflags` LDFLAGS += `sdl-config --libs` endif bindir = $(prefix) endif all: $(meltname) $(meltname): $(OBJS) $(CC) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(meltname) install: all install -d "$(DESTDIR)$(bindir)" install -c -m 755 $(meltname) "$(DESTDIR)$(bindir)" ifeq ($(extra_versioning), true) ifeq ($(melt_noversion), false) ln -s $(meltname) "$(DESTDIR)$(bindir)/melt" endif endif uninstall: rm -f "$(DESTDIR)$(bindir)/$(meltname)" ifeq ($(extra_versioning), true) ifeq ($(melt_noversion), false) rm -f "$(DESTDIR)$(bindir)/melt" endif endif ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/melt/io.c000066400000000000000000000100721215300731300146120ustar00rootroot00000000000000/* * io.c -- melt input/output * Copyright (C) 2002-2003 Ushodaya Enterprises Limited * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif /* System header files */ #include #include #include #include #ifndef WIN32 #include #else // MinGW defines struct timespec in pthread.h #include #endif #include #include /* Application header files */ #include "io.h" char *chomp( char *input ) { if ( input != NULL ) { int length = strlen( input ); if ( length && input[ length - 1 ] == '\n' ) input[ length - 1 ] = '\0'; if ( length > 1 && input[ length - 2 ] == '\r' ) input[ length - 2 ] = '\0'; } return input; } char *trim( char *input ) { if ( input != NULL ) { int length = strlen( input ); int first = 0; while( first < length && isspace( input[ first ] ) ) first ++; memmove( input, input + first, length - first + 1 ); length = length - first; while ( length > 0 && isspace( input[ length - 1 ] ) ) input[ -- length ] = '\0'; } return input; } char *strip_quotes( char *input ) { if ( input != NULL ) { char *ptr = strrchr( input, '\"' ); if ( ptr != NULL ) *ptr = '\0'; if ( input[ 0 ] == '\"' ) strcpy( input, input + 1 ); } return input; } int *get_int( int *output, int use ) { int *value = NULL; char temp[ 132 ]; *output = use; if ( trim( chomp( fgets( temp, 132, stdin ) ) ) != NULL ) { if ( strcmp( temp, "" ) ) *output = atoi( temp ); value = output; } return value; } /** This stores the previous settings */ static struct termios oldtty; static int mode = 0; /** This is called automatically on application exit to restore the previous tty settings. */ void term_exit(void) { #ifndef WIN32 if ( mode == 1 ) { tcsetattr( 0, TCSANOW, &oldtty ); mode = 0; } #endif } /** Init terminal so that we can grab keys without blocking. */ void term_init( ) { #ifndef WIN32 struct termios tty; tcgetattr( 0, &tty ); oldtty = tty; tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); tty.c_oflag |= OPOST; tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); tty.c_cflag &= ~(CSIZE|PARENB); tty.c_cflag |= CS8; tty.c_cc[ VMIN ] = 1; tty.c_cc[ VTIME ] = 0; tcsetattr( 0, TCSANOW, &tty ); mode = 1; atexit( term_exit ); #endif } /** Check for a keypress without blocking infinitely. Returns: ASCII value of keypress or -1 if no keypress detected. */ int term_read( ) { #ifndef WIN32 int n = 1; unsigned char ch; struct timeval tv; fd_set rfds; FD_ZERO( &rfds ); FD_SET( 0, &rfds ); tv.tv_sec = 0; tv.tv_usec = 40000; n = select( 1, &rfds, NULL, NULL, &tv ); if (n > 0) { n = read( 0, &ch, 1 ); tcflush( 0, TCIFLUSH ); if (n == 1) return ch; return n; } #else struct timespec tm = { 0, 40000000 }; nanosleep( &tm, NULL ); #endif return -1; } char get_keypress( ) { char value = '\0'; int pressed = 0; fflush( stdout ); term_init( ); while ( ( pressed = term_read( ) ) == -1 ) ; term_exit( ); value = (char)pressed; return value; } void wait_for_any_key( char *message ) { if ( message == NULL ) printf( "Press any key to continue: " ); else printf( "%s", message ); get_keypress( ); printf( "\n\n" ); } void beep( ) { printf( "%c", 7 ); fflush( stdout ); } mlt-0.9.0/src/melt/io.h000066400000000000000000000024561215300731300146260ustar00rootroot00000000000000/* * io.h -- melt input/output * Copyright (C) 2002-2003 Ushodaya Enterprises Limited * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _DEMO_IO_H_ #define _DEMO_IO_H_ #ifdef __cplusplus extern "C" { #endif extern char *chomp( char * ); extern char *trim( char * ); extern char *strip_quotes( char * ); extern char *get_string( char *, int, char * ); extern int *get_int( int *, int ); extern void term_init( ); extern int term_read( ); extern void term_exit( ); extern char get_keypress( ); extern void wait_for_any_key( char * ); extern void beep( ); #ifdef __cplusplus } #endif #endif mlt-0.9.0/src/melt/melt.c000066400000000000000000000745501215300731300151570ustar00rootroot00000000000000/* * melt.c -- MLT command line utility * Copyright (C) 2002-2013 Ushodaya Enterprises Limited * Authors: Charles Yates * Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #if (defined(__DARWIN__) || defined(WIN32)) && !defined(MELT_NOSDL) #include #endif #include "io.h" static mlt_producer melt = NULL; static void stop_handler(int signum) { if ( melt ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( melt ); mlt_properties_set_int( properties, "done", 1 ); } } static void abnormal_exit_handler(int signum) { // The process is going down hard. Restore the terminal first. term_exit(); // Reset the default handler so the core gets dumped. signal( signum, SIG_DFL ); raise( signum ); } static void transport_action( mlt_producer producer, char *value ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_multitrack multitrack = mlt_properties_get_data( properties, "multitrack", NULL ); mlt_consumer consumer = mlt_properties_get_data( properties, "transport_consumer", NULL ); mlt_properties jack = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES( consumer ), "jack_filter", NULL ); mlt_position position = producer? mlt_producer_position( producer ) : 0; mlt_properties_set_int( properties, "stats_off", 1 ); if ( strlen( value ) == 1 ) { switch( value[ 0 ] ) { case 'q': case 'Q': mlt_properties_set_int( properties, "done", 1 ); mlt_events_fire( jack, "jack-stop", NULL ); break; case '0': position = 0; mlt_producer_set_speed( producer, 1 ); mlt_producer_seek( producer, position ); mlt_consumer_purge( consumer ); mlt_events_fire( jack, "jack-seek", &position, NULL ); break; case '1': mlt_producer_set_speed( producer, -10 ); break; case '2': mlt_producer_set_speed( producer, -5 ); break; case '3': mlt_producer_set_speed( producer, -2 ); break; case '4': mlt_producer_set_speed( producer, -1 ); break; case '5': mlt_producer_set_speed( producer, 0 ); mlt_consumer_purge( consumer ); mlt_producer_seek( producer, mlt_consumer_position( consumer ) + 1 ); mlt_events_fire( jack, "jack-stop", NULL ); break; case '6': case ' ': if ( !jack || mlt_producer_get_speed( producer ) != 0 ) mlt_producer_set_speed( producer, 1 ); mlt_consumer_purge( consumer ); mlt_events_fire( jack, "jack-start", NULL ); break; case '7': mlt_producer_set_speed( producer, 2 ); break; case '8': mlt_producer_set_speed( producer, 5 ); break; case '9': mlt_producer_set_speed( producer, 10 ); break; case 'd': if ( multitrack != NULL ) { int i = 0; mlt_position last = -1; fprintf( stderr, "\n" ); for ( i = 0; 1; i ++ ) { position = mlt_multitrack_clip( multitrack, mlt_whence_relative_start, i ); if ( position == last ) break; last = position; fprintf( stderr, "%d: %d\n", i, (int)position ); } } break; case 'g': if ( multitrack != NULL ) { position = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 0 ); mlt_producer_seek( producer, position ); mlt_consumer_purge( consumer ); mlt_events_fire( jack, "jack-seek", &position, NULL ); } break; case 'H': if ( producer != NULL ) { position -= mlt_producer_get_fps( producer ) * 60; mlt_consumer_purge( consumer ); mlt_producer_seek( producer, position ); mlt_events_fire( jack, "jack-seek", &position, NULL ); } break; case 'h': if ( producer != NULL ) { position--; mlt_producer_set_speed( producer, 0 ); mlt_consumer_purge( consumer ); mlt_producer_seek( producer, position ); mlt_events_fire( jack, "jack-stop", NULL ); mlt_events_fire( jack, "jack-seek", &position, NULL ); } break; case 'j': if ( multitrack != NULL ) { position = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 1 ); mlt_consumer_purge( consumer ); mlt_producer_seek( producer, position ); mlt_events_fire( jack, "jack-seek", &position, NULL ); } break; case 'k': if ( multitrack != NULL ) { position = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, -1 ); mlt_consumer_purge( consumer ); mlt_producer_seek( producer, position ); mlt_events_fire( jack, "jack-seek", &position, NULL ); } break; case 'l': if ( producer != NULL ) { position++; mlt_consumer_purge( consumer ); if ( mlt_producer_get_speed( producer ) != 0 ) { mlt_producer_set_speed( producer, 0 ); mlt_events_fire( jack, "jack-stop", NULL ); } else { mlt_producer_seek( producer, position ); mlt_events_fire( jack, "jack-seek", &position, NULL ); } } break; case 'L': if ( producer != NULL ) { position += mlt_producer_get_fps( producer ) * 60; mlt_consumer_purge( consumer ); mlt_producer_seek( producer, position ); mlt_events_fire( jack, "jack-seek", &position, NULL ); } break; } mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "refresh", 1 ); } mlt_properties_set_int( properties, "stats_off", 0 ); } static void on_jack_started( mlt_properties owner, mlt_consumer consumer, mlt_position *position ) { mlt_producer producer = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES(consumer), "transport_producer", NULL ); if ( producer ) { if ( mlt_producer_get_speed( producer ) != 0 ) { mlt_properties jack = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES( consumer ), "jack_filter", NULL ); mlt_events_fire( jack, "jack-stop", NULL ); } else { mlt_producer_set_speed( producer, 1 ); mlt_consumer_purge( consumer ); mlt_producer_seek( producer, *position ); mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "refresh", 1 ); } } } static void on_jack_stopped( mlt_properties owner, mlt_consumer consumer, mlt_position *position ) { mlt_producer producer = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES(consumer), "transport_producer", NULL ); if ( producer ) { mlt_producer_set_speed( producer, 0 ); mlt_consumer_purge( consumer ); mlt_producer_seek( producer, *position ); mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "refresh", 1 ); } } static void setup_jack_transport( mlt_consumer consumer, mlt_profile profile ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_filter jack = mlt_factory_filter( profile, "jackrack", NULL ); mlt_properties jack_properties = MLT_FILTER_PROPERTIES(jack); mlt_service_attach( MLT_CONSUMER_SERVICE(consumer), jack ); mlt_properties_set_int( properties, "audio_off", 1 ); mlt_properties_set_data( properties, "jack_filter", jack, 0, (mlt_destructor) mlt_filter_close, NULL ); // mlt_properties_set( jack_properties, "out_1", "system:playback_1" ); // mlt_properties_set( jack_properties, "out_2", "system:playback_2" ); mlt_events_listen( jack_properties, consumer, "jack-started", (mlt_listener) on_jack_started ); mlt_events_listen( jack_properties, consumer, "jack-stopped", (mlt_listener) on_jack_stopped ); } static mlt_consumer create_consumer( mlt_profile profile, char *id ) { char *myid = id ? strdup( id ) : NULL; char *arg = myid ? strchr( myid, ':' ) : NULL; if ( arg != NULL ) *arg ++ = '\0'; mlt_consumer consumer = mlt_factory_consumer( profile, myid, arg ); if ( consumer != NULL ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_properties_set_data( properties, "transport_callback", transport_action, 0, NULL, NULL ); } if ( myid ) free( myid ); return consumer; } static void load_consumer( mlt_consumer *consumer, mlt_profile profile, int argc, char **argv ) { int i; int multi = 0; int qglsl = 0; for ( i = 1; i < argc; i ++ ) { // See if we need multi consumer. multi += !strcmp( argv[i], "-consumer" ); // Seee if we need the qglsl variant of multi consumer. if ( !strncmp( argv[i], "glsl.", 5 ) || !strncmp( argv[i], "movit.", 6 ) ) qglsl = 1; } // Disable qglsl if xgl is being used! for ( i = 1; qglsl && i < argc; i ++ ) if ( !strcmp( argv[i], "xgl" ) ) qglsl = 0; if ( multi > 1 || qglsl ) { // If there is more than one -consumer use the 'multi' consumer. int k = 0; char key[20]; if ( *consumer ) mlt_consumer_close( *consumer ); *consumer = create_consumer( profile, ( qglsl? "qglsl" : "multi" ) ); mlt_properties properties = MLT_CONSUMER_PROPERTIES( *consumer ); for ( i = 1; i < argc; i ++ ) { if ( !strcmp( argv[ i ], "-consumer" ) && argv[ i + 1 ]) { // Create a properties object for each sub-consumer mlt_properties new_props = mlt_properties_new(); snprintf( key, sizeof(key), "%d", k++ ); mlt_properties_set_data( properties, key, new_props, 0, (mlt_destructor) mlt_properties_close, NULL ); if ( strchr( argv[i + 1], ':' ) ) { char *temp = strdup( argv[++i] ); char *service = temp; char *target = strchr( temp, ':' ); *target++ = 0; mlt_properties_set( new_props, "mlt_service", service ); mlt_properties_set( new_props, "target", target ); } else { mlt_properties_set( new_props, "mlt_service", argv[ ++i ] ); } while ( argv[ i + 1 ] && strchr( argv[ i + 1 ], '=' ) ) mlt_properties_parse( new_props, argv[ ++ i ] ); } } } else for ( i = 1; i < argc; i ++ ) { if ( !strcmp( argv[ i ], "-consumer" ) ) { if ( *consumer ) mlt_consumer_close( *consumer ); *consumer = create_consumer( profile, argv[ ++ i ] ); if ( *consumer ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( *consumer ); while ( argv[ i + 1 ] != NULL && strchr( argv[ i + 1 ], '=' ) ) mlt_properties_parse( properties, argv[ ++ i ] ); } } } } #if (defined(__DARWIN__) || defined(WIN32)) && !defined(MELT_NOSDL) static void event_handling( mlt_producer producer, mlt_consumer consumer ) { SDL_Event event; while ( SDL_PollEvent( &event ) ) { switch( event.type ) { case SDL_QUIT: mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( consumer ), "done", 1 ); break; case SDL_KEYDOWN: if ( event.key.keysym.unicode < 0x80 && event.key.keysym.unicode > 0 ) { char keyboard[ 2 ] = { event.key.keysym.unicode, 0 }; transport_action( producer, keyboard ); } break; } } } #endif static void transport( mlt_producer producer, mlt_consumer consumer ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); int silent = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( consumer ), "silent" ); int progress = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( consumer ), "progress" ); struct timespec tm = { 0, 40000000 }; int total_length = mlt_producer_get_length( producer ); int last_position = 0; if ( mlt_properties_get_int( properties, "done" ) == 0 && !mlt_consumer_is_stopped( consumer ) ) { if ( !silent && !progress ) { term_init( ); fprintf( stderr, "+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+\n" ); fprintf( stderr, "|1=-10| |2= -5| |3= -2| |4= -1| |5= 0| |6= 1| |7= 2| |8= 5| |9= 10|\n" ); fprintf( stderr, "+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+\n" ); fprintf( stderr, "+---------------------------------------------------------------------+\n" ); fprintf( stderr, "| H = back 1 minute, L = forward 1 minute |\n" ); fprintf( stderr, "| h = previous frame, l = next frame |\n" ); fprintf( stderr, "| g = start of clip, j = next clip, k = previous clip |\n" ); fprintf( stderr, "| 0 = restart, q = quit, space = play |\n" ); fprintf( stderr, "+---------------------------------------------------------------------+\n" ); } while( mlt_properties_get_int( properties, "done" ) == 0 && !mlt_consumer_is_stopped( consumer ) ) { int value = ( silent || progress )? -1 : term_read( ); if ( value != -1 ) { char string[ 2 ] = { value, 0 }; transport_action( producer, string ); } #if (defined(__DARWIN__) || defined(WIN32)) && !defined(MELT_NOSDL) event_handling( producer, consumer ); #endif if ( !silent && mlt_properties_get_int( properties, "stats_off" ) == 0 ) { if ( progress ) { int current_position = mlt_producer_position( producer ); if ( current_position > last_position ) { fprintf( stderr, "Current Frame: %10d, percentage: %10d%c", current_position, 100 * current_position / total_length, progress == 2 ? '\n' : '\r' ); last_position = current_position; } } else { fprintf( stderr, "Current Position: %10d\r", (int)mlt_consumer_position( consumer ) ); } fflush( stderr ); } if ( silent || progress ) nanosleep( &tm, NULL ); } if ( !silent ) fprintf( stderr, "\n" ); } } static void show_usage( char *program_name ) { fprintf( stdout, "Usage: %s [options] [producer [name=value]* ]+\n" "Options:\n" " -attach filter[:arg] [name=value]* Attach a filter to the output\n" " -attach-cut filter[:arg] [name=value]* Attach a filter to a cut\n" " -attach-track filter[:arg] [name=value]* Attach a filter to a track\n" " -attach-clip filter[:arg] [name=value]* Attach a filter to a producer\n" " -audio-track | -hide-video Add an audio-only track\n" " -blank frames Add blank silence to a track\n" " -consumer id[:arg] [name=value]* Set the consumer (sink)\n" " -debug Set the logging level to debug\n" " -filter filter[:arg] [name=value]* Add a filter to the current track\n" " -group [name=value]* Apply properties repeatedly\n" " -help Show this message\n" " -jack Enable JACK transport synchronization\n" " -join clips Join multiple clips into one cut\n" " -mix length Add a mix between the last two cuts\n" " -mixer transition Add a transition to the mix\n" " -null-track | -hide-track Add a hidden track\n" " -profile name Set the processing settings\n" " -progress Display progress along with position\n" " -remove Remove the most recent cut\n" " -repeat times Repeat the last cut\n" " -query List all of the registered services\n" " -query \"consumers\" | \"consumer\"=id List consumers or show info about one\n" " -query \"filters\" | \"filter\"=id List filters or show info about one\n" " -query \"producers\" | \"producer\"=id List producers or show info about one\n" " -query \"transitions\" | \"transition\"=id List transitions, show info about one\n" " -query \"profiles\" | \"profile\"=id List profiles, show info about one\n" " -query \"presets\" | \"preset\"=id List presets, show info about one\n" " -query \"formats\" List audio/video formats\n" " -query \"audio_codecs\" List audio codecs\n" " -query \"video_codecs\" List video codecs\n" " -serialise [filename] Write the commands to a text file\n" " -silent Do not display position/transport\n" " -split relative-frame Split the last cut into two cuts\n" " -swap Rearrange the last two cuts\n" " -track Add a track\n" " -transition id[:arg] [name=value]* Add a transition\n" " -verbose Set the logging level to verbose\n" " -version Show the version and copyright\n" " -video-track | -hide-audio Add a video-only track\n" "For more help: \n", basename( program_name ) ); } static void query_metadata( mlt_repository repo, mlt_service_type type, const char *typestr, char *id ) { mlt_properties metadata = mlt_repository_metadata( repo, type, id ); if ( metadata ) { char *s = mlt_properties_serialise_yaml( metadata ); fprintf( stdout, "%s", s ); free( s ); } else { fprintf( stdout, "# No metadata for %s \"%s\"\n", typestr, id ); } } static int is_service_hidden(mlt_repository repo, mlt_service_type type, const char *service_name ) { mlt_properties metadata = NULL; mlt_properties tags = NULL; metadata = mlt_repository_metadata(repo, type, service_name); if( metadata ) { tags = mlt_properties_get_data( metadata, "tags", NULL ); if( tags ) { int k; for ( k = 0; k < mlt_properties_count( tags ); k++ ) { const char* value = mlt_properties_get_value(tags, k); if( !strcmp("Hidden", value) ) { return 1; } } } } return 0; } static void query_services( mlt_repository repo, mlt_service_type type ) { mlt_properties services = NULL; const char *typestr = NULL; switch ( type ) { case consumer_type: services = mlt_repository_consumers( repo ); typestr = "consumers"; break; case filter_type: services = mlt_repository_filters( repo ); typestr = "filters"; break; case producer_type: services = mlt_repository_producers( repo ); typestr = "producers"; break; case transition_type: services = mlt_repository_transitions( repo ); typestr = "transitions"; break; default: return; } fprintf( stdout, "---\n%s:\n", typestr ); if ( services ) { int j; for ( j = 0; j < mlt_properties_count( services ); j++ ) { const char* service_name = mlt_properties_get_name( services, j ); if( !is_service_hidden(repo, type, service_name ) ) fprintf( stdout, " - %s\n", service_name ); } } fprintf( stdout, "...\n" ); } static void query_profiles() { mlt_properties profiles = mlt_profile_list(); fprintf( stdout, "---\nprofiles:\n" ); if ( profiles ) { int j; for ( j = 0; j < mlt_properties_count( profiles ); j++ ) fprintf( stdout, " - %s\n", mlt_properties_get_name( profiles, j ) ); } fprintf( stdout, "...\n" ); mlt_properties_close( profiles ); } static void query_profile( const char *id ) { mlt_properties profiles = mlt_profile_list(); mlt_properties profile = mlt_properties_get_data( profiles, id, NULL ); if ( profile ) { char *s = mlt_properties_serialise_yaml( profile ); fprintf( stdout, "%s", s ); free( s ); } else { fprintf( stdout, "# No metadata for profile \"%s\"\n", id ); } mlt_properties_close( profiles ); } static void query_presets() { mlt_properties presets = mlt_repository_presets(); fprintf( stdout, "---\npresets:\n" ); if ( presets ) { int j; for ( j = 0; j < mlt_properties_count( presets ); j++ ) fprintf( stdout, " - %s\n", mlt_properties_get_name( presets, j ) ); } fprintf( stdout, "...\n" ); mlt_properties_close( presets ); } static void query_preset( const char *id ) { mlt_properties presets = mlt_repository_presets(); mlt_properties preset = mlt_properties_get_data( presets, id, NULL ); if ( preset ) { char *s = mlt_properties_serialise_yaml( preset ); fprintf( stdout, "%s", s ); free( s ); } else { fprintf( stdout, "# No metadata for preset \"%s\"\n", id ); } mlt_properties_close( presets ); } static void query_formats( ) { mlt_consumer consumer = mlt_factory_consumer( NULL, "avformat", NULL ); if ( consumer ) { mlt_properties_set( MLT_CONSUMER_PROPERTIES(consumer), "f", "list" ); mlt_consumer_start( consumer ); mlt_consumer_close( consumer ); } else { fprintf( stdout, "# No formats - failed to load avformat consumer\n" ); } } static void query_acodecs( ) { mlt_consumer consumer = mlt_factory_consumer( NULL, "avformat", NULL ); if ( consumer ) { mlt_properties_set( MLT_CONSUMER_PROPERTIES(consumer), "acodec", "list" ); mlt_consumer_start( consumer ); mlt_consumer_close( consumer ); } else { fprintf( stdout, "# No audio codecs - failed to load avformat consumer\n" ); } } static void query_vcodecs( ) { mlt_consumer consumer = mlt_factory_consumer( NULL, "avformat", NULL ); if ( consumer ) { mlt_properties_set( MLT_CONSUMER_PROPERTIES(consumer), "vcodec", "list" ); mlt_consumer_start( consumer ); mlt_consumer_close( consumer ); } else { fprintf( stdout, "# No video codecs - failed to load avformat consumer\n" ); } } static void on_fatal_error( mlt_properties owner, mlt_consumer consumer ) { mlt_consumer_stop( consumer ); exit( EXIT_FAILURE ); } int main( int argc, char **argv ) { int i; mlt_consumer consumer = NULL; FILE *store = NULL; char *name = NULL; mlt_profile profile = NULL; int is_progress = 0; int is_silent = 0; mlt_profile backup_profile; // Handle abnormal exit situations. signal( SIGSEGV, abnormal_exit_handler ); signal( SIGILL, abnormal_exit_handler ); signal( SIGABRT, abnormal_exit_handler ); // Construct the factory mlt_repository repo = mlt_factory_init( NULL ); #if defined(WIN32) && !defined(MELT_NOSDL) is_silent = 1; #endif for ( i = 1; i < argc; i ++ ) { // Check for serialisation switch if ( !strcmp( argv[ i ], "-serialise" ) ) { name = argv[ ++ i ]; if ( name != NULL && strstr( name, ".melt" ) ) store = fopen( name, "w" ); else { if ( name == NULL || name[0] == '-' ) store = stdout; name = NULL; } } // Look for the profile option else if ( !strcmp( argv[ i ], "-profile" ) ) { const char *pname = argv[ ++ i ]; if ( pname && pname[0] != '-' ) profile = mlt_profile_init( pname ); } else if ( !strcmp( argv[ i ], "-progress" ) ) { is_progress = 1; } else if ( !strcmp( argv[ i ], "-progress2" ) ) { is_progress = 2; } // Look for the query option else if ( !strcmp( argv[ i ], "-query" ) ) { const char *pname = argv[ ++ i ]; if ( pname && pname[0] != '-' ) { if ( !strcmp( pname, "consumers" ) || !strcmp( pname, "consumer" ) ) query_services( repo, consumer_type ); else if ( !strcmp( pname, "filters" ) || !strcmp( pname, "filter" ) ) query_services( repo, filter_type ); else if ( !strcmp( pname, "producers" ) || !strcmp( pname, "producer" ) ) query_services( repo, producer_type ); else if ( !strcmp( pname, "transitions" ) || !strcmp( pname, "transition" ) ) query_services( repo, transition_type ); else if ( !strcmp( pname, "profiles" ) || !strcmp( pname, "profile" ) ) query_profiles(); else if ( !strcmp( pname, "presets" ) || !strcmp( pname, "preset" ) ) query_presets(); else if ( !strncmp( pname, "format", 6 ) ) query_formats(); else if ( !strncmp( pname, "acodec", 6 ) || !strcmp( pname, "audio_codecs" ) ) query_acodecs(); else if ( !strncmp( pname, "vcodec", 6 ) || !strcmp( pname, "video_codecs" ) ) query_vcodecs(); else if ( !strncmp( pname, "consumer=", 9 ) ) query_metadata( repo, consumer_type, "consumer", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "filter=", 7 ) ) query_metadata( repo, filter_type, "filter", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "producer=", 9 ) ) query_metadata( repo, producer_type, "producer", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "transition=", 11 ) ) query_metadata( repo, transition_type, "transition", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "profile=", 8 ) ) query_profile( strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "preset=", 7 ) ) query_preset( strchr( pname, '=' ) + 1 ); else goto query_all; } else { query_all: query_services( repo, consumer_type ); query_services( repo, filter_type ); query_services( repo, producer_type ); query_services( repo, transition_type ); fprintf( stdout, "# You can query the metadata for a specific service using:\n" "# -query =\n" "# where is one of: consumer, filter, producer, or transition.\n" ); } goto exit_factory; } else if ( !strcmp( argv[ i ], "-silent" ) ) { is_silent = 1; } else if ( !strcmp( argv[ i ], "-verbose" ) ) { mlt_log_set_level( MLT_LOG_VERBOSE ); } else if ( !strcmp( argv[ i ], "-version" ) || !strcmp( argv[ i ], "--version" ) ) { fprintf( stdout, "%s " VERSION "\n" "Copyright (C) 2002-2013 Ushodaya Enterprises Limited\n" "\n" "This is free software; see the source for copying conditions. There is NO\n" "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", basename( argv[0] ) ); goto exit_factory; } else if ( !strcmp( argv[ i ], "-debug" ) ) { mlt_log_set_level( MLT_LOG_DEBUG ); } } if ( !is_silent && !isatty( STDIN_FILENO ) && !is_progress ) is_progress = 1; // Create profile if not set explicitly if ( getenv( "MLT_PROFILE" ) ) profile = mlt_profile_init( NULL ); if ( profile == NULL ) profile = mlt_profile_init( NULL ); else profile->is_explicit = 1; // Look for the consumer option to load profile settings from consumer properties backup_profile = mlt_profile_clone( profile ); load_consumer( &consumer, profile, argc, argv ); // If the consumer changed the profile, then it is explicit. if ( backup_profile && !profile->is_explicit && ( profile->width != backup_profile->width || profile->height != backup_profile->height || profile->sample_aspect_num != backup_profile->sample_aspect_num || profile->sample_aspect_den != backup_profile->sample_aspect_den || profile->frame_rate_den != backup_profile->frame_rate_den || profile->frame_rate_num != backup_profile->frame_rate_num || profile->colorspace != backup_profile->colorspace ) ) profile->is_explicit = 1; mlt_profile_close( backup_profile ); // Get melt producer if ( argc > 1 ) melt = mlt_factory_producer( profile, "melt", &argv[ 1 ] ); if ( melt ) { // Generate an automatic profile if needed. if ( ! profile->is_explicit ) { mlt_profile_from_producer( profile, melt ); mlt_producer_close( melt ); melt = mlt_factory_producer( profile, "melt", &argv[ 1 ] ); } // Reload the consumer with the fully qualified profile. // The producer or auto-profile could have changed the profile. load_consumer( &consumer, profile, argc, argv ); // See if producer has consumer already attached if ( !store && !consumer ) { consumer = MLT_CONSUMER( mlt_service_consumer( MLT_PRODUCER_SERVICE( melt ) ) ); if ( consumer ) { mlt_properties_inc_ref( MLT_CONSUMER_PROPERTIES(consumer) ); // because we explicitly close it mlt_properties_set_data( MLT_CONSUMER_PROPERTIES(consumer), "transport_callback", transport_action, 0, NULL, NULL ); } } // If we have no consumer, default to sdl if ( store == NULL && consumer == NULL ) consumer = create_consumer( profile, NULL ); } // Set transport properties on consumer and produder if ( consumer != NULL && melt != NULL ) { mlt_properties_set_data( MLT_CONSUMER_PROPERTIES( consumer ), "transport_producer", melt, 0, NULL, NULL ); mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( melt ), "transport_consumer", consumer, 0, NULL, NULL ); if ( is_progress ) mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "progress", is_progress ); if ( is_silent ) mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "silent", is_silent ); } if ( argc > 1 && melt != NULL && mlt_producer_get_length( melt ) > 0 ) { // Parse the arguments for ( i = 1; i < argc; i ++ ) { if ( !strcmp( argv[ i ], "-jack" ) ) { setup_jack_transport( consumer, profile ); } else if ( !strcmp( argv[ i ], "-serialise" ) ) { if ( store != stdout ) i ++; } else { if ( store != NULL ) fprintf( store, "%s\n", argv[ i ] ); i ++; while ( argv[ i ] != NULL && argv[ i ][ 0 ] != '-' ) { if ( store != NULL ) fprintf( store, "%s\n", argv[ i ] ); i += 1; } i --; } } if ( consumer != NULL && store == NULL ) { // Get melt's properties mlt_properties melt_props = MLT_PRODUCER_PROPERTIES( melt ); // Get the last group mlt_properties group = mlt_properties_get_data( melt_props, "group", 0 ); // Apply group settings mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_properties_inherit( properties, group ); // Connect consumer to melt mlt_consumer_connect( consumer, MLT_PRODUCER_SERVICE( melt ) ); // Start the consumer mlt_events_listen( properties, consumer, "consumer-fatal-error", ( mlt_listener )on_fatal_error ); if ( mlt_consumer_start( consumer ) == 0 ) { // Try to exit gracefully upon these signals signal( SIGINT, stop_handler ); signal( SIGTERM, stop_handler ); #ifndef WIN32 signal( SIGHUP, stop_handler ); signal( SIGPIPE, stop_handler ); #endif // Transport functionality transport( melt, consumer ); // Stop the consumer mlt_consumer_stop( consumer ); } } else if ( store != NULL && store != stdout && name != NULL ) { fprintf( stderr, "Project saved as %s.\n", name ); fclose( store ); } } else { show_usage( argv[0] ); } // Disconnect producer from consumer to prevent ref cycles from closing services if ( consumer ) { mlt_consumer_connect( consumer, NULL ); mlt_events_fire( MLT_CONSUMER_PROPERTIES(consumer), "consumer-cleanup", NULL); } // Close the producer if ( melt != NULL ) mlt_producer_close( melt ); // Close the consumer if ( consumer != NULL ) mlt_consumer_close( consumer ); // Close the factory mlt_profile_close( profile ); exit_factory: mlt_factory_close( ); return 0; } mlt-0.9.0/src/mlt++/000077500000000000000000000000001215300731300140205ustar00rootroot00000000000000mlt-0.9.0/src/mlt++/Makefile000066400000000000000000000046011215300731300154610ustar00rootroot00000000000000include ../../config.mak include config.mak INSTALL = install ifeq ($(targetos), Darwin) NAME = libmlt++$(LIBSUF) TARGET = libmlt++.$(version)$(LIBSUF) SONAME = libmlt++.$(soversion)$(LIBSUF) LIBFLAGS += -install_name $(libdir)/$(SONAME) -current_version $(version) -compatibility_version $(soversion) else ifeq ($(targetos), MinGW) NAME = libmlt++$(LIBSUF) TARGET = libmlt++-$(soversion)$(LIBSUF) CXXFLAGS += -DMLTPP_EXPORTS LIBFLAGS += -Wl,--output-def,libmlt++.def else NAME = libmlt++$(LIBSUF) TARGET = $(NAME).$(version) SONAME = $(NAME).$(soversion) LIBFLAGS += -Wl,-soname,$(SONAME) endif CXXFLAGS += -I.. $(RDYNAMIC) -DVERSION=\"$(version)\" -fvisibility=hidden LDFLAGS += -L../framework -lmlt ifeq ($(targetos), Linux) LDFLAGS += -Wl,--version-script=mlt++.vers endif OBJS = MltConsumer.o \ MltDeque.o \ MltEvent.o \ MltFactory.o \ MltField.o \ MltFilter.o \ MltFilteredConsumer.o \ MltFilteredProducer.o \ MltFrame.o \ MltGeometry.o \ MltMultitrack.o \ MltParser.o \ MltPlaylist.o \ MltProducer.o \ MltProfile.o \ MltProperties.o \ MltPushConsumer.o \ MltRepository.o \ MltService.o \ MltTokeniser.o \ MltTractor.o \ MltTransition.o SRCS = $(OBJS:.o=.cpp) HEADERS = config.h Mlt.h $(OBJS:.o=.h) all: $(TARGET) $(TARGET): $(OBJS) $(CXX) $(LIBFLAGS) -o $@ $(OBJS) $(LDFLAGS) ln -sf $(TARGET) $(NAME) if [ "$(targetos)" != "MinGW" ]; then \ ln -sf $(TARGET) $(SONAME) ; \ fi depend: $(SRCS) $(CXX) -MM $(CXXFLAGS) $^ 1>.depend clean: $(RM) $(OBJS) $(TARGET) $(NAME) $(SONAME) distclean: clean install: $(INSTALL) -d "$(DESTDIR)$(libdir)" if [ "$(targetos)" = "MinGW" ]; then \ $(INSTALL) -m 755 $(TARGET) $(DESTDIR)$(prefix) ; \ $(INSTALL) -m 755 $(TARGET) $(DESTDIR)$(libdir)/libmlt++.dll ; \ $(INSTALL) -m 644 libmlt++.def $(DESTDIR)$(libdir) ; \ else \ $(INSTALL) -m 755 $(TARGET) $(DESTDIR)$(libdir) ; \ ln -sf $(TARGET) $(DESTDIR)$(libdir)/$(SONAME) ; \ ln -sf $(TARGET) $(DESTDIR)$(libdir)/$(NAME) ; \ fi $(INSTALL) -d "$(DESTDIR)$(prefix)/include/mlt++" $(INSTALL) -m 644 $(HEADERS) "$(DESTDIR)$(prefix)/include/mlt++" uninstall: rm -f "$(DESTDIR)$(libdir)/$(TARGET)" if [ "$(targetos)" != "MinGW" ]; then \ rm -f "$(DESTDIR)$(libdir)/$(NAME)" ; \ rm -f "$(DESTDIR)$(libdir)/$(SONAME)" ; \ fi rm -rf "$(DESTDIR)$(prefix)/include/mlt++" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/mlt++/Mlt.h000066400000000000000000000026751215300731300147370ustar00rootroot00000000000000/** * Mlt.h - Convenience header file for all mlt++ objects * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_H_ #define _MLTPP_H_ #include "MltConsumer.h" #include "MltDeque.h" #include "MltEvent.h" #include "MltFactory.h" #include "MltField.h" #include "MltFilter.h" #include "MltFilteredConsumer.h" #include "MltFrame.h" #include "MltGeometry.h" #include "MltMultitrack.h" #include "MltParser.h" #include "MltPlaylist.h" #include "MltProducer.h" #include "MltProfile.h" #include "MltProperties.h" #include "MltPushConsumer.h" #include "MltRepository.h" #include "MltService.h" #include "MltTokeniser.h" #include "MltTractor.h" #include "MltTransition.h" #endif mlt-0.9.0/src/mlt++/MltConsumer.cpp000066400000000000000000000057041215300731300170020ustar00rootroot00000000000000/** * MltConsumer.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "MltConsumer.h" #include "MltEvent.h" #include "MltProfile.h" using namespace Mlt; Consumer::Consumer( ) : instance( NULL ) { instance = mlt_factory_consumer( NULL, NULL, NULL ); } Consumer::Consumer( Profile& profile ) : instance( NULL ) { instance = mlt_factory_consumer( profile.get_profile(), NULL, NULL ); } Consumer::Consumer( Profile& profile, const char *id, const char *arg ) : instance( NULL ) { if ( id == NULL || arg != NULL ) { instance = mlt_factory_consumer( profile.get_profile(), id, arg ); } else { if ( strchr( id, ':' ) ) { char *temp = strdup( id ); char *arg = strchr( temp, ':' ) + 1; *( arg - 1 ) = '\0'; instance = mlt_factory_consumer( profile.get_profile(), temp, arg ); free( temp ); } else { instance = mlt_factory_consumer( profile.get_profile(), id, NULL ); } } } Consumer::Consumer( Service &consumer ) : instance( NULL ) { if ( consumer.type( ) == consumer_type ) { instance = ( mlt_consumer )consumer.get_service( ); inc_ref( ); } } Consumer::Consumer( Consumer &consumer ) : Mlt::Service( consumer ), instance( consumer.get_consumer( ) ) { inc_ref( ); } Consumer::Consumer( mlt_consumer consumer ) : instance( consumer ) { inc_ref( ); } Consumer::~Consumer( ) { mlt_consumer_close( instance ); } mlt_consumer Consumer::get_consumer( ) { return instance; } mlt_service Consumer::get_service( ) { return mlt_consumer_service( get_consumer( ) ); } int Consumer::connect( Service &service ) { return connect_producer( service ); } int Consumer::start( ) { return mlt_consumer_start( get_consumer( ) ); } void Consumer::purge( ) { mlt_consumer_purge( get_consumer( ) ); } int Consumer::stop( ) { return mlt_consumer_stop( get_consumer( ) ); } bool Consumer::is_stopped( ) { return mlt_consumer_is_stopped( get_consumer( ) ) != 0; } int Consumer::run( ) { int ret = start( ); if ( !is_stopped( ) ) { Event *e = setup_wait_for( "consumer-stopped" ); wait_for( e ); delete e; } return ret; } int Consumer::position( ) { return mlt_consumer_position( get_consumer() ); } mlt-0.9.0/src/mlt++/MltConsumer.h000066400000000000000000000031561215300731300164460ustar00rootroot00000000000000/** * MltConsumer.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_CONSUMER_H_ #define _MLTPP_CONSUMER_H_ #include "config.h" #include #include "MltService.h" namespace Mlt { class Service; class Profile; class MLTPP_DECLSPEC Consumer : public Service { private: mlt_consumer instance; public: Consumer( ); Consumer( Profile& profile ); Consumer( Profile& profile, const char *id , const char *service = NULL ); Consumer( Service &consumer ); Consumer( Consumer &consumer ); Consumer( mlt_consumer consumer ); virtual ~Consumer( ); virtual mlt_consumer get_consumer( ); mlt_service get_service( ); virtual int connect( Service &service ); int run( ); int start( ); void purge( ); int stop( ); bool is_stopped( ); int position( ); }; } #endif mlt-0.9.0/src/mlt++/MltDeque.cpp000066400000000000000000000030721215300731300162460ustar00rootroot00000000000000/** * MltDeque.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "MltDeque.h" using namespace Mlt; Deque::Deque( ) { deque = mlt_deque_init( ); } Deque::~Deque( ) { mlt_deque_close( deque ); } int Deque::count( ) { return mlt_deque_count( deque ); } int Deque::push_back( void *item ) { return mlt_deque_push_back( deque, item ); } void *Deque::pop_back( ) { return mlt_deque_pop_back( deque ); } int Deque::push_front( void *item ) { return mlt_deque_push_front( deque, item ); } void *Deque::pop_front( ) { return mlt_deque_pop_front( deque ); } void *Deque::peek_back( ) { return mlt_deque_peek_back( deque ); } void *Deque::peek_front( ) { return mlt_deque_peek_front( deque ); } void *Deque::peek( int index ) { return mlt_deque_peek( deque, index ); } mlt-0.9.0/src/mlt++/MltDeque.h000066400000000000000000000024201215300731300157070ustar00rootroot00000000000000/** * MltDeque.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_DEQUE_H #define _MLTPP_DEQUE_H #include "config.h" #include namespace Mlt { class MLTPP_DECLSPEC Deque { private: mlt_deque deque; public: Deque( ); ~Deque( ); int count( ); int push_back( void *item ); void *pop_back( ); int push_front( void *item ); void *pop_front( ); void *peek_back( ); void *peek_front( ); void *peek( int index ); }; } #endif mlt-0.9.0/src/mlt++/MltEvent.cpp000066400000000000000000000025561215300731300162720ustar00rootroot00000000000000/** * MltEvent.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "MltEvent.h" using namespace Mlt; Event::Event( mlt_event event ) : instance( event ) { mlt_event_inc_ref( instance ); } Event::Event( Event &event ) : instance( event.get_event( ) ) { mlt_event_inc_ref( instance ); } Event::~Event( ) { mlt_event_close( instance ); } mlt_event Event::get_event( ) { return instance; } bool Event::is_valid( ) { return instance != NULL; } void Event::block( ) { mlt_event_block( get_event( ) ); } void Event::unblock( ) { mlt_event_unblock( get_event( ) ); } mlt-0.9.0/src/mlt++/MltEvent.h000066400000000000000000000023031215300731300157250ustar00rootroot00000000000000/** * MltEvent.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_EVENT_H_ #define _MLTPP_EVENT_H_ #include "config.h" #include namespace Mlt { class MLTPP_DECLSPEC Event { private: mlt_event instance; public: Event( mlt_event ); Event( Event & ); ~Event( ); mlt_event get_event( ); bool is_valid( ); void block( ); void unblock( ); }; } #endif mlt-0.9.0/src/mlt++/MltFactory.cpp000066400000000000000000000034401215300731300166110ustar00rootroot00000000000000/** * MltFactory.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Copyright (C) 2008 Dan Dennedy * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "MltFactory.h" #include "MltProducer.h" #include "MltFilter.h" #include "MltTransition.h" #include "MltConsumer.h" #include "MltRepository.h" using namespace Mlt; Repository *Factory::init( const char *directory ) { return new Repository( mlt_factory_init( directory ) ); } Properties *Factory::event_object( ) { return new Properties( mlt_factory_event_object( ) ); } Producer *Factory::producer( Profile& profile, char *id, char *arg ) { return new Producer( profile, id, arg ); } Filter *Factory::filter( Profile& profile, char *id, char *arg ) { return new Filter( profile, id, arg ); } Transition *Factory::transition( Profile& profile, char *id, char *arg ) { return new Transition( profile, id, arg ); } Consumer *Factory::consumer( Profile& profile, char *id, char *arg ) { return new Consumer( profile, id, arg ); } void Factory::close( ) { mlt_factory_close( ); } mlt-0.9.0/src/mlt++/MltFactory.h000066400000000000000000000032441215300731300162600ustar00rootroot00000000000000/** * MltFactory.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Copyright (C) 2008 Dan Dennedy * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_FACTORY_H_ #define _MLTPP_FACTORY_H_ #include "config.h" #ifdef SWIG #define MLTPP_DECLSPEC #endif #include namespace Mlt { class Properties; class Producer; class Filter; class Transition; class Consumer; class Profile; class Repository; class MLTPP_DECLSPEC Factory { public: static Repository *init( const char *directory = NULL ); static Properties *event_object( ); static Producer *producer( Profile& profile, char *id, char *arg = NULL ); static Filter *filter( Profile& profile, char *id, char *arg = NULL ); static Transition *transition( Profile& profile, char *id, char *arg = NULL ); static Consumer *consumer( Profile& profile, char *id, char *arg = NULL ); static void close( ); }; } #endif mlt-0.9.0/src/mlt++/MltField.cpp000066400000000000000000000033571215300731300162340ustar00rootroot00000000000000/** * MltField.cpp - Field wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "MltField.h" #include "MltFilter.h" #include "MltTransition.h" using namespace Mlt; Field::Field( mlt_field field ) : instance( field ) { inc_ref( ); } Field::Field( Field &field ) : Mlt::Service( field ), instance( field.get_field( ) ) { inc_ref( ); } Field::~Field( ) { mlt_field_close( instance ); } mlt_field Field::get_field( ) { return instance; } mlt_service Field::get_service( ) { return mlt_field_service( get_field( ) ); } int Field::plant_filter( Filter &filter, int track ) { return mlt_field_plant_filter( get_field( ), filter.get_filter( ), track ); } int Field::plant_transition( Transition &transition, int a_track, int b_track ) { return mlt_field_plant_transition( get_field( ), transition.get_transition( ), a_track, b_track ); } void Field::disconnect_service( Service &service ) { mlt_field_disconnect_service( get_field(), service.get_service() ); } mlt-0.9.0/src/mlt++/MltField.h000066400000000000000000000027221215300731300156740ustar00rootroot00000000000000/** * MltField.h - Field wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_FIELD_H_ #define _MLTPP_FIELD_H_ #include "config.h" #include #include "MltService.h" namespace Mlt { class Service; class Filter; class Transition; class MLTPP_DECLSPEC Field : public Service { private: mlt_field instance; public: Field( mlt_field field ); Field( Field &field ); virtual ~Field( ); mlt_field get_field( ); mlt_service get_service( ); int plant_filter( Filter &filter, int track = 0 ); int plant_transition( Transition &transition, int a_track = 0, int b_track = 1 ); void disconnect_service( Service &service ); }; } #endif mlt-0.9.0/src/mlt++/MltFilter.cpp000066400000000000000000000055431215300731300164350ustar00rootroot00000000000000/** * MltFilter.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "MltFilter.h" #include "MltProfile.h" using namespace Mlt; Filter::Filter( Profile& profile, const char *id, const char *arg ) : instance( NULL ) { if ( arg != NULL ) { instance = mlt_factory_filter( profile.get_profile(), id, arg ); } else { if ( strchr( id, ':' ) ) { char *temp = strdup( id ); char *arg = strchr( temp, ':' ) + 1; *( arg - 1 ) = '\0'; instance = mlt_factory_filter( profile.get_profile(), temp, arg ); free( temp ); } else { instance = mlt_factory_filter( profile.get_profile(), id, NULL ); } } } Filter::Filter( Service &filter ) : instance( NULL ) { if ( filter.type( ) == filter_type ) { instance = ( mlt_filter )filter.get_service( ); inc_ref( ); } } Filter::Filter( Filter &filter ) : Mlt::Service( filter ), instance( filter.get_filter( ) ) { inc_ref( ); } Filter::Filter( mlt_filter filter ) : instance( filter ) { inc_ref( ); } Filter::~Filter( ) { mlt_filter_close( instance ); } mlt_filter Filter::get_filter( ) { return instance; } mlt_service Filter::get_service( ) { return mlt_filter_service( get_filter( ) ); } int Filter::connect( Service &service, int index ) { return mlt_filter_connect( get_filter( ), service.get_service( ), index ); } void Filter::set_in_and_out( int in, int out ) { mlt_filter_set_in_and_out( get_filter( ), in, out ); } int Filter::get_in( ) { return mlt_filter_get_in( get_filter( ) ); } int Filter::get_out( ) { return mlt_filter_get_out( get_filter( ) ); } int Filter::get_length( ) { return mlt_filter_get_length( get_filter( ) ); } int Filter::get_length2( Frame &frame ) { return mlt_filter_get_length2( get_filter( ), frame.get_frame() ); } int Filter::get_track( ) { return mlt_filter_get_track( get_filter( ) ); } int Filter::get_position( Frame &frame ) { return mlt_filter_get_position( get_filter( ), frame.get_frame( ) ); } double Filter::get_progress( Frame &frame ) { return mlt_filter_get_progress( get_filter( ), frame.get_frame( ) ); } mlt-0.9.0/src/mlt++/MltFilter.h000066400000000000000000000032561215300731300161010ustar00rootroot00000000000000/** * MltFilter.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_FILTER_H_ #define _MLTPP_FILTER_H_ #include "config.h" #include #include "MltService.h" namespace Mlt { class Service; class Profile; class Frame; class MLTPP_DECLSPEC Filter : public Service { private: mlt_filter instance; public: Filter( Profile& profile, const char *id, const char *service = NULL ); Filter( Service &filter ); Filter( Filter &filter ); Filter( mlt_filter filter ); virtual ~Filter( ); virtual mlt_filter get_filter( ); mlt_service get_service( ); int connect( Service &service, int index = 0 ); void set_in_and_out( int in, int out ); int get_in( ); int get_out( ); int get_length( ); int get_length2( Frame &frame ); int get_track( ); int get_position( Frame &frame ); double get_progress( Frame &frame ); }; } #endif mlt-0.9.0/src/mlt++/MltFilteredConsumer.cpp000066400000000000000000000055301215300731300204560ustar00rootroot00000000000000/** * MltFilteredConsumer.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "MltFilteredConsumer.h" using namespace Mlt; FilteredConsumer::FilteredConsumer( Profile& profile, const char *id, const char *arg ) : Consumer( profile, id, arg ) { // Create a reference to the first service first = new Service( *this ); } FilteredConsumer::FilteredConsumer( Consumer &consumer ) : Consumer( consumer ) { // Create a reference to the first service first = new Service( *this ); } FilteredConsumer::~FilteredConsumer( ) { // Delete the reference to the first service delete first; } int FilteredConsumer::connect( Service &service ) { // All producers must connect to the first service, hence the use of the virtual here return first->connect_producer( service ); } int FilteredConsumer::attach( Filter &filter ) { int error = 0; if ( filter.is_valid( ) ) { Service *producer = first->producer( ); error = filter.connect( *producer ); if ( error == 0 ) { first->connect_producer( filter ); delete first; first = new Service( filter ); } delete producer; } else { error = 1; } return error; } int FilteredConsumer::last( Filter &filter ) { int error = 0; if ( filter.is_valid( ) ) { Service *producer = this->producer( ); error = filter.connect( *producer ); if ( error == 0 ) connect_producer( filter ); delete producer; } else { error = 1; } return error; } int FilteredConsumer::detach( Filter &filter ) { if ( filter.is_valid( ) ) { Service *it = new Service( *first ); while ( it->is_valid( ) && it->get_service( ) != filter.get_service( ) ) { Service *consumer = it->consumer( ); delete it; it = consumer; } if ( it->get_service( ) == filter.get_service( ) ) { Service *producer = it->producer( ); Service *consumer = it->consumer( ); consumer->connect_producer( *producer ); Service dummy( NULL ); it->connect_producer( dummy ); if ( first->get_service( ) == it->get_service( ) ) { delete first; first = new Service( *consumer ); } } delete it; } return 0; } mlt-0.9.0/src/mlt++/MltFilteredConsumer.h000066400000000000000000000027751215300731300201330ustar00rootroot00000000000000/** * MltFilteredConsumer.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_FILTERED_CONSUMER_H_ #define _MLTPP_FILTERED_CONSUMER_H_ #include "config.h" #include "MltConsumer.h" #include "MltFilter.h" #include "MltService.h" namespace Mlt { class Consumer; class Service; class Filter; class Profile; class MLTPP_DECLSPEC FilteredConsumer : public Consumer { private: Service *first; public: FilteredConsumer( Profile& profile, const char *id, const char *arg = NULL ); FilteredConsumer( Consumer &consumer ); virtual ~FilteredConsumer( ); int connect( Service &service ); int attach( Filter &filter ); int last( Filter &filter ); int detach( Filter &filter ); }; } #endif mlt-0.9.0/src/mlt++/MltFilteredProducer.cpp000066400000000000000000000044621215300731300204510ustar00rootroot00000000000000/** * MltFilteredProducer.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "MltFilteredProducer.h" #include "MltProfile.h" using namespace Mlt; FilteredProducer::FilteredProducer( Profile& profile, const char *id, const char *arg ) : Producer( profile, id, arg ) { // Create a reference to the last service last = new Service( *this ); } FilteredProducer::~FilteredProducer( ) { // Delete the reference to the last service delete last; } int FilteredProducer::attach( Filter &filter ) { int error = 0; if ( filter.is_valid( ) ) { Service *consumer = last->consumer( ); filter.connect_producer( *last ); if ( consumer->is_valid( ) ) consumer->connect_producer( filter ); delete consumer; delete last; last = new Service( filter ); } else { error = 1; } return error; } int FilteredProducer::detach( Filter &filter ) { if ( filter.is_valid( ) ) { Service *it = new Service( *last ); while ( it->is_valid( ) && it->get_service( ) != filter.get_service( ) ) { Service *producer = it->producer( ); delete it; it = producer; } if ( it->get_service( ) == filter.get_service( ) ) { Service *producer = it->producer( ); Service *consumer = it->consumer( ); if ( consumer->is_valid( ) ) consumer->connect_producer( *producer ); Profile p( get_profile() ); Producer dummy( p, "colour" ); dummy.connect_producer( *it ); if ( last->get_service( ) == it->get_service( ) ) { delete last; last = new Service( *producer ); } } delete it; } return 0; } mlt-0.9.0/src/mlt++/MltFilteredProducer.h000066400000000000000000000026161215300731300201150ustar00rootroot00000000000000/** * MltFilteredProducer.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_FILTERED_PRODUCER_H_ #define _MLTPP_FILTERED_PRODUCER_H_ #include "config.h" #include "MltProducer.h" #include "MltFilter.h" #include "MltService.h" namespace Mlt { class Producer; class Service; class Filter; class Profile; class MLTPP_DECLSPEC FilteredProducer : public Producer { private: Service *last; public: FilteredProducer( Profile& profile, const char *id, const char *arg = NULL ); virtual ~FilteredProducer( ); int attach( Filter &filter ); int detach( Filter &filter ); }; } #endif mlt-0.9.0/src/mlt++/MltFrame.cpp000066400000000000000000000056561215300731300162470ustar00rootroot00000000000000/** * MltFrame.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "MltFrame.h" #include "MltProducer.h" using namespace Mlt; Frame::Frame( mlt_frame frame ) : Properties( false ), instance( frame ) { inc_ref( ); } Frame::Frame( Frame &frame ) : Mlt::Properties( frame ), instance( frame.get_frame( ) ) { inc_ref( ); } Frame::~Frame( ) { mlt_frame_close( instance ); } mlt_frame Frame::get_frame( ) { return instance; } mlt_properties Frame::get_properties( ) { return mlt_frame_properties( get_frame( ) ); } uint8_t *Frame::get_image( mlt_image_format &format, int &w, int &h, int writable ) { uint8_t *image = NULL; if ( get_double( "consumer_aspect_ratio" ) == 0.0 ) set( "consumer_aspect_ratio", 1.0 ); mlt_frame_get_image( get_frame( ), &image, &format, &w, &h, writable ); set( "format", format ); set( "writable", writable ); return image; } unsigned char *Frame::fetch_image( mlt_image_format f, int w, int h, int writable ) { uint8_t *image = NULL; if ( get_double( "consumer_aspect_ratio" ) == 0.0 ) set( "consumer_aspect_ratio", 1.0 ); mlt_frame_get_image( get_frame( ), &image, &f, &w, &h, writable ); set( "format", f ); set( "writable", writable ); return image; } void *Frame::get_audio( mlt_audio_format &format, int &frequency, int &channels, int &samples ) { void *audio = NULL; mlt_frame_get_audio( get_frame( ), &audio, &format, &frequency, &channels, &samples ); return audio; } unsigned char *Frame::get_waveform( int w, int h ) { return mlt_frame_get_waveform( get_frame( ), w, h ); } Producer *Frame::get_original_producer( ) { return new Producer( mlt_frame_get_original_producer( get_frame( ) ) ); } mlt_properties Frame::get_unique_properties( Service &service ) { return mlt_frame_unique_properties( get_frame(), service.get_service() ); } int Frame::get_position( ) { return mlt_frame_get_position( get_frame() ); } int Frame::set_image( uint8_t *image, int size, mlt_destructor destroy ) { return mlt_frame_set_image( get_frame(), image, size, destroy ); } int Frame::set_alpha( uint8_t *alpha, int size, mlt_destructor destroy ) { return mlt_frame_set_alpha( get_frame(), alpha, size, destroy ); } mlt-0.9.0/src/mlt++/MltFrame.h000066400000000000000000000035561215300731300157110ustar00rootroot00000000000000/** * MltFilter.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_FRAME_H_ #define _MLTPP_FRAME_H_ #include "config.h" #include #include "MltProperties.h" namespace Mlt { class Properties; class Producer; class Service; class MLTPP_DECLSPEC Frame : public Properties { private: mlt_frame instance; public: Frame( mlt_frame frame ); Frame( Frame &frame ); virtual ~Frame( ); virtual mlt_frame get_frame( ); mlt_properties get_properties( ); uint8_t *get_image( mlt_image_format &format, int &w, int &h, int writable = 0 ); unsigned char *fetch_image( mlt_image_format format, int w, int h, int writable = 0 ); void *get_audio( mlt_audio_format &format, int &frequency, int &channels, int &samples ); unsigned char *get_waveform( int w, int h ); Producer *get_original_producer( ); int get_position( ); mlt_properties get_unique_properties( Service &service ); int set_image( uint8_t *image, int size, mlt_destructor destroy ); int set_alpha( uint8_t *alpha, int size, mlt_destructor destroy ); }; } #endif mlt-0.9.0/src/mlt++/MltGeometry.cpp000066400000000000000000000054631215300731300170040ustar00rootroot00000000000000/** * MltGeometry.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "MltGeometry.h" using namespace Mlt; Geometry::Geometry( char *data, int length, int nw, int nh ) { geometry = mlt_geometry_init( ); parse( data, length, nw, nh ); } Geometry::~Geometry( ) { mlt_geometry_close( geometry ); } int Geometry::parse( char *data, int length, int nw, int nh ) { return mlt_geometry_parse( geometry, data, length, nw, nh ); } // Fetch a geometry item for an absolute position int Geometry::fetch( GeometryItem &item, float position ) { return mlt_geometry_fetch( geometry, item.get_item( ), position ); } int Geometry::fetch( GeometryItem *item, float position ) { return mlt_geometry_fetch( geometry, item->get_item( ), position ); } // Specify a geometry item at an absolute position int Geometry::insert( GeometryItem &item ) { return mlt_geometry_insert( geometry, item.get_item( ) ); } int Geometry::insert( GeometryItem *item ) { return mlt_geometry_insert( geometry, item->get_item( ) ); } // Remove the key at the specified position int Geometry::remove( int position ) { return mlt_geometry_remove( geometry, position ); } void Geometry::interpolate( ) { mlt_geometry_interpolate( geometry ); } // Get the key at the position or the next following int Geometry::next_key( GeometryItem &item, int position ) { return mlt_geometry_next_key( geometry, item.get_item( ), position ); } int Geometry::next_key( GeometryItem *item, int position ) { return mlt_geometry_next_key( geometry, item->get_item( ), position ); } int Geometry::prev_key( GeometryItem &item, int position ) { return mlt_geometry_prev_key( geometry, item.get_item( ), position ); } int Geometry::prev_key( GeometryItem *item, int position ) { return mlt_geometry_prev_key( geometry, item->get_item( ), position ); } // Serialise the current geometry char *Geometry::serialise( int in, int out ) { return mlt_geometry_serialise_cut( geometry, in, out ); } char *Geometry::serialise( ) { return mlt_geometry_serialise( geometry ); } mlt-0.9.0/src/mlt++/MltGeometry.h000066400000000000000000000053531215300731300164470ustar00rootroot00000000000000/** * MltGeometry.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_GEOMETRY_H #define _MLTPP_GEOMETRY_H #include "config.h" #include namespace Mlt { // Just for consistent naming purposes class MLTPP_DECLSPEC GeometryItem { private: struct mlt_geometry_item_s item; public: mlt_geometry_item get_item( ) { return &item; } bool key( ) { return item.key != 0; } int frame( ) { return item.frame; } void frame( int value ) { item.frame = value; } float x( ) { return item.x; } void x( float value ) { item.f[0] = 1; item.x = value; } float y( ) { return item.y; } void y( float value ) { item.f[1] = 1; item.y = value; } float w( ) { return item.w; } void w( float value ) { item.f[2] = 1; item.w = value; } float h( ) { return item.h; } void h( float value ) { item.f[3] = 1; item.h = value; } float mix( ) { return item.mix; } void mix( float value ) { item.f[4] = 1; item.mix = value; } }; class MLTPP_DECLSPEC Geometry { private: mlt_geometry geometry; public: Geometry( char *data = NULL, int length = 0, int nw = -1, int nh = -1 ); ~Geometry( ); int parse( char *data, int length, int nw = -1, int nh = -1 ); // Fetch a geometry item for an absolute position int fetch( GeometryItem &item, float position ); int fetch( GeometryItem *item, float position ); // Specify a geometry item at an absolute position int insert( GeometryItem &item ); int insert( GeometryItem *item ); // Remove the key at the specified position int remove( int position ); void interpolate( ); // Get the key at the position or the next following int next_key( GeometryItem &item, int position ); int next_key( GeometryItem *item, int position ); int prev_key( GeometryItem &item, int position ); int prev_key( GeometryItem *item, int position ); // Serialise the current geometry char *serialise( int in, int out ); char *serialise( ); }; } #endif mlt-0.9.0/src/mlt++/MltMultitrack.cpp000066400000000000000000000042031215300731300173170ustar00rootroot00000000000000/** * MltMultitrack.h - Multitrack wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "MltMultitrack.h" #include "MltProducer.h" using namespace Mlt; Multitrack::Multitrack( mlt_multitrack multitrack ) : instance( multitrack ) { inc_ref( ); } Multitrack::Multitrack( Service &multitrack ) : instance( NULL ) { if ( multitrack.type( ) == multitrack_type ) { instance = ( mlt_multitrack )multitrack.get_service( ); inc_ref( ); } } Multitrack::Multitrack( Multitrack &multitrack ) : Mlt::Producer( multitrack ), instance( multitrack.get_multitrack( ) ) { inc_ref( ); } Multitrack::~Multitrack( ) { mlt_multitrack_close( instance ); } mlt_multitrack Multitrack::get_multitrack( ) { return instance; } mlt_producer Multitrack::get_producer( ) { return mlt_multitrack_producer( get_multitrack( ) ); } int Multitrack::connect( Producer &producer, int index ) { return mlt_multitrack_connect( get_multitrack( ), producer.get_producer( ), index ); } int Multitrack::clip( mlt_whence whence, int index ) { return mlt_multitrack_clip( get_multitrack( ), whence, index ); } int Multitrack::count( ) { return mlt_multitrack_count( get_multitrack( ) ); } Producer *Multitrack::track( int index ) { return new Producer( mlt_multitrack_track( get_multitrack( ), index ) ); } void Multitrack::refresh( ) { return mlt_multitrack_refresh( get_multitrack( ) ); } mlt-0.9.0/src/mlt++/MltMultitrack.h000066400000000000000000000030371215300731300167700ustar00rootroot00000000000000/** * MltMultitrack.h - Multitrack wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_MULTITRACK_H_ #define _MLTPP_MULTITRACK_H_ #include "config.h" #include #include "MltProducer.h" namespace Mlt { class Service; class Producer; class MLTPP_DECLSPEC Multitrack : public Producer { private: mlt_multitrack instance; public: Multitrack( mlt_multitrack multitrack ); Multitrack( Service &multitrack ); Multitrack( Multitrack &multitrack ); virtual ~Multitrack( ); mlt_multitrack get_multitrack( ); mlt_producer get_producer( ); int connect( Producer &producer, int index ); int clip( mlt_whence whence, int index ); int count( ); Producer *track( int index ); void refresh( ); }; } #endif mlt-0.9.0/src/mlt++/MltParser.cpp000066400000000000000000000202271215300731300164400ustar00rootroot00000000000000/** * MltParser.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "Mlt.h" using namespace Mlt; static int on_invalid_cb( mlt_parser self, mlt_service object ) { mlt_properties properties = mlt_parser_properties( self ); Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); Service service( object ); return parser->on_invalid( &service ); } static int on_unknown_cb( mlt_parser self, mlt_service object ) { mlt_properties properties = mlt_parser_properties( self ); Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); Service service( object ); return parser->on_unknown( &service ); } static int on_start_producer_cb( mlt_parser self, mlt_producer object ) { mlt_properties properties = mlt_parser_properties( self ); Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); Producer producer( object ); return parser->on_start_producer( &producer ); } static int on_end_producer_cb( mlt_parser self, mlt_producer object ) { mlt_properties properties = mlt_parser_properties( self ); Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); Producer producer( object ); return parser->on_end_producer( &producer ); } static int on_start_playlist_cb( mlt_parser self, mlt_playlist object ) { mlt_properties properties = mlt_parser_properties( self ); Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); Playlist playlist( object ); return parser->on_start_playlist( &playlist ); } static int on_end_playlist_cb( mlt_parser self, mlt_playlist object ) { mlt_properties properties = mlt_parser_properties( self ); Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); Playlist playlist( object ); return parser->on_end_playlist( &playlist ); } static int on_start_tractor_cb( mlt_parser self, mlt_tractor object ) { mlt_properties properties = mlt_parser_properties( self ); Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); Tractor tractor( object ); return parser->on_start_tractor( &tractor ); } static int on_end_tractor_cb( mlt_parser self, mlt_tractor object ) { mlt_properties properties = mlt_parser_properties( self ); Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); Tractor tractor( object ); return parser->on_end_tractor( &tractor ); } static int on_start_multitrack_cb( mlt_parser self, mlt_multitrack object ) { mlt_properties properties = mlt_parser_properties( self ); Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); Multitrack multitrack( object ); return parser->on_start_multitrack( &multitrack ); } static int on_end_multitrack_cb( mlt_parser self, mlt_multitrack object ) { mlt_properties properties = mlt_parser_properties( self ); Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); Multitrack multitrack( object ); return parser->on_end_multitrack( &multitrack ); } static int on_start_track_cb( mlt_parser self ) { mlt_properties properties = mlt_parser_properties( self ); Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); return parser->on_start_track( ); } static int on_end_track_cb( mlt_parser self ) { mlt_properties properties = mlt_parser_properties( self ); Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); return parser->on_end_track( ); } static int on_start_filter_cb( mlt_parser self, mlt_filter object ) { mlt_properties properties = mlt_parser_properties( self ); Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); Filter filter( object ); return parser->on_start_filter( &filter ); } static int on_end_filter_cb( mlt_parser self, mlt_filter object ) { mlt_properties properties = mlt_parser_properties( self ); Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); Filter filter( object ); return parser->on_end_filter( &filter ); } static int on_start_transition_cb( mlt_parser self, mlt_transition object ) { mlt_properties properties = mlt_parser_properties( self ); Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); Transition transition( object ); return parser->on_start_transition( &transition ); } static int on_end_transition_cb( mlt_parser self, mlt_transition object ) { mlt_properties properties = mlt_parser_properties( self ); Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); Transition transition( object ); return parser->on_end_transition( &transition ); } Parser::Parser( ) : Properties( false ) { parser = mlt_parser_new( ); set( "_parser_object", this, 0 ); parser->on_invalid = on_invalid_cb; parser->on_unknown = on_unknown_cb; parser->on_start_producer = on_start_producer_cb; parser->on_end_producer = on_end_producer_cb; parser->on_start_playlist = on_start_playlist_cb; parser->on_end_playlist = on_end_playlist_cb; parser->on_start_tractor = on_start_tractor_cb; parser->on_end_tractor = on_end_tractor_cb; parser->on_start_multitrack = on_start_multitrack_cb; parser->on_end_multitrack = on_end_multitrack_cb; parser->on_start_track = on_start_track_cb; parser->on_end_track = on_end_track_cb; parser->on_start_filter = on_start_filter_cb; parser->on_end_filter = on_end_filter_cb; parser->on_start_transition = on_start_transition_cb; parser->on_end_transition = on_end_transition_cb; } Parser::~Parser( ) { mlt_parser_close( parser ); } mlt_properties Parser::get_properties( ) { return mlt_parser_properties( parser ); } int Parser::start( Service &service ) { return mlt_parser_start( parser, service.get_service( ) ); } int Parser::on_invalid( Service *object ) { object->debug( "Invalid" ); return 0; } int Parser::on_unknown( Service *object ) { object->debug( "Unknown" ); return 0; } int Parser::on_start_producer( Producer *object ) { object->debug( "on_start_producer" ); return 0; } int Parser::on_end_producer( Producer *object ) { object->debug( "on_end_producer" ); return 0; } int Parser::on_start_playlist( Playlist *object ) { object->debug( "on_start_playlist" ); return 0; } int Parser::on_end_playlist( Playlist *object ) { object->debug( "on_end_playlist" ); return 0; } int Parser::on_start_tractor( Tractor *object ) { object->debug( "on_start_tractor" ); return 0; } int Parser::on_end_tractor( Tractor *object ) { object->debug( "on_end_tractor" ); return 0; } int Parser::on_start_multitrack( Multitrack *object ) { object->debug( "on_start_multitrack" ); return 0; } int Parser::on_end_multitrack( Multitrack *object ) { object->debug( "on_end_multitrack" ); return 0; } int Parser::on_start_track( ) { fprintf( stderr, "on_start_track\n" ); return 0; } int Parser::on_end_track( ) { fprintf( stderr, "on_end_track\n" ); return 0; } int Parser::on_start_filter( Filter *object ) { object->debug( "on_start_filter" ); return 0; } int Parser::on_end_filter( Filter *object ) { object->debug( "on_end_filter" ); return 0; } int Parser::on_start_transition( Transition *object ) { object->debug( "on_start_transition" ); return 0; } int Parser::on_end_transition( Transition *object ) { object->debug( "on_end_transition" ); return 0; } mlt-0.9.0/src/mlt++/MltParser.h000066400000000000000000000041701215300731300161040ustar00rootroot00000000000000/** * MltParser.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_PARSER_H_ #define _MLTPP_PARSER_H_ #include "config.h" #include #include "MltProperties.h" namespace Mlt { class Properties; class Service; class Producer; class Playlist; class Tractor; class Multitrack; class Filter; class Transition; class MLTPP_DECLSPEC Parser : public Properties { private: mlt_parser parser; public: Parser( ); ~Parser( ); int start( Service &service ); virtual mlt_properties get_properties( ); virtual int on_invalid( Service *object ); virtual int on_unknown( Service *object ); virtual int on_start_producer( Producer *object ); virtual int on_end_producer( Producer *object ); virtual int on_start_playlist( Playlist *object ); virtual int on_end_playlist( Playlist *object ); virtual int on_start_tractor( Tractor *object ); virtual int on_end_tractor( Tractor *object ); virtual int on_start_multitrack( Multitrack *object ); virtual int on_end_multitrack( Multitrack *object ); virtual int on_start_track( ); virtual int on_end_track( ); virtual int on_start_filter( Filter *object ); virtual int on_end_filter( Filter *object ); virtual int on_start_transition( Transition *object ); virtual int on_end_transition( Transition *object ); }; } #endif mlt-0.9.0/src/mlt++/MltPlaylist.cpp000066400000000000000000000172341215300731300170110ustar00rootroot00000000000000/** * MltPlaylist.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "MltPlaylist.h" #include "MltTransition.h" #include "MltProfile.h" using namespace Mlt; ClipInfo::ClipInfo( ) : clip( 0 ), producer( NULL ), cut( NULL ), start( 0 ), resource( NULL ), frame_in( 0 ), frame_out( 0 ), frame_count( 0 ), length( 0 ), fps( 0 ), repeat( 0 ) { } ClipInfo::ClipInfo( mlt_playlist_clip_info *info ) : clip( info->clip ), producer( new Producer( info->producer ) ), cut( new Producer( info->cut ) ), start( info->start ), resource( info->resource? strdup( info->resource ) : 0 ), frame_in( info->frame_in ), frame_out( info->frame_out ), frame_count( info->frame_count ), length( info->length ), fps( info->fps ), repeat( info->repeat ) { } ClipInfo::~ClipInfo( ) { delete producer; delete cut; free( resource ); } void ClipInfo::update( mlt_playlist_clip_info *info ) { delete producer; delete cut; free( resource ); clip = info->clip; producer = new Producer( info->producer ); cut = new Producer( info->cut ); start = info->start; resource = strdup( info->resource ); frame_in = info->frame_in; frame_out = info->frame_out; frame_count = info->frame_count; length = info->length; fps = info->fps; repeat = info->repeat; } Playlist::Playlist( ) : instance( NULL ) { instance = mlt_playlist_init( ); } Playlist::Playlist( Profile& profile ) : instance( NULL ) { instance = mlt_playlist_new( profile.get_profile() ); } Playlist::Playlist( Service &producer ) : instance( NULL ) { if ( producer.type( ) == playlist_type ) { instance = ( mlt_playlist )producer.get_service( ); inc_ref( ); } } Playlist::Playlist( Playlist &playlist ) : Mlt::Producer( playlist ), instance( playlist.get_playlist( ) ) { inc_ref( ); } Playlist::Playlist( mlt_playlist playlist ) : instance( playlist ) { inc_ref( ); } Playlist::~Playlist( ) { mlt_playlist_close( instance ); } mlt_playlist Playlist::get_playlist( ) { return instance; } mlt_producer Playlist::get_producer( ) { return mlt_playlist_producer( get_playlist( ) ); } int Playlist::count( ) { return mlt_playlist_count( get_playlist( ) ); } int Playlist::clear( ) { return mlt_playlist_clear( get_playlist( ) ); } int Playlist::append( Producer &producer, int in, int out ) { return mlt_playlist_append_io( get_playlist( ), producer.get_producer( ), in, out ); } int Playlist::blank( int out ) { return mlt_playlist_blank( get_playlist( ), out ); } int Playlist::blank( const char *length ) { return mlt_playlist_blank_time( get_playlist( ), length ); } int Playlist::clip( mlt_whence whence, int index ) { return mlt_playlist_clip( get_playlist( ), whence, index ); } int Playlist::current_clip( ) { return mlt_playlist_current_clip( get_playlist( ) ); } Producer *Playlist::current( ) { return new Producer( mlt_playlist_current( get_playlist( ) ) ); } ClipInfo *Playlist::clip_info( int index, ClipInfo *info ) { mlt_playlist_clip_info clip_info; if ( mlt_playlist_get_clip_info( get_playlist( ), &clip_info, index ) ) return NULL; if ( info == NULL ) return new ClipInfo( &clip_info ); info->update( &clip_info ); return info; } void Playlist::delete_clip_info( ClipInfo *info ) { delete info; } int Playlist::insert( Producer &producer, int where, int in, int out ) { return mlt_playlist_insert( get_playlist( ), producer.get_producer( ), where, in, out ); } int Playlist::remove( int where ) { return mlt_playlist_remove( get_playlist( ), where ); } int Playlist::move( int from, int to ) { return mlt_playlist_move( get_playlist( ), from, to ); } int Playlist::resize_clip( int clip, int in, int out ) { return mlt_playlist_resize_clip( get_playlist( ), clip, in, out ); } int Playlist::split( int clip, int position ) { return mlt_playlist_split( get_playlist( ), clip, position ); } int Playlist::split_at( int position, bool left ) { return mlt_playlist_split_at( get_playlist( ), position, left ); } int Playlist::join( int clip, int count, int merge ) { return mlt_playlist_join( get_playlist( ), clip, count, merge ); } int Playlist::mix( int clip, int length, Transition *transition ) { return mlt_playlist_mix( get_playlist( ), clip, length, transition == NULL ? NULL : transition->get_transition( ) ); } int Playlist::mix_add( int clip, Transition *transition ) { return mlt_playlist_mix_add( get_playlist( ), clip, transition == NULL ? NULL : transition->get_transition( ) ); } int Playlist::repeat( int clip, int count ) { return mlt_playlist_repeat_clip( get_playlist( ), clip, count ); } Producer *Playlist::get_clip( int clip ) { mlt_producer producer = mlt_playlist_get_clip( get_playlist( ), clip ); return producer != NULL ? new Producer( producer ) : NULL; } Producer *Playlist::get_clip_at( int position ) { mlt_producer producer = mlt_playlist_get_clip_at( get_playlist( ), position ); return producer != NULL ? new Producer( producer ) : NULL; } int Playlist::get_clip_index_at( int position ) { return mlt_playlist_get_clip_index_at( get_playlist( ), position ); } bool Playlist::is_mix( int clip ) { return mlt_playlist_clip_is_mix( get_playlist( ), clip ) != 0; } bool Playlist::is_blank( int clip ) { return mlt_playlist_is_blank( get_playlist( ), clip ) != 0; } bool Playlist::is_blank_at( int position ) { return mlt_playlist_is_blank_at( get_playlist( ), position ) != 0; } Producer *Playlist::replace_with_blank( int clip ) { mlt_producer producer = mlt_playlist_replace_with_blank( get_playlist( ), clip ); Producer *object = producer != NULL ? new Producer( producer ) : NULL; mlt_producer_close( producer ); return object; } void Playlist::consolidate_blanks( int keep_length ) { return mlt_playlist_consolidate_blanks( get_playlist( ), keep_length ); } void Playlist::insert_blank( int clip, int length ) { mlt_playlist_insert_blank( get_playlist( ), clip, length ); } void Playlist::pad_blanks( int position, int length, int find ) { mlt_playlist_pad_blanks( get_playlist( ), position, length, find ); } int Playlist::insert_at( int position, Producer *producer, int mode ) { return mlt_playlist_insert_at( get_playlist( ), position, producer->get_producer( ), mode ); } int Playlist::insert_at( int position, Producer &producer, int mode ) { return mlt_playlist_insert_at( get_playlist( ), position, producer.get_producer( ), mode ); } int Playlist::clip_start( int clip ) { return mlt_playlist_clip_start( get_playlist( ), clip ); } int Playlist::blanks_from( int clip, int bounded ) { return mlt_playlist_blanks_from( get_playlist( ), clip, bounded ); } int Playlist::clip_length( int clip ) { return mlt_playlist_clip_length( get_playlist( ), clip ); } int Playlist::remove_region( int position, int length ) { return mlt_playlist_remove_region( get_playlist( ), position, length ); } int Playlist::move_region( int position, int length, int new_position ) { return mlt_playlist_move_region( get_playlist( ), position, length, new_position ); } mlt-0.9.0/src/mlt++/MltPlaylist.h000066400000000000000000000066131215300731300164550ustar00rootroot00000000000000/** * MltPlaylist.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_PLAYLIST_H_ #define _MLTPP_PLAYLIST_H_ #include "config.h" #include #include "MltProducer.h" namespace Mlt { class Producer; class Service; class Playlist; class Transition; class Profile; class MLTPP_DECLSPEC ClipInfo { public: ClipInfo( ); ClipInfo( mlt_playlist_clip_info *info ); ~ClipInfo( ); void update( mlt_playlist_clip_info *info ); int clip; Producer *producer; Producer *cut; int start; char *resource; int frame_in; int frame_out; int frame_count; int length; float fps; int repeat; }; class MLTPP_DECLSPEC Playlist : public Producer { private: mlt_playlist instance; public: Playlist( ); Playlist( Profile& profile ); Playlist( Service &playlist ); Playlist( Playlist &playlist ); Playlist( mlt_playlist playlist ); virtual ~Playlist( ); virtual mlt_playlist get_playlist( ); mlt_producer get_producer( ); int count( ); int clear( ); int append( Producer &producer, int in = -1, int out = -1 ); int blank( int out ); int blank( const char *length ); int clip( mlt_whence whence, int index ); int current_clip( ); Producer *current( ); ClipInfo *clip_info( int index, ClipInfo *info = NULL ); static void delete_clip_info( ClipInfo *info ); int insert( Producer &producer, int where, int in = -1, int out = -1 ); int remove( int where ); int move( int from, int to ); int resize_clip( int clip, int in, int out ); int split( int clip, int position ); int split_at( int position, bool left = true ); int join( int clip, int count = 1, int merge = 1 ); int mix( int clip, int length, Transition *transition = NULL ); int mix_add( int clip, Transition *transition ); int repeat( int clip, int count ); Producer *get_clip( int clip ); Producer *get_clip_at( int position ); int get_clip_index_at( int position ); bool is_mix( int clip ); bool is_blank( int clip ); bool is_blank_at( int position ); void consolidate_blanks( int keep_length = 0 ); Producer *replace_with_blank( int clip ); void insert_blank( int clip, int length ); void pad_blanks( int position, int length, int find = 0 ); int insert_at( int position, Producer *producer, int mode = 0 ); int insert_at( int position, Producer &producer, int mode = 0 ); int clip_start( int clip ); int clip_length( int clip ); int blanks_from( int clip, int bounded = 0 ); int remove_region( int position, int length ); int move_region( int position, int length, int new_position ); }; } #endif mlt-0.9.0/src/mlt++/MltProducer.cpp000066400000000000000000000122231215300731300167640ustar00rootroot00000000000000/** * MltProducer.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "MltProducer.h" #include "MltFilter.h" #include "MltProfile.h" #include "MltEvent.h" #include "MltConsumer.h" using namespace Mlt; Producer::Producer( ) : instance( NULL ), parent_( NULL ) { } Producer::Producer( Profile& profile, const char *id, const char *service ) : instance( NULL ), parent_( NULL ) { if ( id != NULL && service != NULL ) instance = mlt_factory_producer( profile.get_profile(), id, service ); else instance = mlt_factory_producer( profile.get_profile(), NULL, id != NULL ? id : service ); } Producer::Producer( Service &producer ) : instance( NULL ), parent_( NULL ) { mlt_service_type type = producer.type( ); if ( type == producer_type || type == playlist_type || type == tractor_type || type == multitrack_type ) { instance = ( mlt_producer )producer.get_service( ); inc_ref( ); } } Producer::Producer( mlt_producer producer ) : instance( producer ), parent_( NULL ) { inc_ref( ); } Producer::Producer( Producer &producer ) : Mlt::Service( producer ), instance( producer.get_producer( ) ), parent_( NULL ) { inc_ref( ); } Producer::Producer( Producer *producer ) : instance( producer != NULL ? producer->get_producer( ) : NULL ), parent_( NULL ) { if ( is_valid( ) ) inc_ref( ); } Producer::~Producer( ) { delete parent_; mlt_producer_close( instance ); instance = NULL; } mlt_producer Producer::get_producer( ) { return instance; } mlt_producer Producer::get_parent( ) { return get_producer( ) != NULL && mlt_producer_cut_parent( get_producer( ) ) != NULL ? mlt_producer_cut_parent( get_producer( ) ) : get_producer( ); } Producer &Producer::parent( ) { if ( is_cut( ) && parent_ == NULL ) parent_ = new Producer( get_parent( ) ); return parent_ == NULL ? *this : *parent_; } mlt_service Producer::get_service( ) { return mlt_producer_service( get_producer( ) ); } int Producer::seek( int position ) { return mlt_producer_seek( get_producer( ), position ); } int Producer::seek( const char *time ) { return mlt_producer_seek_time( get_producer( ), time ); } int Producer::position( ) { return mlt_producer_position( get_producer( ) ); } int Producer::frame( ) { return mlt_producer_frame( get_producer( ) ); } char* Producer::frame_time( mlt_time_format format ) { return mlt_producer_frame_time( get_producer(), format ); } int Producer::set_speed( double speed ) { return mlt_producer_set_speed( get_producer( ), speed ); } int Producer::pause() { int result = 0; if ( get_speed() != 0 ) { Consumer consumer( ( mlt_consumer ) mlt_service_consumer( get_service( ) ) ); Event *event = consumer.setup_wait_for( "consumer-sdl-paused" ); result = mlt_producer_set_speed( get_producer( ), 0 ); if ( result == 0 && consumer.is_valid() && !consumer.is_stopped() ) consumer.wait_for( event ); delete event; } return result; } double Producer::get_speed( ) { return mlt_producer_get_speed( get_producer( ) ); } double Producer::get_fps( ) { return mlt_producer_get_fps( get_producer( ) ); } int Producer::set_in_and_out( int in, int out ) { return mlt_producer_set_in_and_out( get_producer( ), in, out ); } int Producer::get_in( ) { return mlt_producer_get_in( get_producer( ) ); } int Producer::get_out( ) { return mlt_producer_get_out( get_producer( ) ); } int Producer::get_length( ) { return mlt_producer_get_length( get_producer( ) ); } char* Producer::get_length_time( mlt_time_format format ) { return mlt_producer_get_length_time( get_producer( ), format ); } int Producer::get_playtime( ) { return mlt_producer_get_playtime( get_producer( ) ); } Producer *Producer::cut( int in, int out ) { mlt_producer producer = mlt_producer_cut( get_producer( ), in, out ); Producer *result = new Producer( producer ); mlt_producer_close( producer ); return result; } bool Producer::is_cut( ) { return mlt_producer_is_cut( get_producer( ) ) != 0; } bool Producer::is_blank( ) { return mlt_producer_is_blank( get_producer( ) ) != 0; } bool Producer::same_clip( Producer &that ) { return mlt_producer_cut_parent( get_producer( ) ) == mlt_producer_cut_parent( that.get_producer( ) ); } bool Producer::runs_into( Producer &that ) { return same_clip( that ) && get_out( ) == ( that.get_in( ) - 1 ); } void Producer::optimise( ) { mlt_producer_optimise( get_producer( ) ); } int Producer::clear( ) { return mlt_producer_clear( get_producer( ) ); } mlt-0.9.0/src/mlt++/MltProducer.h000066400000000000000000000042761215300731300164420ustar00rootroot00000000000000/** * MltProducer.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_PRODUCER_H_ #define _MLTPP_PRODUCER_H_ #include "config.h" #include #include "MltService.h" namespace Mlt { class Service; class Filter; class Profile; class Frame; class MLTPP_DECLSPEC Producer : public Service { private: mlt_producer instance; Producer *parent_; public: Producer( ); Producer( Profile& profile, const char *id, const char *service = NULL ); Producer( Service &producer ); Producer( mlt_producer producer ); Producer( Producer &producer ); Producer( Producer *producer ); virtual ~Producer( ); virtual mlt_producer get_producer( ); Producer &parent( ); mlt_producer get_parent( ); mlt_service get_service( ); int seek( int position ); int seek( const char* time ); int position( ); int frame( ); char* frame_time( mlt_time_format = mlt_time_smpte ); int set_speed( double speed ); int pause( ); double get_speed( ); double get_fps( ); int set_in_and_out( int in, int out ); int get_in( ); int get_out( ); int get_length( ); char* get_length_time( mlt_time_format = mlt_time_smpte ); int get_playtime( ); Producer *cut( int in = 0, int out = -1 ); bool is_cut( ); bool is_blank( ); bool same_clip( Producer &that ); bool runs_into( Producer &that ); void optimise( ); int clear( ); }; } #endif mlt-0.9.0/src/mlt++/MltProfile.cpp000066400000000000000000000066121215300731300166060ustar00rootroot00000000000000/** * MltProfile.cpp - MLT Wrapper * Copyright (C) 2008 Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "MltProfile.h" #include "MltProperties.h" #include "MltProducer.h" using namespace Mlt; Profile::Profile( ) : instance( NULL ) { instance = mlt_profile_init( NULL ); } Profile::Profile( const char* name ) : instance( NULL ) { instance = mlt_profile_init( name ); } Profile::Profile( Properties& properties ) : instance( NULL ) { instance = mlt_profile_load_properties( properties.get_properties() ); } Profile::Profile( mlt_profile profile ) : instance( profile ) { } Profile::~Profile( ) { if ( instance ) mlt_profile_close( instance ); instance = NULL; } mlt_profile Profile::get_profile( ) const { return instance; } char* Profile::description() const { return instance->description; } int Profile::frame_rate_num() const { return instance->frame_rate_num; } int Profile::frame_rate_den() const { return instance->frame_rate_den; } double Profile::fps() const { return mlt_profile_fps( instance ); } int Profile::width() const { return instance->width; } int Profile::height() const { return instance->height; } bool Profile::progressive() const { return instance->progressive; } int Profile::sample_aspect_num() const { return instance->sample_aspect_num; } int Profile::sample_aspect_den() const { return instance->sample_aspect_den; } double Profile::sar() const { return mlt_profile_sar( instance ); } int Profile::display_aspect_num() const { return instance->display_aspect_num; } int Profile::display_aspect_den() const { return instance->display_aspect_den; } double Profile::dar() const { return mlt_profile_dar( instance ); } int Profile::is_explicit() const { return instance->is_explicit; } int Profile::colorspace() const { return instance->colorspace; } Properties* Profile::list() { return new Properties( mlt_profile_list() ); } void Profile::from_producer( Producer &producer ) { mlt_profile_from_producer( instance, producer.get_producer() ); } void Profile::set_width( int width ) { instance->width = width; } void Profile::set_height( int height ) { instance->height = height; } void Profile::set_sample_aspect( int numerator, int denominator ) { instance->sample_aspect_num = numerator; instance->sample_aspect_den = denominator; } void Profile::set_progressive( int progressive ) { instance->progressive = progressive; } void Profile::set_colorspace( int colorspace ) { instance->colorspace = colorspace; } void Profile::set_frame_rate( int numerator, int denominator ) { instance->frame_rate_num = numerator; instance->frame_rate_den = denominator; } void Profile::set_explicit( int boolean ) { instance->is_explicit = boolean; } mlt-0.9.0/src/mlt++/MltProfile.h000066400000000000000000000040711215300731300162500ustar00rootroot00000000000000/** * MltProfile.h - MLT Wrapper * Copyright (C) 2008 Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_PROFILE_H_ #define _MLTPP_PROFILE_H_ #include "config.h" #ifdef SWIG #define MLTPP_DECLSPEC #endif #include namespace Mlt { class Properties; class Producer; class MLTPP_DECLSPEC Profile { private: mlt_profile instance; public: Profile( ); Profile( const char* name ); Profile( Properties& properties ); Profile( mlt_profile profile ); ~Profile(); mlt_profile get_profile( ) const; char* description() const; int frame_rate_num() const; int frame_rate_den() const; double fps() const; int width() const; int height() const; bool progressive() const; int sample_aspect_num() const; int sample_aspect_den() const; double sar() const; int display_aspect_num() const; int display_aspect_den() const; double dar() const; int is_explicit() const; int colorspace() const; static Properties* list(); void from_producer( Producer &producer ); void set_width( int width ); void set_height( int height ); void set_sample_aspect( int numerator, int denominator ); void set_progressive( int progressive ); void set_colorspace( int colorspace ); void set_frame_rate( int numerator, int denominator ); void set_explicit( int boolean ); }; } #endif mlt-0.9.0/src/mlt++/MltProperties.cpp000066400000000000000000000234271215300731300173450ustar00rootroot00000000000000/** * MltProperties.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "MltProperties.h" #include "MltEvent.h" using namespace Mlt; Properties::Properties( ) : instance( NULL ) { instance = mlt_properties_new( ); } Properties::Properties( bool /*dummy*/ ) : instance( NULL ) { } Properties::Properties( Properties &properties ) : instance( properties.get_properties( ) ) { inc_ref( ); } Properties::Properties( mlt_properties properties ) : instance( properties ) { inc_ref( ); } Properties::Properties( void *properties ) : instance( mlt_properties( properties ) ) { inc_ref( ); } Properties::Properties( const char *file ) : instance( NULL ) { instance = mlt_properties_load( file ); } Properties::~Properties( ) { mlt_properties_close( instance ); } mlt_properties Properties::get_properties( ) { return instance; } int Properties::inc_ref( ) { return mlt_properties_inc_ref( get_properties( ) ); } int Properties::dec_ref( ) { return mlt_properties_dec_ref( get_properties( ) ); } int Properties::ref_count( ) { return mlt_properties_ref_count( get_properties( ) ); } void Properties::lock( ) { mlt_properties_lock( get_properties( ) ); } void Properties::unlock( ) { mlt_properties_unlock( get_properties( ) ); } void Properties::block( void *object ) { mlt_events_block( get_properties( ), object != NULL ? object : get_properties( ) ); } void Properties::unblock( void *object ) { mlt_events_unblock( get_properties( ), object != NULL ? object : get_properties( ) ); } void Properties::fire_event( const char *event ) { mlt_events_fire( get_properties( ), event, NULL ); } bool Properties::is_valid( ) { return get_properties( ) != NULL; } int Properties::count( ) { return mlt_properties_count( get_properties( ) ); } char *Properties::get( const char *name ) { return mlt_properties_get( get_properties( ), name ); } int Properties::get_int( const char *name ) { return mlt_properties_get_int( get_properties( ), name ); } int64_t Properties::get_int64( const char *name ) { return mlt_properties_get_int64( get_properties( ), name ); } double Properties::get_double( const char *name ) { return mlt_properties_get_double( get_properties( ), name ); } void *Properties::get_data( const char *name, int &size ) { return mlt_properties_get_data( get_properties( ), name, &size ); } void *Properties::get_data( const char *name ) { return mlt_properties_get_data( get_properties( ), name, NULL ); } int Properties::set( const char *name, const char *value ) { return mlt_properties_set( get_properties( ), name, value ); } int Properties::set( const char *name, int value ) { return mlt_properties_set_int( get_properties( ), name, value ); } int Properties::set( const char *name, int64_t value ) { return mlt_properties_set_int64( get_properties( ), name, value ); } int Properties::set( const char *name, double value ) { return mlt_properties_set_double( get_properties( ), name, value ); } int Properties::set( const char *name, void *value, int size, mlt_destructor destructor, mlt_serialiser serialiser ) { return mlt_properties_set_data( get_properties( ), name, value, size, destructor, serialiser ); } void Properties::pass_property( Properties &that, const char *name ) { return mlt_properties_pass_property( get_properties( ), that.get_properties( ), name ); } int Properties::pass_values( Properties &that, const char *prefix ) { return mlt_properties_pass( get_properties( ), that.get_properties( ), prefix ); } int Properties::pass_list( Properties &that, const char *list ) { return mlt_properties_pass_list( get_properties( ), that.get_properties( ), list ); } int Properties::parse( const char *namevalue ) { return mlt_properties_parse( get_properties( ), namevalue ); } char *Properties::get_name( int index ) { return mlt_properties_get_name( get_properties( ), index ); } char *Properties::get( int index ) { return mlt_properties_get_value( get_properties( ), index ); } void *Properties::get_data( int index, int &size ) { return mlt_properties_get_data_at( get_properties( ), index, &size ); } void Properties::mirror( Properties &that ) { mlt_properties_mirror( get_properties( ), that.get_properties( ) ); } int Properties::inherit( Properties &that ) { return mlt_properties_inherit( get_properties( ), that.get_properties( ) ); } int Properties::rename( const char *source, const char *dest ) { return mlt_properties_rename( get_properties( ), source, dest ); } void Properties::dump( FILE *output ) { mlt_properties_dump( get_properties( ), output ); } void Properties::debug( const char *title, FILE *output ) { mlt_properties_debug( get_properties( ), title, output ); } void Properties::load( const char *file ) { mlt_properties properties = mlt_properties_load( file ); if ( properties != NULL ) mlt_properties_pass( get_properties( ), properties, "" ); mlt_properties_close( properties ); } int Properties::save( const char *file ) { #ifdef WIN32 return mlt_properties_save( get_properties( ), file ); #else int error = 0; FILE *f = fopen( file, "w" ); if ( f != NULL ) { dump( f ); fclose( f ); } else { error = 1; } return error; #endif } #if defined( __DARWIN__ ) && GCC_VERSION < 40000 Event *Properties::listen( const char *id, void *object, void (*listener)( ... ) ) { mlt_event event = mlt_events_listen( get_properties( ), object, id, ( mlt_listener )listener ); return new Event( event ); } #else Event *Properties::listen( const char *id, void *object, mlt_listener listener ) { mlt_event event = mlt_events_listen( get_properties( ), object, id, listener ); return new Event( event ); } #endif Event *Properties::setup_wait_for( const char *id ) { return new Event( mlt_events_setup_wait_for( get_properties( ), id ) ); } void Properties::delete_event( Event *event ) { delete event; } void Properties::wait_for( Event *event, bool destroy ) { mlt_events_wait_for( get_properties( ), event->get_event( ) ); if ( destroy ) mlt_events_close_wait_for( get_properties( ), event->get_event( ) ); } void Properties::wait_for( const char *id ) { Event *event = setup_wait_for( id ); wait_for( event ); delete event; } bool Properties::is_sequence( ) { return mlt_properties_is_sequence( get_properties( ) ); } Properties *Properties::parse_yaml( const char *file ) { return new Properties( mlt_properties_parse_yaml( file ) ); } char *Properties::serialise_yaml( ) { return mlt_properties_serialise_yaml( get_properties( ) ); } int Properties::preset( const char *name ) { return mlt_properties_preset( get_properties(), name ); } int Properties::set_lcnumeric( const char *locale ) { return mlt_properties_set_lcnumeric( get_properties(), locale ); } const char *Properties::get_lcnumeric( ) { return mlt_properties_get_lcnumeric( get_properties() ); } char *Properties::get_time( const char *name, mlt_time_format format ) { return mlt_properties_get_time( get_properties(), name, format ); } mlt_color Properties::get_color( const char *name ) { return mlt_properties_get_color( get_properties(), name ); } int Properties::set( const char *name, mlt_color value ) { return mlt_properties_set_color( get_properties(), name, value ); } char *Properties::anim_get( const char *name, int position, int length ) { return mlt_properties_anim_get( get_properties(), name, position, length ); } int Properties::anim_set( const char *name, const char *value, int position, int length ) { return mlt_properties_anim_set( get_properties(), name, value, position, length ); } int Properties::anim_get_int( const char *name, int position, int length ) { return mlt_properties_anim_get_int( get_properties(), name, position, length ); } int Properties::anim_set( const char *name, int value, int position, int length, mlt_keyframe_type keyframe_type ) { return mlt_properties_anim_set_int( get_properties(), name, value, position, length, keyframe_type ); } double Properties::anim_get_double(const char *name, int position, int length) { return mlt_properties_anim_get_double( get_properties(), name, position, length ); } int Properties::anim_set( const char *name, double value, int position, int length, mlt_keyframe_type keyframe_type ) { return mlt_properties_anim_set_double( get_properties(), name, value, position, length, keyframe_type ); } int Properties::set( const char *name, mlt_rect value ) { return mlt_properties_set_rect( get_properties(), name, value ); } int Properties::set( const char *name, double x, double y, double w, double h, double opacity ) { mlt_rect value = { x, y, w, h, opacity }; return mlt_properties_set_rect( get_properties(), name, value ); } mlt_rect Properties::get_rect( const char *name ) { return mlt_properties_get_rect( get_properties(), name ); } int Properties::anim_set( const char *name, mlt_rect value, int position, int length, mlt_keyframe_type keyframe_type ) { return mlt_properties_anim_set_rect( get_properties(), name, value, position, length, keyframe_type ); } mlt_rect Properties::anim_get_rect(const char *name, int position, int length) { return mlt_properties_anim_get_rect( get_properties(), name, position, length ); } mlt-0.9.0/src/mlt++/MltProperties.h000066400000000000000000000107761215300731300170150ustar00rootroot00000000000000/** * MltProperties.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_PROPERTIES_H_ #define _MLTPP_PROPERTIES_H_ #include "config.h" #include #include namespace Mlt { class Event; /** Abstract Properties class. */ class MLTPP_DECLSPEC Properties { private: mlt_properties instance; public: Properties( ); Properties( bool dummy ); Properties( Properties &properties ); Properties( mlt_properties properties ); Properties( void *properties ); Properties( const char *file ); virtual ~Properties( ); virtual mlt_properties get_properties( ); int inc_ref( ); int dec_ref( ); int ref_count( ); void lock( ); void unlock( ); void block( void *object = NULL ); void unblock( void *object = NULL ); void fire_event( const char *event ); bool is_valid( ); int count( ); char *get( const char *name ); int get_int( const char *name ); int64_t get_int64( const char *name ); double get_double( const char *name ); void *get_data( const char *name, int &size ); void *get_data( const char *name ); int set( const char *name, const char *value ); int set( const char *name, int value ); int set( const char *name, int64_t value ); int set( const char *name, double value ); int set( const char *name, void *value, int size, mlt_destructor destroy = NULL, mlt_serialiser serial = NULL ); void pass_property( Properties &that, const char *name ); int pass_values( Properties &that, const char *prefix ); int pass_list( Properties &that, const char *list ); int parse( const char *namevalue ); char *get_name( int index ); char *get( int index ); void *get_data( int index, int &size ); void mirror( Properties &that ); int inherit( Properties &that ); int rename( const char *source, const char *dest ); void dump( FILE *output = stderr ); void debug( const char *title = "Object", FILE *output = stderr ); void load( const char *file ); int save( const char *file ); #if defined( __DARWIN__ ) && GCC_VERSION < 40000 Event *listen( const char *id, void *object, void (*)( ... ) ); #else Event *listen( const char *id, void *object, mlt_listener ); #endif static void delete_event( Event * ); Event *setup_wait_for( const char *id ); void wait_for( Event *, bool destroy = true ); void wait_for( const char *id ); bool is_sequence( ); static Properties *parse_yaml( const char *file ); char *serialise_yaml( ); int preset( const char *name ); int set_lcnumeric( const char *locale ); const char *get_lcnumeric( ); char *get_time( const char *name, mlt_time_format = mlt_time_smpte ); mlt_color get_color( const char *name ); int set( const char *name , mlt_color value ); char* anim_get( const char *name, int position, int length = 0 ); int anim_set( const char *name, const char *value, int position, int length = 0 ); int anim_get_int( const char *name, int position, int length = 0 ); int anim_set( const char *name, int value, int position, int length = 0, mlt_keyframe_type keyframe_type = mlt_keyframe_linear ); double anim_get_double( const char *name, int position, int length = 0 ); int anim_set( const char *name, double value, int position, int length = 0, mlt_keyframe_type keyframe_type = mlt_keyframe_linear ); int set( const char *name, mlt_rect value ); int set( const char *name, double x, double y, double w, double h, double opacity = 1.0 ); mlt_rect get_rect( const char* name ); int anim_set( const char *name, mlt_rect value, int position, int length = 0, mlt_keyframe_type keyframe_type = mlt_keyframe_linear ); mlt_rect anim_get_rect( const char *name, int position, int length = 0 ); }; } #endif mlt-0.9.0/src/mlt++/MltPushConsumer.cpp000066400000000000000000000102661215300731300176410ustar00rootroot00000000000000/** * MltPushConsumer.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "MltPushConsumer.h" #include "MltFilter.h" using namespace Mlt; namespace Mlt { class PushPrivate { public: PushPrivate( ) { } }; } static void filter_destructor( void *arg ) { Filter *filter = ( Filter * )arg; delete filter; } PushConsumer::PushConsumer( Profile& profile, const char *id , const char *service ) : Consumer( profile, id, service ), m_private( new PushPrivate( ) ) { if ( is_valid( ) ) { // Set up push mode (known as put mode in mlt) set( "real_time", 0 ); set( "put_mode", 1 ); set( "terminate_on_pause", 0 ); set( "buffer", 0 ); // We might need resize and rescale filters so we'll create them now // NB: Try to use the best rescaler available here Filter *resize = new Filter( profile, "resize" ); Filter *rescale = new Filter( profile, "mcrescale" ); if ( !rescale->is_valid( ) ) { delete rescale; rescale = new Filter( profile, "gtkrescale" ); } if ( !rescale->is_valid( ) ) { delete rescale; rescale = new Filter( profile, "rescale" ); } Filter *convert = new Filter( profile, "avcolour_space" ); set( "filter_convert", convert, 0, filter_destructor ); set( "filter_resize", resize, 0, filter_destructor ); set( "filter_rescale", rescale, 0, filter_destructor ); } } PushConsumer::~PushConsumer( ) { } void PushConsumer::set_render( int width, int height, double aspect_ratio ) { set( "render_width", width ); set( "render_height", height ); set( "render_aspect_ratio", aspect_ratio ); } int PushConsumer::connect( Service &/*service*/ ) { return -1; } int PushConsumer::push( Frame *frame ) { frame->inc_ref( ); // Here we have the option to process the frame at a render resolution (this will // typically be PAL or NTSC) prior to scaling according to the consumers profile // This is done to optimise quality, esp. with regard to compositing positions if ( get_int( "render_width" ) ) { // Process the projects render resolution first mlt_image_format format = mlt_image_yuv422; int w = get_int( "render_width" ); int h = get_int( "render_height" ); frame->set( "consumer_aspect_ratio", get_double( "render_aspect_ratio" ) ); frame->set( "consumer_deinterlace", get_int( "deinterlace" ) ); frame->set( "deinterlace_method", get_int( "deinterlace_method" ) ); frame->set( "rescale.interp", get( "rescale" ) ); // Render the frame frame->get_image( format, w, h ); // Now set up the post image scaling Filter *convert = ( Filter * )get_data( "filter_convert" ); mlt_filter_process( convert->get_filter( ), frame->get_frame( ) ); Filter *rescale = ( Filter * )get_data( "filter_rescale" ); mlt_filter_process( rescale->get_filter( ), frame->get_frame( ) ); Filter *resize = ( Filter * )get_data( "filter_resize" ); mlt_filter_process( resize->get_filter( ), frame->get_frame( ) ); } return mlt_consumer_put_frame( ( mlt_consumer )get_service( ), frame->get_frame( ) ); } int PushConsumer::push( Frame &frame ) { return push( &frame ); } int PushConsumer::drain( ) { return 0; } // Convenience function - generates a frame with an image of a given size Frame *PushConsumer::construct( int size ) { mlt_frame f = mlt_frame_init( get_service() ); Frame *frame = new Frame( f ); uint8_t *buffer = ( uint8_t * )mlt_pool_alloc( size ); frame->set( "image", buffer, size, mlt_pool_release ); mlt_frame_close( f ); return frame; } mlt-0.9.0/src/mlt++/MltPushConsumer.h000066400000000000000000000027451215300731300173110ustar00rootroot00000000000000/** * MltPushConsumer.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef MLTPP_PUSH_CONSUMER_H #define MLTPP_PUSH_CONSUMER_H #include "config.h" #include "MltConsumer.h" namespace Mlt { class Frame; class Service; class PushPrivate; class Profile; class MLTPP_DECLSPEC PushConsumer : public Consumer { private: PushPrivate *m_private; public: PushConsumer( Profile& profile, const char *id , const char *service = NULL ); virtual ~PushConsumer( ); void set_render( int width, int height, double aspect_ratio ); virtual int connect( Service &service ); int push( Frame *frame ); int push( Frame &frame ); int drain( ); Frame *construct( int ); }; } #endif mlt-0.9.0/src/mlt++/MltRepository.cpp000066400000000000000000000051551215300731300173660ustar00rootroot00000000000000/** * MltRepository.cpp - MLT Wrapper * Copyright (C) 2008 Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "MltRepository.h" #include "MltProfile.h" #include "MltProperties.h" using namespace Mlt; Repository::Repository( const char* directory ) : instance( NULL ) { instance = mlt_repository_init( directory ); } Repository::Repository( mlt_repository repository ) : instance( repository ) { } Repository::~Repository( ) { if ( instance ) mlt_repository_close( instance ); instance = NULL; } void Repository::register_service( mlt_service_type service_type, const char *service, mlt_register_callback symbol ) { mlt_repository_register( instance, service_type, service, symbol ); } void *Repository::create( Profile& profile, mlt_service_type type, const char *service, void *arg ) { return mlt_repository_create( instance, profile.get_profile(), type, service, arg ); } Properties *Repository::consumers( ) const { return new Properties( mlt_repository_consumers( instance ) ); } Properties *Repository::filters( ) const { return new Properties( mlt_repository_filters( instance ) ); } Properties *Repository::producers( ) const { return new Properties( mlt_repository_producers( instance ) ); } Properties *Repository::transitions( ) const { return new Properties( mlt_repository_transitions( instance ) ); } void Repository::register_metadata( mlt_service_type type, const char *service, mlt_metadata_callback callback, void *callback_data ) { mlt_repository_register_metadata( instance, type, service, callback, callback_data ); } Properties *Repository::metadata( mlt_service_type type, const char *service ) const { return new Properties( mlt_repository_metadata( instance, type, service ) ); } Properties *Repository::languages( ) const { return new Properties( mlt_repository_languages( instance ) ); } Properties *Repository::presets( ) { return new Properties( mlt_repository_presets( ) ); } mlt-0.9.0/src/mlt++/MltRepository.h000066400000000000000000000035071215300731300170320ustar00rootroot00000000000000/** * MltRepository.h - MLT Wrapper * Copyright (C) 2008 Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_REPOSITORY_H_ #define _MLTPP_REPOSITORY_H_ #include "config.h" #ifdef SWIG #define MLTPP_DECLSPEC #endif #include namespace Mlt { class Profile; class Properties; class MLTPP_DECLSPEC Repository { private: mlt_repository instance; Repository( ) { } public: Repository( const char* directory ); Repository( mlt_repository repository ); ~Repository(); void register_service( mlt_service_type service_type, const char *service, mlt_register_callback symbol ); void *create( Profile& profile, mlt_service_type type, const char *service, void *arg ); Properties *consumers( ) const; Properties *filters( ) const; Properties *producers( ) const; Properties *transitions( ) const; void register_metadata( mlt_service_type type, const char *service, mlt_metadata_callback, void *callback_data ); Properties *metadata( mlt_service_type type, const char *service ) const; Properties *languages( ) const; static Properties *presets(); }; } #endif mlt-0.9.0/src/mlt++/MltService.cpp000066400000000000000000000061001215300731300165760ustar00rootroot00000000000000/** * MltService.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "MltService.h" #include "MltFilter.h" #include "MltProfile.h" using namespace Mlt; Service::Service( ) : Properties( false ), instance( NULL ) { } Service::Service( Service &service ) : Properties( false ), instance( service.get_service( ) ) { inc_ref( ); } Service::Service( mlt_service service ) : Properties( false ), instance( service ) { inc_ref( ); } Service::~Service( ) { mlt_service_close( instance ); } mlt_service Service::get_service( ) { return instance; } mlt_properties Service::get_properties( ) { return mlt_service_properties( get_service( ) ); } void Service::lock( ) { mlt_service_lock( get_service( ) ); } void Service::unlock( ) { mlt_service_unlock( get_service( ) ); } int Service::connect_producer( Service &producer, int index ) { return mlt_service_connect_producer( get_service( ), producer.get_service( ), index ); } Service *Service::producer( ) { return new Service( mlt_service_producer( get_service( ) ) ); } Service *Service::consumer( ) { return new Service( mlt_service_consumer( get_service( ) ) ); } Profile *Service::profile( ) { return new Profile( mlt_service_profile( get_service() ) ); } mlt_profile Service::get_profile() { return mlt_service_profile( get_service() ); } Frame *Service::get_frame( int index ) { mlt_frame frame = NULL; mlt_service_get_frame( get_service( ), &frame, index ); Frame *result = new Frame( frame ); mlt_frame_close( frame ); return result; } mlt_service_type Service::type( ) { return mlt_service_identify( get_service( ) ); } int Service::attach( Filter &filter ) { return mlt_service_attach( get_service( ), filter.get_filter( ) ); } int Service::detach( Filter &filter ) { return mlt_service_detach( get_service( ), filter.get_filter( ) ); } int Service::filter_count() { return mlt_service_filter_count( get_service() ); } int Service::move_filter(int from, int to) { return mlt_service_move_filter( get_service(), from, to ); } Filter *Service::filter( int index ) { mlt_filter result = mlt_service_filter( get_service( ), index ); return result == NULL ? NULL : new Filter( result ); } void Service::set_profile( Profile &profile ) { mlt_service_set_profile( get_service( ), profile.get_profile( ) ); } mlt-0.9.0/src/mlt++/MltService.h000066400000000000000000000035271215300731300162550ustar00rootroot00000000000000/** * MltService.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_SERVICE_H_ #define _MLTPP_SERVICE_H_ #include "config.h" #include #include "MltProperties.h" #include "MltFrame.h" namespace Mlt { class Properties; class Filter; class Frame; class Profile; class MLTPP_DECLSPEC Service : public Properties { private: mlt_service instance; public: Service( ); Service( Service &service ); Service( mlt_service service ); virtual ~Service( ); virtual mlt_service get_service( ); void lock( ); void unlock( ); virtual mlt_properties get_properties( ); int connect_producer( Service &producer, int index = 0 ); Service *consumer( ); Service *producer( ); Profile *profile( ); mlt_profile get_profile( ); Frame *get_frame( int index = 0 ); mlt_service_type type( ); int attach( Filter &filter ); int detach( Filter &filter ); int filter_count( ); int move_filter( int from, int to ); Filter *filter( int index ); void set_profile( Profile &profile ); }; } #endif mlt-0.9.0/src/mlt++/MltTokeniser.cpp000066400000000000000000000027571215300731300171570ustar00rootroot00000000000000/** * MltTokeniser.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "MltTokeniser.h" using namespace Mlt; Tokeniser::Tokeniser( char *text, char *delimiter ) { tokens = mlt_tokeniser_init( ); if ( text != NULL ) mlt_tokeniser_parse_new( tokens, text, delimiter ); } Tokeniser::~Tokeniser( ) { mlt_tokeniser_close( tokens ); } int Tokeniser::parse( char *text, char *delimiter ) { return mlt_tokeniser_parse_new( tokens, text, delimiter ); } int Tokeniser::count( ) { return mlt_tokeniser_count( tokens ); } char *Tokeniser::get( int index ) { return mlt_tokeniser_get_string( tokens, index ); } char *Tokeniser::input( ) { return mlt_tokeniser_get_input( tokens ); } mlt-0.9.0/src/mlt++/MltTokeniser.h000066400000000000000000000023771215300731300166220ustar00rootroot00000000000000/** * MltTokeniser.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_TOKENISER_H #define _MLTPP_TOKENISER_H #include "config.h" #include namespace Mlt { class MLTPP_DECLSPEC Tokeniser { private: mlt_tokeniser tokens; public: Tokeniser( char *text = NULL, char *delimiter = " " ); ~Tokeniser( ); int parse( char *text, char *delimiter = " " ); int count( ); char *get( int index ); char *input( ); }; } #endif mlt-0.9.0/src/mlt++/MltTractor.cpp000066400000000000000000000100251215300731300166150ustar00rootroot00000000000000/** * MltTractor.cpp - Tractor wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "MltTractor.h" #include "MltMultitrack.h" #include "MltField.h" #include "MltTransition.h" #include "MltFilter.h" #include "MltPlaylist.h" using namespace Mlt; Tractor::Tractor( ) : instance( mlt_tractor_new( ) ) { } Tractor::Tractor( Service &tractor ) : instance( NULL ) { if ( tractor.type( ) == tractor_type ) { instance = ( mlt_tractor )tractor.get_service( ); inc_ref( ); } } Tractor::Tractor( mlt_tractor tractor ) : instance( tractor ) { inc_ref( ); } Tractor::Tractor( Tractor &tractor ) : Mlt::Producer( tractor ), instance( tractor.get_tractor( ) ) { inc_ref( ); } Tractor::Tractor( Profile& profile, char *id, char *resource ) : instance( NULL ) { Producer producer( profile, id, resource ); if ( producer.is_valid( ) && producer.type( ) == tractor_type ) { instance = ( mlt_tractor )producer.get_producer( ); inc_ref( ); } else if ( producer.is_valid( ) ) { instance = mlt_tractor_new( ); set_track( producer, 0 ); } } Tractor::~Tractor( ) { mlt_tractor_close( instance ); } mlt_tractor Tractor::get_tractor( ) { return instance; } mlt_producer Tractor::get_producer( ) { return mlt_tractor_producer( get_tractor( ) ); } Multitrack *Tractor::multitrack( ) { return new Multitrack( mlt_tractor_multitrack( get_tractor( ) ) ); } Field *Tractor::field( ) { return new Field( mlt_tractor_field( get_tractor( ) ) ); } void Tractor::refresh( ) { return mlt_tractor_refresh( get_tractor( ) ); } int Tractor::set_track( Producer &producer, int index ) { return mlt_tractor_set_track( get_tractor( ), producer.get_producer( ), index ); } Producer *Tractor::track( int index ) { mlt_producer producer = mlt_tractor_get_track( get_tractor( ), index ); return producer != NULL ? new Producer( producer ) : NULL; } int Tractor::count( ) { return mlt_multitrack_count( mlt_tractor_multitrack( get_tractor( ) ) ); } void Tractor::plant_transition( Transition &transition, int a_track, int b_track ) { mlt_field_plant_transition( mlt_tractor_field( get_tractor( ) ), transition.get_transition( ), a_track, b_track ); } void Tractor::plant_transition( Transition *transition, int a_track, int b_track ) { if ( transition != NULL ) mlt_field_plant_transition( mlt_tractor_field( get_tractor( ) ), transition->get_transition( ), a_track, b_track ); } void Tractor::plant_filter( Filter &filter, int track ) { mlt_field_plant_filter( mlt_tractor_field( get_tractor( ) ), filter.get_filter( ), track ); } void Tractor::plant_filter( Filter *filter, int track ) { mlt_field_plant_filter( mlt_tractor_field( get_tractor( ) ), filter->get_filter( ), track ); } bool Tractor::locate_cut( Producer *producer, int &track, int &cut ) { bool found = false; for ( track = 0; producer != NULL && !found && track < count( ); track ++ ) { Playlist playlist( ( mlt_playlist )mlt_tractor_get_track( get_tractor( ), track ) ); for ( cut = 0; !found && cut < playlist.count( ); cut ++ ) { Producer *clip = playlist.get_clip( cut ); found = producer->get_producer( ) == clip->get_producer( ); delete clip; } } track --; cut --; return found; } int Tractor::connect( Producer &producer ) { return mlt_tractor_connect( get_tractor( ), producer.get_service( ) ); } mlt-0.9.0/src/mlt++/MltTractor.h000066400000000000000000000040111215300731300162600ustar00rootroot00000000000000/** * MltTractor.h - Tractor wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_TRACTOR_H_ #define _MLTPP_TRACTOR_H_ #include "config.h" #include #include "MltProducer.h" namespace Mlt { class Producer; class Field; class Multitrack; class Transition; class Filter; class Profile; class MLTPP_DECLSPEC Tractor : public Producer { private: mlt_tractor instance; public: Tractor( ); Tractor( Service &tractor ); Tractor( mlt_tractor tractor ); Tractor( Tractor &tractor ); Tractor( Profile& profile, char *id, char *arg = NULL ); virtual ~Tractor( ); virtual mlt_tractor get_tractor( ); mlt_producer get_producer( ); Multitrack *multitrack( ); Field *field( ); void refresh( ); int set_track( Producer &producer, int index ); Producer *track( int index ); int count( ); void plant_transition( Transition &transition, int a_track = 0, int b_track = 1 ); void plant_transition( Transition *transition, int a_track = 0, int b_track = 1 ); void plant_filter( Filter &filter, int track = 0 ); void plant_filter( Filter *filter, int track = 0 ); bool locate_cut( Producer *producer, int &track, int &cut ); int connect( Producer &producer ); }; } #endif mlt-0.9.0/src/mlt++/MltTransition.cpp000066400000000000000000000063761215300731300173470ustar00rootroot00000000000000/** * MltTransition.cpp - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "MltTransition.h" #include "MltProfile.h" #include "MltProducer.h" using namespace Mlt; Transition::Transition( Profile& profile, const char *id, const char *arg ) : instance( NULL ) { if ( arg != NULL ) { instance = mlt_factory_transition( profile.get_profile(), id, arg ); } else { if ( strchr( id, ':' ) ) { char *temp = strdup( id ); char *arg = strchr( temp, ':' ) + 1; *( arg - 1 ) = '\0'; instance = mlt_factory_transition( profile.get_profile(), temp, arg ); free( temp ); } else { instance = mlt_factory_transition( profile.get_profile(), id, NULL ); } } } Transition::Transition( Service &transition ) : instance( NULL ) { if ( transition.type( ) == transition_type ) { instance = ( mlt_transition )transition.get_service( ); inc_ref( ); } } Transition::Transition( Transition &transition ) : Mlt::Service( transition ), instance( transition.get_transition( ) ) { inc_ref( ); } Transition::Transition( mlt_transition transition ) : instance( transition ) { inc_ref( ); } Transition::~Transition( ) { mlt_transition_close( instance ); } mlt_transition Transition::get_transition( ) { return instance; } mlt_service Transition::get_service( ) { return mlt_transition_service( get_transition( ) ); } void Transition::set_in_and_out( int in, int out ) { mlt_transition_set_in_and_out( get_transition( ), in, out ); } int Transition::connect( Producer &producer, int a_track, int b_track ) { return mlt_transition_connect( get_transition(), producer.get_service(), a_track, b_track ); } int Transition::get_a_track( ) { return mlt_transition_get_a_track( get_transition() ); } int Transition::get_b_track( ) { return mlt_transition_get_b_track( get_transition() ); } int Transition::get_in( ) { return mlt_transition_get_in( get_transition() ); } int Transition::get_out( ) { return mlt_transition_get_out( get_transition() ); } int Transition::get_length( ) { return mlt_transition_get_length( get_transition( ) ); } int Transition::get_position( Frame &frame ) { return mlt_transition_get_position( get_transition( ), frame.get_frame( ) ); } double Transition::get_progress( Frame &frame ) { return mlt_transition_get_progress( get_transition( ), frame.get_frame( ) ); } double Transition::get_progress_delta( Frame &frame ) { return mlt_transition_get_progress_delta( get_transition( ), frame.get_frame( ) ); } mlt-0.9.0/src/mlt++/MltTransition.h000066400000000000000000000034351215300731300170050ustar00rootroot00000000000000/** * MltTransition.h - MLT Wrapper * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _MLTPP_TRANSITION_H_ #define _MLTPP_TRANSITION_H_ #include "config.h" #include #include "MltService.h" namespace Mlt { class Service; class Profile; class Frame; class MLTPP_DECLSPEC Transition : public Service { private: mlt_transition instance; public: Transition( Profile& profile, const char *id, const char *arg = NULL ); Transition( Service &transition ); Transition( Transition &transition ); Transition( mlt_transition transition ); virtual ~Transition( ); virtual mlt_transition get_transition( ); mlt_service get_service( ); void set_in_and_out( int in, int out ); int connect( Producer &producer, int a_track, int b_track ); int get_a_track( ); int get_b_track( ); int get_in( ); int get_out( ); int get_length( ); int get_position( Frame &frame ); double get_progress( Frame &frame ); double get_progress_delta( Frame &frame ); }; } #endif mlt-0.9.0/src/mlt++/config.h000066400000000000000000000024141215300731300154370ustar00rootroot00000000000000/** * config.h - Convenience header file for all mlt++ objects * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef MLTPP_CONFIG_H_ #define MLTPP_CONFIG_H_ #if defined(WIN32) #ifdef MLTPP_EXPORTS #define MLTPP_DECLSPEC __declspec( dllexport ) #else #define MLTPP_DECLSPEC __declspec( dllimport ) #endif #else #if __GNUC__ >= 4 #define MLTPP_DECLSPEC __attribute__ ((visibility ("default"))) #else #define MLTPP_DECLSPEC #endif #endif #endif mlt-0.9.0/src/mlt++/configure000077500000000000000000000012261215300731300157300ustar00rootroot00000000000000#!/bin/sh echo "soversion=3" > config.mak echo "mlt++ -I$prefix/include -I$prefix/include/mlt++ -D_REENTRANT -L$libdir -lmlt++" >> ../../packages.dat WARNINGS="-W -Wwrite-strings -Wcast-qual -Wpointer-arith -Wcast-align -Wredundant-decls" case $targetos in Darwin) echo LIBSUF=.dylib echo "CXXFLAGS+=-D__DARWIN__ -Wall -fPIC" echo "LIBFLAGS=-dynamiclib -single_module" ;; Linux|FreeBSD|NetBSD|GNU/kFreeBSD|GNU) echo LIBSUF=.so echo "CXXFLAGS+=-Wall $WARNINGS -fPIC -DPIC" echo "LIBFLAGS=-shared" ;; MinGW) echo LIBSUF=.dll echo "CXXFLAGS+=-Wall $WARNINGS -DPIC" echo "LIBFLAGS=-Wl,-enable-auto-import -shared" ;; esac >> config.mak mlt-0.9.0/src/mlt++/mlt++.vers000066400000000000000000000500541215300731300156470ustar00rootroot00000000000000MLTPP_0.8.8 { global: extern "C++" { "Mlt::ClipInfo::~ClipInfo()"; "Mlt::ClipInfo::ClipInfo()"; "Mlt::ClipInfo::ClipInfo(mlt_playlist_clip_info*)"; "Mlt::ClipInfo::update(mlt_playlist_clip_info*)"; "typeinfo for Mlt::Consumer"; "typeinfo name for Mlt::Consumer"; "vtable for Mlt::Consumer"; "Mlt::Consumer::connect(Mlt::Service&)"; "Mlt::Consumer::~Consumer()"; "Mlt::Consumer::Consumer()"; "Mlt::Consumer::Consumer(Mlt::Consumer&)"; "Mlt::Consumer::Consumer(mlt_consumer_s*)"; "Mlt::Consumer::Consumer(Mlt::Profile&)"; "Mlt::Consumer::Consumer(Mlt::Profile&, char const*, char const*)"; "Mlt::Consumer::Consumer(Mlt::Service&)"; "Mlt::Consumer::get_consumer()"; "Mlt::Consumer::get_service()"; "Mlt::Consumer::is_stopped()"; "Mlt::Consumer::position()"; "Mlt::Consumer::purge()"; "Mlt::Consumer::run()"; "Mlt::Consumer::start()"; "Mlt::Consumer::stop()"; "Mlt::Deque::count()"; "Mlt::Deque::~Deque()"; "Mlt::Deque::Deque()"; "Mlt::Deque::peek_back()"; "Mlt::Deque::peek_front()"; "Mlt::Deque::pop_back()"; "Mlt::Deque::pop_front()"; "Mlt::Deque::push_back(void*)"; "Mlt::Deque::push_front(void*)"; "Mlt::Event::block()"; "Mlt::Event::~Event()"; "Mlt::Event::Event(Mlt::Event&)"; "Mlt::Event::Event(mlt_event_struct*)"; "Mlt::Event::get_event()"; "Mlt::Event::is_valid()"; "Mlt::Event::unblock()"; "Mlt::Factory::close()"; "Mlt::Factory::consumer(Mlt::Profile&, char*, char*)"; "Mlt::Factory::event_object()"; "Mlt::Factory::filter(Mlt::Profile&, char*, char*)"; "Mlt::Factory::init(char const*)"; "Mlt::Factory::producer(Mlt::Profile&, char*, char*)"; "Mlt::Factory::transition(Mlt::Profile&, char*, char*)"; "typeinfo for Mlt::Field"; "typeinfo name for Mlt::Field"; "vtable for Mlt::Field"; "Mlt::Field::disconnect_service(Mlt::Service&)"; "Mlt::Field::~Field()"; "Mlt::Field::Field(Mlt::Field&)"; "Mlt::Field::Field(mlt_field_s*)"; "Mlt::Field::get_field()"; "Mlt::Field::get_service()"; "Mlt::Field::plant_filter(Mlt::Filter&, int)"; "Mlt::Field::plant_transition(Mlt::Transition&, int, int)"; "typeinfo for Mlt::FilteredConsumer"; "typeinfo name for Mlt::FilteredConsumer"; "vtable for Mlt::FilteredConsumer"; "Mlt::FilteredConsumer::attach(Mlt::Filter&)"; "Mlt::FilteredConsumer::connect(Mlt::Service&)"; "Mlt::FilteredConsumer::detach(Mlt::Filter&)"; "Mlt::FilteredConsumer::~FilteredConsumer()"; "Mlt::FilteredConsumer::FilteredConsumer(Mlt::Consumer&)"; "Mlt::FilteredConsumer::FilteredConsumer(Mlt::Profile&, char const*, char const*)"; "Mlt::FilteredConsumer::last(Mlt::Filter&)"; "typeinfo for Mlt::FilteredProducer"; "typeinfo name for Mlt::FilteredProducer"; "vtable for Mlt::FilteredProducer"; "Mlt::FilteredProducer::attach(Mlt::Filter&)"; "Mlt::FilteredProducer::detach(Mlt::Filter&)"; "Mlt::FilteredProducer::~FilteredProducer()"; "Mlt::FilteredProducer::FilteredProducer(Mlt::Profile&, char const*, char const*)"; "typeinfo for Mlt::Filter"; "typeinfo name for Mlt::Filter"; "vtable for Mlt::Filter"; "Mlt::Filter::connect(Mlt::Service&, int)"; "Mlt::Filter::~Filter()"; "Mlt::Filter::Filter(Mlt::Filter&)"; "Mlt::Filter::Filter(mlt_filter_s*)"; "Mlt::Filter::Filter(Mlt::Profile&, char const*, char const*)"; "Mlt::Filter::Filter(Mlt::Service&)"; "Mlt::Filter::get_filter()"; "Mlt::Filter::get_in()"; "Mlt::Filter::get_length()"; "Mlt::Filter::get_length2(Mlt::Frame&)"; "Mlt::Filter::get_out()"; "Mlt::Filter::get_position(Mlt::Frame&)"; "Mlt::Filter::get_progress(Mlt::Frame&)"; "Mlt::Filter::get_service()"; "Mlt::Filter::get_track()"; "Mlt::Filter::set_in_and_out(int, int)"; "typeinfo for Mlt::Frame"; "typeinfo name for Mlt::Frame"; "vtable for Mlt::Frame"; "Mlt::Frame::fetch_image(mlt_image_format, int, int, int)"; "Mlt::Frame::~Frame()"; "Mlt::Frame::Frame(Mlt::Frame&)"; "Mlt::Frame::Frame(mlt_frame_s*)"; "Mlt::Frame::get_audio(mlt_audio_format&, int&, int&, int&)"; "Mlt::Frame::get_frame()"; "Mlt::Frame::get_image(mlt_image_format&, int&, int&, int)"; "Mlt::Frame::get_original_producer()"; "Mlt::Frame::get_position()"; "Mlt::Frame::get_properties()"; "Mlt::Frame::get_unique_properties(Mlt::Service&)"; "Mlt::Frame::get_waveform(int, int)"; "Mlt::Frame::set_alpha(unsigned char*, int, void (*)(void*))"; "Mlt::Frame::set_image(unsigned char*, int, void (*)(void*))"; "Mlt::Geometry::fetch(Mlt::GeometryItem*, float)"; "Mlt::Geometry::fetch(Mlt::GeometryItem&, float)"; "Mlt::Geometry::~Geometry()"; "Mlt::Geometry::Geometry(char*, int, int, int)"; "Mlt::Geometry::insert(Mlt::GeometryItem*)"; "Mlt::Geometry::insert(Mlt::GeometryItem&)"; "Mlt::Geometry::interpolate()"; "Mlt::Geometry::next_key(Mlt::GeometryItem*, int)"; "Mlt::Geometry::next_key(Mlt::GeometryItem&, int)"; "Mlt::Geometry::parse(char*, int, int, int)"; "Mlt::Geometry::prev_key(Mlt::GeometryItem*, int)"; "Mlt::Geometry::prev_key(Mlt::GeometryItem&, int)"; "Mlt::Geometry::remove(int)"; "Mlt::Geometry::serialise()"; "Mlt::Geometry::serialise(int, int)"; "typeinfo for Mlt::Multitrack"; "typeinfo name for Mlt::Multitrack"; "vtable for Mlt::Multitrack"; "Mlt::Multitrack::clip(mlt_whence, int)"; "Mlt::Multitrack::connect(Mlt::Producer&, int)"; "Mlt::Multitrack::count()"; "Mlt::Multitrack::get_multitrack()"; "Mlt::Multitrack::get_producer()"; "Mlt::Multitrack::~Multitrack()"; "Mlt::Multitrack::Multitrack(Mlt::Multitrack&)"; "Mlt::Multitrack::Multitrack(mlt_multitrack_s*)"; "Mlt::Multitrack::Multitrack(Mlt::Service&)"; "Mlt::Multitrack::refresh()"; "Mlt::Multitrack::track(int)"; "typeinfo for Mlt::Parser"; "typeinfo name for Mlt::Parser"; "vtable for Mlt::Parser"; "Mlt::Parser::get_properties()"; "Mlt::Parser::on_end_filter(Mlt::Filter*)"; "Mlt::Parser::on_end_multitrack(Mlt::Multitrack*)"; "Mlt::Parser::on_end_playlist(Mlt::Playlist*)"; "Mlt::Parser::on_end_producer(Mlt::Producer*)"; "Mlt::Parser::on_end_track()"; "Mlt::Parser::on_end_tractor(Mlt::Tractor*)"; "Mlt::Parser::on_end_transition(Mlt::Transition*)"; "Mlt::Parser::on_invalid(Mlt::Service*)"; "Mlt::Parser::on_start_filter(Mlt::Filter*)"; "Mlt::Parser::on_start_multitrack(Mlt::Multitrack*)"; "Mlt::Parser::on_start_playlist(Mlt::Playlist*)"; "Mlt::Parser::on_start_producer(Mlt::Producer*)"; "Mlt::Parser::on_start_track()"; "Mlt::Parser::on_start_tractor(Mlt::Tractor*)"; "Mlt::Parser::on_start_transition(Mlt::Transition*)"; "Mlt::Parser::on_unknown(Mlt::Service*)"; "Mlt::Parser::~Parser()"; "Mlt::Parser::Parser()"; "Mlt::Parser::start(Mlt::Service&)"; "typeinfo for Mlt::Playlist"; "typeinfo name for Mlt::Playlist"; "vtable for Mlt::Playlist"; "Mlt::Playlist::append(Mlt::Producer&, int, int)"; "Mlt::Playlist::blank(char const*)"; "Mlt::Playlist::blank(int)"; "Mlt::Playlist::blanks_from(int, int)"; "Mlt::Playlist::clear()"; "Mlt::Playlist::clip_info(int, Mlt::ClipInfo*)"; "Mlt::Playlist::clip_length(int)"; "Mlt::Playlist::clip(mlt_whence, int)"; "Mlt::Playlist::clip_start(int)"; "Mlt::Playlist::consolidate_blanks(int)"; "Mlt::Playlist::count()"; "Mlt::Playlist::current()"; "Mlt::Playlist::current_clip()"; "Mlt::Playlist::delete_clip_info(Mlt::ClipInfo*)"; "Mlt::Playlist::get_clip_at(int)"; "Mlt::Playlist::get_clip_index_at(int)"; "Mlt::Playlist::get_clip(int)"; "Mlt::Playlist::get_playlist()"; "Mlt::Playlist::get_producer()"; "Mlt::Playlist::insert_at(int, Mlt::Producer*, int)"; "Mlt::Playlist::insert_at(int, Mlt::Producer&, int)"; "Mlt::Playlist::insert_blank(int, int)"; "Mlt::Playlist::insert(Mlt::Producer&, int, int, int)"; "Mlt::Playlist::is_blank_at(int)"; "Mlt::Playlist::is_blank(int)"; "Mlt::Playlist::is_mix(int)"; "Mlt::Playlist::join(int, int, int)"; "Mlt::Playlist::mix_add(int, Mlt::Transition*)"; "Mlt::Playlist::mix(int, int, Mlt::Transition*)"; "Mlt::Playlist::move(int, int)"; "Mlt::Playlist::move_region(int, int, int)"; "Mlt::Playlist::pad_blanks(int, int, int)"; "Mlt::Playlist::~Playlist()"; "Mlt::Playlist::Playlist()"; "Mlt::Playlist::Playlist(Mlt::Playlist&)"; "Mlt::Playlist::Playlist(mlt_playlist_s*)"; "Mlt::Playlist::Playlist(Mlt::Profile&)"; "Mlt::Playlist::Playlist(Mlt::Service&)"; "Mlt::Playlist::remove(int)"; "Mlt::Playlist::remove_region(int, int)"; "Mlt::Playlist::repeat(int, int)"; "Mlt::Playlist::replace_with_blank(int)"; "Mlt::Playlist::resize_clip(int, int, int)"; "Mlt::Playlist::split_at(int, bool)"; "Mlt::Playlist::split(int, int)"; "typeinfo for Mlt::Producer"; "typeinfo name for Mlt::Producer"; "vtable for Mlt::Producer"; "Mlt::Producer::clear()"; "Mlt::Producer::cut(int, int)"; "Mlt::Producer::frame()"; "Mlt::Producer::frame_time(mlt_time_format)"; "Mlt::Producer::get_fps()"; "Mlt::Producer::get_in()"; "Mlt::Producer::get_length()"; "Mlt::Producer::get_length_time(mlt_time_format)"; "Mlt::Producer::get_out()"; "Mlt::Producer::get_parent()"; "Mlt::Producer::get_playtime()"; "Mlt::Producer::get_producer()"; "Mlt::Producer::get_service()"; "Mlt::Producer::get_speed()"; "Mlt::Producer::is_blank()"; "Mlt::Producer::is_cut()"; "Mlt::Producer::optimise()"; "Mlt::Producer::parent()"; "Mlt::Producer::pause()"; "Mlt::Producer::position()"; "Mlt::Producer::~Producer()"; "Mlt::Producer::Producer()"; "Mlt::Producer::Producer(Mlt::Producer*)"; "Mlt::Producer::Producer(Mlt::Producer&)"; "Mlt::Producer::Producer(mlt_producer_s*)"; "Mlt::Producer::Producer(Mlt::Profile&, char const*, char const*)"; "Mlt::Producer::Producer(Mlt::Service&)"; "Mlt::Producer::runs_into(Mlt::Producer&)"; "Mlt::Producer::same_clip(Mlt::Producer&)"; "Mlt::Producer::seek(char const*)"; "Mlt::Producer::seek(int)"; "Mlt::Producer::set_in_and_out(int, int)"; "Mlt::Producer::set_speed(double)"; "Mlt::Profile::colorspace() const"; "Mlt::Profile::dar() const"; "Mlt::Profile::description() const"; "Mlt::Profile::display_aspect_den() const"; "Mlt::Profile::display_aspect_num() const"; "Mlt::Profile::fps() const"; "Mlt::Profile::frame_rate_den() const"; "Mlt::Profile::frame_rate_num() const"; "Mlt::Profile::from_producer(Mlt::Producer&)"; "Mlt::Profile::get_profile() const"; "Mlt::Profile::height() const"; "Mlt::Profile::is_explicit() const"; "Mlt::Profile::list()"; "Mlt::Profile::~Profile()"; "Mlt::Profile::Profile()"; "Mlt::Profile::Profile(char const*)"; "Mlt::Profile::Profile(mlt_profile_s*)"; "Mlt::Profile::Profile(Mlt::Properties&)"; "Mlt::Profile::progressive() const"; "Mlt::Profile::sample_aspect_den() const"; "Mlt::Profile::sample_aspect_num() const"; "Mlt::Profile::sar() const"; "Mlt::Profile::set_colorspace(int)"; "Mlt::Profile::set_explicit(int)"; "Mlt::Profile::set_frame_rate(int, int)"; "Mlt::Profile::set_height(int)"; "Mlt::Profile::set_progressive(int)"; "Mlt::Profile::set_sample_aspect(int, int)"; "Mlt::Profile::set_width(int)"; "Mlt::Profile::width() const"; "typeinfo for Mlt::Properties"; "typeinfo name for Mlt::Properties"; "vtable for Mlt::Properties"; "Mlt::Properties::block(void*)"; "Mlt::Properties::count()"; "Mlt::Properties::debug(char const*, _IO_FILE*)"; "Mlt::Properties::dec_ref()"; "Mlt::Properties::delete_event(Mlt::Event*)"; "Mlt::Properties::dump(_IO_FILE*)"; "Mlt::Properties::fire_event(char const*)"; "Mlt::Properties::get(char const*)"; "Mlt::Properties::get_data(char const*)"; "Mlt::Properties::get_data(char const*, int&)"; "Mlt::Properties::get_data(int, int&)"; "Mlt::Properties::get_double(char const*)"; "Mlt::Properties::get(int)"; "Mlt::Properties::get_int64(char const*)"; "Mlt::Properties::get_int(char const*)"; "Mlt::Properties::get_lcnumeric()"; "Mlt::Properties::get_name(int)"; "Mlt::Properties::get_properties()"; "Mlt::Properties::get_time(char const*, mlt_time_format)"; "Mlt::Properties::inc_ref()"; "Mlt::Properties::inherit(Mlt::Properties&)"; "Mlt::Properties::is_sequence()"; "Mlt::Properties::is_valid()"; "Mlt::Properties::listen(char const*, void*, void (*)(void*, ...))"; "Mlt::Properties::load(char const*)"; "Mlt::Properties::lock()"; "Mlt::Properties::mirror(Mlt::Properties&)"; "Mlt::Properties::parse(char const*)"; "Mlt::Properties::parse_yaml(char const*)"; "Mlt::Properties::pass_list(Mlt::Properties&, char const*)"; "Mlt::Properties::pass_property(Mlt::Properties&, char const*)"; "Mlt::Properties::pass_values(Mlt::Properties&, char const*)"; "Mlt::Properties::preset(char const*)"; "Mlt::Properties::~Properties()"; "Mlt::Properties::Properties()"; "Mlt::Properties::Properties(bool)"; "Mlt::Properties::Properties(char const*)"; "Mlt::Properties::Properties(Mlt::Properties&)"; "Mlt::Properties::Properties(mlt_properties_s*)"; "Mlt::Properties::Properties(void*)"; "Mlt::Properties::ref_count()"; "Mlt::Properties::rename(char const*, char const*)"; "Mlt::Properties::save(char const*)"; "Mlt::Properties::serialise_yaml()"; "Mlt::Properties::set(char const*, char const*)"; "Mlt::Properties::set(char const*, double)"; "Mlt::Properties::set(char const*, int)"; "Mlt::Properties::set(char const*, long)"; "Mlt::Properties::set(char const*, long long)"; "Mlt::Properties::set(char const*, void*, int, void (*)(void*), char* (*)(void*, int))"; "Mlt::Properties::set_lcnumeric(char const*)"; "Mlt::Properties::setup_wait_for(char const*)"; "Mlt::Properties::unblock(void*)"; "Mlt::Properties::unlock()"; "Mlt::Properties::wait_for(char const*)"; "Mlt::Properties::wait_for(Mlt::Event*, bool)"; "typeinfo for Mlt::PushConsumer"; "typeinfo name for Mlt::PushConsumer"; "vtable for Mlt::PushConsumer"; "Mlt::PushConsumer::connect(Mlt::Service&)"; "Mlt::PushConsumer::construct(int)"; "Mlt::PushConsumer::drain()"; "Mlt::PushConsumer::~PushConsumer()"; "Mlt::PushConsumer::PushConsumer(Mlt::Profile&, char const*, char const*)"; "Mlt::PushConsumer::push(Mlt::Frame*)"; "Mlt::PushConsumer::push(Mlt::Frame&)"; "Mlt::PushConsumer::set_render(int, int, double)"; "Mlt::Repository::consumers() const"; "Mlt::Repository::create(Mlt::Profile&, mlt_service_type, char const*, void*)"; "Mlt::Repository::filters() const"; "Mlt::Repository::languages() const"; "Mlt::Repository::metadata(mlt_service_type, char const*) const"; "Mlt::Repository::presets()"; "Mlt::Repository::producers() const"; "Mlt::Repository::register_metadata(mlt_service_type, char const*, mlt_properties_s* (*)(mlt_service_type, char const*, void*), void*)"; "Mlt::Repository::register_service(mlt_service_type, char const*, void* (*)(mlt_profile_s*, mlt_service_type, char const*, void const*))"; "Mlt::Repository::~Repository()"; "Mlt::Repository::Repository(char const*)"; "Mlt::Repository::Repository(mlt_repository_s*)"; "Mlt::Repository::transitions() const"; "typeinfo for Mlt::Service"; "typeinfo name for Mlt::Service"; "vtable for Mlt::Service"; "Mlt::Service::attach(Mlt::Filter&)"; "Mlt::Service::connect_producer(Mlt::Service&, int)"; "Mlt::Service::consumer()"; "Mlt::Service::detach(Mlt::Filter&)"; "Mlt::Service::filter(int)"; "Mlt::Service::get_frame(int)"; "Mlt::Service::get_profile()"; "Mlt::Service::get_properties()"; "Mlt::Service::get_service()"; "Mlt::Service::lock()"; "Mlt::Service::producer()"; "Mlt::Service::profile()"; "Mlt::Service::~Service()"; "Mlt::Service::Service()"; "Mlt::Service::Service(Mlt::Service&)"; "Mlt::Service::Service(mlt_service_s*)"; "Mlt::Service::set_profile(Mlt::Profile&)"; "Mlt::Service::type()"; "Mlt::Service::unlock()"; "Mlt::Tokeniser::count()"; "Mlt::Tokeniser::get(int)"; "Mlt::Tokeniser::input()"; "Mlt::Tokeniser::parse(char*, char*)"; "Mlt::Tokeniser::~Tokeniser()"; "Mlt::Tokeniser::Tokeniser(char*, char*)"; "typeinfo for Mlt::Tractor"; "typeinfo name for Mlt::Tractor"; "vtable for Mlt::Tractor"; "Mlt::Tractor::connect(Mlt::Producer&)"; "Mlt::Tractor::count()"; "Mlt::Tractor::field()"; "Mlt::Tractor::get_producer()"; "Mlt::Tractor::get_tractor()"; "Mlt::Tractor::locate_cut(Mlt::Producer*, int&, int&)"; "Mlt::Tractor::multitrack()"; "Mlt::Tractor::plant_filter(Mlt::Filter*, int)"; "Mlt::Tractor::plant_filter(Mlt::Filter&, int)"; "Mlt::Tractor::plant_transition(Mlt::Transition*, int, int)"; "Mlt::Tractor::plant_transition(Mlt::Transition&, int, int)"; "Mlt::Tractor::refresh()"; "Mlt::Tractor::set_track(Mlt::Producer&, int)"; "Mlt::Tractor::track(int)"; "Mlt::Tractor::~Tractor()"; "Mlt::Tractor::Tractor()"; "Mlt::Tractor::Tractor(Mlt::Profile&, char*, char*)"; "Mlt::Tractor::Tractor(Mlt::Service&)"; "Mlt::Tractor::Tractor(Mlt::Tractor&)"; "Mlt::Tractor::Tractor(mlt_tractor_s*)"; "typeinfo for Mlt::Transition"; "typeinfo name for Mlt::Transition"; "vtable for Mlt::Transition"; "Mlt::Transition::connect(Mlt::Producer&, int, int)"; "Mlt::Transition::get_a_track()"; "Mlt::Transition::get_b_track()"; "Mlt::Transition::get_in()"; "Mlt::Transition::get_length()"; "Mlt::Transition::get_out()"; "Mlt::Transition::get_position(Mlt::Frame&)"; "Mlt::Transition::get_progress_delta(Mlt::Frame&)"; "Mlt::Transition::get_progress(Mlt::Frame&)"; "Mlt::Transition::get_service()"; "Mlt::Transition::get_transition()"; "Mlt::Transition::set_in_and_out(int, int)"; "Mlt::Transition::~Transition()"; "Mlt::Transition::Transition(Mlt::Profile&, char const*, char const*)"; "Mlt::Transition::Transition(Mlt::Service&)"; "Mlt::Transition::Transition(Mlt::Transition&)"; "Mlt::Transition::Transition(mlt_transition_s*)"; }; local: *; }; MLTPP_0.9.0 { global: extern "C++" { "Mlt::Deque::peek(int)"; "Mlt::Properties::anim_get(char const*, int, int)"; "Mlt::Properties::anim_get_double(char const*, int, int)"; "Mlt::Properties::anim_get_int(char const*, int, int)"; "Mlt::Properties::anim_get_rect(char const*, int, int)"; "Mlt::Properties::anim_set(char const*, char const*, int, int)"; "Mlt::Properties::anim_set(char const*, double, int, int, mlt_keyframe_type)"; "Mlt::Properties::anim_set(char const*, int, int, int, mlt_keyframe_type)"; "Mlt::Properties::anim_set(char const*, mlt_rect, int, int, mlt_keyframe_type)"; "Mlt::Properties::get_color(char const*)"; "Mlt::Properties::get_rect(char const*)"; "Mlt::Properties::set(char const*, double, double, double, double, double)"; "Mlt::Properties::set(char const*, mlt_color)"; "Mlt::Properties::set(char const*, mlt_rect)"; "Mlt::Service::filter_count()"; "Mlt::Service::move_filter(int, int)"; }; } MLTPP_0.8.8; mlt-0.9.0/src/modules/000077500000000000000000000000001215300731300145465ustar00rootroot00000000000000mlt-0.9.0/src/modules/Makefile000066400000000000000000000013161215300731300162070ustar00rootroot00000000000000include ../../config.mak include make.inc all clean depend: list='$(SUBDIRS)'; \ for subdir in $$list; do \ if [ -f $$subdir/Makefile -a ! -f disable-$$subdir ] ; \ then $(MAKE) -C $$subdir $@ || exit 1; \ fi \ done distclean: rm -f consumers.dat filters.dat producers.dat transitions.dat make.inc; \ list='$(SUBDIRS)'; \ for subdir in $$list; do \ if [ -f $$subdir/Makefile -a ! -f disable-$$subdir ] ; \ then $(MAKE) -C $$subdir $@ || exit 1; \ fi \ done install: list='$(SUBDIRS)'; \ for subdir in $$list; do \ if [ -f $$subdir/Makefile -a ! -f disable-$$subdir ] ; \ then $(MAKE) DESTDIR=$(DESTDIR) -C $$subdir $@ || exit 1; \ fi \ done uninstall: rm -rf "$(DESTDIR)$(moduledir)" mlt-0.9.0/src/modules/avformat/000077500000000000000000000000001215300731300163655ustar00rootroot00000000000000mlt-0.9.0/src/modules/avformat/Makefile000066400000000000000000000031221215300731300200230ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lpthread include ../../../config.mak include config.mak LDFLAGS += -lavformat$(AVFORMAT_SUFFIX) LDFLAGS += -lavcodec$(AVFORMAT_SUFFIX) LDFLAGS += -lavutil$(AVFORMAT_SUFFIX) LDFLAGS += -lswscale$(AVFORMAT_SUFFIX) LDFLAGS += $(EXTRA_LIBS) ifndef CODECS TARGET = ../libmltffmpeg$(LIBSUF) else TARGET = ../libmltavformat$(LIBSUF) endif OBJS = factory.o ifdef FILTERS OBJS += filter_avcolour_space.o \ filter_avresample.o \ filter_avdeinterlace.o \ filter_swscale.o CFLAGS += -DFILTERS endif ifdef VDPAU CFLAGS += -DVDPAU `pkg-config --cflags x11` LDFLAGS += $(LIBDL) `pkg-config --libs x11` endif ifdef CODECS OBJS += producer_avformat.o \ consumer_avformat.o CFLAGS += -DCODECS endif ifdef DEVICES CFLAGS += -DAVDEVICE LDFLAGS += -lavdevice$(AVFORMAT_SUFFIX) endif SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) ../libmltffmpeg$(LIBSUF) ../libmltavformat$(LIBSUF) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/avformat" install -m 644 producer_avformat.yml "$(DESTDIR)$(mltdatadir)/avformat" install -m 644 consumer_avformat.yml "$(DESTDIR)$(mltdatadir)/avformat" uninstall: rm "$(DESTDIR)$(moduledir)/libmltavformat$(LIBSUF)" 2> /dev/null || true rm "$(DESTDIR)$(moduledir)/libmltffmpeg$(LIBSUF)" 2> /dev/null || true rm -rf "$(DESTDIR)$(mltdatadir)/avformat" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/avformat/configure000077500000000000000000000115241215300731300202770ustar00rootroot00000000000000#!/bin/sh # Determine whether to recommend/use the HEAD revision of FFmpeg (unreleased) # or a specific revision based upon whether the last digit of our version # is even or odd. An odd MLT version number always represents unreleased. ffmpeg_ver="1.2" libav_ver="0.8.7" micro_version=$(echo $version | cut -d . -f 3) odd_version=$(($micro_version % 2)) [ "$odd_version" -eq "1" ] && ffmpeg_ver="HEAD" && libav_ver="HEAD" if [ "$help" = "1" ] then cat << EOF FFmpeg/avformat options: --avformat-shared=path - Link against a shared installation of libavformat (default) --avformat-static=path - Link against a static build of libavformat --avformat-ldextra=libs - Provide additional libs to link with --avformat-suffix=suff - Specify a custom suffix --avformat-no-codecs - Disable the producer and consumer to avoid the codecs --avformat-no-filters - Disable the filters to make a codecs+muxers-only plugin --avformat-no-devices - Disable support for libavdevice --avformat-vdpau - Enable support for NVIDIA VDPAU NOTE: The recommended version of FFmpeg is $ffmpeg_ver or libav $libav_ver. EOF else targetos=$(uname -s) case $targetos in Darwin) export LIBSUF=.dylib ;; Linux|FreeBSD|NetBSD) export LIBSUF=.so ;; *) ;; esac bits=$(uname -m) case $bits in x86_64) [ -d /usr/lib/lib64 ] && export LIBDIR=lib64 || export LIBDIR=lib ;; *) export LIBDIR=lib ;; esac echo > config.mak export static_ffmpeg= export shared_ffmpeg= export extra_libs= export avformat_suffix= export codecs=true export filters=true export devices=true export vdpau=false pkg-config x11 > /dev/null 2>&1 export x11=$? for i in "$@" do case $i in --avformat-static=* ) static_ffmpeg="${i#--avformat-static=}" ;; --avformat-shared=* ) shared_ffmpeg="${i#--avformat-shared=}" ;; --avformat-ldextra=* ) extra_libs="${i#--avformat-ldextra=}" ;; --avformat-suffix=* ) avformat_suffix="${i#--avformat-suffix=}" ;; --avformat-no-codecs ) codecs=false ;; --avformat-no-filters ) filters=false ;; --avformat-no-devices ) devices=false ;; --avformat-no-vdpau ) vdpau=false ;; --avformat-vdpau ) vdpau=true ;; esac done : ${shared_ffmpeg:=$(pkg-config --variable=prefix libavformat${avformat_suffix})} if [ "$static_ffmpeg" != "" ] then if [ -d "$static_ffmpeg" ] then echo "CFLAGS+=-DAVDATADIR=\\\"${static_ffmpeg}/ffpresets/\\\"" >> config.mak echo "CFLAGS+=-I$static_ffmpeg" >> config.mak echo "LDFLAGS+=-L$static_ffmpeg/libavformat -L$static_ffmpeg/libavcodec -L$static_ffmpeg/libavutil" >> config.mak echo "LDFLAGS+=-L$static_ffmpeg/libswscale" >> config.mak [ $targetos = "Darwin" ] && echo "LDFLAGS+=-single_module" >> config.mak if [ "$devices" = "true" ] then echo "LDFLAGS+=-L$static_ffmpeg/libavdevice" >> config.mak fi echo "LDFLAGS+=-Wl,-Bsymbolic" >> config.mak extra_libs="$extra_libs -lm -lz -lbz2" if [ "$vdpau" = "true" ] then printf "#include \n int main(){ VdpBitstreamBuffer test; test.struct_version; return 0;}" | $CC -I"$static_ffmpeg" $CFLAGS -c -x c - >/dev/null 2>&1 [ "$x11" = "0" -a "$?" = "0" ] && echo "VDPAU=1" >> config.mak fi else echo "avformat: Invalid path specified: $static_ffmpeg" touch ../disable-avformat echo 0 fi elif [ "$shared_ffmpeg" != "" ] then echo "PREFIX=$shared_ffmpeg" >> config.mak case $targetos in MINGW32_NT-*) echo "CFLAGS+=-DAVDATADIR=\\\"share/ffmpeg/\\\"" >> config.mak ;; *) echo "CFLAGS+=-DAVDATADIR=\\\"${shared_ffmpeg}/share/ffmpeg${avformat_suffix}/\\\"" >> config.mak ;; esac echo "CFLAGS+=$(pkg-config --cflags libavformat${avformat_suffix})" >> config.mak echo "LDFLAGS+=$(pkg-config --libs-only-L libavformat${avformat_suffix})" >> config.mak echo "CFLAGS+=$(pkg-config --cflags libswscale${avformat_suffix})" >> config.mak echo "LDFLAGS+=$(pkg-config --libs-only-L libswscale${avformat_suffix})" >> config.mak if [ "$devices" = "true" ] then echo "CFLAGS+=$(pkg-config --cflags libavdevice${avformat_suffix})" >> config.mak echo "LDFLAGS+=$(pkg-config --libs-only-L libavdevice${avformat_suffix})" >> config.mak fi if [ "$vdpau" = "true" ] then printf "#include \n int main(){ VdpBitstreamBuffer test; test.struct_version; return 0;}" | $CC $(pkg-config --cflags libavformat${avformat_suffix}) -I"$shared_ffmpeg/include" $CFLAGS -c -x c - >/dev/null 2>&1 [ "$x11" = "0" -a "$?" = "0" ] && echo "VDPAU=1" >> config.mak fi else echo "- libavformat not found: disabling" touch ../disable-avformat exit 0 fi echo "EXTRA_LIBS=$extra_libs" >> config.mak echo "AVFORMAT_SUFFIX=$avformat_suffix" >> config.mak [ "$codecs" = "true" ] && echo "CODECS=1" >> config.mak [ "$filters" = "true" ] && echo "FILTERS=1" >> config.mak [ "$devices" = "true" ] && echo "DEVICES=1" >> config.mak exit 0 fi mlt-0.9.0/src/modules/avformat/consumer_avformat.c000066400000000000000000002101261215300731300222650ustar00rootroot00000000000000/* * consumer_avformat.c -- an encoder based on avformat * Copyright (C) 2003-2012 Ushodaya Enterprises Limited * Author: Charles Yates * Author: Dan Dennedy * Much code borrowed from ffmpeg.c: Copyright (c) 2000-2003 Fabrice Bellard * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // mlt Header files #include #include #include #include #include // System header files #include #include #include #include #include #include #include // avformat header files #include #include #include #include #include #include #if LIBAVCODEC_VERSION_MAJOR >= 53 #include #define CODEC_TYPE_VIDEO AVMEDIA_TYPE_VIDEO #define CODEC_TYPE_AUDIO AVMEDIA_TYPE_AUDIO #define PKT_FLAG_KEY AV_PKT_FLAG_KEY #else #include #endif #if LIBAVCODEC_VERSION_MAJOR < 55 #define AV_CODEC_ID_PCM_S16LE CODEC_ID_PCM_S16LE #define AV_CODEC_ID_PCM_S16BE CODEC_ID_PCM_S16BE #define AV_CODEC_ID_PCM_U16LE CODEC_ID_PCM_U16LE #define AV_CODEC_ID_PCM_U16BE CODEC_ID_PCM_U16BE #define AV_CODEC_ID_H264 CODEC_ID_H264 #define AV_CODEC_ID_NONE CODEC_ID_NONE #define AV_CODEC_ID_AC3 CODEC_ID_AC3 #define AV_CODEC_ID_VORBIS CODEC_ID_VORBIS #endif #define MAX_AUDIO_STREAMS (8) #define AUDIO_ENCODE_BUFFER_SIZE (48000 * 2 * MAX_AUDIO_STREAMS) #define AUDIO_BUFFER_SIZE (1024 * 42) #define VIDEO_BUFFER_SIZE (2048 * 1024) // // This structure should be extended and made globally available in mlt // typedef struct { uint8_t *buffer; int size; int used; double time; int frequency; int channels; } *sample_fifo, sample_fifo_s; sample_fifo sample_fifo_init( int frequency, int channels ) { sample_fifo fifo = calloc( 1, sizeof( sample_fifo_s ) ); fifo->frequency = frequency; fifo->channels = channels; return fifo; } // count is the number of samples multiplied by the number of bytes per sample void sample_fifo_append( sample_fifo fifo, uint8_t *samples, int count ) { if ( ( fifo->size - fifo->used ) < count ) { fifo->size += count * 5; fifo->buffer = realloc( fifo->buffer, fifo->size ); } memcpy( &fifo->buffer[ fifo->used ], samples, count ); fifo->used += count; } int sample_fifo_used( sample_fifo fifo ) { return fifo->used; } int sample_fifo_fetch( sample_fifo fifo, uint8_t *samples, int count ) { if ( count > fifo->used ) count = fifo->used; memcpy( samples, fifo->buffer, count ); fifo->used -= count; memmove( fifo->buffer, &fifo->buffer[ count ], fifo->used ); fifo->time += ( double )count / fifo->channels / fifo->frequency; return count; } void sample_fifo_close( sample_fifo fifo ) { free( fifo->buffer ); free( fifo ); } // Forward references. static void property_changed( mlt_properties owner, mlt_consumer self, char *name ); static int consumer_start( mlt_consumer consumer ); static int consumer_stop( mlt_consumer consumer ); static int consumer_is_stopped( mlt_consumer consumer ); static void *consumer_thread( void *arg ); static void consumer_close( mlt_consumer consumer ); /** Initialise the consumer. */ mlt_consumer consumer_avformat_init( mlt_profile profile, char *arg ) { // Allocate the consumer mlt_consumer consumer = mlt_consumer_new( profile ); // If memory allocated and initialises without error if ( consumer != NULL ) { // Get properties from the consumer mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Assign close callback consumer->close = consumer_close; // Interpret the argument if ( arg != NULL ) mlt_properties_set( properties, "target", arg ); // sample and frame queue mlt_properties_set_data( properties, "frame_queue", mlt_deque_init( ), 0, ( mlt_destructor )mlt_deque_close, NULL ); // Audio options not fully handled by AVOptions #define QSCALE_NONE (-99999) mlt_properties_set_int( properties, "aq", QSCALE_NONE ); // Video options not fully handled by AVOptions mlt_properties_set_int( properties, "dc", 8 ); // Muxer options not fully handled by AVOptions mlt_properties_set_double( properties, "muxdelay", 0.7 ); mlt_properties_set_double( properties, "muxpreload", 0.5 ); // Ensure termination at end of the stream mlt_properties_set_int( properties, "terminate_on_pause", 1 ); // Default to separate processing threads for producer and consumer with no frame dropping! mlt_properties_set_int( properties, "real_time", -1 ); mlt_properties_set_int( properties, "prefill", 1 ); // Set up start/stop/terminated callbacks consumer->start = consumer_start; consumer->stop = consumer_stop; consumer->is_stopped = consumer_is_stopped; mlt_events_register( properties, "consumer-fatal-error", NULL ); mlt_event event = mlt_events_listen( properties, consumer, "property-changed", ( mlt_listener )property_changed ); mlt_properties_set_data( properties, "property-changed event", event, 0, NULL, NULL ); } // Return consumer return consumer; } static void property_changed( mlt_properties owner, mlt_consumer self, char *name ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); if ( !strcmp( name, "s" ) ) { // Obtain the size property char *size = mlt_properties_get( properties, "s" ); int width = mlt_properties_get_int( properties, "width" ); int height = mlt_properties_get_int( properties, "height" ); int tw, th; if ( sscanf( size, "%dx%d", &tw, &th ) == 2 && tw > 0 && th > 0 ) { width = tw; height = th; } else { mlt_log_warning( MLT_CONSUMER_SERVICE(self), "Invalid size property %s - ignoring.\n", size ); } // Now ensure we honour the multiple of two requested by libavformat width = ( width / 2 ) * 2; height = ( height / 2 ) * 2; mlt_properties_set_int( properties, "width", width ); mlt_properties_set_int( properties, "height", height ); } // "-aspect" on ffmpeg command line is display aspect ratio else if ( !strcmp( name, "aspect" ) ) { double ar = mlt_properties_get_double( properties, "aspect" ); AVRational rational = av_d2q( ar, 255 ); int width = mlt_properties_get_int( properties, "width" ); int height = mlt_properties_get_int( properties, "height" ); // Update the profile and properties as well since this is an alias // for mlt properties that correspond to profile settings mlt_properties_set_int( properties, "display_aspect_num", rational.num ); mlt_properties_set_int( properties, "display_aspect_den", rational.den ); // Now compute the sample aspect ratio rational = av_d2q( ar * height / FFMAX(width, 1), 255 ); // Update the profile and properties as well since this is an alias // for mlt properties that correspond to profile settings mlt_properties_set_int( properties, "sample_aspect_num", rational.num ); mlt_properties_set_int( properties, "sample_aspect_den", rational.den ); } // Handle the ffmpeg command line "-r" property for frame rate else if ( !strcmp( name, "r" ) ) { double frame_rate = mlt_properties_get_double( properties, "r" ); AVRational rational = av_d2q( frame_rate, 255 ); mlt_properties_set_int( properties, "frame_rate_num", rational.num ); mlt_properties_set_int( properties, "frame_rate_den", rational.den ); } } /** Start the consumer. */ static int consumer_start( mlt_consumer consumer ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); int error = 0; // Report information about available muxers and codecs as YAML Tiny char *s = mlt_properties_get( properties, "f" ); if ( s && strcmp( s, "list" ) == 0 ) { mlt_properties doc = mlt_properties_new(); mlt_properties formats = mlt_properties_new(); char key[20]; AVOutputFormat *format = NULL; mlt_properties_set_data( properties, "f", formats, 0, (mlt_destructor) mlt_properties_close, NULL ); mlt_properties_set_data( doc, "formats", formats, 0, NULL, NULL ); while ( ( format = av_oformat_next( format ) ) ) { snprintf( key, sizeof(key), "%d", mlt_properties_count( formats ) ); mlt_properties_set( formats, key, format->name ); } s = mlt_properties_serialise_yaml( doc ); fprintf( stdout, "%s", s ); free( s ); mlt_properties_close( doc ); error = 1; } s = mlt_properties_get( properties, "acodec" ); if ( s && strcmp( s, "list" ) == 0 ) { mlt_properties doc = mlt_properties_new(); mlt_properties codecs = mlt_properties_new(); char key[20]; AVCodec *codec = NULL; mlt_properties_set_data( properties, "acodec", codecs, 0, (mlt_destructor) mlt_properties_close, NULL ); mlt_properties_set_data( doc, "audio_codecs", codecs, 0, NULL, NULL ); while ( ( codec = av_codec_next( codec ) ) ) #if (defined(FFUDIV) && LIBAVCODEC_VERSION_INT >= ((54<<16)+(56<<8)+100)) || (LIBAVCODEC_VERSION_INT >= ((54<<16)+(27<<8)+0)) if ( codec->encode2 && codec->type == CODEC_TYPE_AUDIO ) #elif LIBAVCODEC_VERSION_INT >= ((54<<16)+(0<<8)+0) if ( ( codec->encode || codec->encode2 ) && codec->type == CODEC_TYPE_AUDIO ) #else if ( codec->encode && codec->type == CODEC_TYPE_AUDIO ) #endif { snprintf( key, sizeof(key), "%d", mlt_properties_count( codecs ) ); mlt_properties_set( codecs, key, codec->name ); } s = mlt_properties_serialise_yaml( doc ); fprintf( stdout, "%s", s ); free( s ); mlt_properties_close( doc ); error = 1; } s = mlt_properties_get( properties, "vcodec" ); if ( s && strcmp( s, "list" ) == 0 ) { mlt_properties doc = mlt_properties_new(); mlt_properties codecs = mlt_properties_new(); char key[20]; AVCodec *codec = NULL; mlt_properties_set_data( properties, "vcodec", codecs, 0, (mlt_destructor) mlt_properties_close, NULL ); mlt_properties_set_data( doc, "video_codecs", codecs, 0, NULL, NULL ); while ( ( codec = av_codec_next( codec ) ) ) #if (defined(FFUDIV) && LIBAVCODEC_VERSION_INT >= ((54<<16)+(56<<8)+100)) || (LIBAVCODEC_VERSION_INT >= ((54<<16)+(27<<8)+0)) if ( codec->encode2 && codec->type == CODEC_TYPE_VIDEO ) #elif LIBAVCODEC_VERSION_INT >= ((54<<16)+(0<<8)+0) if ( (codec->encode || codec->encode2) && codec->type == CODEC_TYPE_VIDEO ) #else if ( codec->encode && codec->type == CODEC_TYPE_VIDEO ) #endif { snprintf( key, sizeof(key), "%d", mlt_properties_count( codecs ) ); mlt_properties_set( codecs, key, codec->name ); } s = mlt_properties_serialise_yaml( doc ); fprintf( stdout, "%s", s ); free( s ); mlt_properties_close( doc ); error = 1; } // Check that we're not already running if ( !error && !mlt_properties_get_int( properties, "running" ) ) { // Allocate a thread pthread_t *thread = calloc( 1, sizeof( pthread_t ) ); mlt_event_block( mlt_properties_get_data( properties, "property-changed event", NULL ) ); // Apply AVOptions that are synonyms for standard mlt_consumer options if ( mlt_properties_get( properties, "ac" ) ) mlt_properties_set_int( properties, "channels", mlt_properties_get_int( properties, "ac" ) ); if ( mlt_properties_get( properties, "ar" ) ) mlt_properties_set_int( properties, "frequency", mlt_properties_get_int( properties, "ar" ) ); // Assign the thread to properties mlt_properties_set_data( properties, "thread", thread, sizeof( pthread_t ), free, NULL ); // Create the thread pthread_create( thread, NULL, consumer_thread, consumer ); // Set the running state mlt_properties_set_int( properties, "running", 1 ); } return error; } /** Stop the consumer. */ static int consumer_stop( mlt_consumer consumer ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); pthread_t *thread = mlt_properties_get_data( properties, "thread", NULL ); // Check that we're running if ( thread ) { // Stop the thread mlt_properties_set_int( properties, "running", 0 ); // Wait for termination pthread_join( *thread, NULL ); mlt_properties_set_data( properties, "thread", NULL, 0, NULL, NULL ); mlt_event_unblock( mlt_properties_get_data( properties, "property-changed event", NULL ) ); } return 0; } /** Determine if the consumer is stopped. */ static int consumer_is_stopped( mlt_consumer consumer ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); return !mlt_properties_get_int( properties, "running" ); } /** Process properties as AVOptions and apply to AV context obj */ static void apply_properties( void *obj, mlt_properties properties, int flags ) { int i; int count = mlt_properties_count( properties ); #if LIBAVUTIL_VERSION_INT < ((51<<16)+(12<<8)+0) int alloc = 1; #endif for ( i = 0; i < count; i++ ) { const char *opt_name = mlt_properties_get_name( properties, i ); #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(10<<8)+0) const AVOption *opt = av_opt_find( obj, opt_name, NULL, flags, flags ); #else const AVOption *opt = av_find_opt( obj, opt_name, NULL, flags, flags ); #endif // If option not found, see if it was prefixed with a or v (-vb) if ( !opt && ( ( opt_name[0] == 'v' && ( flags & AV_OPT_FLAG_VIDEO_PARAM ) ) || ( opt_name[0] == 'a' && ( flags & AV_OPT_FLAG_AUDIO_PARAM ) ) ) ) #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(10<<8)+0) opt = av_opt_find( obj, ++opt_name, NULL, flags, flags ); #else opt = av_find_opt( obj, ++opt_name, NULL, flags, flags ); #endif // Apply option if found if ( opt ) #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(12<<8)+0) av_opt_set( obj, opt_name, mlt_properties_get_value( properties, i), 0 ); #else av_set_string3( obj, opt_name, mlt_properties_get_value( properties, i), alloc, NULL ); #endif } } static enum PixelFormat pick_pix_fmt( mlt_image_format img_fmt ) { switch ( img_fmt ) { case mlt_image_rgb24: return PIX_FMT_RGB24; case mlt_image_rgb24a: return PIX_FMT_RGBA; case mlt_image_yuv420p: return PIX_FMT_YUV420P; default: return PIX_FMT_YUYV422; } } static int get_mlt_audio_format( int av_sample_fmt ) { switch ( av_sample_fmt ) { case AV_SAMPLE_FMT_U8: return mlt_audio_u8; case AV_SAMPLE_FMT_S32: return mlt_audio_s32le; case AV_SAMPLE_FMT_FLT: return mlt_audio_f32le; #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(17<<8)+0) case AV_SAMPLE_FMT_U8P: return mlt_audio_u8; case AV_SAMPLE_FMT_S32P: return mlt_audio_s32le; case AV_SAMPLE_FMT_FLTP: return mlt_audio_f32le; #endif default: return mlt_audio_s16; } } static int pick_sample_fmt( mlt_properties properties, AVCodec *codec ) { int sample_fmt = AV_SAMPLE_FMT_S16; const char *format = mlt_properties_get( properties, "mlt_audio_format" ); const int *p = codec->sample_fmts; // get default av_sample_fmt from mlt_audio_format if ( format ) { if ( !strcmp( format, "s32le" ) ) sample_fmt = AV_SAMPLE_FMT_S32; else if ( !strcmp( format, "f32le" ) ) sample_fmt = AV_SAMPLE_FMT_FLT; else if ( !strcmp( format, "u8" ) ) sample_fmt = AV_SAMPLE_FMT_U8; #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(17<<8)+0) else if ( !strcmp( format, "s32" ) ) sample_fmt = AV_SAMPLE_FMT_S32P; else if ( !strcmp( format, "float" ) ) sample_fmt = AV_SAMPLE_FMT_FLTP; #endif } // check if codec supports our mlt_audio_format for ( ; *p != -1; p++ ) { if ( *p == sample_fmt ) return sample_fmt; } // no match - pick first one we support for ( p = codec->sample_fmts; *p != -1; p++ ) { switch (*p) { case AV_SAMPLE_FMT_U8: case AV_SAMPLE_FMT_S16: case AV_SAMPLE_FMT_S32: case AV_SAMPLE_FMT_FLT: #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(17<<8)+0) case AV_SAMPLE_FMT_U8P: case AV_SAMPLE_FMT_S16P: case AV_SAMPLE_FMT_S32P: case AV_SAMPLE_FMT_FLTP: #endif return *p; default: break; } } mlt_log_error( properties, "audio codec sample_fmt not compatible" ); return AV_SAMPLE_FMT_NONE; } static uint8_t* interleaved_to_planar( int samples, int channels, uint8_t* audio, int bytes_per_sample ) { uint8_t *buffer = mlt_pool_alloc( AUDIO_ENCODE_BUFFER_SIZE ); uint8_t *p = buffer; int c; memset( buffer, 0, AUDIO_ENCODE_BUFFER_SIZE ); for ( c = 0; c < channels; c++ ) { uint8_t *q = audio + c * bytes_per_sample; int i = samples + 1; while ( --i ) { memcpy( p, q, bytes_per_sample ); p += bytes_per_sample; q += channels * bytes_per_sample; } } return buffer; } /** Add an audio output stream */ static AVStream *add_audio_stream( mlt_consumer consumer, AVFormatContext *oc, AVCodec *codec, int channels ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Create a new stream #if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(10<<8)+0) AVStream *st = avformat_new_stream( oc, codec ); #else AVStream *st = av_new_stream( oc, oc->nb_streams ); #endif // If created, then initialise from properties if ( st != NULL ) { AVCodecContext *c = st->codec; // Establish defaults from AVOptions #if LIBAVCODEC_VERSION_MAJOR >= 53 avcodec_get_context_defaults3( c, codec ); #else avcodec_get_context_defaults2( c, CODEC_TYPE_AUDIO ); #endif c->codec_id = codec->id; c->codec_type = CODEC_TYPE_AUDIO; c->sample_fmt = pick_sample_fmt( properties, codec ); #if 0 // disabled until some audio codecs are multi-threaded // Setup multi-threading int thread_count = mlt_properties_get_int( properties, "threads" ); if ( thread_count == 0 && getenv( "MLT_AVFORMAT_THREADS" ) ) thread_count = atoi( getenv( "MLT_AVFORMAT_THREADS" ) ); if ( thread_count > 1 ) c->thread_count = thread_count; #endif if (oc->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; // Allow the user to override the audio fourcc if ( mlt_properties_get( properties, "atag" ) ) { char *tail = NULL; char *arg = mlt_properties_get( properties, "atag" ); int tag = strtol( arg, &tail, 0); if( !tail || *tail ) tag = arg[ 0 ] + ( arg[ 1 ] << 8 ) + ( arg[ 2 ] << 16 ) + ( arg[ 3 ] << 24 ); c->codec_tag = tag; } // Process properties as AVOptions char *apre = mlt_properties_get( properties, "apre" ); if ( apre ) { mlt_properties p = mlt_properties_load( apre ); apply_properties( c, p, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM ); mlt_properties_close( p ); } apply_properties( c, properties, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM ); int audio_qscale = mlt_properties_get_int( properties, "aq" ); if ( audio_qscale > QSCALE_NONE ) { c->flags |= CODEC_FLAG_QSCALE; c->global_quality = FF_QP2LAMBDA * audio_qscale; #if LIBAVFORMAT_VERSION_MAJOR < 53 st->quality = c->global_quality; #endif } // Set parameters controlled by MLT c->sample_rate = mlt_properties_get_int( properties, "frequency" ); c->time_base = ( AVRational ){ 1, c->sample_rate }; c->channels = channels; if ( mlt_properties_get( properties, "alang" ) != NULL ) #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(8<<8)+0) av_dict_set( &oc->metadata, "language", mlt_properties_get( properties, "alang" ), 0 ); #else av_metadata_set2( &oc->metadata, "language", mlt_properties_get( properties, "alang" ), 0 ); #endif } else { mlt_log_error( MLT_CONSUMER_SERVICE( consumer ), "Could not allocate a stream for audio\n" ); } return st; } static int open_audio( mlt_properties properties, AVFormatContext *oc, AVStream *st, int audio_outbuf_size, const char *codec_name ) { // We will return the audio input size from here int audio_input_frame_size = 0; // Get the context AVCodecContext *c = st->codec; // Find the encoder AVCodec *codec; if ( codec_name ) codec = avcodec_find_encoder_by_name( codec_name ); else codec = avcodec_find_encoder( c->codec_id ); // Process properties as AVOptions on the AVCodec if ( codec && codec->priv_class ) { char *apre = mlt_properties_get( properties, "apre" ); if ( !c->priv_data && codec->priv_data_size ) { c->priv_data = av_mallocz( codec->priv_data_size ); *(const AVClass **) c->priv_data = codec->priv_class; // av_opt_set_defaults( c ); } if ( apre ) { mlt_properties p = mlt_properties_load( apre ); apply_properties( c->priv_data, p, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM ); mlt_properties_close( p ); } apply_properties( c->priv_data, properties, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM ); } // Continue if codec found and we can open it #if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) if ( codec && avcodec_open2( c, codec, NULL ) >= 0 ) #else if ( codec && avcodec_open( c, codec ) >= 0 ) #endif { // ugly hack for PCM codecs (will be removed ASAP with new PCM // support to compute the input frame size in samples if ( c->frame_size <= 1 ) { audio_input_frame_size = audio_outbuf_size / c->channels; switch(st->codec->codec_id) { case AV_CODEC_ID_PCM_S16LE: case AV_CODEC_ID_PCM_S16BE: case AV_CODEC_ID_PCM_U16LE: case AV_CODEC_ID_PCM_U16BE: audio_input_frame_size >>= 1; break; default: break; } } else { audio_input_frame_size = c->frame_size; } // Some formats want stream headers to be seperate (hmm) if ( !strcmp( oc->oformat->name, "mp4" ) || !strcmp( oc->oformat->name, "mov" ) || !strcmp( oc->oformat->name, "3gp" ) ) c->flags |= CODEC_FLAG_GLOBAL_HEADER; } else { mlt_log_warning( NULL, "%s: Unable to encode audio - disabling audio output.\n", __FILE__ ); audio_input_frame_size = 0; } return audio_input_frame_size; } static void close_audio( AVFormatContext *oc, AVStream *st ) { if ( st && st->codec ) avcodec_close( st->codec ); } /** Add a video output stream */ static AVStream *add_video_stream( mlt_consumer consumer, AVFormatContext *oc, AVCodec *codec ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Create a new stream #if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(10<<8)+0) AVStream *st = avformat_new_stream( oc, codec ); #else AVStream *st = av_new_stream( oc, oc->nb_streams ); #endif if ( st != NULL ) { char *pix_fmt = mlt_properties_get( properties, "pix_fmt" ); AVCodecContext *c = st->codec; // Establish defaults from AVOptions #if LIBAVCODEC_VERSION_MAJOR >= 53 avcodec_get_context_defaults3( c, codec ); #else avcodec_get_context_defaults2( c, CODEC_TYPE_VIDEO ); #endif c->codec_id = codec->id; c->codec_type = CODEC_TYPE_VIDEO; // Setup multi-threading int thread_count = mlt_properties_get_int( properties, "threads" ); if ( thread_count == 0 && getenv( "MLT_AVFORMAT_THREADS" ) ) thread_count = atoi( getenv( "MLT_AVFORMAT_THREADS" ) ); if ( thread_count > 1 ) #if LIBAVCODEC_VERSION_MAJOR >= 53 c->thread_count = thread_count; #else avcodec_thread_init( c, thread_count ); #endif // Process properties as AVOptions char *vpre = mlt_properties_get( properties, "vpre" ); if ( vpre ) { mlt_properties p = mlt_properties_load( vpre ); #ifdef AVDATADIR if ( mlt_properties_count( p ) < 1 ) { AVCodec *codec = avcodec_find_encoder( c->codec_id ); if ( codec ) { char *path = malloc( strlen(AVDATADIR) + strlen(codec->name) + strlen(vpre) + strlen(".ffpreset") + 2 ); strcpy( path, AVDATADIR ); strcat( path, codec->name ); strcat( path, "-" ); strcat( path, vpre ); strcat( path, ".ffpreset" ); mlt_properties_close( p ); p = mlt_properties_load( path ); if ( mlt_properties_count( p ) > 0 ) mlt_properties_debug( p, path, stderr ); free( path ); } } else { mlt_properties_debug( p, vpre, stderr ); } #endif apply_properties( c, p, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM ); mlt_properties_close( p ); } int colorspace = mlt_properties_get_int( properties, "colorspace" ); mlt_properties_set( properties, "colorspace", NULL ); apply_properties( c, properties, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM ); mlt_properties_set_int( properties, "colorspace", colorspace ); // Set options controlled by MLT c->width = mlt_properties_get_int( properties, "width" ); c->height = mlt_properties_get_int( properties, "height" ); c->time_base.num = mlt_properties_get_int( properties, "frame_rate_den" ); c->time_base.den = mlt_properties_get_int( properties, "frame_rate_num" ); if ( st->time_base.den == 0 ) st->time_base = c->time_base; c->pix_fmt = pix_fmt ? av_get_pix_fmt( pix_fmt ) : PIX_FMT_YUV420P; switch ( colorspace ) { case 170: c->colorspace = AVCOL_SPC_SMPTE170M; break; case 240: c->colorspace = AVCOL_SPC_SMPTE240M; break; case 470: c->colorspace = AVCOL_SPC_BT470BG; break; case 601: c->colorspace = ( 576 % c->height ) ? AVCOL_SPC_SMPTE170M : AVCOL_SPC_BT470BG; break; case 709: c->colorspace = AVCOL_SPC_BT709; break; } if ( mlt_properties_get( properties, "aspect" ) ) { // "-aspect" on ffmpeg command line is display aspect ratio double ar = mlt_properties_get_double( properties, "aspect" ); c->sample_aspect_ratio = av_d2q( ar * c->height / c->width, 255 ); } else { c->sample_aspect_ratio.num = mlt_properties_get_int( properties, "sample_aspect_num" ); c->sample_aspect_ratio.den = mlt_properties_get_int( properties, "sample_aspect_den" ); } st->sample_aspect_ratio = c->sample_aspect_ratio; if ( mlt_properties_get_double( properties, "qscale" ) > 0 ) { c->flags |= CODEC_FLAG_QSCALE; c->global_quality = FF_QP2LAMBDA * mlt_properties_get_double( properties, "qscale" ); #if LIBAVFORMAT_VERSION_MAJOR < 53 st->quality = c->global_quality; #endif } // Allow the user to override the video fourcc if ( mlt_properties_get( properties, "vtag" ) ) { char *tail = NULL; const char *arg = mlt_properties_get( properties, "vtag" ); int tag = strtol( arg, &tail, 0); if( !tail || *tail ) tag = arg[ 0 ] + ( arg[ 1 ] << 8 ) + ( arg[ 2 ] << 16 ) + ( arg[ 3 ] << 24 ); c->codec_tag = tag; } // Some formats want stream headers to be seperate if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) c->flags |= CODEC_FLAG_GLOBAL_HEADER; // Translate these standard mlt consumer properties to ffmpeg if ( mlt_properties_get_int( properties, "progressive" ) == 0 && mlt_properties_get_int( properties, "deinterlace" ) == 0 ) { if ( ! mlt_properties_get( properties, "ildct" ) || mlt_properties_get_int( properties, "ildct" ) ) c->flags |= CODEC_FLAG_INTERLACED_DCT; if ( ! mlt_properties_get( properties, "ilme" ) || mlt_properties_get_int( properties, "ilme" ) ) c->flags |= CODEC_FLAG_INTERLACED_ME; } // parse the ratecontrol override string int i; char *rc_override = mlt_properties_get( properties, "rc_override" ); for ( i = 0; rc_override; i++ ) { int start, end, q; int e = sscanf( rc_override, "%d,%d,%d", &start, &end, &q ); if ( e != 3 ) mlt_log_warning( MLT_CONSUMER_SERVICE( consumer ), "Error parsing rc_override\n" ); c->rc_override = av_realloc( c->rc_override, sizeof( RcOverride ) * ( i + 1 ) ); c->rc_override[i].start_frame = start; c->rc_override[i].end_frame = end; if ( q > 0 ) { c->rc_override[i].qscale = q; c->rc_override[i].quality_factor = 1.0; } else { c->rc_override[i].qscale = 0; c->rc_override[i].quality_factor = -q / 100.0; } rc_override = strchr( rc_override, '/' ); if ( rc_override ) rc_override++; } c->rc_override_count = i; if ( !c->rc_initial_buffer_occupancy ) c->rc_initial_buffer_occupancy = c->rc_buffer_size * 3/4; c->intra_dc_precision = mlt_properties_get_int( properties, "dc" ) - 8; // Setup dual-pass i = mlt_properties_get_int( properties, "pass" ); if ( i == 1 ) c->flags |= CODEC_FLAG_PASS1; else if ( i == 2 ) c->flags |= CODEC_FLAG_PASS2; if ( codec->id != AV_CODEC_ID_H264 && ( c->flags & ( CODEC_FLAG_PASS1 | CODEC_FLAG_PASS2 ) ) ) { char logfilename[1024]; FILE *f; int size; char *logbuffer; snprintf( logfilename, sizeof(logfilename), "%s_2pass.log", mlt_properties_get( properties, "passlogfile" ) ? mlt_properties_get( properties, "passlogfile" ) : mlt_properties_get( properties, "target" ) ); if ( c->flags & CODEC_FLAG_PASS1 ) { f = fopen( logfilename, "w" ); if ( !f ) perror( logfilename ); else mlt_properties_set_data( properties, "_logfile", f, 0, ( mlt_destructor )fclose, NULL ); } else { /* read the log file */ f = fopen( logfilename, "r" ); if ( !f ) { perror(logfilename); } else { mlt_properties_set( properties, "_logfilename", logfilename ); fseek( f, 0, SEEK_END ); size = ftell( f ); fseek( f, 0, SEEK_SET ); logbuffer = av_malloc( size + 1 ); if ( !logbuffer ) mlt_log_fatal( MLT_CONSUMER_SERVICE( consumer ), "Could not allocate log buffer\n" ); else { if ( size >= 0 ) { size = fread( logbuffer, 1, size, f ); logbuffer[size] = '\0'; c->stats_in = logbuffer; } } fclose( f ); } } } } else { mlt_log_error( MLT_CONSUMER_SERVICE( consumer ), "Could not allocate a stream for video\n" ); } return st; } static AVFrame *alloc_picture( int pix_fmt, int width, int height ) { // Allocate a frame AVFrame *picture = avcodec_alloc_frame(); // Determine size of the int size = avpicture_get_size(pix_fmt, width, height); // Allocate the picture buf uint8_t *picture_buf = av_malloc(size); // If we have both, then fill the image if ( picture != NULL && picture_buf != NULL ) { // Fill the frame with the allocated buffer avpicture_fill( (AVPicture *)picture, picture_buf, pix_fmt, width, height); } else { // Something failed - clean up what we can av_free( picture ); av_free( picture_buf ); picture = NULL; } return picture; } static int open_video( mlt_properties properties, AVFormatContext *oc, AVStream *st, const char *codec_name ) { // Get the codec AVCodecContext *video_enc = st->codec; // find the video encoder AVCodec *codec; if ( codec_name ) codec = avcodec_find_encoder_by_name( codec_name ); else codec = avcodec_find_encoder( video_enc->codec_id ); // Process properties as AVOptions on the AVCodec if ( codec && codec->priv_class ) { char *vpre = mlt_properties_get( properties, "vpre" ); if ( !video_enc->priv_data && codec->priv_data_size ) { video_enc->priv_data = av_mallocz( codec->priv_data_size ); *(const AVClass **) video_enc->priv_data = codec->priv_class; // av_opt_set_defaults( video_enc ); } if ( vpre ) { mlt_properties p = mlt_properties_load( vpre ); apply_properties( video_enc->priv_data, p, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM ); mlt_properties_close( p ); } apply_properties( video_enc->priv_data, properties, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM ); } if( codec && codec->pix_fmts ) { const enum PixelFormat *p = codec->pix_fmts; for( ; *p!=-1; p++ ) { if( *p == video_enc->pix_fmt ) break; } if( *p == -1 ) video_enc->pix_fmt = codec->pix_fmts[ 0 ]; } #if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) int result = codec && avcodec_open2( video_enc, codec, NULL ) >= 0; #else int result = codec && avcodec_open( video_enc, codec ) >= 0; #endif return result; } void close_video(AVFormatContext *oc, AVStream *st) { if ( st && st->codec ) { av_freep( &st->codec->stats_in ); avcodec_close(st->codec); } } static inline long time_difference( struct timeval *time1 ) { struct timeval time2; gettimeofday( &time2, NULL ); return time2.tv_sec * 1000000 + time2.tv_usec - time1->tv_sec * 1000000 - time1->tv_usec; } static int mlt_write(void *h, uint8_t *buf, int size) { mlt_properties properties = (mlt_properties) h; mlt_events_fire( properties, "avformat-write", buf, &size, NULL ); return 0; } static void write_transmitter( mlt_listener listener, mlt_properties owner, mlt_service service, void **args ) { int *p_size = (int*) args[1]; listener( owner, service, (uint8_t*) args[0], *p_size ); } /** The main thread - the argument is simply the consumer. */ static void *consumer_thread( void *arg ) { // Map the argument to the object mlt_consumer consumer = arg; // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Get the terminate on pause property int terminate_on_pause = mlt_properties_get_int( properties, "terminate_on_pause" ); int terminated = 0; // Determine if feed is slow (for realtime stuff) int real_time_output = mlt_properties_get_int( properties, "real_time" ); // Time structures struct timeval ante; // Get the frame rate double fps = mlt_properties_get_double( properties, "fps" ); // Get width and height int width = mlt_properties_get_int( properties, "width" ); int height = mlt_properties_get_int( properties, "height" ); int img_width = width; int img_height = height; // Get default audio properties int channels = mlt_properties_get_int( properties, "channels" ); int total_channels = channels; int frequency = mlt_properties_get_int( properties, "frequency" ); void *pcm = NULL; int samples = 0; // AVFormat audio buffer and frame size int audio_outbuf_size = AUDIO_BUFFER_SIZE; uint8_t *audio_outbuf = av_malloc( audio_outbuf_size ); int audio_input_nb_samples = 0; // AVFormat video buffer and frame count int frame_count = 0; int video_outbuf_size = VIDEO_BUFFER_SIZE; uint8_t *video_outbuf = av_malloc( video_outbuf_size ); // Used for the frame properties mlt_frame frame = NULL; mlt_properties frame_properties = NULL; // Get the queues mlt_deque queue = mlt_properties_get_data( properties, "frame_queue", NULL ); sample_fifo fifo = mlt_properties_get_data( properties, "sample_fifo", NULL ); // For receiving images from an mlt_frame uint8_t *image; mlt_image_format img_fmt = mlt_image_yuv422; // Get the image format to use for rendering threads const char* img_fmt_name = mlt_properties_get( properties, "mlt_image_format" ); if ( img_fmt_name ) { if ( !strcmp( img_fmt_name, "rgb24" ) ) img_fmt = mlt_image_rgb24; else if ( !strcmp( img_fmt_name, "rgb24a" ) ) img_fmt = mlt_image_rgb24a; else if ( !strcmp( img_fmt_name, "yuv420p" ) ) img_fmt = mlt_image_yuv420p; } else if ( mlt_properties_get( properties, "pix_fmt" ) ) { img_fmt_name = mlt_properties_get( properties, "pix_fmt" ); if ( !strcmp( img_fmt_name, "rgba" ) || !strcmp( img_fmt_name, "argb" ) || !strcmp( img_fmt_name, "bgra" ) ) img_fmt = mlt_image_rgb24a; } // Need two av pictures for converting AVFrame *converted_avframe = NULL; AVFrame *audio_avframe = NULL; AVFrame *video_avframe = alloc_picture( pick_pix_fmt( img_fmt ), width, height ); // For receiving audio samples back from the fifo uint8_t *audio_buf_1 = av_malloc( AUDIO_ENCODE_BUFFER_SIZE ); uint8_t *audio_buf_2 = NULL; int count = 0; // Allocate the context AVFormatContext *oc = avformat_alloc_context( ); // Streams AVStream *video_st = NULL; AVStream *audio_st[ MAX_AUDIO_STREAMS ]; // Time stamps double audio_pts = 0; double video_pts = 0; // Frames dispatched long int frames = 0; long int total_time = 0; // Determine the format AVOutputFormat *fmt = NULL; const char *filename = mlt_properties_get( properties, "target" ); char *format = mlt_properties_get( properties, "f" ); char *vcodec = mlt_properties_get( properties, "vcodec" ); char *acodec = mlt_properties_get( properties, "acodec" ); AVCodec *audio_codec = NULL; AVCodec *video_codec = NULL; // Used to store and override codec ids int audio_codec_id; int video_codec_id; // Misc char key[27]; mlt_properties frame_meta_properties = mlt_properties_new(); int error_count = 0; int64_t synth_audio_pts = 0; // Initialize audio_st int i = MAX_AUDIO_STREAMS; while ( i-- ) audio_st[i] = NULL; // Check for user selected format first if ( format != NULL ) fmt = av_guess_format( format, NULL, NULL ); // Otherwise check on the filename if ( fmt == NULL && filename != NULL ) fmt = av_guess_format( NULL, filename, NULL ); // Otherwise default to mpeg if ( fmt == NULL ) fmt = av_guess_format( "mpeg", NULL, NULL ); // We need a filename - default to stdout? if ( filename == NULL || !strcmp( filename, "" ) ) filename = "pipe:"; // Get the codec ids selected audio_codec_id = fmt->audio_codec; video_codec_id = fmt->video_codec; // Check for audio codec overides if ( ( acodec && strcmp( acodec, "none" ) == 0 ) || mlt_properties_get_int( properties, "an" ) ) audio_codec_id = AV_CODEC_ID_NONE; else if ( acodec ) { audio_codec = avcodec_find_encoder_by_name( acodec ); if ( audio_codec ) { audio_codec_id = audio_codec->id; if ( audio_codec_id == AV_CODEC_ID_AC3 && avcodec_find_encoder_by_name( "ac3_fixed" ) ) { mlt_properties_set( properties, "_acodec", "ac3_fixed" ); acodec = mlt_properties_get( properties, "_acodec" ); audio_codec = avcodec_find_encoder_by_name( acodec ); } else if ( !strcmp( acodec, "aac" ) || !strcmp( acodec, "vorbis" ) ) { mlt_properties_set( properties, "astrict", "experimental" ); } } else { audio_codec_id = AV_CODEC_ID_NONE; mlt_log_warning( MLT_CONSUMER_SERVICE( consumer ), "audio codec %s unrecognised - ignoring\n", acodec ); } } else { audio_codec = avcodec_find_encoder( audio_codec_id ); } // Check for video codec overides if ( ( vcodec && strcmp( vcodec, "none" ) == 0 ) || mlt_properties_get_int( properties, "vn" ) ) video_codec_id = AV_CODEC_ID_NONE; else if ( vcodec ) { video_codec = avcodec_find_encoder_by_name( vcodec ); if ( video_codec ) { video_codec_id = video_codec->id; } else { video_codec_id = AV_CODEC_ID_NONE; mlt_log_warning( MLT_CONSUMER_SERVICE( consumer ), "video codec %s unrecognised - ignoring\n", vcodec ); } } else { video_codec = avcodec_find_encoder( video_codec_id ); } // Write metadata for ( i = 0; i < mlt_properties_count( properties ); i++ ) { char *name = mlt_properties_get_name( properties, i ); if ( name && !strncmp( name, "meta.attr.", 10 ) ) { char *key = strdup( name + 10 ); char *markup = strrchr( key, '.' ); if ( markup && !strcmp( markup, ".markup") ) { markup[0] = '\0'; if ( !strstr( key, ".stream." ) ) #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(8<<8)+0) av_dict_set( &oc->metadata, key, mlt_properties_get_value( properties, i ), 0 ); #else av_metadata_set2( &oc->metadata, key, mlt_properties_get_value( properties, i ), 0 ); #endif } free( key ); } } oc->oformat = fmt; snprintf( oc->filename, sizeof(oc->filename), "%s", filename ); // Get a frame now, so we can set some AVOptions from properties. frame = mlt_consumer_rt_frame( consumer ); // Set the timecode from the MLT metadata if available. if ( frame ) { const char *timecode = mlt_properties_get( MLT_FRAME_PROPERTIES(frame), "meta.attr.vitc.markup" ); if ( timecode && strcmp( timecode, "" ) ) { mlt_properties_set( properties, "timecode", timecode ); if ( strchr( timecode, ';' ) ) mlt_properties_set_int( properties, "drop_frame_timecode", 1 ); } } // Add audio and video streams if ( video_codec_id != AV_CODEC_ID_NONE ) video_st = add_video_stream( consumer, oc, video_codec ); if ( audio_codec_id != AV_CODEC_ID_NONE ) { int is_multi = 0; total_channels = 0; // multitrack audio for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) { sprintf( key, "channels.%d", i ); int j = mlt_properties_get_int( properties, key ); if ( j ) { is_multi = 1; total_channels += j; audio_st[i] = add_audio_stream( consumer, oc, audio_codec, j ); } } // single track if ( !is_multi ) { audio_st[0] = add_audio_stream( consumer, oc, audio_codec, channels ); total_channels = channels; } } mlt_properties_set_int( properties, "channels", total_channels ); // Audio format is determined when adding the audio stream mlt_audio_format aud_fmt = mlt_audio_none; if ( audio_st[0] ) aud_fmt = get_mlt_audio_format( audio_st[0]->codec->sample_fmt ); int sample_bytes = mlt_audio_format_size( aud_fmt, 1, 1 ); sample_bytes = sample_bytes ? sample_bytes : 1; // prevent divide by zero // Set the parameters (even though we have none...) #if LIBAVFORMAT_VERSION_INT < ((53<<16)+(2<<8)+0) if ( av_set_parameters(oc, NULL) >= 0 ) #endif { #if LIBAVFORMAT_VERSION_MAJOR >= 53 if ( mlt_properties_get( properties, "muxpreload" ) && ! mlt_properties_get( properties, "preload" ) ) mlt_properties_set_double( properties, "preload", mlt_properties_get_double( properties, "muxpreload" ) ); #else oc->preload = ( int )( mlt_properties_get_double( properties, "muxpreload" ) * AV_TIME_BASE ); #endif oc->max_delay= ( int )( mlt_properties_get_double( properties, "muxdelay" ) * AV_TIME_BASE ); // Process properties as AVOptions char *fpre = mlt_properties_get( properties, "fpre" ); if ( fpre ) { mlt_properties p = mlt_properties_load( fpre ); apply_properties( oc, p, AV_OPT_FLAG_ENCODING_PARAM ); if ( oc->oformat && oc->oformat->priv_class && oc->priv_data ) apply_properties( oc->priv_data, p, AV_OPT_FLAG_ENCODING_PARAM ); mlt_properties_close( p ); } apply_properties( oc, properties, AV_OPT_FLAG_ENCODING_PARAM ); if ( oc->oformat && oc->oformat->priv_class && oc->priv_data ) apply_properties( oc->priv_data, properties, AV_OPT_FLAG_ENCODING_PARAM ); if ( video_st && !open_video( properties, oc, video_st, vcodec? vcodec : NULL ) ) video_st = NULL; for ( i = 0; i < MAX_AUDIO_STREAMS && audio_st[i]; i++ ) { audio_input_nb_samples = open_audio( properties, oc, audio_st[i], audio_outbuf_size, acodec? acodec : NULL ); if ( !audio_input_nb_samples ) { // Remove the audio stream from the output context int j; for ( j = 0; j < oc->nb_streams; j++ ) { if ( oc->streams[j] == audio_st[i] ) av_freep( &oc->streams[j] ); } --oc->nb_streams; audio_st[i] = NULL; } } // Setup custom I/O if redirecting if ( mlt_properties_get_int( properties, "redirect" ) ) { int buffer_size = 32768; unsigned char *buffer = av_malloc( buffer_size ); #if LIBAVFORMAT_VERSION_MAJOR >= 53 AVIOContext* io = avio_alloc_context( buffer, buffer_size, 1, properties, NULL, mlt_write, NULL ); #else ByteIOContext* io = av_alloc_put_byte( buffer, buffer_size, 1, properties, NULL, mlt_write, NULL ); #endif if ( buffer && io ) { oc->pb = io; #if LIBAVFORMAT_VERSION_MAJOR >= 53 oc->flags |= AVFMT_FLAG_CUSTOM_IO; #endif mlt_properties_set_data( properties, "avio_buffer", buffer, buffer_size, av_free, NULL ); mlt_properties_set_data( properties, "avio_context", io, 0, av_free, NULL ); mlt_events_register( properties, "avformat-write", (mlt_transmitter) write_transmitter ); } else { av_free( buffer ); mlt_log_error( MLT_CONSUMER_SERVICE(consumer), "failed to setup output redirection\n" ); } } // Open the output file, if needed else if ( !( fmt->flags & AVFMT_NOFILE ) ) { #if LIBAVFORMAT_VERSION_MAJOR >= 53 if ( avio_open( &oc->pb, filename, AVIO_FLAG_WRITE ) < 0 ) #else if ( url_fopen( &oc->pb, filename, URL_WRONLY ) < 0 ) #endif { mlt_log_error( MLT_CONSUMER_SERVICE( consumer ), "Could not open '%s'\n", filename ); mlt_events_fire( properties, "consumer-fatal-error", NULL ); goto on_fatal_error; } } // Write the stream header. if ( mlt_properties_get_int( properties, "running" ) ) #if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(2<<8)+0) avformat_write_header( oc, NULL ); #else av_write_header( oc ); #endif } #if LIBAVFORMAT_VERSION_INT < ((53<<16)+(2<<8)+0) else { mlt_log_error( MLT_CONSUMER_SERVICE( consumer ), "Invalid output format parameters\n" ); mlt_events_fire( properties, "consumer-fatal-error", NULL ); goto on_fatal_error; } #endif // Last check - need at least one stream if ( !audio_st[0] && !video_st ) { mlt_events_fire( properties, "consumer-fatal-error", NULL ); goto on_fatal_error; } // Allocate picture if ( video_st ) converted_avframe = alloc_picture( video_st->codec->pix_fmt, width, height ); #if LIBAVCODEC_VERSION_MAJOR >= 55 // Allocate audio AVFrame if ( audio_st[0] ) { audio_avframe = avcodec_alloc_frame(); if ( audio_avframe ) { AVCodecContext *c = audio_st[0]->codec; audio_avframe->format = c->sample_fmt; audio_avframe->nb_samples = audio_input_nb_samples; audio_avframe->channel_layout = c->channel_layout; } else { mlt_log_error( MLT_CONSUMER_SERVICE(consumer), "failed to allocate audio AVFrame\n" ); mlt_events_fire( properties, "consumer-fatal-error", NULL ); goto on_fatal_error; } } #endif // Get the starting time (can ignore the times above) gettimeofday( &ante, NULL ); // Loop while running while( mlt_properties_get_int( properties, "running" ) && ( !terminated || ( video_st && mlt_deque_count( queue ) ) ) ) { if ( !frame ) frame = mlt_consumer_rt_frame( consumer ); // Check that we have a frame to work with if ( frame != NULL ) { // Increment frames dispatched frames ++; // Default audio args frame_properties = MLT_FRAME_PROPERTIES( frame ); // Check for the terminated condition terminated = terminate_on_pause && mlt_properties_get_double( frame_properties, "_speed" ) == 0.0; // Get audio and append to the fifo if ( !terminated && audio_st[0] ) { samples = mlt_sample_calculator( fps, frequency, count ++ ); channels = total_channels; mlt_frame_get_audio( frame, &pcm, &aud_fmt, &frequency, &channels, &samples ); // Save the audio channel remap properties for later mlt_properties_pass( frame_meta_properties, frame_properties, "meta.map.audio." ); // Create the fifo if we don't have one if ( fifo == NULL ) { fifo = sample_fifo_init( frequency, channels ); mlt_properties_set_data( properties, "sample_fifo", fifo, 0, ( mlt_destructor )sample_fifo_close, NULL ); } if ( pcm ) { // Silence if not normal forward speed if ( mlt_properties_get_double( frame_properties, "_speed" ) != 1.0 ) memset( pcm, 0, samples * channels * sample_bytes ); // Append the samples sample_fifo_append( fifo, pcm, samples * channels * sample_bytes ); total_time += ( samples * 1000000 ) / frequency; } if ( !video_st ) mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); } // Encode the image if ( !terminated && video_st ) mlt_deque_push_back( queue, frame ); else mlt_frame_close( frame ); frame = NULL; } // While we have stuff to process, process... while ( 1 ) { // Write interleaved audio and video frames if ( !video_st || ( video_st && audio_st[0] && audio_pts < video_pts ) ) { // Write audio if ( ( video_st && terminated ) || ( channels * audio_input_nb_samples ) < sample_fifo_used( fifo ) / sample_bytes ) { int j = 0; // channel offset into interleaved source buffer int n = FFMIN( FFMIN( channels * audio_input_nb_samples, sample_fifo_used( fifo ) / sample_bytes ), AUDIO_ENCODE_BUFFER_SIZE ); // Get the audio samples if ( n > 0 ) { sample_fifo_fetch( fifo, audio_buf_1, n * sample_bytes ); } else if ( audio_codec_id == AV_CODEC_ID_VORBIS && terminated ) { // This prevents an infinite loop when some versions of vorbis do not // increment pts when encoding silence. audio_pts = video_pts; break; } else { memset( audio_buf_1, 0, AUDIO_ENCODE_BUFFER_SIZE ); } samples = n / channels; // For each output stream for ( i = 0; i < MAX_AUDIO_STREAMS && audio_st[i] && j < total_channels; i++ ) { AVStream *stream = audio_st[i]; AVCodecContext *codec = stream->codec; AVPacket pkt; av_init_packet( &pkt ); pkt.data = audio_outbuf; pkt.size = audio_outbuf_size; // Optimized for single track and no channel remap if ( !audio_st[1] && !mlt_properties_count( frame_meta_properties ) ) { void* p = audio_buf_1; #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(17<<8)+0) if ( codec->sample_fmt == AV_SAMPLE_FMT_FLTP ) p = interleaved_to_planar( samples, channels, p, sizeof( float ) ); else if ( codec->sample_fmt == AV_SAMPLE_FMT_S16P ) p = interleaved_to_planar( samples, channels, p, sizeof( int16_t ) ); else if ( codec->sample_fmt == AV_SAMPLE_FMT_S32P ) p = interleaved_to_planar( samples, channels, p, sizeof( int32_t ) ); else if ( codec->sample_fmt == AV_SAMPLE_FMT_U8P ) p = interleaved_to_planar( samples, channels, p, sizeof( uint8_t ) ); #endif #if LIBAVCODEC_VERSION_MAJOR >= 55 audio_avframe->nb_samples = FFMAX( samples, audio_input_nb_samples ); if ( audio_codec_id == AV_CODEC_ID_VORBIS ) audio_avframe->pts = synth_audio_pts; synth_audio_pts += audio_avframe->nb_samples; avcodec_fill_audio_frame( audio_avframe, codec->channels, codec->sample_fmt, (const uint8_t*) p, AUDIO_ENCODE_BUFFER_SIZE, 0 ); int got_packet = 0; int ret = avcodec_encode_audio2( codec, &pkt, audio_avframe, &got_packet ); if ( ret < 0 ) pkt.size = ret; else if ( !got_packet ) pkt.size = 0; #else codec->frame_size = FFMAX( samples, audio_input_nb_samples ); pkt.size = avcodec_encode_audio( codec, audio_outbuf, audio_outbuf_size, p ); pkt.pts = codec->coded_frame? codec->coded_frame->pts : AV_NOPTS_VALUE; pkt.flags |= PKT_FLAG_KEY; #endif #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(17<<8)+0) if ( p != audio_buf_1 ) mlt_pool_release( p ); #endif } else { // Extract the audio channels according to channel mapping int dest_offset = 0; // channel offset into interleaved dest buffer // Get the number of channels for this stream sprintf( key, "channels.%d", i ); int current_channels = mlt_properties_get_int( properties, key ); // Clear the destination audio buffer. if ( !audio_buf_2 ) audio_buf_2 = av_mallocz( AUDIO_ENCODE_BUFFER_SIZE ); else memset( audio_buf_2, 0, AUDIO_ENCODE_BUFFER_SIZE ); // For each output channel while ( dest_offset < current_channels && j < total_channels ) { int map_start = -1, map_channels = 0; int source_offset = 0; int k; // Look for a mapping that starts at j for ( k = 0; k < (MAX_AUDIO_STREAMS * 2) && map_start != j; k++ ) { sprintf( key, "%d.channels", k ); map_channels = mlt_properties_get_int( frame_meta_properties, key ); sprintf( key, "%d.start", k ); if ( mlt_properties_get( frame_meta_properties, key ) ) map_start = mlt_properties_get_int( frame_meta_properties, key ); if ( map_start != j ) source_offset += map_channels; } // If no mapping if ( map_start != j ) { map_channels = current_channels; source_offset = j; } // Copy samples if source offset valid if ( source_offset < channels ) { // Interleave the audio buffer with the # channels for this stream/mapping. for ( k = 0; k < map_channels; k++, j++, source_offset++, dest_offset++ ) { void *src = audio_buf_1 + source_offset * sample_bytes; void *dest = audio_buf_2 + dest_offset * sample_bytes; int s = samples + 1; while ( --s ) { memcpy( dest, src, sample_bytes ); dest += current_channels * sample_bytes; src += channels * sample_bytes; } } } // Otherwise silence else { j += current_channels; dest_offset += current_channels; } } #if LIBAVCODEC_VERSION_MAJOR >= 55 audio_avframe->nb_samples = FFMAX( samples, audio_input_nb_samples ); if ( audio_codec_id == AV_CODEC_ID_VORBIS ) audio_avframe->pts = synth_audio_pts; synth_audio_pts += audio_avframe->nb_samples; avcodec_fill_audio_frame( audio_avframe, codec->channels, codec->sample_fmt, (const uint8_t*) audio_buf_2, AUDIO_ENCODE_BUFFER_SIZE, 0 ); int got_packet = 0; int ret = avcodec_encode_audio2( codec, &pkt, audio_avframe, &got_packet ); if ( ret < 0 ) pkt.size = ret; else if ( !got_packet ) pkt.size = 0; #else codec->frame_size = FFMAX( samples, audio_input_nb_samples ); pkt.size = avcodec_encode_audio( codec, audio_outbuf, audio_outbuf_size, (short*) audio_buf_2 ); pkt.pts = codec->coded_frame? codec->coded_frame->pts : AV_NOPTS_VALUE; pkt.flags |= PKT_FLAG_KEY; #endif } if ( pkt.size > 0 ) { // Write the compressed frame in the media file if ( pkt.pts != AV_NOPTS_VALUE ) pkt.pts = av_rescale_q( pkt.pts, codec->time_base, stream->time_base ); #if LIBAVCODEC_VERSION_MAJOR >= 55 if ( pkt.dts != AV_NOPTS_VALUE ) pkt.dts = av_rescale_q( pkt.dts, codec->time_base, stream->time_base ); if ( pkt.duration > 0 ) pkt.duration = av_rescale_q( pkt.duration, codec->time_base, stream->time_base ); #endif pkt.stream_index = stream->index; if ( av_interleaved_write_frame( oc, &pkt ) ) { mlt_log_fatal( MLT_CONSUMER_SERVICE( consumer ), "error writing audio frame\n" ); mlt_events_fire( properties, "consumer-fatal-error", NULL ); goto on_fatal_error; } error_count = 0; mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), "audio stream %d pkt pts %"PRId64" frame_size %d stream pts %"PRId64"\n", stream->index, pkt.pts, codec->frame_size, stream->pts.val ); } else if ( pkt.size < 0 ) { mlt_log_warning( MLT_CONSUMER_SERVICE( consumer ), "error with audio encode %d\n", frame_count ); if ( ++error_count > 2 ) goto on_fatal_error; } if ( i == 0 ) { audio_pts = (double)stream->pts.val * av_q2d( stream->time_base ); } } } else { break; } } else if ( video_st ) { // Write video if ( mlt_deque_count( queue ) ) { int ret = 0; AVCodecContext *c = video_st->codec; frame = mlt_deque_pop_front( queue ); frame_properties = MLT_FRAME_PROPERTIES( frame ); if ( mlt_properties_get_int( frame_properties, "rendered" ) ) { int i = 0; uint8_t *p; uint8_t *q; int stride = mlt_image_format_size( img_fmt, width, 0, NULL ); mlt_frame_get_image( frame, &image, &img_fmt, &img_width, &img_height, 0 ); q = image; // Convert the mlt frame to an AVPicture if ( img_fmt == mlt_image_yuv420p ) { memcpy( video_avframe->data[0], q, video_avframe->linesize[0] ); q += stride; memcpy( video_avframe->data[1], q, video_avframe->linesize[1] ); q += stride / 4; memcpy( video_avframe->data[2], q, video_avframe->linesize[2] ); } else for ( i = 0; i < height; i ++ ) { p = video_avframe->data[0] + i * video_avframe->linesize[0]; memcpy( p, q, stride ); q += stride; } // Do the colour space conversion int flags = SWS_BICUBIC; #ifdef USE_MMX flags |= SWS_CPU_CAPS_MMX; #endif #ifdef USE_SSE flags |= SWS_CPU_CAPS_MMX2; #endif struct SwsContext *context = sws_getContext( width, height, pick_pix_fmt( img_fmt ), width, height, c->pix_fmt, flags, NULL, NULL, NULL); sws_scale( context, (const uint8_t* const*) video_avframe->data, video_avframe->linesize, 0, height, converted_avframe->data, converted_avframe->linesize); sws_freeContext( context ); mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); // Apply the alpha if applicable if ( !mlt_properties_get( properties, "mlt_image_format" ) || strcmp( mlt_properties_get( properties, "mlt_image_format" ), "rgb24a" ) ) if ( c->pix_fmt == PIX_FMT_RGBA || c->pix_fmt == PIX_FMT_ARGB || c->pix_fmt == PIX_FMT_BGRA ) { uint8_t *alpha = mlt_frame_get_alpha_mask( frame ); register int n; for ( i = 0; i < height; i ++ ) { n = ( width + 7 ) / 8; p = converted_avframe->data[ 0 ] + i * converted_avframe->linesize[ 0 ] + 3; switch( width % 8 ) { case 0: do { *p = *alpha++; p += 4; case 7: *p = *alpha++; p += 4; case 6: *p = *alpha++; p += 4; case 5: *p = *alpha++; p += 4; case 4: *p = *alpha++; p += 4; case 3: *p = *alpha++; p += 4; case 2: *p = *alpha++; p += 4; case 1: *p = *alpha++; p += 4; } while( --n ); } } } } if (oc->oformat->flags & AVFMT_RAWPICTURE) { // raw video case. The API will change slightly in the near future for that AVPacket pkt; av_init_packet(&pkt); // Set frame interlace hints c->coded_frame->interlaced_frame = !mlt_properties_get_int( frame_properties, "progressive" ); c->coded_frame->top_field_first = mlt_properties_get_int( frame_properties, "top_field_first" ); #if LIBAVCODEC_VERSION_INT >= ((53<<16)+(61<<8)+100) if ( mlt_properties_get_int( frame_properties, "progressive" ) ) c->field_order = AV_FIELD_PROGRESSIVE; else c->field_order = (mlt_properties_get_int( frame_properties, "top_field_first" )) ? AV_FIELD_TT : AV_FIELD_BB; #endif pkt.flags |= PKT_FLAG_KEY; pkt.stream_index = video_st->index; pkt.data = (uint8_t *)converted_avframe; pkt.size = sizeof(AVPicture); ret = av_write_frame(oc, &pkt); video_pts += c->frame_size; } else { AVPacket pkt; av_init_packet( &pkt ); pkt.data = video_outbuf; pkt.size = video_outbuf_size; // Set the quality converted_avframe->quality = c->global_quality; // Set frame interlace hints converted_avframe->interlaced_frame = !mlt_properties_get_int( frame_properties, "progressive" ); converted_avframe->top_field_first = mlt_properties_get_int( frame_properties, "top_field_first" ); converted_avframe->pts = frame_count; // Encode the image #if LIBAVCODEC_VERSION_MAJOR >= 55 int got_packet; ret = avcodec_encode_video2( c, &pkt, converted_avframe, &got_packet ); if ( ret < 0 ) pkt.size = ret; else if ( !got_packet ) pkt.size = 0; #else pkt.size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, converted_avframe ); pkt.pts = c->coded_frame? c->coded_frame->pts : AV_NOPTS_VALUE; if ( c->coded_frame && c->coded_frame->key_frame ) pkt.flags |= PKT_FLAG_KEY; #endif // If zero size, it means the image was buffered if ( pkt.size > 0 ) { if ( pkt.pts != AV_NOPTS_VALUE ) pkt.pts = av_rescale_q( pkt.pts, c->time_base, video_st->time_base ); #if LIBAVCODEC_VERSION_MAJOR >= 55 if ( pkt.dts != AV_NOPTS_VALUE ) pkt.dts = av_rescale_q( pkt.dts, c->time_base, video_st->time_base ); #endif pkt.stream_index = video_st->index; // write the compressed frame in the media file ret = av_interleaved_write_frame(oc, &pkt); mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), " frame_size %d\n", c->frame_size ); video_pts = (double)video_st->pts.val * av_q2d( video_st->time_base ); // Dual pass logging if ( mlt_properties_get_data( properties, "_logfile", NULL ) && c->stats_out ) fprintf( mlt_properties_get_data( properties, "_logfile", NULL ), "%s", c->stats_out ); error_count = 0; } else if ( pkt.size < 0 ) { mlt_log_warning( MLT_CONSUMER_SERVICE( consumer ), "error with video encode %d\n", frame_count ); if ( ++error_count > 2 ) goto on_fatal_error; ret = 0; } } frame_count++; if ( ret ) { mlt_log_fatal( MLT_CONSUMER_SERVICE( consumer ), "error writing video frame\n" ); mlt_events_fire( properties, "consumer-fatal-error", NULL ); goto on_fatal_error; } mlt_frame_close( frame ); frame = NULL; } else { break; } } if ( audio_st[0] ) mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), "audio pts %"PRId64" (%f) ", audio_st[0]->pts.val, audio_pts ); if ( video_st ) mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), "video pts %"PRId64" (%f) ", video_st->pts.val, video_pts ); mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), "\n" ); } if ( real_time_output == 1 && frames % 2 == 0 ) { long passed = time_difference( &ante ); if ( fifo != NULL ) { long pending = ( ( ( long )sample_fifo_used( fifo ) / sample_bytes * 1000 ) / frequency ) * 1000; passed -= pending; } if ( passed < total_time ) { long total = ( total_time - passed ); struct timespec t = { total / 1000000, ( total % 1000000 ) * 1000 }; nanosleep( &t, NULL ); } } } // Flush the encoder buffers if ( real_time_output <= 0 ) { // Flush audio fifo // TODO: flush all audio streams if ( audio_st[0] && audio_st[0]->codec->frame_size > 1 ) for (;;) { AVCodecContext *c = audio_st[0]->codec; AVPacket pkt; av_init_packet( &pkt ); pkt.data = audio_outbuf; pkt.size = 0; if ( fifo && sample_fifo_used( fifo ) > 0 ) { // Drain the MLT FIFO int samples = FFMIN( FFMIN( channels * audio_input_nb_samples, sample_fifo_used( fifo ) / sample_bytes ), AUDIO_ENCODE_BUFFER_SIZE ); sample_fifo_fetch( fifo, audio_buf_1, samples * sample_bytes ); void* p = audio_buf_1; #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(17<<8)+0) if ( c->sample_fmt == AV_SAMPLE_FMT_FLTP ) p = interleaved_to_planar( audio_input_nb_samples, channels, p, sizeof( float ) ); else if ( c->sample_fmt == AV_SAMPLE_FMT_S16P ) p = interleaved_to_planar( audio_input_nb_samples, channels, p, sizeof( int16_t ) ); else if ( c->sample_fmt == AV_SAMPLE_FMT_S32P ) p = interleaved_to_planar( audio_input_nb_samples, channels, p, sizeof( int32_t ) ); else if ( c->sample_fmt == AV_SAMPLE_FMT_U8P ) p = interleaved_to_planar( audio_input_nb_samples, channels, p, sizeof( uint8_t ) ); #endif #if LIBAVCODEC_VERSION_MAJOR >= 55 pkt.size = audio_outbuf_size; audio_avframe->nb_samples = FFMAX( samples / channels, audio_input_nb_samples ); if ( audio_codec_id == AV_CODEC_ID_VORBIS ) audio_avframe->pts = synth_audio_pts; synth_audio_pts += audio_avframe->nb_samples; avcodec_fill_audio_frame( audio_avframe, c->channels, c->sample_fmt, (const uint8_t*) p, AUDIO_ENCODE_BUFFER_SIZE, 0 ); int got_packet = 0; int ret = avcodec_encode_audio2( c, &pkt, audio_avframe, &got_packet ); if ( ret < 0 ) pkt.size = ret; else if ( !got_packet ) pkt.size = 0; #else c->frame_size = FFMAX( samples / channels, audio_input_nb_samples ); pkt.size = avcodec_encode_audio( c, audio_outbuf, audio_outbuf_size, p ); #endif #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(17<<8)+0) if ( p != audio_buf_1 ) mlt_pool_release( p ); #endif mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), "flushing audio size %d\n", pkt.size ); } else { // Drain the codec if ( pkt.size <= 0 ) { #if LIBAVCODEC_VERSION_MAJOR >= 55 pkt.size = audio_outbuf_size; int got_packet = 0; int ret = avcodec_encode_audio2( c, &pkt, NULL, &got_packet ); if ( ret < 0 ) pkt.size = ret; else if ( !got_packet ) pkt.size = 0; #else pkt.size = avcodec_encode_audio( c, audio_outbuf, audio_outbuf_size, NULL ); pkt.pts = c->coded_frame? c->coded_frame->pts : AV_NOPTS_VALUE; pkt.flags |= PKT_FLAG_KEY; #endif } mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), "flushing audio size %d\n", pkt.size ); if ( pkt.size <= 0 ) break; } // Write the compressed frame in the media file if ( pkt.pts != AV_NOPTS_VALUE ) pkt.pts = av_rescale_q( pkt.pts, c->time_base, audio_st[0]->time_base ); #if LIBAVCODEC_VERSION_MAJOR >= 55 if ( pkt.dts != AV_NOPTS_VALUE ) pkt.dts = av_rescale_q( pkt.dts, c->time_base, audio_st[0]->time_base ); if ( pkt.duration > 0 ) pkt.duration = av_rescale_q( pkt.duration, c->time_base, audio_st[0]->time_base ); #endif pkt.stream_index = audio_st[0]->index; if ( av_interleaved_write_frame( oc, &pkt ) != 0 ) { mlt_log_warning( MLT_CONSUMER_SERVICE( consumer ), "error writing flushed audio frame\n" ); break; } } // Flush video if ( video_st && !( oc->oformat->flags & AVFMT_RAWPICTURE ) ) for (;;) { AVCodecContext *c = video_st->codec; AVPacket pkt; av_init_packet( &pkt ); pkt.data = video_outbuf; pkt.size = video_outbuf_size; // Encode the image #if LIBAVCODEC_VERSION_MAJOR >= 55 int got_packet = 0; int ret = avcodec_encode_video2( c, &pkt, NULL, &got_packet ); if ( ret < 0 ) pkt.size = ret; else if ( !got_packet ) pkt.size = 0; #else pkt.size = avcodec_encode_video( c, video_outbuf, video_outbuf_size, NULL ); pkt.pts = c->coded_frame? c->coded_frame->pts : AV_NOPTS_VALUE; if( c->coded_frame && c->coded_frame->key_frame ) pkt.flags |= PKT_FLAG_KEY; #endif mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), "flushing video size %d\n", pkt.size ); if ( pkt.size <= 0 ) break; if ( pkt.pts != AV_NOPTS_VALUE ) pkt.pts = av_rescale_q( pkt.pts, c->time_base, video_st->time_base ); #if LIBAVCODEC_VERSION_MAJOR >= 55 if ( pkt.dts != AV_NOPTS_VALUE ) pkt.dts = av_rescale_q( pkt.dts, c->time_base, video_st->time_base ); #endif pkt.stream_index = video_st->index; // write the compressed frame in the media file if ( av_interleaved_write_frame( oc, &pkt ) != 0 ) { mlt_log_fatal( MLT_CONSUMER_SERVICE(consumer), "error writing flushed video frame\n" ); mlt_events_fire( properties, "consumer-fatal-error", NULL ); goto on_fatal_error; } // Dual pass logging if ( mlt_properties_get_data( properties, "_logfile", NULL ) && c->stats_out ) fprintf( mlt_properties_get_data( properties, "_logfile", NULL ), "%s", c->stats_out ); } } on_fatal_error: // Write the trailer, if any if ( frames ) av_write_trailer( oc ); // close each codec if ( video_st ) close_video(oc, video_st); for ( i = 0; i < MAX_AUDIO_STREAMS && audio_st[i]; i++ ) close_audio( oc, audio_st[i] ); // Free the streams for ( i = 0; i < oc->nb_streams; i++ ) av_freep( &oc->streams[i] ); // Close the output file if ( !( fmt->flags & AVFMT_NOFILE ) && !mlt_properties_get_int( properties, "redirect" ) ) { #if LIBAVFORMAT_VERSION_MAJOR >= 53 if ( oc->pb ) avio_close( oc->pb ); #else if ( oc->pb ) url_fclose( oc->pb ); #endif } // Clean up input and output frames if ( converted_avframe ) av_free( converted_avframe->data[0] ); av_free( converted_avframe ); av_free( video_avframe->data[0] ); av_free( video_avframe ); av_free( video_outbuf ); av_free( audio_avframe ); av_free( audio_buf_1 ); av_free( audio_buf_2 ); // Free the stream av_free( oc ); // Just in case we terminated on pause mlt_consumer_stopped( consumer ); mlt_properties_close( frame_meta_properties ); if ( mlt_properties_get_int( properties, "pass" ) > 1 ) { // Remove the dual pass log file if ( mlt_properties_get( properties, "_logfilename" ) ) remove( mlt_properties_get( properties, "_logfilename" ) ); // Remove the x264 dual pass logs char *cwd = getcwd( NULL, 0 ); const char *file = "x264_2pass.log"; char *full = malloc( strlen( cwd ) + strlen( file ) + 2 ); sprintf( full, "%s/%s", cwd, file ); remove( full ); free( full ); file = "x264_2pass.log.temp"; full = malloc( strlen( cwd ) + strlen( file ) + 2 ); sprintf( full, "%s/%s", cwd, file ); remove( full ); free( full ); file = "x264_2pass.log.mbtree"; full = malloc( strlen( cwd ) + strlen( file ) + 2 ); sprintf( full, "%s/%s", cwd, file ); remove( full ); free( full ); free( cwd ); remove( "x264_2pass.log.temp" ); } while ( ( frame = mlt_deque_pop_back( queue ) ) ) mlt_frame_close( frame ); return NULL; } /** Close the consumer. */ static void consumer_close( mlt_consumer consumer ) { // Stop the consumer mlt_consumer_stop( consumer ); // Close the parent mlt_consumer_close( consumer ); // Free the memory free( consumer ); } mlt-0.9.0/src/modules/avformat/consumer_avformat.yml000066400000000000000000000235421215300731300226500ustar00rootroot00000000000000schema_version: 0.1 type: consumer identifier: avformat title: FFmpeg Output version: 2 copyright: Copyright (C) 2003-2011 Ushodaya Enterprises Limited license: LGPL language: en url: http://www.ffmpeg.org/ creator: Charles Yates contributor: - Dan Dennedy tags: - Audio - Video description: Write or stream audio and/or video using FFmpeg parameters: - identifier: argument title: File/URL type: string required: yes widget: filesave - identifier: target title: File/URL type: string description: This is not the same thing as the ffmpeg -target option! readonly: yes - identifier: mlt_profile title: MLT Profile type: string description: > Choose a MLT basic video settings preset. This overrides a profile that may have been set elsewhere. - identifier: redirect title: Redirect I/O description: > This option allows other services to encapsulate the avformat consumer and do something different (not already available in a protocol) with its output by listening to the avformat-write event. type: integer minimum: 0 maximum: 1 default: 0 widget: checkbox # These override the MLT profile - identifier: width title: Width type: integer minimum: 0 unit: pixels - identifier: height title: Height type: integer minimum: 0 unit: pixels - identifier: display_aspect_num title: Display aspect ratio numerator type: integer minimum: 0 - identifier: display_aspect_den title: Display aspect ratio denominator type: integer minimum: 0 - identifier: display_ratio title: Display aspect ratio readonly: yes - identifier: sample_aspect_num title: Sample aspect ratio numerator type: integer minimum: 0 - identifier: sample_aspect_den title: Sample aspect ratio denominator type: integer minimum: 1 - identifier: progressive title: Progressive type: integer minimum: 0 maximum: 1 widget: checkbox - identifier: colorspace title: Colorspace type: integer description: Set the video colorspace (Y'CbCr only). values: - 240 # SMPTE 240M - 601 # ITU-R BT.601 - 709 # ITU-R BT.709 - identifier: frame_rate_num title: Frame rate numerator type: integer minimum: 0 unit: frames/second - identifier: frame_rate_den title: Frame rate denominator type: integer minimum: 1 unit: frames/second - identifier: fps title: Frame rate readonly: yes unit: frames/second # These are common to all consumers. - identifier: deinterlace_method title: Deinterlacer type: string default: yadif values: - greedy - linearblend - onefield - yadif - yadif-nospatial - identifier: rescale title: Image scaler type: string description: Set the pixel interpolation mode. values: - nearest - bilinear - bicubic - bicublin - gauss - sinc - lanczos - spline - identifier: frequency title: Audio sample rate type: integer minimum: 0 maximum: 256000 default: 48000 unit: Hz - identifier: channels title: Audio channels type: integer minimum: 1 maximum: 16 default: 2 - identifier: channels.0 title: Channels on track 1 type: integer description: Used to map a bundle of channels to multi-track audio. minimum: 0 maximum: 16 default: 0 - identifier: channels.1 title: Channels on track 2 type: integer description: Used to map a bundle of channels to multi-track audio. minimum: 0 maximum: 16 default: 0 - identifier: channels.2 title: Channels on track 3 type: integer description: Used to map a bundle of channels to multi-track audio. minimum: 0 maximum: 16 default: 0 - identifier: channels.3 title: Channels on track 4 type: integer description: Used to map a bundle of channels to multi-track audio. minimum: 0 maximum: 16 default: 0 - identifier: channels.4 title: Channels on track 5 type: integer description: Used to map a bundle of channels to multi-track audio. minimum: 0 maximum: 16 default: 0 - identifier: channels.5 title: Channels on track 6 type: integer description: Used to map a bundle of channels to multi-track audio. minimum: 0 maximum: 16 default: 0 - identifier: channels.6 title: Channels on track 7 type: integer description: Used to map a bundle of channels to multi-track audio. minimum: 0 maximum: 16 default: 0 - identifier: channels.7 title: Channels on track 8 type: integer description: Used to map a bundle of channels to multi-track audio. minimum: 0 maximum: 16 default: 0 # These are common to all consumers and affect runtime behavior - identifier: terminate_on_pause title: File output type: integer description: Disable this for streaming. minimum: 0 maximum: 1 default: 1 widget: checkbox - identifier: real_time title: Drop frames type: integer description: > Set the number of processing threads and enable frame-dropping (positive) or disable frame-dropping (negative). default: -1 widget: spinner unit: threads - identifier: prefill title: Pre-roll type: integer description: Set the number of frames to buffer before starting actual output. minimum: 1 default: 1 unit: frames - identifier: buffer title: Buffer type: integer description: > Set the maximum number of frames to buffer - process ahead of the output position. minimum: 1 default: 25 unit: frames # These are ffmpeg-compatible aliases to MLT properties - identifier: s title: Size type: string description: > This is a ffmpeg-compatible equivalent to the MLT profile and width and height parameters. format: WxH unit: pixels - identifier: aspect title: Aspect ratio type: string description: > This is a ffmpeg-compatible equivalent to the MLT profile and other aspect ratio parameters. format: numerator:denominator - identifier: deinterlace title: Deinterlace type: integer description: > This is a ffmpeg-compatible equivalent to the MLT profile and progressive parameter. minimum: 0 maximum: 1 - identifier: r title: Frame rate type: float description: > This is a ffmpeg-compatible equivalent to the MLT profile and frame rate parameters. minimum: 5.0 - identifier: ac title: Audio channels type: integer description: > This is a ffmpeg-compatible equivalent to the channels parameter. minimum: 1 maximum: 16 default: 2 - identifier: ar title: Audio sample rate type: integer description: > This is a ffmpeg-compatible equivalent to the frequency parameter. minimum: 0 maximum: 256000 default: 48000 unit: Hz # These are other non-AVOption parameters specific to FFmpeg. - identifier: threads title: Encoding threads type: integer minimum: 0 maximum: 16 default: 1 widget: spinner unit: threads - identifier: aq title: Audio quality type: integer description: The meaning depends upon the codec. - identifier: dc title: Intra DC precision type: integer default: 8 - identifier: muxdelay title: Muxer delay type: float description: Set the maximum demux-decode delay. default: 0.7 unit: seconds - identifier: muxpreload title: Muxer preload type: float description: Set the initial demux-decode delay. default: 0.5 unit: seconds - identifier: f title: Format type: string description: Use "list" to see the list of formats. default: mpeg - identifier: acodec title: Audio codec description: Use "list" to see the list of audio codecs. default: mp2 - identifier: vcodec title: Video codec description: Use "list" to see the list of video codecs. default: mpeg2video - identifier: atag title: Audio FourCC type: string - identifier: apre title: Audio codec preset type: string - identifier: vpre title: Video codec preset type: string - identifier: fpre title: Format preset type: string - identifier: alang title: Audio language type: string description: Set the 3-character ISO 639 language code of the current audio stream. - identifier: pix_fmt title: Pixel format type: string description: > See 'ffmpeg -pix_fmt list' to see a list of values. Normally, this is not required, but some codecs support multiple pixel formats, especially chroma bit-depth. - identifier: qscale title: Video quantizer type: float description: Set a fixed video quantizer scale for constant quality VBR output. - identifier: vtag title: Video FourCC type: string - identifier: rc_override title: Rate control type: string format: start_frame,end_frame,qscale/... description: This is an override for specific intervals. - identifier: pass title: Pass type: integer description: Select the pass number for two-pass encoding. minimum: 1 maximum: 2 - identifier: passlogfile title: Two-pass log file type: string - identifier: vb title: Video bitrate type: string unit: bits/second description: > Normally this is an integer, but you can append a K suffix for convenience. minimum: 0 - identifier: ab title: Audio bitrate type: string unit: bits/second description: > Normally this is an integer, but you can append a K suffix for convenience. - identifier: an title: Disable audio type: integer minimum: 0 maximum: 1 widget: checkbox - identifier: vn title: Disable video type: integer minimum: 0 maximum: 1 widget: checkbox mlt-0.9.0/src/modules/avformat/factory.c000066400000000000000000000276011215300731300202060ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2003-2012 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include extern mlt_consumer consumer_avformat_init( mlt_profile profile, char *file ); extern mlt_filter filter_avcolour_space_init( void *arg ); extern mlt_filter filter_avdeinterlace_init( void *arg ); extern mlt_filter filter_avresample_init( char *arg ); extern mlt_filter filter_swscale_init( mlt_profile profile, char *arg ); extern mlt_producer producer_avformat_init( mlt_profile profile, const char *service, char *file ); // ffmpeg Header files #include #ifdef AVDEVICE #include #endif #if LIBAVCODEC_VERSION_MAJOR >= 53 #include #else #include #endif #if LIBAVUTIL_VERSION_INT < ((51<<16)+(12<<8)+0) #define AV_OPT_TYPE_FLAGS FF_OPT_TYPE_FLAGS #define AV_OPT_TYPE_INT FF_OPT_TYPE_INT #define AV_OPT_TYPE_INT64 FF_OPT_TYPE_INT64 #define AV_OPT_TYPE_DOUBLE FF_OPT_TYPE_DOUBLE #define AV_OPT_TYPE_FLOAT FF_OPT_TYPE_FLOAT #define AV_OPT_TYPE_STRING FF_OPT_TYPE_STRING #define AV_OPT_TYPE_RATIONAL FF_OPT_TYPE_RATIONAL #define AV_OPT_TYPE_BINARY FF_OPT_TYPE_BINARY #define AV_OPT_TYPE_CONST FF_OPT_TYPE_CONST #endif // A static flag used to determine if avformat has been initialised static int avformat_initialised = 0; static int avformat_lockmgr(void **mutex, enum AVLockOp op) { pthread_mutex_t** pmutex = (pthread_mutex_t**) mutex; switch (op) { case AV_LOCK_CREATE: *pmutex = (pthread_mutex_t*) malloc(sizeof(pthread_mutex_t)); if (!*pmutex) return -1; pthread_mutex_init(*pmutex, NULL); break; case AV_LOCK_OBTAIN: if (!*pmutex) return -1; pthread_mutex_lock(*pmutex); break; case AV_LOCK_RELEASE: if (!*pmutex) return -1; pthread_mutex_unlock(*pmutex); break; case AV_LOCK_DESTROY: if (!*pmutex) return -1; pthread_mutex_destroy(*pmutex); free(*pmutex); *pmutex = NULL; break; } return 0; } static void unregister_lockmgr( void *p ) { av_lockmgr_register( NULL ); } static void avformat_init( ) { // Initialise avformat if necessary if ( avformat_initialised == 0 ) { avformat_initialised = 1; av_lockmgr_register( &avformat_lockmgr ); mlt_factory_register_for_clean_up( &avformat_lockmgr, unregister_lockmgr ); av_register_all( ); #ifdef AVDEVICE avdevice_register_all(); #endif #if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(13<<8)) avformat_network_init(); #endif av_log_set_level( mlt_log_get_level() ); } } static void *create_service( mlt_profile profile, mlt_service_type type, const char *id, void *arg ) { avformat_init( ); #ifdef CODECS if ( !strncmp( id, "avformat", 8 ) ) { if ( type == producer_type ) return producer_avformat_init( profile, id, arg ); else if ( type == consumer_type ) return consumer_avformat_init( profile, arg ); } #endif #ifdef FILTERS if ( !strcmp( id, "avcolor_space" ) ) return filter_avcolour_space_init( arg ); if ( !strcmp( id, "avcolour_space" ) ) return filter_avcolour_space_init( arg ); if ( !strcmp( id, "avdeinterlace" ) ) return filter_avdeinterlace_init( arg ); #if defined(FFUDIV) || (LIBAVCODEC_VERSION_INT < ((54<<16)+(26<<8)+0)) if ( !strcmp( id, "avresample" ) ) return filter_avresample_init( arg ); #endif if ( !strcmp( id, "swscale" ) ) return filter_swscale_init( profile, arg ); #endif return NULL; } static void add_parameters( mlt_properties params, void *object, int req_flags, const char *unit, const char *subclass ) { const AVOption *opt = NULL; // For each AVOption on the AVClass object #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(12<<8)+0) while ( ( opt = av_opt_next( object, opt ) ) ) #else while ( ( opt = av_next_option( object, opt ) ) ) #endif { // If matches flags and not a binary option (not supported by Mlt) if ( !( opt->flags & req_flags ) || ( opt->type == AV_OPT_TYPE_BINARY ) ) continue; // Ignore constants (keyword values) if ( !unit && opt->type == AV_OPT_TYPE_CONST ) continue; // When processing a groups of options (unit)... // ...ignore non-constants else if ( unit && opt->type != AV_OPT_TYPE_CONST ) continue; // ...ignore constants not in this group else if ( unit && opt->type == AV_OPT_TYPE_CONST && strcmp( unit, opt->unit ) ) continue; // ..add constants to the 'values' sequence else if ( unit && opt->type == AV_OPT_TYPE_CONST ) { char key[20]; snprintf( key, 20, "%d", mlt_properties_count( params ) ); mlt_properties_set( params, key, opt->name ); continue; } // Create a map for this option. mlt_properties p = mlt_properties_new(); char key[20]; snprintf( key, 20, "%d", mlt_properties_count( params ) ); // Add the map to the 'parameters' sequence. mlt_properties_set_data( params, key, p, 0, (mlt_destructor) mlt_properties_close, NULL ); // Add the parameter metadata for this AVOption. mlt_properties_set( p, "identifier", opt->name ); if ( opt->help ) { if ( subclass ) { char *s = malloc( strlen( opt->help ) + strlen( subclass ) + 4 ); strcpy( s, opt->help ); strcat( s, " (" ); strcat( s, subclass ); strcat( s, ")" ); mlt_properties_set( p, "description", s ); free( s ); } else mlt_properties_set( p, "description", opt->help ); } switch ( opt->type ) { case AV_OPT_TYPE_FLAGS: mlt_properties_set( p, "type", "string" ); mlt_properties_set( p, "format", "flags" ); break; case AV_OPT_TYPE_INT: if ( !opt->unit ) { mlt_properties_set( p, "type", "integer" ); if ( opt->min != INT_MIN ) mlt_properties_set_int( p, "minimum", (int) opt->min ); if ( opt->max != INT_MAX ) mlt_properties_set_int( p, "maximum", (int) opt->max ); #if LIBAVUTIL_VERSION_MAJOR > 50 mlt_properties_set_int( p, "default", (int) opt->default_val.dbl ); #endif } else { mlt_properties_set( p, "type", "string" ); mlt_properties_set( p, "format", "integer or keyword" ); } break; case AV_OPT_TYPE_INT64: mlt_properties_set( p, "type", "integer" ); mlt_properties_set( p, "format", "64-bit" ); if ( opt->min != INT64_MIN ) mlt_properties_set_int64( p, "minimum", (int64_t) opt->min ); if ( opt->max != INT64_MAX ) mlt_properties_set_int64( p, "maximum", (int64_t) opt->max ); #if LIBAVUTIL_VERSION_MAJOR > 50 mlt_properties_set_int64( p, "default", (int64_t) opt->default_val.dbl ); #endif break; case AV_OPT_TYPE_FLOAT: mlt_properties_set( p, "type", "float" ); if ( opt->min != FLT_MIN && opt->min != -340282346638528859811704183484516925440.0 ) mlt_properties_set_double( p, "minimum", opt->min ); if ( opt->max != FLT_MAX ) mlt_properties_set_double( p, "maximum", opt->max ); #if LIBAVUTIL_VERSION_MAJOR > 50 mlt_properties_set_double( p, "default", opt->default_val.dbl ); #endif break; case AV_OPT_TYPE_DOUBLE: mlt_properties_set( p, "type", "float" ); mlt_properties_set( p, "format", "double" ); if ( opt->min != DBL_MIN ) mlt_properties_set_double( p, "minimum", opt->min ); if ( opt->max != DBL_MAX ) mlt_properties_set_double( p, "maximum", opt->max ); #if LIBAVUTIL_VERSION_MAJOR > 50 mlt_properties_set_double( p, "default", opt->default_val.dbl ); #endif break; case AV_OPT_TYPE_STRING: mlt_properties_set( p, "type", "string" ); #if LIBAVUTIL_VERSION_MAJOR > 50 mlt_properties_set( p, "default", opt->default_val.str ); #endif break; case AV_OPT_TYPE_RATIONAL: mlt_properties_set( p, "type", "string" ); mlt_properties_set( p, "format", "numerator:denominator" ); break; case AV_OPT_TYPE_CONST: default: mlt_properties_set( p, "type", "integer" ); mlt_properties_set( p, "format", "constant" ); break; } // If the option belongs to a group (unit) and is not a constant (keyword value) if ( opt->unit && opt->type != AV_OPT_TYPE_CONST ) { // Create a 'values' sequence. mlt_properties values = mlt_properties_new(); // Recurse to add constants in this group to the 'values' sequence. add_parameters( values, object, req_flags, opt->unit, NULL ); if ( mlt_properties_count( values ) ) mlt_properties_set_data( p, "values", values, 0, (mlt_destructor) mlt_properties_close, NULL ); else mlt_properties_close( values ); } } } static mlt_properties avformat_metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; const char *service_type = NULL; mlt_properties result = NULL; // Convert the service type to a string. switch ( type ) { case consumer_type: service_type = "consumer"; break; case filter_type: service_type = "filter"; break; case producer_type: service_type = "producer"; break; case transition_type: service_type = "transition"; break; default: return NULL; } // Load the yaml file snprintf( file, PATH_MAX, "%s/avformat/%s_%s.yml", mlt_environment( "MLT_DATA" ), service_type, id ); result = mlt_properties_parse_yaml( file ); if ( result && ( type == consumer_type || type == producer_type ) ) { // Annotate the yaml properties with AVOptions. mlt_properties params = (mlt_properties) mlt_properties_get_data( result, "parameters", NULL ); AVFormatContext *avformat = avformat_alloc_context(); #if LIBAVCODEC_VERSION_INT > ((53<<16)+(8<<8)+0) AVCodecContext *avcodec = avcodec_alloc_context3( NULL ); #else AVCodecContext *avcodec = avcodec_alloc_context(); #endif int flags = ( type == consumer_type )? AV_OPT_FLAG_ENCODING_PARAM : AV_OPT_FLAG_DECODING_PARAM; add_parameters( params, avformat, flags, NULL, NULL ); #if LIBAVFORMAT_VERSION_MAJOR >= 53 avformat_init(); if ( type == producer_type ) { AVInputFormat *f = NULL; while ( ( f = av_iformat_next( f ) ) ) if ( f->priv_class ) add_parameters( params, &f->priv_class, flags, NULL, f->name ); } else { AVOutputFormat *f = NULL; while ( ( f = av_oformat_next( f ) ) ) if ( f->priv_class ) add_parameters( params, &f->priv_class, flags, NULL, f->name ); } #endif add_parameters( params, avcodec, flags, NULL, NULL ); #if LIBAVCODEC_VERSION_MAJOR >= 53 AVCodec *c = NULL; while ( ( c = av_codec_next( c ) ) ) if ( c->priv_class ) add_parameters( params, &c->priv_class, flags, NULL, c->name ); #endif av_free( avformat ); av_free( avcodec ); } return result; } MLT_REPOSITORY { #ifdef CODECS MLT_REGISTER( consumer_type, "avformat", create_service ); MLT_REGISTER( producer_type, "avformat", create_service ); MLT_REGISTER( producer_type, "avformat-novalidate", create_service ); MLT_REGISTER_METADATA( consumer_type, "avformat", avformat_metadata, NULL ); MLT_REGISTER_METADATA( producer_type, "avformat", avformat_metadata, NULL ); #endif #ifdef FILTERS MLT_REGISTER( filter_type, "avcolour_space", create_service ); MLT_REGISTER( filter_type, "avcolor_space", create_service ); MLT_REGISTER( filter_type, "avdeinterlace", create_service ); #if defined(FFUDIV) || (LIBAVCODEC_VERSION_INT < ((54<<16)+(26<<8)+0)) MLT_REGISTER( filter_type, "avresample", create_service ); #endif MLT_REGISTER( filter_type, "swscale", create_service ); #endif } mlt-0.9.0/src/modules/avformat/filter_avcolour_space.c000066400000000000000000000236101215300731300231050ustar00rootroot00000000000000/* * filter_avcolour_space.c -- Colour space filter * Copyright (C) 2004-2005 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include // ffmpeg Header files #include #include #include #include #if 0 // This test might come in handy elsewhere someday. static int is_big_endian( ) { union { int i; char c[ 4 ]; } big_endian_test; big_endian_test.i = 1; return big_endian_test.c[ 0 ] != 1; } #endif static int convert_mlt_to_av_cs( mlt_image_format format ) { int value = 0; switch( format ) { case mlt_image_rgb24: value = PIX_FMT_RGB24; break; case mlt_image_rgb24a: case mlt_image_opengl: value = PIX_FMT_RGBA; break; case mlt_image_yuv422: value = PIX_FMT_YUYV422; break; case mlt_image_yuv420p: value = PIX_FMT_YUV420P; break; default: mlt_log_error( NULL, "[filter avcolor_space] Invalid format %s\n", mlt_image_format_name( format ) ); break; } return value; } static void set_luma_transfer( struct SwsContext *context, int colorspace, int use_full_range ) { int *coefficients; const int *new_coefficients; int full_range; int brightness, contrast, saturation; if ( sws_getColorspaceDetails( context, &coefficients, &full_range, &coefficients, &full_range, &brightness, &contrast, &saturation ) != -1 ) { // Don't change these from defaults unless explicitly told to. if ( use_full_range >= 0 ) full_range = use_full_range; switch ( colorspace ) { case 170: case 470: case 601: case 624: new_coefficients = sws_getCoefficients( SWS_CS_ITU601 ); break; case 240: new_coefficients = sws_getCoefficients( SWS_CS_SMPTE240M ); break; case 709: new_coefficients = sws_getCoefficients( SWS_CS_ITU709 ); break; default: new_coefficients = coefficients; break; } sws_setColorspaceDetails( context, new_coefficients, full_range, new_coefficients, full_range, brightness, contrast, saturation ); } } static void av_convert_image( uint8_t *out, uint8_t *in, int out_fmt, int in_fmt, int width, int height, int colorspace, int use_full_range ) { AVPicture input; AVPicture output; int flags = SWS_BICUBIC | SWS_ACCURATE_RND; if ( out_fmt == PIX_FMT_YUYV422 ) flags |= SWS_FULL_CHR_H_INP; else flags |= SWS_FULL_CHR_H_INT; #ifdef USE_MMX flags |= SWS_CPU_CAPS_MMX; #endif #ifdef USE_SSE flags |= SWS_CPU_CAPS_MMX2; #endif avpicture_fill( &input, in, in_fmt, width, height ); avpicture_fill( &output, out, out_fmt, width, height ); struct SwsContext *context = sws_getContext( width, height, in_fmt, width, height, out_fmt, flags, NULL, NULL, NULL); if ( context ) { set_luma_transfer( context, colorspace, use_full_range ); sws_scale( context, (const uint8_t* const*) input.data, input.linesize, 0, height, output.data, output.linesize); sws_freeContext( context ); } } /** Do it :-). */ static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, mlt_image_format output_format ) { mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); int width = mlt_properties_get_int( properties, "width" ); int height = mlt_properties_get_int( properties, "height" ); int error = 0; if ( *format != output_format ) { int colorspace = mlt_properties_get_int( properties, "colorspace" ); int force_full_luma = -1; mlt_log_debug( NULL, "[filter avcolor_space] %s -> %s @ %dx%d space %d\n", mlt_image_format_name( *format ), mlt_image_format_name( output_format ), width, height, colorspace ); int in_fmt = convert_mlt_to_av_cs( *format ); int out_fmt = convert_mlt_to_av_cs( output_format ); int size = FFMAX( avpicture_get_size( out_fmt, width, height ), mlt_image_format_size( output_format, width, height, NULL ) ); uint8_t *output = mlt_pool_alloc( size ); if ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) { register int len = width * height; uint8_t *alpha = mlt_pool_alloc( len ); if ( alpha ) { // Extract the alpha mask from the RGBA image using Duff's Device register uint8_t *s = *image + 3; // start on the alpha component register uint8_t *d = alpha; register int n = ( len + 7 ) / 8; switch ( len % 8 ) { case 0: do { *d++ = *s; s += 4; case 7: *d++ = *s; s += 4; case 6: *d++ = *s; s += 4; case 5: *d++ = *s; s += 4; case 4: *d++ = *s; s += 4; case 3: *d++ = *s; s += 4; case 2: *d++ = *s; s += 4; case 1: *d++ = *s; s += 4; } while ( --n > 0 ); } mlt_frame_set_alpha( frame, alpha, len, mlt_pool_release ); } } // Update the output if ( *format == mlt_image_yuv422 && mlt_properties_get( properties, "force_full_luma" ) && ( output_format == mlt_image_rgb24 || output_format == mlt_image_rgb24a ) ) { // By removing the frame property we only permit the luma to skip scaling once. // Thereafter, we let swscale scale the luma range as it pleases since it seems // we do not have control over the RGB to YUV conversion. force_full_luma = mlt_properties_get_int( properties, "force_full_luma" ); mlt_properties_set( properties, "force_full_luma", NULL ); } av_convert_image( output, *image, out_fmt, in_fmt, width, height, colorspace, force_full_luma ); *image = output; *format = output_format; mlt_frame_set_image( frame, output, size, mlt_pool_release ); mlt_properties_set_int( properties, "format", output_format ); if ( output_format == mlt_image_rgb24a || output_format == mlt_image_opengl ) { register int len = width * height; int alpha_size = 0; uint8_t *alpha = mlt_frame_get_alpha_mask( frame ); mlt_properties_get_data( properties, "alpha", &alpha_size ); if ( alpha && alpha_size >= len ) { // Merge the alpha mask from into the RGBA image using Duff's Device register uint8_t *s = alpha; register uint8_t *d = *image + 3; // start on the alpha component register int n = ( len + 7 ) / 8; switch ( len % 8 ) { case 0: do { *d = *s++; d += 4; case 7: *d = *s++; d += 4; case 6: *d = *s++; d += 4; case 5: *d = *s++; d += 4; case 4: *d = *s++; d += 4; case 3: *d = *s++; d += 4; case 2: *d = *s++; d += 4; case 1: *d = *s++; d += 4; } while ( --n > 0 ); } } } } return error; } /* TODO: The below is not working because swscale does not have * adjustable coefficients yet for RGB->YUV */ #if 0 static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; mlt_profile profile = (mlt_profile) mlt_frame_pop_get_image( frame ); mlt_properties properties = MLT_FRAME_PROPERTIES(frame); mlt_image_format format_from = *format; mlt_image_format format_to = mlt_image_rgb24; error = mlt_frame_get_image( frame, image, format, width, height, writable ); int frame_colorspace = mlt_properties_get_int( properties, "colorspace" ); if ( !error && *format == mlt_image_yuv422 && profile->colorspace > 0 && frame_colorspace > 0 && frame_colorspace != profile->colorspace ) { mlt_log_debug( NULL, "[filter avcolor_space] colorspace %d -> %d\n", frame_colorspace, profile->colorspace ); // Convert to RGB using frame's colorspace error = convert_image( frame, image, &format_from, format_to ); // Convert to YUV using profile's colorspace if ( !error ) { *image = mlt_properties_get_data( properties, "image", NULL ); format_from = mlt_image_rgb24; format_to = *format; mlt_properties_set_int( properties, "colorspace", profile->colorspace ); error = convert_image( frame, image, &format_from, format_to ); *image = mlt_properties_get_data( properties, "image", NULL ); } } return error; } #endif /** Filter processing. */ static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { // Set a default colorspace on the frame if not yet set by the producer. // The producer may still change it during get_image. // This way we do not have to modify each producer to set a valid colorspace. mlt_properties properties = MLT_FRAME_PROPERTIES(frame); if ( mlt_properties_get_int( properties, "colorspace" ) <= 0 ) mlt_properties_set_int( properties, "colorspace", mlt_service_profile( MLT_FILTER_SERVICE(filter) )->colorspace ); if ( !frame->convert_image ) frame->convert_image = convert_image; // Not working yet - see comment for get_image() above. // mlt_frame_push_service( frame, mlt_service_profile( MLT_FILTER_SERVICE( filter ) ) ); // mlt_frame_push_get_image( frame, get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_avcolour_space_init( void *arg ) { // Test to see if swscale accepts the arg as resolution if ( arg ) { int *width = (int*) arg; if ( *width > 0 ) { struct SwsContext *context = sws_getContext( *width, *width, PIX_FMT_RGB32, 64, 64, PIX_FMT_RGB32, SWS_BILINEAR, NULL, NULL, NULL); if ( context ) sws_freeContext( context ); else return NULL; } } mlt_filter filter = mlt_filter_new( ); if ( filter != NULL ) filter->process = filter_process; return filter; } mlt-0.9.0/src/modules/avformat/filter_avdeinterlace.c000066400000000000000000000244431215300731300227130ustar00rootroot00000000000000/* * filter_avdeinterlace.c -- deinterlace filter * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include // ffmpeg Header files #include #ifdef USE_MMX #include "mmx.h" #else #define MAX_NEG_CROP 1024 static uint8_t ff_cropTbl[256 + 2 * MAX_NEG_CROP] = {0,}; #endif #ifdef USE_MMX #define DEINT_INPLACE_LINE_LUM \ movd_m2r(lum_m4[0],mm0);\ movd_m2r(lum_m3[0],mm1);\ movd_m2r(lum_m2[0],mm2);\ movd_m2r(lum_m1[0],mm3);\ movd_m2r(lum[0],mm4);\ punpcklbw_r2r(mm7,mm0);\ movd_r2m(mm2,lum_m4[0]);\ punpcklbw_r2r(mm7,mm1);\ punpcklbw_r2r(mm7,mm2);\ punpcklbw_r2r(mm7,mm3);\ punpcklbw_r2r(mm7,mm4);\ paddw_r2r(mm3,mm1);\ psllw_i2r(1,mm2);\ paddw_r2r(mm4,mm0);\ psllw_i2r(2,mm1);\ paddw_r2r(mm6,mm2);\ paddw_r2r(mm2,mm1);\ psubusw_r2r(mm0,mm1);\ psrlw_i2r(3,mm1);\ packuswb_r2r(mm7,mm1);\ movd_r2m(mm1,lum_m2[0]); #define DEINT_LINE_LUM \ movd_m2r(lum_m4[0],mm0);\ movd_m2r(lum_m3[0],mm1);\ movd_m2r(lum_m2[0],mm2);\ movd_m2r(lum_m1[0],mm3);\ movd_m2r(lum[0],mm4);\ punpcklbw_r2r(mm7,mm0);\ punpcklbw_r2r(mm7,mm1);\ punpcklbw_r2r(mm7,mm2);\ punpcklbw_r2r(mm7,mm3);\ punpcklbw_r2r(mm7,mm4);\ paddw_r2r(mm3,mm1);\ psllw_i2r(1,mm2);\ paddw_r2r(mm4,mm0);\ psllw_i2r(2,mm1);\ paddw_r2r(mm6,mm2);\ paddw_r2r(mm2,mm1);\ psubusw_r2r(mm0,mm1);\ psrlw_i2r(3,mm1);\ packuswb_r2r(mm7,mm1);\ movd_r2m(mm1,dst[0]); #endif /* filter parameters: [-1 4 2 4 -1] // 8 */ static inline void deinterlace_line(uint8_t *dst, const uint8_t *lum_m4, const uint8_t *lum_m3, const uint8_t *lum_m2, const uint8_t *lum_m1, const uint8_t *lum, int size) { #ifndef USE_MMX uint8_t *cm = ff_cropTbl + MAX_NEG_CROP; int sum; for(;size > 0;size--) { sum = -lum_m4[0]; sum += lum_m3[0] << 2; sum += lum_m2[0] << 1; sum += lum_m1[0] << 2; sum += -lum[0]; dst[0] = cm[(sum + 4) >> 3]; lum_m4++; lum_m3++; lum_m2++; lum_m1++; lum++; dst++; } #else { mmx_t rounder; rounder.uw[0]=4; rounder.uw[1]=4; rounder.uw[2]=4; rounder.uw[3]=4; pxor_r2r(mm7,mm7); movq_m2r(rounder,mm6); } for (;size > 3; size-=4) { DEINT_LINE_LUM lum_m4+=4; lum_m3+=4; lum_m2+=4; lum_m1+=4; lum+=4; dst+=4; } #endif } static inline void deinterlace_line_inplace(uint8_t *lum_m4, uint8_t *lum_m3, uint8_t *lum_m2, uint8_t *lum_m1, uint8_t *lum, int size) { #ifndef USE_MMX uint8_t *cm = ff_cropTbl + MAX_NEG_CROP; int sum; for(;size > 0;size--) { sum = -lum_m4[0]; sum += lum_m3[0] << 2; sum += lum_m2[0] << 1; lum_m4[0]=lum_m2[0]; sum += lum_m1[0] << 2; sum += -lum[0]; lum_m2[0] = cm[(sum + 4) >> 3]; lum_m4++; lum_m3++; lum_m2++; lum_m1++; lum++; } #else { mmx_t rounder; rounder.uw[0]=4; rounder.uw[1]=4; rounder.uw[2]=4; rounder.uw[3]=4; pxor_r2r(mm7,mm7); movq_m2r(rounder,mm6); } for (;size > 3; size-=4) { DEINT_INPLACE_LINE_LUM lum_m4+=4; lum_m3+=4; lum_m2+=4; lum_m1+=4; lum+=4; } #endif } /* deinterlacing : 2 temporal taps, 3 spatial taps linear filter. The top field is copied as is, but the bottom field is deinterlaced against the top field. */ static inline void deinterlace_bottom_field(uint8_t *dst, int dst_wrap, const uint8_t *src1, int src_wrap, int width, int height) { const uint8_t *src_m2, *src_m1, *src_0, *src_p1, *src_p2; int y; src_m2 = src1; src_m1 = src1; src_0=&src_m1[src_wrap]; src_p1=&src_0[src_wrap]; src_p2=&src_p1[src_wrap]; for(y=0;y<(height-2);y+=2) { memcpy(dst,src_m1,width); dst += dst_wrap; deinterlace_line(dst,src_m2,src_m1,src_0,src_p1,src_p2,width); src_m2 = src_0; src_m1 = src_p1; src_0 = src_p2; src_p1 += 2*src_wrap; src_p2 += 2*src_wrap; dst += dst_wrap; } memcpy(dst,src_m1,width); dst += dst_wrap; /* do last line */ deinterlace_line(dst,src_m2,src_m1,src_0,src_0,src_0,width); } static inline void deinterlace_bottom_field_inplace(uint8_t *src1, int src_wrap, int width, int height) { uint8_t *src_m1, *src_0, *src_p1, *src_p2; int y; uint8_t *buf; buf = (uint8_t*)av_malloc(width); src_m1 = src1; memcpy(buf,src_m1,width); src_0=&src_m1[src_wrap]; src_p1=&src_0[src_wrap]; src_p2=&src_p1[src_wrap]; for(y=0;y<(height-2);y+=2) { deinterlace_line_inplace(buf,src_m1,src_0,src_p1,src_p2,width); src_m1 = src_p1; src_0 = src_p2; src_p1 += 2*src_wrap; src_p2 += 2*src_wrap; } /* do last line */ deinterlace_line_inplace(buf,src_m1,src_0,src_0,src_0,width); av_free(buf); } /* deinterlace - if not supported return -1 */ static int mlt_avpicture_deinterlace(AVPicture *dst, const AVPicture *src, int pix_fmt, int width, int height) { int i; if (pix_fmt != PIX_FMT_YUV420P && pix_fmt != PIX_FMT_YUV422P && pix_fmt != PIX_FMT_YUYV422 && pix_fmt != PIX_FMT_YUV444P && pix_fmt != PIX_FMT_YUV411P) return -1; if ((width & 3) != 0 || (height & 3) != 0) return -1; if ( pix_fmt != PIX_FMT_YUYV422 ) { for(i=0;i<3;i++) { if (i == 1) { switch(pix_fmt) { case PIX_FMT_YUV420P: width >>= 1; height >>= 1; break; case PIX_FMT_YUV422P: width >>= 1; break; case PIX_FMT_YUV411P: width >>= 2; break; default: break; } } if (src == dst) { deinterlace_bottom_field_inplace(dst->data[i], dst->linesize[i], width, height); } else { deinterlace_bottom_field(dst->data[i],dst->linesize[i], src->data[i], src->linesize[i], width, height); } } } else { if (src == dst) { deinterlace_bottom_field_inplace(dst->data[0], dst->linesize[0], width<<1, height); } else { deinterlace_bottom_field(dst->data[0],dst->linesize[0], src->data[0], src->linesize[0], width<<1, height); } } #ifdef USE_MMX emms(); #endif return 0; } /** Do it :-). */ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; int deinterlace = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace" ); // Determine if we need a writable version or not if ( deinterlace && !writable ) writable = !mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "progressive" ); // Get the input image *format = mlt_image_yuv422; error = mlt_frame_get_image( frame, image, format, width, height, 1 ); // Check that we want progressive and we aren't already progressive if ( deinterlace && *format == mlt_image_yuv422 && *image != NULL && !mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "progressive" ) ) { // Create a picture AVPicture *output = mlt_pool_alloc( sizeof( AVPicture ) ); // Fill the picture avpicture_fill( output, *image, PIX_FMT_YUYV422, *width, *height ); mlt_avpicture_deinterlace( output, output, PIX_FMT_YUYV422, *width, *height ); // Free the picture mlt_pool_release( output ); // Make sure that others know the frame is deinterlaced mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "progressive", 1 ); } return error; } /** Deinterlace filter processing - this should be lazy evaluation here... */ static mlt_frame deinterlace_process( mlt_filter filter, mlt_frame frame ) { // Push the get_image method on to the stack mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_avdeinterlace_init( void *arg ) { #ifndef USE_MMX if ( ff_cropTbl[MAX_NEG_CROP + 1] == 0 ) { int i; for(i=0;i<256;i++) ff_cropTbl[i + MAX_NEG_CROP] = i; for(i=0;iprocess = deinterlace_process; return filter; } mlt-0.9.0/src/modules/avformat/filter_avresample.c000066400000000000000000000122521215300731300222370ustar00rootroot00000000000000/* * filter_avresample.c -- adjust audio sample frequency * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include // ffmpeg Header files #include #include #if defined(FFUDIV) || (LIBAVCODEC_VERSION_INT < ((54<<16)+(26<<8)+0)) #define MAX_AUDIO_FRAME_SIZE (192000) // 1 second of 48khz 32bit audio /** Get the audio. */ static int resample_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); // Get the resample information int output_rate = mlt_properties_get_int( filter_properties, "frequency" ); int16_t *sample_buffer = mlt_properties_get_data( filter_properties, "buffer", NULL ); // Obtain the resample context if it exists ReSampleContext *resample = mlt_properties_get_data( filter_properties, "audio_resample", NULL ); // If no resample frequency is specified, default to requested value if ( output_rate == 0 ) output_rate = *frequency; // Get the producer's audio int error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); if ( error ) return error; // Return now if no work to do if ( output_rate != *frequency ) { // Will store number of samples created int used = 0; mlt_log_debug( MLT_FILTER_SERVICE(filter), "channels %d samples %d frequency %d -> %d\n", *channels, *samples, *frequency, output_rate ); // Do not convert to s16 unless we need to change the rate if ( *format != mlt_audio_s16 ) { *format = mlt_audio_s16; mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); } // Create a resampler if nececessary if ( resample == NULL || *frequency != mlt_properties_get_int( filter_properties, "last_frequency" ) ) { // Create the resampler resample = av_audio_resample_init( *channels, *channels, output_rate, *frequency, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16, 16, 10, 0, 0.8 ); // And store it on properties mlt_properties_set_data( filter_properties, "audio_resample", resample, 0, ( mlt_destructor )audio_resample_close, NULL ); // And remember what it was created for mlt_properties_set_int( filter_properties, "last_frequency", *frequency ); } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); // Resample the audio used = audio_resample( resample, sample_buffer, *buffer, *samples ); int size = used * *channels * sizeof( int16_t ); // Resize if necessary if ( used > *samples ) { *buffer = mlt_pool_realloc( *buffer, size ); mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); } // Copy samples memcpy( *buffer, sample_buffer, size ); // Update output variables *samples = used; *frequency = output_rate; } else { mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { // Only call this if we have a means to get audio if ( mlt_frame_is_test_audio( frame ) == 0 ) { // Push the filter on to the stack mlt_frame_push_audio( frame, filter ); // Assign our get_audio method mlt_frame_push_audio( frame, resample_get_audio ); } return frame; } /** Constructor for the filter. */ mlt_filter filter_avresample_init( char *arg ) { // Create a filter mlt_filter filter = mlt_filter_new( ); // Initialise if successful if ( filter != NULL ) { // Calculate size of the buffer int size = MAX_AUDIO_FRAME_SIZE * sizeof( int16_t ); // Allocate the buffer int16_t *buffer = mlt_pool_alloc( size ); // Assign the process method filter->process = filter_process; // Deal with argument if ( arg != NULL ) mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "frequency", arg ); // Default to 2 channel output mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "channels", 2 ); // Store the buffer mlt_properties_set_data( MLT_FILTER_PROPERTIES( filter ), "buffer", buffer, size, mlt_pool_release, NULL ); } return filter; } #endif // defined(FFUDIV) || (LIBAVCODEC_VERSION_INT < ((54<<16)+(26<<8)+0)) mlt-0.9.0/src/modules/avformat/filter_swscale.c000066400000000000000000000143411215300731300215420ustar00rootroot00000000000000/* * filter_swscale.c -- image scaling filter * Copyright (C) 2008-2009 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include // ffmpeg Header files #include #include #include #include #include static inline int convert_mlt_to_av_cs( mlt_image_format format ) { int value = 0; switch( format ) { case mlt_image_rgb24: value = PIX_FMT_RGB24; break; case mlt_image_rgb24a: case mlt_image_opengl: value = PIX_FMT_RGBA; break; case mlt_image_yuv422: value = PIX_FMT_YUYV422; break; case mlt_image_yuv420p: value = PIX_FMT_YUV420P; break; default: fprintf( stderr, "Invalid format...\n" ); break; } return value; } static int filter_scale( mlt_frame frame, uint8_t **image, mlt_image_format *format, int iwidth, int iheight, int owidth, int oheight ) { // Get the properties mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Get the requested interpolation method char *interps = mlt_properties_get( properties, "rescale.interp" ); // Convert to the SwScale flag int interp = SWS_BILINEAR; if ( strcmp( interps, "nearest" ) == 0 || strcmp( interps, "neighbor" ) == 0 ) interp = SWS_POINT; else if ( strcmp( interps, "tiles" ) == 0 || strcmp( interps, "fast_bilinear" ) == 0 ) interp = SWS_FAST_BILINEAR; else if ( strcmp( interps, "bilinear" ) == 0 ) interp = SWS_BILINEAR; else if ( strcmp( interps, "bicubic" ) == 0 ) interp = SWS_BICUBIC; else if ( strcmp( interps, "bicublin" ) == 0 ) interp = SWS_BICUBLIN; else if ( strcmp( interps, "gauss" ) == 0 ) interp = SWS_GAUSS; else if ( strcmp( interps, "sinc" ) == 0 ) interp = SWS_SINC; else if ( strcmp( interps, "hyper" ) == 0 || strcmp( interps, "lanczos" ) == 0 ) interp = SWS_LANCZOS; else if ( strcmp( interps, "spline" ) == 0 ) interp = SWS_SPLINE; interp |= SWS_ACCURATE_RND; // Determine the bytes per pixel int bpp; mlt_image_format_size( *format, 0, 0, &bpp ); // Set swscale flags to get good quality switch ( *format ) { case mlt_image_yuv422: interp |= SWS_FULL_CHR_H_INP; break; case mlt_image_rgb24: interp |= SWS_FULL_CHR_H_INT; break; case mlt_image_rgb24a: case mlt_image_opengl: interp |= SWS_FULL_CHR_H_INT; break; default: // XXX: we only know how to rescale packed formats return 1; } #ifdef USE_MMX interp |= SWS_CPU_CAPS_MMX; #endif #ifdef USE_SSE interp |= SWS_CPU_CAPS_MMX2; #endif // Convert the pixel formats int avformat = convert_mlt_to_av_cs( *format ); // Fill out the AVPictures AVPicture input; AVPicture output; uint8_t *outbuf = mlt_pool_alloc( owidth * ( oheight + 1 ) * bpp ); avpicture_fill( &input, *image, avformat, iwidth, iheight ); avpicture_fill( &output, outbuf, avformat, owidth, oheight ); // Create the context and output image owidth = owidth > 5120 ? 5120 : owidth; struct SwsContext *context = sws_getContext( iwidth, iheight, avformat, owidth, oheight, avformat, interp, NULL, NULL, NULL); if ( !context ) { owidth = owidth > 2048 ? 2048 : owidth; context = sws_getContext( iwidth, iheight, avformat, owidth, oheight, avformat, interp, NULL, NULL, NULL); } if ( context ) { // Perform the scaling sws_scale( context, (const uint8_t* const*) input.data, input.linesize, 0, iheight, output.data, output.linesize); sws_freeContext( context ); // Now update the frame mlt_frame_set_image( frame, output.data[0], owidth * ( oheight + 1 ) * bpp, mlt_pool_release ); // Return the output *image = output.data[0]; // Scale the alpha channel only if exists and not correct size int alpha_size = 0; mlt_properties_get_data( properties, "alpha", &alpha_size ); if ( alpha_size > 0 && alpha_size != ( owidth * oheight ) ) { // Create the context and output image uint8_t *alpha = mlt_frame_get_alpha_mask( frame ); if ( alpha ) { avformat = PIX_FMT_GRAY8; struct SwsContext *context = sws_getContext( iwidth, iheight, avformat, owidth, oheight, avformat, interp, NULL, NULL, NULL); avpicture_fill( &input, alpha, avformat, iwidth, iheight ); outbuf = mlt_pool_alloc( owidth * oheight ); avpicture_fill( &output, outbuf, avformat, owidth, oheight ); // Perform the scaling sws_scale( context, (const uint8_t* const*) input.data, input.linesize, 0, iheight, output.data, output.linesize); sws_freeContext( context ); // Set it back on the frame mlt_frame_set_alpha( frame, output.data[0], owidth * oheight, mlt_pool_release ); } } return 0; } else { return 1; } } /** Constructor for the filter. */ mlt_filter filter_swscale_init( mlt_profile profile, void *arg ) { // Test to see if swscale accepts the arg as resolution if ( arg ) { int *width = (int*) arg; if ( *width > 0 ) { struct SwsContext *context = sws_getContext( *width, *width, PIX_FMT_RGB32, 64, 64, PIX_FMT_RGB32, SWS_BILINEAR, NULL, NULL, NULL); if ( context ) sws_freeContext( context ); else return NULL; } } // Create a new scaler mlt_filter filter = mlt_factory_filter( profile, "rescale", NULL ); // If successful, then initialise it if ( filter != NULL ) { // Get the properties mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); // Set the inerpolation mlt_properties_set( properties, "interpolation", "bilinear" ); // Set the method mlt_properties_set_data( properties, "method", filter_scale, 0, NULL, NULL ); } return filter; } mlt-0.9.0/src/modules/avformat/mmx.h000066400000000000000000000225341215300731300173450ustar00rootroot00000000000000/* * mmx.h * Copyright (C) 1997-2001 H. Dietz and R. Fisher */ #ifndef AVCODEC_I386MMX_H #define AVCODEC_I386MMX_H /* * The type of an value that fits in an MMX register (note that long * long constant values MUST be suffixed by LL and unsigned long long * values by ULL, lest they be truncated by the compiler) */ typedef union { long long q; /* Quadword (64-bit) value */ unsigned long long uq; /* Unsigned Quadword */ int d[2]; /* 2 Doubleword (32-bit) values */ unsigned int ud[2]; /* 2 Unsigned Doubleword */ short w[4]; /* 4 Word (16-bit) values */ unsigned short uw[4]; /* 4 Unsigned Word */ char b[8]; /* 8 Byte (8-bit) values */ unsigned char ub[8]; /* 8 Unsigned Byte */ float s[2]; /* Single-precision (32-bit) value */ } mmx_t; /* On an 8-byte (64-bit) boundary */ #define mmx_i2r(op,imm,reg) \ __asm__ __volatile__ (#op " %0, %%" #reg \ : /* nothing */ \ : "i" (imm) ) #define mmx_m2r(op,mem,reg) \ __asm__ __volatile__ (#op " %0, %%" #reg \ : /* nothing */ \ : "m" (mem)) #define mmx_r2m(op,reg,mem) \ __asm__ __volatile__ (#op " %%" #reg ", %0" \ : "=m" (mem) \ : /* nothing */ ) #define mmx_r2r(op,regs,regd) \ __asm__ __volatile__ (#op " %" #regs ", %" #regd) #define emms() __asm__ __volatile__ ("emms") #define movd_m2r(var,reg) mmx_m2r (movd, var, reg) #define movd_r2m(reg,var) mmx_r2m (movd, reg, var) #define movd_r2r(regs,regd) mmx_r2r (movd, regs, regd) #define movq_m2r(var,reg) mmx_m2r (movq, var, reg) #define movq_r2m(reg,var) mmx_r2m (movq, reg, var) #define movq_r2r(regs,regd) mmx_r2r (movq, regs, regd) #define packssdw_m2r(var,reg) mmx_m2r (packssdw, var, reg) #define packssdw_r2r(regs,regd) mmx_r2r (packssdw, regs, regd) #define packsswb_m2r(var,reg) mmx_m2r (packsswb, var, reg) #define packsswb_r2r(regs,regd) mmx_r2r (packsswb, regs, regd) #define packuswb_m2r(var,reg) mmx_m2r (packuswb, var, reg) #define packuswb_r2r(regs,regd) mmx_r2r (packuswb, regs, regd) #define paddb_m2r(var,reg) mmx_m2r (paddb, var, reg) #define paddb_r2r(regs,regd) mmx_r2r (paddb, regs, regd) #define paddd_m2r(var,reg) mmx_m2r (paddd, var, reg) #define paddd_r2r(regs,regd) mmx_r2r (paddd, regs, regd) #define paddw_m2r(var,reg) mmx_m2r (paddw, var, reg) #define paddw_r2r(regs,regd) mmx_r2r (paddw, regs, regd) #define paddsb_m2r(var,reg) mmx_m2r (paddsb, var, reg) #define paddsb_r2r(regs,regd) mmx_r2r (paddsb, regs, regd) #define paddsw_m2r(var,reg) mmx_m2r (paddsw, var, reg) #define paddsw_r2r(regs,regd) mmx_r2r (paddsw, regs, regd) #define paddusb_m2r(var,reg) mmx_m2r (paddusb, var, reg) #define paddusb_r2r(regs,regd) mmx_r2r (paddusb, regs, regd) #define paddusw_m2r(var,reg) mmx_m2r (paddusw, var, reg) #define paddusw_r2r(regs,regd) mmx_r2r (paddusw, regs, regd) #define pand_m2r(var,reg) mmx_m2r (pand, var, reg) #define pand_r2r(regs,regd) mmx_r2r (pand, regs, regd) #define pandn_m2r(var,reg) mmx_m2r (pandn, var, reg) #define pandn_r2r(regs,regd) mmx_r2r (pandn, regs, regd) #define pcmpeqb_m2r(var,reg) mmx_m2r (pcmpeqb, var, reg) #define pcmpeqb_r2r(regs,regd) mmx_r2r (pcmpeqb, regs, regd) #define pcmpeqd_m2r(var,reg) mmx_m2r (pcmpeqd, var, reg) #define pcmpeqd_r2r(regs,regd) mmx_r2r (pcmpeqd, regs, regd) #define pcmpeqw_m2r(var,reg) mmx_m2r (pcmpeqw, var, reg) #define pcmpeqw_r2r(regs,regd) mmx_r2r (pcmpeqw, regs, regd) #define pcmpgtb_m2r(var,reg) mmx_m2r (pcmpgtb, var, reg) #define pcmpgtb_r2r(regs,regd) mmx_r2r (pcmpgtb, regs, regd) #define pcmpgtd_m2r(var,reg) mmx_m2r (pcmpgtd, var, reg) #define pcmpgtd_r2r(regs,regd) mmx_r2r (pcmpgtd, regs, regd) #define pcmpgtw_m2r(var,reg) mmx_m2r (pcmpgtw, var, reg) #define pcmpgtw_r2r(regs,regd) mmx_r2r (pcmpgtw, regs, regd) #define pmaddwd_m2r(var,reg) mmx_m2r (pmaddwd, var, reg) #define pmaddwd_r2r(regs,regd) mmx_r2r (pmaddwd, regs, regd) #define pmulhw_m2r(var,reg) mmx_m2r (pmulhw, var, reg) #define pmulhw_r2r(regs,regd) mmx_r2r (pmulhw, regs, regd) #define pmullw_m2r(var,reg) mmx_m2r (pmullw, var, reg) #define pmullw_r2r(regs,regd) mmx_r2r (pmullw, regs, regd) #define por_m2r(var,reg) mmx_m2r (por, var, reg) #define por_r2r(regs,regd) mmx_r2r (por, regs, regd) #define pslld_i2r(imm,reg) mmx_i2r (pslld, imm, reg) #define pslld_m2r(var,reg) mmx_m2r (pslld, var, reg) #define pslld_r2r(regs,regd) mmx_r2r (pslld, regs, regd) #define psllq_i2r(imm,reg) mmx_i2r (psllq, imm, reg) #define psllq_m2r(var,reg) mmx_m2r (psllq, var, reg) #define psllq_r2r(regs,regd) mmx_r2r (psllq, regs, regd) #define psllw_i2r(imm,reg) mmx_i2r (psllw, imm, reg) #define psllw_m2r(var,reg) mmx_m2r (psllw, var, reg) #define psllw_r2r(regs,regd) mmx_r2r (psllw, regs, regd) #define psrad_i2r(imm,reg) mmx_i2r (psrad, imm, reg) #define psrad_m2r(var,reg) mmx_m2r (psrad, var, reg) #define psrad_r2r(regs,regd) mmx_r2r (psrad, regs, regd) #define psraw_i2r(imm,reg) mmx_i2r (psraw, imm, reg) #define psraw_m2r(var,reg) mmx_m2r (psraw, var, reg) #define psraw_r2r(regs,regd) mmx_r2r (psraw, regs, regd) #define psrld_i2r(imm,reg) mmx_i2r (psrld, imm, reg) #define psrld_m2r(var,reg) mmx_m2r (psrld, var, reg) #define psrld_r2r(regs,regd) mmx_r2r (psrld, regs, regd) #define psrlq_i2r(imm,reg) mmx_i2r (psrlq, imm, reg) #define psrlq_m2r(var,reg) mmx_m2r (psrlq, var, reg) #define psrlq_r2r(regs,regd) mmx_r2r (psrlq, regs, regd) #define psrlw_i2r(imm,reg) mmx_i2r (psrlw, imm, reg) #define psrlw_m2r(var,reg) mmx_m2r (psrlw, var, reg) #define psrlw_r2r(regs,regd) mmx_r2r (psrlw, regs, regd) #define psubb_m2r(var,reg) mmx_m2r (psubb, var, reg) #define psubb_r2r(regs,regd) mmx_r2r (psubb, regs, regd) #define psubd_m2r(var,reg) mmx_m2r (psubd, var, reg) #define psubd_r2r(regs,regd) mmx_r2r (psubd, regs, regd) #define psubw_m2r(var,reg) mmx_m2r (psubw, var, reg) #define psubw_r2r(regs,regd) mmx_r2r (psubw, regs, regd) #define psubsb_m2r(var,reg) mmx_m2r (psubsb, var, reg) #define psubsb_r2r(regs,regd) mmx_r2r (psubsb, regs, regd) #define psubsw_m2r(var,reg) mmx_m2r (psubsw, var, reg) #define psubsw_r2r(regs,regd) mmx_r2r (psubsw, regs, regd) #define psubusb_m2r(var,reg) mmx_m2r (psubusb, var, reg) #define psubusb_r2r(regs,regd) mmx_r2r (psubusb, regs, regd) #define psubusw_m2r(var,reg) mmx_m2r (psubusw, var, reg) #define psubusw_r2r(regs,regd) mmx_r2r (psubusw, regs, regd) #define punpckhbw_m2r(var,reg) mmx_m2r (punpckhbw, var, reg) #define punpckhbw_r2r(regs,regd) mmx_r2r (punpckhbw, regs, regd) #define punpckhdq_m2r(var,reg) mmx_m2r (punpckhdq, var, reg) #define punpckhdq_r2r(regs,regd) mmx_r2r (punpckhdq, regs, regd) #define punpckhwd_m2r(var,reg) mmx_m2r (punpckhwd, var, reg) #define punpckhwd_r2r(regs,regd) mmx_r2r (punpckhwd, regs, regd) #define punpcklbw_m2r(var,reg) mmx_m2r (punpcklbw, var, reg) #define punpcklbw_r2r(regs,regd) mmx_r2r (punpcklbw, regs, regd) #define punpckldq_m2r(var,reg) mmx_m2r (punpckldq, var, reg) #define punpckldq_r2r(regs,regd) mmx_r2r (punpckldq, regs, regd) #define punpcklwd_m2r(var,reg) mmx_m2r (punpcklwd, var, reg) #define punpcklwd_r2r(regs,regd) mmx_r2r (punpcklwd, regs, regd) #define pxor_m2r(var,reg) mmx_m2r (pxor, var, reg) #define pxor_r2r(regs,regd) mmx_r2r (pxor, regs, regd) /* 3DNOW extensions */ #define pavgusb_m2r(var,reg) mmx_m2r (pavgusb, var, reg) #define pavgusb_r2r(regs,regd) mmx_r2r (pavgusb, regs, regd) /* AMD MMX extensions - also available in intel SSE */ #define mmx_m2ri(op,mem,reg,imm) \ __asm__ __volatile__ (#op " %1, %0, %%" #reg \ : /* nothing */ \ : "X" (mem), "X" (imm)) #define mmx_r2ri(op,regs,regd,imm) \ __asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \ : /* nothing */ \ : "X" (imm) ) #define mmx_fetch(mem,hint) \ __asm__ __volatile__ ("prefetch" #hint " %0" \ : /* nothing */ \ : "X" (mem)) #define maskmovq(regs,maskreg) mmx_r2ri (maskmovq, regs, maskreg) #define movntq_r2m(mmreg,var) mmx_r2m (movntq, mmreg, var) #define pavgb_m2r(var,reg) mmx_m2r (pavgb, var, reg) #define pavgb_r2r(regs,regd) mmx_r2r (pavgb, regs, regd) #define pavgw_m2r(var,reg) mmx_m2r (pavgw, var, reg) #define pavgw_r2r(regs,regd) mmx_r2r (pavgw, regs, regd) #define pextrw_r2r(mmreg,reg,imm) mmx_r2ri (pextrw, mmreg, reg, imm) #define pinsrw_r2r(reg,mmreg,imm) mmx_r2ri (pinsrw, reg, mmreg, imm) #define pmaxsw_m2r(var,reg) mmx_m2r (pmaxsw, var, reg) #define pmaxsw_r2r(regs,regd) mmx_r2r (pmaxsw, regs, regd) #define pmaxub_m2r(var,reg) mmx_m2r (pmaxub, var, reg) #define pmaxub_r2r(regs,regd) mmx_r2r (pmaxub, regs, regd) #define pminsw_m2r(var,reg) mmx_m2r (pminsw, var, reg) #define pminsw_r2r(regs,regd) mmx_r2r (pminsw, regs, regd) #define pminub_m2r(var,reg) mmx_m2r (pminub, var, reg) #define pminub_r2r(regs,regd) mmx_r2r (pminub, regs, regd) #define pmovmskb(mmreg,reg) \ __asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg) #define pmulhuw_m2r(var,reg) mmx_m2r (pmulhuw, var, reg) #define pmulhuw_r2r(regs,regd) mmx_r2r (pmulhuw, regs, regd) #define prefetcht0(mem) mmx_fetch (mem, t0) #define prefetcht1(mem) mmx_fetch (mem, t1) #define prefetcht2(mem) mmx_fetch (mem, t2) #define prefetchnta(mem) mmx_fetch (mem, nta) #define psadbw_m2r(var,reg) mmx_m2r (psadbw, var, reg) #define psadbw_r2r(regs,regd) mmx_r2r (psadbw, regs, regd) #define pshufw_m2r(var,reg,imm) mmx_m2ri(pshufw, var, reg, imm) #define pshufw_r2r(regs,regd,imm) mmx_r2ri(pshufw, regs, regd, imm) #define sfence() __asm__ __volatile__ ("sfence\n\t") #endif /* AVCODEC_I386MMX_H */ mlt-0.9.0/src/modules/avformat/producer_avformat.c000066400000000000000000002600321215300731300222560ustar00rootroot00000000000000/* * producer_avformat.c -- avformat producer * Copyright (C) 2003-2012 Ushodaya Enterprises Limited * Author: Charles Yates * Author: Dan Dennedy * Much code borrowed from ffmpeg.c: Copyright (c) 2000-2003 Fabrice Bellard * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // MLT Header files #include #include #include #include #include #include #include // ffmpeg Header files #include #include #include #include #ifdef VDPAU # include #endif #if (LIBAVUTIL_VERSION_INT >= ((51<<16)+(8<<8)+0)) # include #endif // System header files #include #include #include #include #if LIBAVCODEC_VERSION_MAJOR >= 53 #include #define CODEC_TYPE_VIDEO AVMEDIA_TYPE_VIDEO #define CODEC_TYPE_AUDIO AVMEDIA_TYPE_AUDIO #define PKT_FLAG_KEY AV_PKT_FLAG_KEY #else #include #endif #if LIBAVCODEC_VERSION_MAJOR < 55 #define AV_CODEC_ID_DVVIDEO CODEC_ID_DVVIDEO #define AV_CODEC_ID_H264 CODEC_ID_H264 #endif #define POSITION_INITIAL (-2) #define POSITION_INVALID (-1) #define MAX_AUDIO_STREAMS (32) #define MAX_VDPAU_SURFACES (10) #define MAX_AUDIO_FRAME_SIZE (192000) // 1 second of 48khz 32bit audio struct producer_avformat_s { mlt_producer parent; AVFormatContext *dummy_context; AVFormatContext *audio_format; AVFormatContext *video_format; AVCodecContext *audio_codec[ MAX_AUDIO_STREAMS ]; AVCodecContext *video_codec; AVFrame *video_frame; AVFrame *audio_frame; AVPacket pkt; mlt_position audio_expected; mlt_position video_expected; int audio_index; int video_index; int64_t first_pts; int64_t last_position; int seekable; int64_t current_position; mlt_position nonseek_position; int top_field_first; uint8_t *audio_buffer[ MAX_AUDIO_STREAMS ]; size_t audio_buffer_size[ MAX_AUDIO_STREAMS ]; uint8_t *decode_buffer[ MAX_AUDIO_STREAMS ]; int audio_used[ MAX_AUDIO_STREAMS ]; int audio_streams; int audio_max_stream; int total_channels; int max_channel; int max_frequency; unsigned int invalid_pts_counter; unsigned int invalid_dts_counter; mlt_cache image_cache; int colorspace; int full_luma; pthread_mutex_t video_mutex; pthread_mutex_t audio_mutex; mlt_deque apackets; mlt_deque vpackets; pthread_mutex_t packets_mutex; pthread_mutex_t open_mutex; int is_mutex_init; AVRational video_time_base; #ifdef VDPAU struct { // from FFmpeg struct vdpau_render_state render_states[MAX_VDPAU_SURFACES]; // internal mlt_deque deque; int b_age; int ip_age[2]; int is_decoded; uint8_t *buffer; VdpDevice device; VdpDecoder decoder; } *vdpau; #endif }; typedef struct producer_avformat_s *producer_avformat; // Forward references. static int list_components( char* file ); static int producer_open( producer_avformat self, mlt_profile profile, const char *URL, int take_lock ); static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ); static void producer_avformat_close( producer_avformat ); static void producer_close( mlt_producer parent ); static void producer_set_up_video( producer_avformat self, mlt_frame frame ); static void producer_set_up_audio( producer_avformat self, mlt_frame frame ); static void apply_properties( void *obj, mlt_properties properties, int flags ); static int video_codec_init( producer_avformat self, int index, mlt_properties properties ); static void get_audio_streams_info( producer_avformat self ); static mlt_audio_format pick_audio_format( int sample_fmt ); #ifdef VDPAU #include "vdpau.c" #endif /** Constructor for libavformat. */ mlt_producer producer_avformat_init( mlt_profile profile, const char *service, char *file ) { if ( list_components( file ) ) return NULL; mlt_producer producer = NULL; // Check that we have a non-NULL argument if ( file ) { // Construct the producer producer_avformat self = calloc( 1, sizeof( struct producer_avformat_s ) ); producer = calloc( 1, sizeof( struct mlt_producer_s ) ); // Initialise it if ( mlt_producer_init( producer, self ) == 0 ) { self->parent = producer; // Get the properties mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); // Set the resource property (required for all producers) mlt_properties_set( properties, "resource", file ); // Register transport implementation with the producer producer->close = (mlt_destructor) producer_close; // Register our get_frame implementation producer->get_frame = producer_get_frame; if ( strcmp( service, "avformat-novalidate" ) ) { // Open the file if ( producer_open( self, profile, file, 1 ) != 0 ) { // Clean up mlt_producer_close( producer ); producer = NULL; producer_avformat_close( self ); } else if ( self->seekable ) { // Close the file to release resources for large playlists - reopen later as needed #if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(17<<8)+0) if ( self->audio_format ) avformat_close_input( &self->audio_format ); if ( self->video_format ) avformat_close_input( &self->video_format ); #else if ( self->audio_format ) av_close_input_file( self->audio_format ); if ( self->video_format ) av_close_input_file( self->video_format ); #endif self->audio_format = NULL; self->video_format = NULL; } } if ( producer ) { // Default the user-selectable indices from the auto-detected indices mlt_properties_set_int( properties, "audio_index", self->audio_index ); mlt_properties_set_int( properties, "video_index", self->video_index ); #ifdef VDPAU mlt_service_cache_set_size( MLT_PRODUCER_SERVICE(producer), "producer_avformat", 5 ); #endif mlt_service_cache_put( MLT_PRODUCER_SERVICE(producer), "producer_avformat", self, 0, (mlt_destructor) producer_avformat_close ); } } } return producer; } int list_components( char* file ) { int skip = 0; // Report information about available demuxers and codecs as YAML Tiny if ( file && strstr( file, "f-list" ) ) { fprintf( stderr, "---\nformats:\n" ); AVInputFormat *format = NULL; while ( ( format = av_iformat_next( format ) ) ) fprintf( stderr, " - %s\n", format->name ); fprintf( stderr, "...\n" ); skip = 1; } if ( file && strstr( file, "acodec-list" ) ) { fprintf( stderr, "---\naudio_codecs:\n" ); AVCodec *codec = NULL; while ( ( codec = av_codec_next( codec ) ) ) if ( codec->decode && codec->type == CODEC_TYPE_AUDIO ) fprintf( stderr, " - %s\n", codec->name ); fprintf( stderr, "...\n" ); skip = 1; } if ( file && strstr( file, "vcodec-list" ) ) { fprintf( stderr, "---\nvideo_codecs:\n" ); AVCodec *codec = NULL; while ( ( codec = av_codec_next( codec ) ) ) if ( codec->decode && codec->type == CODEC_TYPE_VIDEO ) fprintf( stderr, " - %s\n", codec->name ); fprintf( stderr, "...\n" ); skip = 1; } return skip; } static int first_video_index( producer_avformat self ) { AVFormatContext *context = self->video_format? self->video_format : self->audio_format; int i = -1; // not found if ( context ) { for ( i = 0; i < context->nb_streams; i++ ) { if ( context->streams[i]->codec && context->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO ) break; } if ( i == context->nb_streams ) i = -1; } return i; } /** Find the default streams. */ static mlt_properties find_default_streams( producer_avformat self ) { int i; char key[200]; #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(8<<8)+0) AVDictionaryEntry *tag = NULL; #else AVMetadataTag *tag = NULL; #endif AVFormatContext *context = self->video_format; mlt_properties meta_media = MLT_PRODUCER_PROPERTIES( self->parent ); // Default to the first audio and video streams found self->audio_index = -1; self->video_index = -1; mlt_properties_set_int( meta_media, "meta.media.nb_streams", context->nb_streams ); // Allow for multiple audio and video streams in the file and select first of each (if available) for( i = 0; i < context->nb_streams; i++ ) { // Get the codec context AVStream *stream = context->streams[ i ]; if ( ! stream ) continue; AVCodecContext *codec_context = stream->codec; if ( ! codec_context ) continue; AVCodec *codec = avcodec_find_decoder( codec_context->codec_id ); if ( ! codec ) continue; snprintf( key, sizeof(key), "meta.media.%d.stream.type", i ); // Determine the type and obtain the first index of each type switch( codec_context->codec_type ) { case CODEC_TYPE_VIDEO: // Use first video stream if ( self->video_index < 0 ) self->video_index = i; mlt_properties_set( meta_media, key, "video" ); snprintf( key, sizeof(key), "meta.media.%d.stream.frame_rate", i ); double ffmpeg_fps = av_q2d( context->streams[ i ]->avg_frame_rate ); #if LIBAVFORMAT_VERSION_MAJOR < 55 if ( isnan( ffmpeg_fps ) || ffmpeg_fps == 0 ) ffmpeg_fps = av_q2d( context->streams[ i ]->r_frame_rate ); #endif mlt_properties_set_double( meta_media, key, ffmpeg_fps ); snprintf( key, sizeof(key), "meta.media.%d.stream.sample_aspect_ratio", i ); mlt_properties_set_double( meta_media, key, av_q2d( context->streams[ i ]->sample_aspect_ratio ) ); snprintf( key, sizeof(key), "meta.media.%d.codec.width", i ); mlt_properties_set_int( meta_media, key, codec_context->width ); snprintf( key, sizeof(key), "meta.media.%d.codec.height", i ); mlt_properties_set_int( meta_media, key, codec_context->height ); snprintf( key, sizeof(key), "meta.media.%d.codec.frame_rate", i ); AVRational frame_rate = { codec_context->time_base.den, codec_context->time_base.num * codec_context->ticks_per_frame }; mlt_properties_set_double( meta_media, key, av_q2d( frame_rate ) ); snprintf( key, sizeof(key), "meta.media.%d.codec.pix_fmt", i ); #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(3<<8)+0) mlt_properties_set( meta_media, key, av_get_pix_fmt_name( codec_context->pix_fmt ) ); #else mlt_properties_set( meta_media, key, avcodec_get_pix_fmt_name( codec_context->pix_fmt ) ); #endif snprintf( key, sizeof(key), "meta.media.%d.codec.sample_aspect_ratio", i ); mlt_properties_set_double( meta_media, key, av_q2d( codec_context->sample_aspect_ratio ) ); snprintf( key, sizeof(key), "meta.media.%d.codec.colorspace", i ); switch ( codec_context->colorspace ) { case AVCOL_SPC_SMPTE240M: mlt_properties_set_int( meta_media, key, 240 ); break; case AVCOL_SPC_BT470BG: case AVCOL_SPC_SMPTE170M: mlt_properties_set_int( meta_media, key, 601 ); break; case AVCOL_SPC_BT709: mlt_properties_set_int( meta_media, key, 709 ); break; default: // This is a heuristic Charles Poynton suggests in "Digital Video and HDTV" mlt_properties_set_int( meta_media, key, codec_context->width * codec_context->height > 750000 ? 709 : 601 ); break; } break; case CODEC_TYPE_AUDIO: if ( !codec_context->channels ) break; // Use first audio stream if ( self->audio_index < 0 && pick_audio_format( codec_context->sample_fmt ) != mlt_audio_none ) self->audio_index = i; mlt_properties_set( meta_media, key, "audio" ); snprintf( key, sizeof(key), "meta.media.%d.codec.sample_fmt", i ); mlt_properties_set( meta_media, key, av_get_sample_fmt_name( codec_context->sample_fmt ) ); snprintf( key, sizeof(key), "meta.media.%d.codec.sample_rate", i ); mlt_properties_set_int( meta_media, key, codec_context->sample_rate ); snprintf( key, sizeof(key), "meta.media.%d.codec.channels", i ); mlt_properties_set_int( meta_media, key, codec_context->channels ); break; default: break; } // snprintf( key, sizeof(key), "meta.media.%d.stream.time_base", i ); // mlt_properties_set_double( meta_media, key, av_q2d( context->streams[ i ]->time_base ) ); snprintf( key, sizeof(key), "meta.media.%d.codec.name", i ); mlt_properties_set( meta_media, key, codec->name ); snprintf( key, sizeof(key), "meta.media.%d.codec.long_name", i ); mlt_properties_set( meta_media, key, codec->long_name ); snprintf( key, sizeof(key), "meta.media.%d.codec.bit_rate", i ); mlt_properties_set_int( meta_media, key, codec_context->bit_rate ); // snprintf( key, sizeof(key), "meta.media.%d.codec.time_base", i ); // mlt_properties_set_double( meta_media, key, av_q2d( codec_context->time_base ) ); // snprintf( key, sizeof(key), "meta.media.%d.codec.profile", i ); // mlt_properties_set_int( meta_media, key, codec_context->profile ); // snprintf( key, sizeof(key), "meta.media.%d.codec.level", i ); // mlt_properties_set_int( meta_media, key, codec_context->level ); // Read Metadata #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(8<<8)+0) while ( ( tag = av_dict_get( stream->metadata, "", tag, AV_DICT_IGNORE_SUFFIX ) ) ) #else while ( ( tag = av_metadata_get( stream->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX ) ) ) #endif { if ( tag->value && strcmp( tag->value, "" ) && strcmp( tag->value, "und" ) ) { snprintf( key, sizeof(key), "meta.attr.%d.stream.%s.markup", i, tag->key ); mlt_properties_set( meta_media, key, tag->value ); } } } #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(8<<8)+0) while ( ( tag = av_dict_get( context->metadata, "", tag, AV_DICT_IGNORE_SUFFIX ) ) ) #else while ( ( tag = av_metadata_get( context->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX ) ) ) #endif { if ( tag->value && strcmp( tag->value, "" ) && strcmp( tag->value, "und" ) ) { snprintf( key, sizeof(key), "meta.attr.%s.markup", tag->key ); mlt_properties_set( meta_media, key, tag->value ); } } return meta_media; } static void get_aspect_ratio( mlt_properties properties, AVStream *stream, AVCodecContext *codec_context ) { AVRational sar = stream->sample_aspect_ratio; if ( sar.num <= 0 || sar.den <= 0 ) sar = codec_context->sample_aspect_ratio; if ( sar.num <= 0 || sar.den <= 0 ) sar.num = sar.den = 1; mlt_properties_set_int( properties, "meta.media.sample_aspect_num", sar.num ); mlt_properties_set_int( properties, "meta.media.sample_aspect_den", sar.den ); mlt_properties_set_double( properties, "aspect_ratio", av_q2d( sar ) ); } #if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) static char* parse_url( mlt_profile profile, const char* URL, AVInputFormat **format, AVDictionary **params ) #else static char* parse_url( mlt_profile profile, const char* URL, AVInputFormat **format, AVFormatParameters *params ) #endif { if ( !URL ) return NULL; char *result = NULL; char *protocol = strdup( URL ); char *url = strchr( protocol, ':' ); // Only if there is not a protocol specification that avformat can handle #if LIBAVFORMAT_VERSION_MAJOR >= 53 if ( url && avio_check( URL, 0 ) < 0 ) #else if ( url && !url_exist( URL ) ) #endif { // Truncate protocol string url[0] = 0; mlt_log_debug( NULL, "%s: protocol=%s resource=%s\n", __FUNCTION__, protocol, url + 1 ); // Lookup the format *format = av_find_input_format( protocol ); // Eat the format designator result = ++url; if ( *format ) { #if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) // support for legacy width and height parameters char *width = NULL; char *height = NULL; #else // These are required by video4linux2 (defaults) params->width = profile->width; params->height = profile->height; if ( !strstr( URL, "&frame_rate" ) ) params->time_base = (AVRational){ profile->frame_rate_den, profile->frame_rate_num }; params->channels = 2; params->sample_rate = 48000; #endif // Parse out params url = strchr( url, '?' ); while ( url ) { url[0] = 0; char *name = strdup( ++url ); char *value = strchr( name, '=' ); if ( !value ) // Also accept : as delimiter for backwards compatibility. value = strchr( name, ':' ); if ( value ) { value[0] = 0; value++; char *t = strchr( value, '&' ); if ( t ) t[0] = 0; #if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) // translate old parameters to new av_dict names if ( !strcmp( name, "frame_rate" ) ) av_dict_set( params, "framerate", value, 0 ); else if ( !strcmp( name, "pix_fmt" ) ) av_dict_set( params, "pixel_format", value, 0 ); else if ( !strcmp( name, "width" ) ) width = strdup( value ); else if ( !strcmp( name, "height" ) ) height = strdup( value ); else // generic demux/device option support av_dict_set( params, name, value, 0 ); #else if ( !strcmp( name, "frame_rate" ) ) params->time_base.den = atoi( value ); else if ( !strcmp( name, "frame_rate_base" ) ) params->time_base.num = atoi( value ); else if ( !strcmp( name, "sample_rate" ) ) params->sample_rate = atoi( value ); else if ( !strcmp( name, "channel" ) ) params->channel = atoi( value ); else if ( !strcmp( name, "channels" ) ) params->channels = atoi( value ); else if ( !strcmp( name, "pix_fmt" ) ) params->pix_fmt = av_get_pix_fmt( value ); else if ( !strcmp( name, "width" ) ) params->width = atoi( value ); else if ( !strcmp( name, "height" ) ) params->height = atoi( value ); else if ( !strcmp( name, "standard" ) ) params->standard = strdup( value ); #endif } free( name ); url = strchr( url, '&' ); } #if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) // continued support for legacy width and height parameters if ( width && height ) { char *s = malloc( strlen( width ) + strlen( height ) + 2 ); strcpy( s, width ); strcat( s, "x"); strcat( s, height ); av_dict_set( params, "video_size", s, 0 ); free( s ); } if ( width ) free( width ); if ( height ) free ( height ); #endif } result = strdup( result ); } else { result = strdup( URL ); } free( protocol ); return result; } static int get_basic_info( producer_avformat self, mlt_profile profile, const char *filename ) { int error = 0; // Get the properties mlt_properties properties = MLT_PRODUCER_PROPERTIES( self->parent ); AVFormatContext *format = self->video_format; // We will treat everything with the producer fps. // TODO: make this more flexible. double fps = mlt_profile_fps( profile ); // Get the duration if ( !mlt_properties_get_int( properties, "_length_computed" ) ) { // The _length_computed flag prevents overwriting explicity set length/out/eof properties // when producer_open is called after initial call when restoring or reseting the producer. if ( format->duration != AV_NOPTS_VALUE ) { // This isn't going to be accurate for all formats mlt_position frames = ( mlt_position )( ( ( double )format->duration / ( double )AV_TIME_BASE ) * fps ); mlt_properties_set_position( properties, "out", frames - 1 ); mlt_properties_set_position( properties, "length", frames ); mlt_properties_set_int( properties, "_length_computed", 1 ); } else { // Set live sources to run forever mlt_properties_set_position( properties, "length", INT_MAX ); mlt_properties_set_position( properties, "out", INT_MAX - 1 ); mlt_properties_set( properties, "eof", "loop" ); mlt_properties_set_int( properties, "_length_computed", 1 ); } } // Check if we're seekable // avdevices are typically AVFMT_NOFILE and not seekable self->seekable = !format->iformat || !( format->iformat->flags & AVFMT_NOFILE ); if ( format->pb ) { // protocols can indicate if they support seeking #if LIBAVFORMAT_VERSION_MAJOR >= 53 self->seekable = format->pb->seekable; #else URLContext *uc = url_fileno( format->pb ); if ( uc ) self->seekable = !uc->is_streamed; #endif } if ( self->seekable ) { // Do a more rigourous test of seekable on a disposable context self->seekable = av_seek_frame( format, -1, format->start_time, AVSEEK_FLAG_BACKWARD ) >= 0; mlt_properties_set_int( properties, "seekable", self->seekable ); self->dummy_context = format; #if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) self->video_format = NULL; avformat_open_input( &self->video_format, filename, NULL, NULL ); avformat_find_stream_info( self->video_format, NULL ); #else av_open_input_file( &self->video_format, filename, NULL, 0, NULL ); av_find_stream_info( self->video_format ); #endif format = self->video_format; } // Fetch the width, height and aspect ratio if ( self->video_index != -1 ) { AVCodecContext *codec_context = format->streams[ self->video_index ]->codec; mlt_properties_set_int( properties, "width", codec_context->width ); mlt_properties_set_int( properties, "height", codec_context->height ); get_aspect_ratio( properties, format->streams[ self->video_index ], codec_context ); // Verify that we can convert this to YUV 4:2:2 // TODO: we can now also return RGB and RGBA and quite possibly more in the future. struct SwsContext *context = sws_getContext( codec_context->width, codec_context->height, codec_context->pix_fmt, codec_context->width, codec_context->height, PIX_FMT_YUYV422, SWS_BILINEAR, NULL, NULL, NULL); if ( context ) sws_freeContext( context ); else error = 1; } return error; } /** Open the file. */ static int producer_open( producer_avformat self, mlt_profile profile, const char *URL, int take_lock ) { // Return an error code (0 == no error) int error = 0; mlt_properties properties = MLT_PRODUCER_PROPERTIES( self->parent ); // Lock the service if ( take_lock ) { if ( !self->is_mutex_init ) { pthread_mutex_init( &self->audio_mutex, NULL ); pthread_mutex_init( &self->video_mutex, NULL ); pthread_mutex_init( &self->packets_mutex, NULL ); pthread_mutex_init( &self->open_mutex, NULL ); self->is_mutex_init = 1; } pthread_mutex_lock( &self->audio_mutex ); pthread_mutex_lock( &self->video_mutex ); } mlt_events_block( properties, self->parent ); // Parse URL AVInputFormat *format = NULL; #if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) AVDictionary *params = NULL; #else AVFormatParameters params; memset( ¶ms, 0, sizeof(params) ); #endif char *filename = parse_url( profile, URL, &format, ¶ms ); // Now attempt to open the file or device with filename #if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) error = avformat_open_input( &self->video_format, filename, format, ¶ms ) < 0; if ( error ) // If the URL is a network stream URL, then we probably need to open with full URL error = avformat_open_input( &self->video_format, URL, format, ¶ms ) < 0; #else error = av_open_input_file( &self->video_format, filename, format, 0, ¶ms ) < 0; if ( error ) // If the URL is a network stream URL, then we probably need to open with full URL error = av_open_input_file( &self->video_format, URL, format, 0, ¶ms ) < 0; #endif // Set MLT properties onto video AVFormatContext if ( !error && self->video_format ) { apply_properties( self->video_format, properties, AV_OPT_FLAG_DECODING_PARAM ); if ( self->video_format->iformat && self->video_format->iformat->priv_class && self->video_format->priv_data ) apply_properties( self->video_format->priv_data, properties, AV_OPT_FLAG_DECODING_PARAM ); } #if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) av_dict_free( ¶ms ); #else // Cleanup AVFormatParameters if ( params.standard ) free( (void*) params.standard ); #endif // If successful, then try to get additional info if ( !error && self->video_format ) { // Get the stream info #if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) error = avformat_find_stream_info( self->video_format, NULL ) < 0; #else error = av_find_stream_info( self->video_format ) < 0; #endif // Continue if no error if ( !error && self->video_format ) { // Find default audio and video streams find_default_streams( self ); error = get_basic_info( self, profile, filename ); // Initialize position info self->first_pts = AV_NOPTS_VALUE; self->last_position = POSITION_INITIAL; if ( !self->audio_format ) { // We're going to cheat here - for seekable A/V files, we will have separate contexts // to support independent seeking of audio from video. // TODO: Is this really necessary? if ( self->audio_index != -1 && self->video_index != -1 ) { if ( self->seekable ) { // And open again for our audio context #if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) avformat_open_input( &self->audio_format, filename, NULL, NULL ); apply_properties( self->audio_format, properties, AV_OPT_FLAG_DECODING_PARAM ); if ( self->audio_format->iformat && self->audio_format->iformat->priv_class && self->audio_format->priv_data ) apply_properties( self->audio_format->priv_data, properties, AV_OPT_FLAG_DECODING_PARAM ); avformat_find_stream_info( self->audio_format, NULL ); #else av_open_input_file( &self->audio_format, filename, NULL, 0, NULL ); apply_properties( self->audio_format, properties, AV_OPT_FLAG_DECODING_PARAM ); #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(110<<8)+0) if ( self->audio_format->iformat && self->audio_format->iformat->priv_class && self->audio_format->priv_data ) apply_properties( self->audio_format->priv_data, properties, AV_OPT_FLAG_DECODING_PARAM ); #endif av_find_stream_info( self->audio_format ); #endif } else { self->audio_format = self->video_format; } } else if ( self->audio_index != -1 ) { // We only have an audio context self->audio_format = self->video_format; self->video_format = NULL; } else if ( self->video_index == -1 ) { // Something has gone wrong error = -1; } if ( self->audio_format && !self->audio_streams ) get_audio_streams_info( self ); } } } if ( filename ) free( filename ); if ( !error ) { self->apackets = mlt_deque_init(); self->vpackets = mlt_deque_init(); } if ( self->dummy_context ) { pthread_mutex_lock( &self->open_mutex ); #if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(17<<8)+0) avformat_close_input( &self->dummy_context ); #else av_close_input_file( self->dummy_context ); #endif self->dummy_context = NULL; pthread_mutex_unlock( &self->open_mutex ); } // Unlock the service if ( take_lock ) { pthread_mutex_unlock( &self->audio_mutex ); pthread_mutex_unlock( &self->video_mutex ); } mlt_events_unblock( properties, self->parent ); return error; } static void prepare_reopen( producer_avformat self ) { mlt_service_lock( MLT_PRODUCER_SERVICE( self->parent ) ); pthread_mutex_lock( &self->audio_mutex ); pthread_mutex_lock( &self->open_mutex ); int i; for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) { mlt_pool_release( self->audio_buffer[i] ); self->audio_buffer[i] = NULL; av_free( self->decode_buffer[i] ); self->decode_buffer[i] = NULL; if ( self->audio_codec[i] ) avcodec_close( self->audio_codec[i] ); self->audio_codec[i] = NULL; } if ( self->video_codec ) avcodec_close( self->video_codec ); self->video_codec = NULL; #if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(17<<8)+0) if ( self->seekable && self->audio_format ) avformat_close_input( &self->audio_format ); if ( self->video_format ) avformat_close_input( &self->video_format ); #else if ( self->seekable && self->audio_format ) av_close_input_file( self->audio_format ); if ( self->video_format ) av_close_input_file( self->video_format ); #endif self->audio_format = NULL; self->video_format = NULL; pthread_mutex_unlock( &self->open_mutex ); // Cleanup the packet queues AVPacket *pkt; if ( self->apackets ) { while ( ( pkt = mlt_deque_pop_back( self->apackets ) ) ) { av_free_packet( pkt ); free( pkt ); } mlt_deque_close( self->apackets ); self->apackets = NULL; } if ( self->vpackets ) { while ( ( pkt = mlt_deque_pop_back( self->vpackets ) ) ) { av_free_packet( pkt ); free( pkt ); } mlt_deque_close( self->vpackets ); self->vpackets = NULL; } pthread_mutex_unlock( &self->audio_mutex ); mlt_service_unlock( MLT_PRODUCER_SERVICE( self->parent ) ); } static int64_t best_pts( producer_avformat self, int64_t pts, int64_t dts ) { self->invalid_pts_counter += pts == AV_NOPTS_VALUE; self->invalid_dts_counter += dts == AV_NOPTS_VALUE; if ( ( self->invalid_pts_counter <= self->invalid_dts_counter || dts == AV_NOPTS_VALUE ) && pts != AV_NOPTS_VALUE ) return pts; else return dts; } static void find_first_pts( producer_avformat self, int video_index ) { // find initial PTS AVFormatContext *context = self->video_format? self->video_format : self->audio_format; int ret = 0; int toscan = 500; AVPacket pkt; while ( ret >= 0 && toscan-- > 0 ) { ret = av_read_frame( context, &pkt ); if ( ret >= 0 && pkt.stream_index == video_index && ( pkt.flags & PKT_FLAG_KEY ) ) { mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "first_pts %"PRId64" dts %"PRId64" pts_dts_delta %d\n", pkt.pts, pkt.dts, (int)(pkt.pts - pkt.dts) ); self->first_pts = best_pts( self, pkt.pts, pkt.dts ); if ( self->first_pts != AV_NOPTS_VALUE ) toscan = 0; } av_free_packet( &pkt ); } av_seek_frame( context, -1, 0, AVSEEK_FLAG_BACKWARD ); } static int seek_video( producer_avformat self, mlt_position position, int64_t req_position, int preseek ) { mlt_producer producer = self->parent; int paused = 0; if ( self->seekable && ( position != self->video_expected || self->last_position < 0 ) ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); // Fetch the video format context AVFormatContext *context = self->video_format; // Get the video stream AVStream *stream = context->streams[ self->video_index ]; // Get codec context AVCodecContext *codec_context = stream->codec; // We may want to use the source fps if available double source_fps = mlt_properties_get_double( properties, "meta.media.frame_rate_num" ) / mlt_properties_get_double( properties, "meta.media.frame_rate_den" ); if ( self->last_position == POSITION_INITIAL ) find_first_pts( self, self->video_index ); if ( self->video_frame && position + 1 == self->video_expected ) { // We're paused - use last image paused = 1; } else if ( self->seekable && ( position < self->video_expected || position - self->video_expected >= 12 || self->last_position < 0 ) ) { // Calculate the timestamp for the requested frame int64_t timestamp = req_position / ( av_q2d( self->video_time_base ) * source_fps ); if ( req_position <= 0 ) timestamp = 0; else if ( self->first_pts != AV_NOPTS_VALUE ) timestamp += self->first_pts; else if ( context->start_time != AV_NOPTS_VALUE ) timestamp += context->start_time; if ( preseek && av_q2d( self->video_time_base ) != 0 ) timestamp -= 2 / av_q2d( self->video_time_base ); if ( timestamp < 0 ) timestamp = 0; mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "seeking timestamp %"PRId64" position " MLT_POSITION_FMT " expected "MLT_POSITION_FMT" last_pos %"PRId64"\n", timestamp, position, self->video_expected, self->last_position ); // Seek to the timestamp codec_context->skip_loop_filter = AVDISCARD_NONREF; av_seek_frame( context, self->video_index, timestamp, AVSEEK_FLAG_BACKWARD ); // flush any pictures still in decode buffer avcodec_flush_buffers( codec_context ); // Remove the cached info relating to the previous position self->current_position = POSITION_INVALID; self->last_position = POSITION_INVALID; av_freep( &self->video_frame ); } } return paused; } /** Convert a frame position to a time code. */ static double producer_time_of_frame( mlt_producer producer, mlt_position position ) { return ( double )position / mlt_producer_get_fps( producer ); } // Collect information about all audio streams static void get_audio_streams_info( producer_avformat self ) { // Fetch the audio format context AVFormatContext *context = self->audio_format; int i; for ( i = 0; i < context->nb_streams; i++ ) { if ( context->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO ) { AVCodecContext *codec_context = context->streams[i]->codec; AVCodec *codec = avcodec_find_decoder( codec_context->codec_id ); // If we don't have a codec and we can't initialise it, we can't do much more... pthread_mutex_lock( &self->open_mutex ); #if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) if ( codec && avcodec_open2( codec_context, codec, NULL ) >= 0 ) #else if ( codec && avcodec_open( codec_context, codec ) >= 0 ) #endif { self->audio_streams++; self->audio_max_stream = i; self->total_channels += codec_context->channels; if ( codec_context->channels > self->max_channel ) self->max_channel = codec_context->channels; if ( codec_context->sample_rate > self->max_frequency ) self->max_frequency = codec_context->sample_rate; avcodec_close( codec_context ); } pthread_mutex_unlock( &self->open_mutex ); } } mlt_log_verbose( NULL, "[producer avformat] audio: total_streams %d max_stream %d total_channels %d max_channels %d\n", self->audio_streams, self->audio_max_stream, self->total_channels, self->max_channel ); } static void set_luma_transfer( struct SwsContext *context, int colorspace, int use_full_range ) { int *coefficients; const int *new_coefficients; int full_range; int brightness, contrast, saturation; if ( sws_getColorspaceDetails( context, &coefficients, &full_range, &coefficients, &full_range, &brightness, &contrast, &saturation ) != -1 ) { // Don't change these from defaults unless explicitly told to. if ( use_full_range >= 0 ) full_range = use_full_range; switch ( colorspace ) { case 170: case 470: case 601: case 624: new_coefficients = sws_getCoefficients( SWS_CS_ITU601 ); break; case 240: new_coefficients = sws_getCoefficients( SWS_CS_SMPTE240M ); break; case 709: new_coefficients = sws_getCoefficients( SWS_CS_ITU709 ); break; default: new_coefficients = coefficients; break; } sws_setColorspaceDetails( context, new_coefficients, full_range, new_coefficients, full_range, brightness, contrast, saturation ); } } static mlt_image_format pick_pix_format( enum PixelFormat pix_fmt ) { switch ( pix_fmt ) { case PIX_FMT_ARGB: case PIX_FMT_RGBA: case PIX_FMT_ABGR: case PIX_FMT_BGRA: return mlt_image_rgb24a; case PIX_FMT_YUV420P: case PIX_FMT_YUVJ420P: case PIX_FMT_YUVA420P: return mlt_image_yuv420p; case PIX_FMT_RGB24: case PIX_FMT_BGR24: case PIX_FMT_GRAY8: case PIX_FMT_MONOWHITE: case PIX_FMT_MONOBLACK: case PIX_FMT_RGB8: case PIX_FMT_BGR8: return mlt_image_rgb24; default: return mlt_image_yuv422; } } static mlt_audio_format pick_audio_format( int sample_fmt ) { switch ( sample_fmt ) { // interleaved case AV_SAMPLE_FMT_U8: return mlt_audio_u8; case AV_SAMPLE_FMT_S16: return mlt_audio_s16; case AV_SAMPLE_FMT_S32: return mlt_audio_s32le; case AV_SAMPLE_FMT_FLT: return mlt_audio_f32le; // planar - this producer converts planar to interleaved #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(17<<8)+0) case AV_SAMPLE_FMT_U8P: return mlt_audio_u8; case AV_SAMPLE_FMT_S16P: return mlt_audio_s16; case AV_SAMPLE_FMT_S32P: return mlt_audio_s32le; case AV_SAMPLE_FMT_FLTP: return mlt_audio_f32le; #endif default: return mlt_audio_none; } } static void convert_image( producer_avformat self, AVFrame *frame, uint8_t *buffer, int pix_fmt, mlt_image_format *format, int width, int height, uint8_t **alpha ) { int flags = SWS_BICUBIC | SWS_ACCURATE_RND; #ifdef USE_MMX flags |= SWS_CPU_CAPS_MMX; #endif #ifdef USE_SSE flags |= SWS_CPU_CAPS_MMX2; #endif // extract alpha from planar formats if ( ( pix_fmt == PIX_FMT_YUVA420P #if defined(FFUDIV) && LIBAVUTIL_VERSION_INT >= ((51<<16)+(35<<8)+101) || pix_fmt == PIX_FMT_YUVA444P #endif ) && *format != mlt_image_rgb24a && *format != mlt_image_opengl && frame->data[3] && frame->linesize[3] ) { int i; uint8_t *src, *dst; dst = *alpha = mlt_pool_alloc( width * height ); src = frame->data[3]; for ( i = 0; i < height; dst += width, src += frame->linesize[3], i++ ) memcpy( dst, src, FFMIN( width, frame->linesize[3] ) ); } if ( *format == mlt_image_yuv420p ) { struct SwsContext *context = sws_getContext( width, height, pix_fmt, width, height, PIX_FMT_YUV420P, flags, NULL, NULL, NULL); AVPicture output; output.data[0] = buffer; output.data[1] = buffer + width * height; output.data[2] = buffer + ( 5 * width * height ) / 4; output.linesize[0] = width; output.linesize[1] = width >> 1; output.linesize[2] = width >> 1; set_luma_transfer( context, self->colorspace, -1 ); sws_scale( context, (const uint8_t* const*) frame->data, frame->linesize, 0, height, output.data, output.linesize); sws_freeContext( context ); } else if ( *format == mlt_image_rgb24 ) { struct SwsContext *context = sws_getContext( width, height, pix_fmt, width, height, PIX_FMT_RGB24, flags | SWS_FULL_CHR_H_INT, NULL, NULL, NULL); AVPicture output; avpicture_fill( &output, buffer, PIX_FMT_RGB24, width, height ); set_luma_transfer( context, self->colorspace, self->full_luma ); sws_scale( context, (const uint8_t* const*) frame->data, frame->linesize, 0, height, output.data, output.linesize); sws_freeContext( context ); } else if ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) { struct SwsContext *context = sws_getContext( width, height, pix_fmt, width, height, PIX_FMT_RGBA, flags | SWS_FULL_CHR_H_INT, NULL, NULL, NULL); AVPicture output; avpicture_fill( &output, buffer, PIX_FMT_RGBA, width, height ); set_luma_transfer( context, self->colorspace, self->full_luma ); sws_scale( context, (const uint8_t* const*) frame->data, frame->linesize, 0, height, output.data, output.linesize); sws_freeContext( context ); } else { struct SwsContext *context = sws_getContext( width, height, pix_fmt, width, height, PIX_FMT_YUYV422, flags | SWS_FULL_CHR_H_INP, NULL, NULL, NULL); AVPicture output; avpicture_fill( &output, buffer, PIX_FMT_YUYV422, width, height ); set_luma_transfer( context, self->colorspace, -1 ); sws_scale( context, (const uint8_t* const*) frame->data, frame->linesize, 0, height, output.data, output.linesize); sws_freeContext( context ); } } /** Allocate the image buffer and set it on the frame. */ static int allocate_buffer( mlt_frame frame, AVCodecContext *codec_context, uint8_t **buffer, mlt_image_format *format, int *width, int *height ) { int size = 0; if ( codec_context->width == 0 || codec_context->height == 0 ) return size; if ( *format == mlt_image_glsl ) *format = pick_pix_format( codec_context->pix_fmt ); *width = codec_context->width; *height = codec_context->height; size = mlt_image_format_size( *format, *width, *height, NULL ); *buffer = mlt_pool_alloc( size ); if ( *buffer ) mlt_frame_set_image( frame, *buffer, size, mlt_pool_release ); else size = 0; return size; } /** Get an image from a frame. */ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { // Get the producer producer_avformat self = mlt_frame_pop_service( frame ); mlt_producer producer = self->parent; // Get the properties from the frame mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); // Obtain the frame number of this frame mlt_position position = mlt_frame_original_position( frame ); // Get the producer properties mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); pthread_mutex_lock( &self->video_mutex ); uint8_t *alpha = NULL; int got_picture = 0; int image_size = 0; // Fetch the video format context AVFormatContext *context = self->video_format; if ( !context ) goto exit_get_image; // Get the video stream AVStream *stream = context->streams[ self->video_index ]; // Get codec context AVCodecContext *codec_context = stream->codec; // Get the image cache if ( ! self->image_cache ) { // if cache size supplied by environment variable int cache_supplied = getenv( "MLT_AVFORMAT_CACHE" ) != NULL; int cache_size = cache_supplied? atoi( getenv( "MLT_AVFORMAT_CACHE" ) ) : 0; // cache size supplied via property if ( mlt_properties_get( properties, "cache" ) ) { cache_supplied = 1; cache_size = mlt_properties_get_int( properties, "cache" ); } if ( mlt_properties_get_int( properties, "noimagecache" ) ) cache_size = 0; // create cache if not disabled if ( !cache_supplied || cache_size > 0 ) self->image_cache = mlt_cache_init(); // set cache size if supplied if ( self->image_cache && cache_supplied ) mlt_cache_set_size( self->image_cache, cache_size ); } if ( self->image_cache ) { mlt_frame original = mlt_cache_get_frame( self->image_cache, position ); if ( original ) { mlt_properties orig_props = MLT_FRAME_PROPERTIES( original ); int size = 0; *buffer = mlt_properties_get_data( orig_props, "alpha", &size ); if (*buffer) mlt_frame_set_alpha( frame, *buffer, size, NULL ); *buffer = mlt_properties_get_data( orig_props, "image", &size ); mlt_frame_set_image( frame, *buffer, size, NULL ); mlt_properties_set_data( frame_properties, "avformat.image_cache", original, 0, (mlt_destructor) mlt_frame_close, NULL ); *format = mlt_properties_get_int( orig_props, "format" ); // Set the resolution *width = codec_context->width; *height = codec_context->height; // Workaround 1088 encodings missing cropping info. if ( *height == 1088 && mlt_profile_dar( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) ) == 16.0/9.0 ) *height = 1080; got_picture = 1; goto exit_get_image; } } // Cache miss // We may want to use the source fps if available double source_fps = mlt_properties_get_double( properties, "meta.media.frame_rate_num" ) / mlt_properties_get_double( properties, "meta.media.frame_rate_den" ); // This is the physical frame position in the source int64_t req_position = ( int64_t )( position / mlt_producer_get_fps( producer ) * source_fps + 0.5 ); // Determines if we have to decode all frames in a sequence // Temporary hack to improve intra frame only int must_decode = !( codec_context->codec && codec_context->codec->name ) || ( strcmp( codec_context->codec->name, "dnxhd" ) && strcmp( codec_context->codec->name, "dvvideo" ) && strcmp( codec_context->codec->name, "huffyuv" ) && strcmp( codec_context->codec->name, "mjpeg" ) && strcmp( codec_context->codec->name, "rawvideo" ) ); double delay = mlt_properties_get_double( properties, "video_delay" ); // Seek if necessary const char *interp = mlt_properties_get( frame_properties, "rescale.interp" ); int preseek = must_decode #if defined(FFUDIV) && LIBAVFORMAT_VERSION_INT >= ((53<<16)+(24<<8)+2) && ( interp && strcmp( interp, "nearest" ) ) #endif && codec_context->has_b_frames; int paused = seek_video( self, position, req_position, preseek ); // Seek might have reopened the file context = self->video_format; stream = context->streams[ self->video_index ]; codec_context = stream->codec; if ( *format == mlt_image_none || codec_context->pix_fmt == PIX_FMT_ARGB || codec_context->pix_fmt == PIX_FMT_RGBA || codec_context->pix_fmt == PIX_FMT_ABGR || codec_context->pix_fmt == PIX_FMT_BGRA ) *format = pick_pix_format( codec_context->pix_fmt ); // Duplicate the last image if necessary if ( self->video_frame && self->video_frame->linesize[0] && ( paused || self->current_position >= req_position ) ) { // Duplicate it if ( ( image_size = allocate_buffer( frame, codec_context, buffer, format, width, height ) ) ) { // Workaround 1088 encodings missing cropping info. if ( *height == 1088 && mlt_profile_dar( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) ) == 16.0/9.0 ) *height = 1080; #ifdef VDPAU if ( self->vdpau && self->vdpau->buffer ) { AVPicture picture; picture.data[0] = self->vdpau->buffer; picture.data[2] = self->vdpau->buffer + codec_context->width * codec_context->height; picture.data[1] = self->vdpau->buffer + codec_context->width * codec_context->height * 5 / 4; picture.linesize[0] = codec_context->width; picture.linesize[1] = codec_context->width / 2; picture.linesize[2] = codec_context->width / 2; convert_image( self, (AVFrame*) &picture, *buffer, PIX_FMT_YUV420P, format, *width, *height, &alpha ); } else #endif convert_image( self, self->video_frame, *buffer, codec_context->pix_fmt, format, *width, *height, &alpha ); got_picture = 1; } } else { int ret = 0; int64_t int_position = 0; int decode_errors = 0; // Construct an AVFrame for YUV422 conversion if ( !self->video_frame ) self->video_frame = avcodec_alloc_frame( ); while( ret >= 0 && !got_picture ) { // Read a packet if ( self->pkt.stream_index == self->video_index ) av_free_packet( &self->pkt ); av_init_packet( &self->pkt ); pthread_mutex_lock( &self->packets_mutex ); if ( mlt_deque_count( self->vpackets ) ) { AVPacket *tmp = (AVPacket*) mlt_deque_pop_front( self->vpackets ); self->pkt = *tmp; free( tmp ); } else { ret = av_read_frame( context, &self->pkt ); if ( ret >= 0 && !self->seekable && self->pkt.stream_index == self->audio_index ) { if ( !av_dup_packet( &self->pkt ) ) { AVPacket *tmp = malloc( sizeof(AVPacket) ); *tmp = self->pkt; mlt_deque_push_back( self->apackets, tmp ); } } else if ( ret < 0 ) { mlt_log_verbose( MLT_PRODUCER_SERVICE(producer), "av_read_frame returned error %d inside get_image\n", ret ); if ( !self->seekable && mlt_properties_get_int( properties, "reconnect" ) ) { // Try to reconnect to live sources by closing context and codecs, // and letting next call to get_frame() reopen. prepare_reopen( self ); pthread_mutex_unlock( &self->packets_mutex ); goto exit_get_image; } if ( !self->seekable && mlt_properties_get_int( properties, "exit_on_disconnect" ) ) { mlt_log_fatal( MLT_PRODUCER_SERVICE(producer), "Exiting with error due to disconnected source.\n" ); exit( EXIT_FAILURE ); } } } pthread_mutex_unlock( &self->packets_mutex ); // We only deal with video from the selected video_index if ( ret >= 0 && self->pkt.stream_index == self->video_index && self->pkt.size > 0 ) { int64_t pts = best_pts( self, self->pkt.pts, self->pkt.dts ); if ( pts != AV_NOPTS_VALUE ) { if ( !self->seekable && self->first_pts == AV_NOPTS_VALUE ) self->first_pts = pts; if ( self->first_pts != AV_NOPTS_VALUE ) pts -= self->first_pts; else if ( context->start_time != AV_NOPTS_VALUE ) pts -= context->start_time; int_position = ( int64_t )( ( av_q2d( self->video_time_base ) * pts + delay ) * source_fps + 0.5 ); if ( int_position == self->last_position ) int_position = self->last_position + 1; } mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "V pkt.pts %"PRId64" pkt.dts %"PRId64" req_pos %"PRId64" cur_pos %"PRId64" pkt_pos %"PRId64"\n", self->pkt.pts, self->pkt.dts, req_position, self->current_position, int_position ); // Make a dumb assumption on streams that contain wild timestamps if ( abs( req_position - int_position ) > 999 ) { int_position = req_position; mlt_log_warning( MLT_PRODUCER_SERVICE(producer), " WILD TIMESTAMP!\n" ); } self->last_position = int_position; // Decode the image if ( must_decode || int_position >= req_position ) { #ifdef VDPAU if ( self->vdpau ) { if ( self->vdpau->decoder == VDP_INVALID_HANDLE ) { vdpau_decoder_init( self ); } self->vdpau->is_decoded = 0; } #endif codec_context->reordered_opaque = int_position; if ( int_position >= req_position ) codec_context->skip_loop_filter = AVDISCARD_NONE; #if (LIBAVCODEC_VERSION_INT >= ((52<<16)+(26<<8)+0)) ret = avcodec_decode_video2( codec_context, self->video_frame, &got_picture, &self->pkt ); #else ret = avcodec_decode_video( codec_context, self->video_frame, &got_picture, self->pkt.data, self->pkt.size ); #endif // Note: decode may fail at the beginning of MPEGfile (B-frames referencing before first I-frame), so allow a few errors. if ( ret < 0 ) { if ( ++decode_errors <= 10 ) ret = 0; else mlt_log_warning( MLT_PRODUCER_SERVICE(producer), "video decoding error %d\n", ret ); } else { decode_errors = 0; } } if ( got_picture ) { // Get position of reordered frame int_position = self->video_frame->reordered_opaque; #if (LIBAVCODEC_VERSION_INT >= ((52<<16)+(106<<8)+0)) pts = best_pts( self, self->video_frame->pkt_pts, self->video_frame->pkt_dts ); if ( pts != AV_NOPTS_VALUE ) { if ( self->first_pts != AV_NOPTS_VALUE ) pts -= self->first_pts; else if ( context->start_time != AV_NOPTS_VALUE ) pts -= context->start_time; int_position = ( int64_t )( ( av_q2d( self->video_time_base ) * pts + delay ) * source_fps + 0.5 ); } #endif if ( int_position < req_position ) got_picture = 0; else if ( int_position >= req_position ) codec_context->skip_loop_filter = AVDISCARD_NONE; } mlt_log_debug( MLT_PRODUCER_SERVICE(producer), " got_pic %d key %d\n", got_picture, self->pkt.flags & PKT_FLAG_KEY ); } // Now handle the picture if we have one if ( got_picture ) { if ( ( image_size = allocate_buffer( frame, codec_context, buffer, format, width, height ) ) ) { // Workaround 1088 encodings missing cropping info. if ( *height == 1088 && mlt_profile_dar( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) ) == 16.0/9.0 ) *height = 1080; #ifdef VDPAU if ( self->vdpau ) { if ( self->vdpau->is_decoded ) { struct vdpau_render_state *render = (struct vdpau_render_state*) self->video_frame->data[0]; void *planes[3]; uint32_t pitches[3]; VdpYCbCrFormat dest_format = VDP_YCBCR_FORMAT_YV12; if ( !self->vdpau->buffer ) self->vdpau->buffer = mlt_pool_alloc( codec_context->width * codec_context->height * 3 / 2 ); self->video_frame->data[0] = planes[0] = self->vdpau->buffer; self->video_frame->data[2] = planes[1] = self->vdpau->buffer + codec_context->width * codec_context->height; self->video_frame->data[1] = planes[2] = self->vdpau->buffer + codec_context->width * codec_context->height * 5 / 4; self->video_frame->linesize[0] = pitches[0] = codec_context->width; self->video_frame->linesize[1] = pitches[1] = codec_context->width / 2; self->video_frame->linesize[2] = pitches[2] = codec_context->width / 2; VdpStatus status = vdp_surface_get_bits( render->surface, dest_format, planes, pitches ); if ( status == VDP_STATUS_OK ) { convert_image( self, self->video_frame, *buffer, PIX_FMT_YUV420P, format, *width, *height, &alpha ); } else { mlt_log_error( MLT_PRODUCER_SERVICE(producer), "VDPAU Error: %s\n", vdp_get_error_string( status ) ); image_size = self->vdpau->is_decoded = 0; } } else { mlt_log_error( MLT_PRODUCER_SERVICE(producer), "VDPAU error in VdpDecoderRender\n" ); image_size = got_picture = 0; } } else #endif convert_image( self, self->video_frame, *buffer, codec_context->pix_fmt, format, *width, *height, &alpha ); self->top_field_first |= self->video_frame->top_field_first; self->current_position = int_position; } else { got_picture = 0; } } // Free packet data if not video and not live audio packet if ( self->pkt.stream_index != self->video_index && !( !self->seekable && self->pkt.stream_index == self->audio_index ) ) av_free_packet( &self->pkt ); } } // set alpha if ( alpha ) mlt_frame_set_alpha( frame, alpha, (*width) * (*height), mlt_pool_release ); if ( image_size > 0 && self->image_cache ) { mlt_properties_set_int( frame_properties, "format", *format ); mlt_cache_put_frame( self->image_cache, frame ); } // Try to duplicate last image if there was a decoding failure // TODO: with multithread decoding a partial frame decoding resulting // in failure also resets av_frame making test below fail. if ( !image_size && self->video_frame && self->video_frame->linesize[0] ) { // Duplicate it if ( ( image_size = allocate_buffer( frame, codec_context, buffer, format, width, height ) ) ) { // Workaround 1088 encodings missing cropping info. if ( *height == 1088 && mlt_profile_dar( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) ) == 16.0/9.0 ) *height = 1080; #ifdef VDPAU if ( self->vdpau && self->vdpau->buffer ) { AVPicture picture; picture.data[0] = self->vdpau->buffer; picture.data[2] = self->vdpau->buffer + codec_context->width * codec_context->height; picture.data[1] = self->vdpau->buffer + codec_context->width * codec_context->height * 5 / 4; picture.linesize[0] = codec_context->width; picture.linesize[1] = codec_context->width / 2; picture.linesize[2] = codec_context->width / 2; convert_image( self, (AVFrame*) &picture, *buffer, PIX_FMT_YUV420P, format, *width, *height, &alpha ); } else #endif convert_image( self, self->video_frame, *buffer, codec_context->pix_fmt, format, *width, *height, &alpha ); got_picture = 1; } } // Regardless of speed, we expect to get the next frame (cos we ain't too bright) self->video_expected = position + 1; exit_get_image: pthread_mutex_unlock( &self->video_mutex ); // Set the progressive flag if ( mlt_properties_get( properties, "force_progressive" ) ) mlt_properties_set_int( frame_properties, "progressive", !!mlt_properties_get_int( properties, "force_progressive" ) ); else if ( self->video_frame ) mlt_properties_set_int( frame_properties, "progressive", !self->video_frame->interlaced_frame ); // Set the field order property for this frame if ( mlt_properties_get( properties, "force_tff" ) ) mlt_properties_set_int( frame_properties, "top_field_first", !!mlt_properties_get_int( properties, "force_tff" ) ); else mlt_properties_set_int( frame_properties, "top_field_first", self->top_field_first ); // Set immutable properties of the selected track's (or overridden) source attributes. mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); mlt_properties_set_int( properties, "meta.media.top_field_first", self->top_field_first ); mlt_properties_set_int( properties, "meta.media.progressive", mlt_properties_get_int( frame_properties, "progressive" ) ); mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); // If we already have RGB, then the full range processing either happened already // or does not apply (RGB source). if ( *format == mlt_image_rgb24 || *format == mlt_image_rgb24a || *format == mlt_image_opengl ) mlt_properties_set( frame_properties, "force_full_luma", NULL ); return !got_picture; } /** Process properties as AVOptions and apply to AV context obj */ static void apply_properties( void *obj, mlt_properties properties, int flags ) { int i; int count = mlt_properties_count( properties ); for ( i = 0; i < count; i++ ) { const char *opt_name = mlt_properties_get_name( properties, i ); #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(10<<8)+0) const AVOption *opt = av_opt_find( obj, opt_name, NULL, flags, flags ); #else const AVOption *opt = av_find_opt( obj, opt_name, NULL, flags, flags ); #endif if ( opt_name && mlt_properties_get( properties, opt_name ) ) { if ( opt ) #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(12<<8)+0) av_opt_set( obj, opt_name, mlt_properties_get( properties, opt_name), 0 ); #elif LIBAVCODEC_VERSION_INT >= ((52<<16)+(7<<8)+0) av_set_string3( obj, opt_name, mlt_properties_get( properties, opt_name), 0, NULL ); #elif LIBAVCODEC_VERSION_INT >= ((51<<16)+(59<<8)+0) av_set_string2( obj, opt_name, mlt_properties_get( properties, opt_name), 0 ); #else av_set_string( obj, opt_name, mlt_properties_get( properties, opt_name) ); #endif } } } /** Initialize the video codec context. */ static int video_codec_init( producer_avformat self, int index, mlt_properties properties ) { // Initialise the codec if necessary if ( !self->video_codec ) { // Get the video stream AVStream *stream = self->video_format->streams[ index ]; // Get codec context AVCodecContext *codec_context = stream->codec; // Find the codec AVCodec *codec = avcodec_find_decoder( codec_context->codec_id ); #ifdef VDPAU if ( codec_context->codec_id == AV_CODEC_ID_H264 ) { if ( ( codec = avcodec_find_decoder_by_name( "h264_vdpau" ) ) ) { if ( vdpau_init( self ) ) { self->video_codec = codec_context; if ( !vdpau_decoder_init( self ) ) vdpau_fini( self ); } } if ( !self->vdpau ) codec = avcodec_find_decoder( codec_context->codec_id ); } #endif // Initialise multi-threading int thread_count = mlt_properties_get_int( properties, "threads" ); if ( thread_count == 0 && getenv( "MLT_AVFORMAT_THREADS" ) ) thread_count = atoi( getenv( "MLT_AVFORMAT_THREADS" ) ); if ( thread_count > 1 ) codec_context->thread_count = thread_count; // If we don't have a codec and we can't initialise it, we can't do much more... pthread_mutex_lock( &self->open_mutex ); #if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) if ( codec && avcodec_open2( codec_context, codec, NULL ) >= 0 ) #else if ( codec && avcodec_open( codec_context, codec ) >= 0 ) #endif { // Now store the codec with its destructor self->video_codec = codec_context; } else { // Remember that we can't use this later self->video_index = -1; pthread_mutex_unlock( &self->open_mutex ); return 0; } pthread_mutex_unlock( &self->open_mutex ); // Process properties as AVOptions apply_properties( codec_context, properties, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM ); #if LIBAVCODEC_VERSION_INT >= ((52<<16)+(122<<8)+0) if ( codec->priv_class && codec_context->priv_data ) apply_properties( codec_context->priv_data, properties, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM ); #endif // Reset some image properties if ( self->video_codec ) { mlt_properties_set_int( properties, "width", self->video_codec->width ); mlt_properties_set_int( properties, "height", self->video_codec->height ); get_aspect_ratio( properties, stream, self->video_codec ); } // Start with the muxer frame rate. #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(42<<8)+0) AVRational frame_rate = stream->avg_frame_rate; #else AVRational frame_rate = stream->r_frame_rate; #endif double fps = av_q2d( frame_rate ); #if LIBAVFORMAT_VERSION_MAJOR < 55 // Verify and sanitize the muxer frame rate. if ( isnan( fps ) || isinf( fps ) || fps == 0 ) { frame_rate = stream->r_frame_rate; fps = av_q2d( frame_rate ); } #endif #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(42<<8)+0) && LIBAVFORMAT_VERSION_MAJOR < 55 // With my samples when r_frame_rate != 1000 but avg_frame_rate is valid, // avg_frame_rate gives some approximate value that does not well match the media. // Also, on my sample where r_frame_rate = 1000, using avg_frame_rate directly // results in some very choppy output, but some value slightly different works // great. if ( av_q2d( stream->r_frame_rate ) >= 1000 && av_q2d( stream->avg_frame_rate ) > 0 ) { frame_rate = av_d2q( av_q2d( stream->avg_frame_rate ), 1024 ); fps = av_q2d( frame_rate ); } #endif // XXX frame rates less than 1 fps are not considered sane if ( isnan( fps ) || isinf( fps ) || fps < 1.0 ) { // Get the frame rate from the codec. frame_rate.num = self->video_codec->time_base.den; frame_rate.den = self->video_codec->time_base.num * self->video_codec->ticks_per_frame; fps = av_q2d( frame_rate ); } if ( isnan( fps ) || isinf( fps ) || fps < 1.0 ) { // Use the profile frame rate if all else fails. mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( self->parent ) ); frame_rate.num = profile->frame_rate_num; frame_rate.den = profile->frame_rate_den; } self->video_time_base = stream->time_base; if ( mlt_properties_get( properties, "force_fps" ) ) { AVRational force_fps = av_d2q( mlt_properties_get_double( properties, "force_fps" ), 1024 ); self->video_time_base = av_mul_q( stream->time_base, av_div_q( frame_rate, force_fps ) ); frame_rate = force_fps; } mlt_properties_set_int( properties, "meta.media.frame_rate_num", frame_rate.num ); mlt_properties_set_int( properties, "meta.media.frame_rate_den", frame_rate.den ); // Set the YUV colorspace from override or detect self->colorspace = mlt_properties_get_int( properties, "force_colorspace" ); #if LIBAVCODEC_VERSION_INT > ((52<<16)+(28<<8)+0) if ( ! self->colorspace ) { switch ( self->video_codec->colorspace ) { case AVCOL_SPC_SMPTE240M: self->colorspace = 240; break; case AVCOL_SPC_BT470BG: case AVCOL_SPC_SMPTE170M: self->colorspace = 601; break; case AVCOL_SPC_BT709: self->colorspace = 709; break; default: // This is a heuristic Charles Poynton suggests in "Digital Video and HDTV" self->colorspace = self->video_codec->width * self->video_codec->height > 750000 ? 709 : 601; break; } } #endif // Let apps get chosen colorspace mlt_properties_set_int( properties, "meta.media.colorspace", self->colorspace ); self->full_luma = -1; #if LIBAVCODEC_VERSION_INT >= ((52<<16)+(72<<8)+2) mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "color_range %d\n", codec_context->color_range ); if ( codec_context->color_range == AVCOL_RANGE_JPEG ) self->full_luma = 1; #endif if ( mlt_properties_get( properties, "set.force_full_luma" ) ) self->full_luma = mlt_properties_get_int( properties, "set.force_full_luma" ); } return self->video_codec && self->video_index > -1; } /** Set up video handling. */ static void producer_set_up_video( producer_avformat self, mlt_frame frame ) { // Get the producer mlt_producer producer = self->parent; // Get the properties mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); // Fetch the video format context AVFormatContext *context = self->video_format; // Get the video_index int index = mlt_properties_get_int( properties, "video_index" ); int unlock_needed = 0; // Reopen the file if necessary if ( !context && index > -1 ) { unlock_needed = 1; pthread_mutex_lock( &self->video_mutex ); producer_open( self, mlt_service_profile( MLT_PRODUCER_SERVICE(producer) ), mlt_properties_get( properties, "resource" ), 0 ); context = self->video_format; } // Exception handling for video_index if ( context && index >= (int) context->nb_streams ) { // Get the last video stream for ( index = context->nb_streams - 1; index >= 0 && context->streams[ index ]->codec->codec_type != CODEC_TYPE_VIDEO; index-- ); mlt_properties_set_int( properties, "video_index", index ); } if ( context && index > -1 && context->streams[ index ]->codec->codec_type != CODEC_TYPE_VIDEO ) { // Invalidate the video stream index = -1; mlt_properties_set_int( properties, "video_index", index ); } // Update the video properties if the index changed if ( index != self->video_index ) { // Reset the video properties if the index changed self->video_index = index; pthread_mutex_lock( &self->open_mutex ); if ( self->video_codec ) avcodec_close( self->video_codec ); self->video_codec = NULL; pthread_mutex_unlock( &self->open_mutex ); } // Get the frame properties mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); // Get the codec if ( context && index > -1 && video_codec_init( self, index, properties ) ) { // Set the frame properties double force_aspect_ratio = mlt_properties_get_double( properties, "force_aspect_ratio" ); double aspect_ratio = ( force_aspect_ratio > 0.0 ) ? force_aspect_ratio : mlt_properties_get_double( properties, "aspect_ratio" ); // Set the width and height mlt_properties_set_int( frame_properties, "width", self->video_codec->width ); mlt_properties_set_int( frame_properties, "height", self->video_codec->height ); mlt_properties_set_int( properties, "meta.media.width", self->video_codec->width ); mlt_properties_set_int( properties, "meta.media.height", self->video_codec->height ); mlt_properties_set_double( frame_properties, "aspect_ratio", aspect_ratio ); mlt_properties_set_int( frame_properties, "colorspace", self->colorspace ); // Workaround 1088 encodings missing cropping info. if ( self->video_codec->height == 1088 && mlt_profile_dar( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) ) == 16.0/9.0 ) { mlt_properties_set_int( properties, "meta.media.height", 1080 ); } // Add our image operation mlt_frame_push_service( frame, self ); mlt_frame_push_get_image( frame, producer_get_image ); } else { // If something failed, use test card image mlt_properties_set_int( frame_properties, "test_image", 1 ); } if ( unlock_needed ) pthread_mutex_unlock( &self->video_mutex ); } static int seek_audio( producer_avformat self, mlt_position position, double timecode ) { int paused = 0; // Seek if necessary if ( self->seekable && ( position != self->audio_expected || self->last_position < 0 ) ) { if ( self->last_position == POSITION_INITIAL ) { int video_index = self->video_index; if ( video_index == -1 ) video_index = first_video_index( self ); if ( video_index >= 0 ) find_first_pts( self, video_index ); } if ( position + 1 == self->audio_expected ) { // We're paused - silence required paused = 1; } else if ( position < self->audio_expected || position - self->audio_expected >= 12 ) { AVFormatContext *context = self->audio_format; int64_t timestamp = ( int64_t )( timecode * AV_TIME_BASE + 0.5 ); if ( context->start_time != AV_NOPTS_VALUE ) timestamp += context->start_time; if ( timestamp < 0 ) timestamp = 0; // Set to the real timecode if ( av_seek_frame( context, -1, timestamp, AVSEEK_FLAG_BACKWARD ) != 0 ) paused = 1; // Clear the usage in the audio buffer int i = MAX_AUDIO_STREAMS + 1; while ( --i ) self->audio_used[i - 1] = 0; } } return paused; } static int sample_bytes( AVCodecContext *context ) { #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(8<<8)+0) return av_get_bytes_per_sample( context->sample_fmt ); #elif LIBAVCODEC_VERSION_MAJOR >= 53 return av_get_bits_per_sample_fmt( context->sample_fmt ) / 8; #else return av_get_bits_per_sample_format( context->sample_fmt ) / 8; #endif } static void planar_to_interleaved( uint8_t *dest, uint8_t *src, int samples, int channels, int bytes_per_sample ) { int s, c; for ( s = 0; s < samples; s++ ) { for ( c = 0; c < channels; c++ ) { memcpy( dest, src + ( c * samples + s ) * bytes_per_sample, bytes_per_sample ); dest += bytes_per_sample; } } } static void planar_to_interleaved2( uint8_t *dest, AVFrame *src, int samples, int channels, int bytes_per_sample ) { int s, c; for ( s = 0; s < samples; s++ ) { for ( c = 0; c < channels; c++ ) { memcpy( dest, &src->data[c][s * bytes_per_sample], bytes_per_sample ); dest += bytes_per_sample; } } } static int decode_audio( producer_avformat self, int *ignore, AVPacket pkt, int channels, int samples, double timecode, double fps ) { // Fetch the audio_format AVFormatContext *context = self->audio_format; // Get the current stream index int index = pkt.stream_index; // Get codec context AVCodecContext *codec_context = self->audio_codec[ index ]; // Obtain the audio buffers uint8_t *audio_buffer = self->audio_buffer[ index ]; uint8_t *decode_buffer = self->decode_buffer[ index ]; int audio_used = self->audio_used[ index ]; uint8_t *ptr = pkt.data; int len = pkt.size; int ret = 0; while ( ptr && ret >= 0 && len > 0 ) { int sizeof_sample = sample_bytes( codec_context ); int data_size = self->audio_buffer_size[ index ]; // Decode the audio #if LIBAVCODEC_VERSION_MAJOR >= 55 if ( !self->audio_frame ) self->audio_frame = avcodec_alloc_frame(); else avcodec_get_frame_defaults( self->audio_frame ); ret = avcodec_decode_audio4( codec_context, self->audio_frame, &data_size, &pkt ); if ( data_size ) { data_size = av_samples_get_buffer_size( NULL, codec_context->channels, self->audio_frame->nb_samples, codec_context->sample_fmt, 1 ); decode_buffer = self->audio_frame->data[0]; } #else ret = avcodec_decode_audio3( codec_context, (int16_t*) decode_buffer, &data_size, &pkt ); #endif if ( ret < 0 ) { mlt_log_warning( MLT_PRODUCER_SERVICE(self->parent), "audio decoding error %d\n", ret ); break; } pkt.size = len -= ret; pkt.data = ptr += ret; // If decoded successfully if ( data_size > 0 ) { // Figure out how many samples will be needed after resampling int convert_samples = data_size / codec_context->channels / sample_bytes( codec_context ); // Resize audio buffer to prevent overflow if ( ( audio_used + convert_samples ) * channels * sizeof_sample > self->audio_buffer_size[ index ] ) { self->audio_buffer_size[ index ] = ( audio_used + convert_samples * 2 ) * channels * sizeof_sample; audio_buffer = self->audio_buffer[ index ] = mlt_pool_realloc( audio_buffer, self->audio_buffer_size[ index ] ); } uint8_t *dest = &audio_buffer[ audio_used * codec_context->channels * sizeof_sample ]; switch ( codec_context->sample_fmt ) { #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(17<<8)+0) case AV_SAMPLE_FMT_U8P: case AV_SAMPLE_FMT_S16P: case AV_SAMPLE_FMT_S32P: case AV_SAMPLE_FMT_FLTP: #if LIBAVCODEC_VERSION_MAJOR >= 55 planar_to_interleaved2( dest, self->audio_frame, convert_samples, codec_context->channels, sizeof_sample ); #else planar_to_interleaved( dest, decode_buffer, convert_samples, codec_context->channels, sizeof_sample ); #endif break; #endif default: // Straight copy to audio buffer memcpy( dest, decode_buffer, data_size ); } audio_used += convert_samples; // Handle ignore while ( *ignore && audio_used ) { *ignore -= 1; audio_used -= audio_used > samples ? samples : audio_used; memmove( audio_buffer, &audio_buffer[ samples * codec_context->channels * sizeof_sample ], audio_used * sizeof_sample ); } } } // If we're behind, ignore this packet // Skip this on non-seekable, audio-only inputs. if ( pkt.pts >= 0 && ( self->seekable || self->video_format ) && *ignore == 0 && audio_used > samples / 2 ) { int64_t pts = pkt.pts; if ( self->first_pts != AV_NOPTS_VALUE ) pts -= self->first_pts; else if ( context->start_time != AV_NOPTS_VALUE ) pts -= context->start_time; double timebase = av_q2d( context->streams[ index ]->time_base ); int64_t int_position = ( int64_t )( timebase * pts * fps + 0.5 ); int64_t req_position = ( int64_t )( timecode * fps + 0.5 ); mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "A pkt.pts %"PRId64" pkt.dts %"PRId64" req_pos %"PRId64" cur_pos %"PRId64" pkt_pos %"PRId64"\n", pkt.pts, pkt.dts, req_position, self->current_position, int_position ); if ( int_position > 0 ) { if ( int_position < req_position ) // We are behind, so skip some *ignore = req_position - int_position; else if ( self->audio_index != INT_MAX && int_position > req_position + 2 ) // We are ahead, so seek backwards some more seek_audio( self, req_position, timecode - 1.0 ); } // Cancel the find_first_pts() in seek_audio() if ( self->video_index == -1 && self->last_position == POSITION_INITIAL ) self->last_position = int_position; } self->audio_used[ index ] = audio_used; return ret; } /** Get the audio from a frame. */ static int producer_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the producer producer_avformat self = mlt_frame_pop_audio( frame ); pthread_mutex_lock( &self->audio_mutex ); // Obtain the frame number of this frame mlt_position position = mlt_frame_original_position( frame ); // Calculate the real time code double real_timecode = producer_time_of_frame( self->parent, position ); // Get the producer fps double fps = mlt_producer_get_fps( self->parent ); // Number of frames to ignore (for ffwd) int ignore[ MAX_AUDIO_STREAMS ] = { 0 }; // Flag for paused (silence) int paused = seek_audio( self, position, real_timecode ); // Initialize ignore for all streams from the seek return value int i = MAX_AUDIO_STREAMS; while ( i-- ) ignore[i] = ignore[0]; // Fetch the audio_format AVFormatContext *context = self->audio_format; if ( !context ) goto exit_get_audio; int sizeof_sample = sizeof( int16_t ); // Determine the tracks to use int index = self->audio_index; int index_max = self->audio_index + 1; if ( self->audio_index == INT_MAX ) { index = 0; index_max = FFMIN( MAX_AUDIO_STREAMS, context->nb_streams ); *channels = self->total_channels; *samples = mlt_sample_calculator( fps, FFMAX( self->max_frequency, *frequency ), position ); *frequency = FFMAX( self->max_frequency, *frequency ); } // Initialize the buffers for ( ; index < index_max && index < MAX_AUDIO_STREAMS; index++ ) { // Get codec context AVCodecContext *codec_context = self->audio_codec[ index ]; if ( codec_context && !self->audio_buffer[ index ] ) { codec_context->request_channels = self->audio_index == INT_MAX ? codec_context->channels : *channels; sizeof_sample = sample_bytes( codec_context ); // Check for audio buffer and create if necessary self->audio_buffer_size[ index ] = MAX_AUDIO_FRAME_SIZE * sizeof_sample; self->audio_buffer[ index ] = mlt_pool_alloc( self->audio_buffer_size[ index ] ); // Check for decoder buffer and create if necessary self->decode_buffer[ index ] = av_malloc( self->audio_buffer_size[ index ] ); } } // Get the audio if required if ( !paused && *frequency > 0 ) { int ret = 0; int got_audio = 0; AVPacket pkt; av_init_packet( &pkt ); // Caller requested number samples based on requested sample rate. if ( self->audio_index != INT_MAX ) *samples = mlt_sample_calculator( fps, self->audio_codec[ self->audio_index ]->sample_rate, position ); while ( ret >= 0 && !got_audio ) { // Check if the buffer already contains the samples required if ( self->audio_index != INT_MAX && self->audio_used[ self->audio_index ] >= *samples && ignore[ self->audio_index ] == 0 ) { got_audio = 1; break; } else if ( self->audio_index == INT_MAX ) { // Check if there is enough audio for all streams got_audio = 1; for ( index = 0; got_audio && index < index_max; index++ ) if ( ( self->audio_codec[ index ] && self->audio_used[ index ] < *samples ) || ignore[ index ] ) got_audio = 0; if ( got_audio ) break; } // Read a packet pthread_mutex_lock( &self->packets_mutex ); if ( mlt_deque_count( self->apackets ) ) { AVPacket *tmp = (AVPacket*) mlt_deque_pop_front( self->apackets ); pkt = *tmp; free( tmp ); } else { ret = av_read_frame( context, &pkt ); if ( ret >= 0 && !self->seekable && pkt.stream_index == self->video_index ) { if ( !av_dup_packet( &pkt ) ) { AVPacket *tmp = malloc( sizeof(AVPacket) ); *tmp = pkt; mlt_deque_push_back( self->vpackets, tmp ); } } else if ( ret < 0 ) { mlt_producer producer = self->parent; mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_log_verbose( MLT_PRODUCER_SERVICE(producer), "av_read_frame returned error %d inside get_audio\n", ret ); if ( !self->seekable && mlt_properties_get_int( properties, "reconnect" ) ) { // Try to reconnect to live sources by closing context and codecs, // and letting next call to get_frame() reopen. prepare_reopen( self ); pthread_mutex_unlock( &self->packets_mutex ); goto exit_get_audio; } if ( !self->seekable && mlt_properties_get_int( properties, "exit_on_disconnect" ) ) { mlt_log_fatal( MLT_PRODUCER_SERVICE(producer), "Exiting with error due to disconnected source.\n" ); exit( EXIT_FAILURE ); } } } pthread_mutex_unlock( &self->packets_mutex ); // We only deal with audio from the selected audio index index = pkt.stream_index; if ( index < MAX_AUDIO_STREAMS && ret >= 0 && pkt.data && pkt.size > 0 && ( index == self->audio_index || ( self->audio_index == INT_MAX && context->streams[ index ]->codec->codec_type == CODEC_TYPE_AUDIO ) ) ) { int channels2 = self->audio_codec[index]->channels; ret = decode_audio( self, &ignore[index], pkt, channels2, *samples, real_timecode, fps ); } if ( self->seekable || index != self->video_index ) av_free_packet( &pkt ); } // Set some additional return values *format = mlt_audio_s16; if ( self->audio_index != INT_MAX ) { index = self->audio_index; *channels = self->audio_codec[ index ]->channels; *frequency = self->audio_codec[ index ]->sample_rate; *format = pick_audio_format( self->audio_codec[ index ]->sample_fmt ); sizeof_sample = sample_bytes( self->audio_codec[ index ] ); } else if ( self->audio_index == INT_MAX ) { for ( index = 0; index < index_max; index++ ) if ( self->audio_codec[ index ] ) { // XXX: This only works if all audio tracks have the same sample format. *format = pick_audio_format( self->audio_codec[ index ]->sample_fmt ); sizeof_sample = sample_bytes( self->audio_codec[ index ] ); break; } } // Allocate and set the frame's audio buffer int size = mlt_audio_format_size( *format, *samples, *channels ); *buffer = mlt_pool_alloc( size ); mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); // Interleave tracks if audio_index=all if ( self->audio_index == INT_MAX ) { uint8_t *dest = *buffer; int i; for ( i = 0; i < *samples; i++ ) { for ( index = 0; index < index_max; index++ ) if ( self->audio_codec[ index ] ) { int current_channels = self->audio_codec[ index ]->channels; uint8_t *src = self->audio_buffer[ index ] + i * current_channels * sizeof_sample; memcpy( dest, src, current_channels * sizeof_sample ); dest += current_channels * sizeof_sample; } } for ( index = 0; index < index_max; index++ ) if ( self->audio_codec[ index ] && self->audio_used[ index ] >= *samples ) { int current_channels = self->audio_codec[ index ]->channels; uint8_t *src = self->audio_buffer[ index ] + *samples * current_channels * sizeof_sample; self->audio_used[index] -= *samples; memmove( self->audio_buffer[ index ], src, self->audio_used[ index ] * current_channels * sizeof_sample ); } } // Copy a single track to the output buffer else { index = self->audio_index; // Now handle the audio if we have enough if ( self->audio_used[ index ] > 0 ) { uint8_t *src = self->audio_buffer[ index ]; // copy samples from audio_buffer size = self->audio_used[ index ] < *samples ? self->audio_used[ index ] : *samples; memcpy( *buffer, src, size * *channels * sizeof_sample ); // supply the remaining requested samples as silence if ( *samples > self->audio_used[ index ] ) memset( *buffer + size * *channels * sizeof_sample, 0, ( *samples - self->audio_used[ index ] ) * *channels * sizeof_sample ); // reposition the samples within audio_buffer self->audio_used[ index ] -= size; memmove( src, src + size * *channels * sizeof_sample, self->audio_used[ index ] * *channels * sizeof_sample ); } else { // Otherwise fill with silence memset( *buffer, 0, *samples * *channels * sizeof_sample ); } } } else { exit_get_audio: // Get silence and don't touch the context mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); } // Regardless of speed (other than paused), we expect to get the next frame if ( !paused ) self->audio_expected = position + 1; pthread_mutex_unlock( &self->audio_mutex ); return 0; } /** Initialize the audio codec context. */ static int audio_codec_init( producer_avformat self, int index, mlt_properties properties ) { // Initialise the codec if necessary if ( !self->audio_codec[ index ] ) { // Get codec context AVCodecContext *codec_context = self->audio_format->streams[index]->codec; // Find the codec AVCodec *codec = avcodec_find_decoder( codec_context->codec_id ); // If we don't have a codec and we can't initialise it, we can't do much more... pthread_mutex_lock( &self->open_mutex ); #if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) if ( codec && avcodec_open2( codec_context, codec, NULL ) >= 0 ) #else if ( codec && avcodec_open( codec_context, codec ) >= 0 ) #endif { // Now store the codec with its destructor if ( self->audio_codec[ index ] ) avcodec_close( self->audio_codec[ index ] ); self->audio_codec[ index ] = codec_context; } else { // Remember that we can't use self later self->audio_index = -1; } pthread_mutex_unlock( &self->open_mutex ); // Process properties as AVOptions apply_properties( codec_context, properties, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM ); if ( codec && codec->priv_class && codec_context->priv_data ) apply_properties( codec_context->priv_data, properties, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM ); } return self->audio_codec[ index ] && self->audio_index > -1; } /** Set up audio handling. */ static void producer_set_up_audio( producer_avformat self, mlt_frame frame ) { // Get the producer mlt_producer producer = self->parent; // Get the properties mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); // Fetch the audio format context AVFormatContext *context = self->audio_format; mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); // Get the audio_index int index = mlt_properties_get_int( properties, "audio_index" ); // Handle all audio tracks if ( self->audio_index > -1 && mlt_properties_get( properties, "audio_index" ) && !strcmp( mlt_properties_get( properties, "audio_index" ), "all" ) ) index = INT_MAX; // Reopen the file if necessary if ( !context && self->audio_index > -1 && index > -1 ) { producer_open( self, mlt_service_profile( MLT_PRODUCER_SERVICE(producer) ), mlt_properties_get( properties, "resource" ), 1 ); context = self->audio_format; } // Exception handling for audio_index if ( context && index >= (int) context->nb_streams && index < INT_MAX ) { for ( index = context->nb_streams - 1; index >= 0 && context->streams[ index ]->codec->codec_type != CODEC_TYPE_AUDIO; index-- ); mlt_properties_set_int( properties, "audio_index", index ); } if ( context && index > -1 && index < INT_MAX && context->streams[ index ]->codec->codec_type != CODEC_TYPE_AUDIO ) { index = self->audio_index; mlt_properties_set_int( properties, "audio_index", index ); } if ( context && index > -1 && index < INT_MAX && pick_audio_format( context->streams[ index ]->codec->sample_fmt ) == mlt_audio_none ) { index = -1; } // Update the audio properties if the index changed if ( context && index > -1 && index != self->audio_index ) { pthread_mutex_lock( &self->open_mutex ); if ( self->audio_codec[ self->audio_index ] ) avcodec_close( self->audio_codec[ self->audio_index ] ); self->audio_codec[ self->audio_index ] = NULL; pthread_mutex_unlock( &self->open_mutex ); } if ( self->audio_index != -1 ) self->audio_index = index; else index = -1; // Get the codec(s) if ( context && index == INT_MAX ) { mlt_properties_set_int( frame_properties, "audio_frequency", self->max_frequency ); mlt_properties_set_int( frame_properties, "audio_channels", self->total_channels ); for ( index = 0; index < context->nb_streams; index++ ) { if ( context->streams[ index ]->codec->codec_type == CODEC_TYPE_AUDIO ) audio_codec_init( self, index, properties ); } } else if ( context && index > -1 && index < MAX_AUDIO_STREAMS && audio_codec_init( self, index, properties ) ) { mlt_properties_set_int( frame_properties, "audio_frequency", self->audio_codec[ index ]->sample_rate ); mlt_properties_set_int( frame_properties, "audio_channels", self->audio_codec[ index ]->channels ); } if ( context && index > -1 ) { // Add our audio operation mlt_frame_push_audio( frame, self ); mlt_frame_push_audio( frame, producer_get_audio ); } } /** Our get frame implementation. */ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Access the private data mlt_service service = MLT_PRODUCER_SERVICE( producer ); mlt_cache_item cache_item = mlt_service_cache_get( service, "producer_avformat" ); producer_avformat self = mlt_cache_item_data( cache_item, NULL ); // If cache miss if ( !self ) { self = calloc( 1, sizeof( struct producer_avformat_s ) ); producer->child = self; self->parent = producer; mlt_service_cache_put( service, "producer_avformat", self, 0, (mlt_destructor) producer_avformat_close ); cache_item = mlt_service_cache_get( service, "producer_avformat" ); } // Create an empty frame *frame = mlt_frame_init( service); if ( *frame ) { mlt_properties_set_data( MLT_FRAME_PROPERTIES(*frame), "avformat_cache", cache_item, 0, (mlt_destructor) mlt_cache_item_close, NULL ); } else { mlt_cache_item_close( cache_item ); return 1; } // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Set up the video producer_set_up_video( self, *frame ); // Set up the audio producer_set_up_audio( self, *frame ); // Set the position of this producer mlt_position position = self->seekable ? mlt_producer_frame( producer ) : self->nonseek_position++; mlt_properties_set_position( MLT_FRAME_PROPERTIES( *frame ), "original_position", position ); // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; } static void producer_avformat_close( producer_avformat self ) { mlt_log_debug( NULL, "producer_avformat_close\n" ); // Cleanup av contexts av_free_packet( &self->pkt ); av_free( self->video_frame ); av_free( self->audio_frame ); pthread_mutex_lock( &self->open_mutex ); int i; for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) { mlt_pool_release( self->audio_buffer[i] ); av_free( self->decode_buffer[i] ); if ( self->audio_codec[i] ) avcodec_close( self->audio_codec[i] ); self->audio_codec[i] = NULL; } if ( self->video_codec ) avcodec_close( self->video_codec ); self->video_codec = NULL; // Close the file #if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(17<<8)+0) if ( self->dummy_context ) avformat_close_input( &self->dummy_context ); if ( self->seekable && self->audio_format ) avformat_close_input( &self->audio_format ); if ( self->video_format ) avformat_close_input( &self->video_format ); #else if ( self->dummy_context ) av_close_input_file( self->dummy_context ); if ( self->seekable && self->audio_format ) av_close_input_file( self->audio_format ); if ( self->video_format ) av_close_input_file( self->video_format ); #endif pthread_mutex_unlock( &self->open_mutex ); #ifdef VDPAU vdpau_producer_close( self ); #endif if ( self->image_cache ) mlt_cache_close( self->image_cache ); // Cleanup the mutexes if ( self->is_mutex_init ) { pthread_mutex_destroy( &self->audio_mutex ); pthread_mutex_destroy( &self->video_mutex ); pthread_mutex_destroy( &self->packets_mutex ); pthread_mutex_destroy( &self->open_mutex ); } // Cleanup the packet queues AVPacket *pkt; if ( self->apackets ) { while ( ( pkt = mlt_deque_pop_back( self->apackets ) ) ) { av_free_packet( pkt ); free( pkt ); } mlt_deque_close( self->apackets ); self->apackets = NULL; } if ( self->vpackets ) { while ( ( pkt = mlt_deque_pop_back( self->vpackets ) ) ) { av_free_packet( pkt ); free( pkt ); } mlt_deque_close( self->vpackets ); self->vpackets = NULL; } free( self ); } static void producer_close( mlt_producer parent ) { // Remove this instance from the cache mlt_service_cache_purge( MLT_PRODUCER_SERVICE(parent) ); // Close the parent parent->close = NULL; mlt_producer_close( parent ); // Free the memory free( parent ); } mlt-0.9.0/src/modules/avformat/producer_avformat.yml000066400000000000000000000134141215300731300226350ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: avformat title: FFmpeg Reader version: 2 copyright: Copyright (C) 2003-2011 Ushodaya Enterprises Limited license: LGPL language: en url: http://www.ffmpeg.org/ creator: Charles Yates contributor: - Dan Dennedy tags: - Audio - Video description: Read an audio and/or video file using FFmpeg bugs: - Audio sync discrepancy with some content. - Not all libavformat supported formats are seekable. - > Seeking is not always accurate. Sometimes it doesn't seek to I-frames so you may get junk for a few frames. - > More than 2 channels of audio more than 16 bits is not supported. parameters: - identifier: argument # 'argument' is a reserved name for a value supplied to the factory title: File/URL type: string description: | A file name specification or URL in the form: [{protocol}|{format}]:{resource}[?{format-parameter}[&{format-parameter}...]] For example, video4linux2:/dev/video1?width=320&height=240 Note: on the bash command line, & must be escaped as '\&'. Use 'f-list' to see a list of supported file formats. Use 'vcodec-list' to see a list of supported video decoders. Use 'acodec-list' to see a list of supported audio decoders. readonly: no required: yes mutable: no widget: fileopen # could provide a button to use a file-open dialog - identifier: audio_index # the name is the mlt_properties name title: Audio index type: integer description: > Choose the index of audio stream to use (-1 is off). When this value is equal to the maximum size of a 32-bit signed integer or the string "all" then all audio tracks are coalesced into a bundle of channels on one audio track. readonly: no mutable: no minimum: -1 default: 0 widget: spinner - identifier: video_index title: Video index type: integer description: Choose the index of video stream to use (-1 is off) readonly: no mutable: no minimum: -1 default: 0 widget: spinner - identifier: threads title: Decoding threads type: integer description: Choose the number of threads to use in the decoder(s) readonly: no mutable: no minimum: 0 maximum: 4 default: 1 widget: spinner unit: threads # the unit is a label that appears after the widget - identifier: force_aspect_ratio title: Sample aspect ratio type: float description: Optionally override a (mis)detected aspect ratio readonly: no mutable: yes minimum: 0.001 # just a UI suggestion maximum: 9.999 # just a suggestion # no default property means it should be blank in the UI and not applied unless provided - identifier: source_fps title: Frame rate type: float scale: 2 # scale is the number of digits to display after the decimal point description: the framerate of the resource readonly: yes unit: frames/second - identifier: seekable title: Supports seeking description: if the resource can seek readonly: yes - identifier: width title: Width type: integer unit: pixels readonly: yes - identifier: height title: Height type: integer unit: pixels readonly: yes - identifier: noimagecache title: Disable image caching type: integer minimum: 0 maximum: 0 default: 0 widget: checkbox - identifier: cache title: Number of images cache type: integer description: > By default, this producer caches images to facilitate YADIF deinterlace, which needs previous and next frames. Also, caching helps with frame- stepping within a player. The default number of images cached is supplied by the MLT framework, which is currently 4, but you can override it with this property. You can also disable caching by setting it to 0. If you are using parallel processing with YADIF deinterlacing, then you might need to increase caching to prevent inadvertent backward seeks. One can also set this value globally for all instances of avformat by setting the environment variable MLT_AVFORMAT_CACHE. - identifier: force_progressive title: Force progressive description: When provided, this overrides the detection of progressive video. type: integer minimum: 0 maximum: 1 widget: checkbox - identifier: force_tff title: Force top field first description: When provided, this overrides the detected field order of interlaced video. type: integer minimum: 0 maximum: 1 widget: checkbox - identifier: force_fps title: Force frame rate description: When provided, this attempts to override the detected frame rate of the video. type: integer minimum: 0 maximum: 1 widget: checkbox - identifier: force_colorspace title: Force colorspace description: When provided, this overrides the detected colorspace of the video (Y'CbCr only). type: integer values: - 240 # SMPTE 240M - 601 # ITU-R BT.601 - 709 # ITU-R BT.709 - identifier: video_delay title: Video delay description: > Manually adjust A/V synchronization. A negative value advances the video instead of delaying it. type: float default: 0 unit: seconds widget: timecode - identifier: reconnect title: Automatically reconnect? description: > Whether to attempt to automatically reconnect to a live source when a read failure occurs. type: integer minimum: 0 maximum: 1 widget: checkbox - identifier: exit_on_disconnect title: Exit upon disconnection? description: > When this is set, the program will terminate with an error if a live source becomes disconnected. type: integer minimum: 0 maximum: 1 widget: checkbox mlt-0.9.0/src/modules/avformat/vdpau.c000066400000000000000000000253221215300731300176540ustar00rootroot00000000000000/* * producer_avformat/vdpau.c -- VDPAU functions for the avformat producer * Copyright (C) 2009 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include extern pthread_mutex_t mlt_sdl_mutex; static VdpDeviceCreateX11 *vdpau_device_create_x11; static VdpDeviceDestroy *vdp_device_destroy; static VdpGetProcAddress *vdp_get_proc_address; static VdpGetErrorString *vdp_get_error_string; static VdpGetApiVersion *vdp_get_api_version; static VdpGetInformationString *vdp_get_information_string; static VdpVideoSurfaceCreate *vdp_surface_create; static VdpVideoSurfaceDestroy *vdp_surface_destroy; static VdpVideoSurfaceGetBitsYCbCr *vdp_surface_get_bits; static VdpDecoderCreate *vdp_decoder_create; static VdpDecoderDestroy *vdp_decoder_destroy; static VdpDecoderRender *vdp_decoder_render; // TODO: Shouldn't these be protected by a mutex? static int vdpau_init_done = 0; static int vdpau_supported = 1; /** VDPAUD functions */ static void vdpau_fini( producer_avformat self ) { if ( !self->vdpau ) return; mlt_log_debug( NULL, "vdpau_fini (%x)\n", self->vdpau->device ); if ( self->vdpau->decoder != VDP_INVALID_HANDLE ) vdp_decoder_destroy( self->vdpau->decoder ); if ( self->vdpau->device != VDP_INVALID_HANDLE ) vdp_device_destroy( self->vdpau->device ); free( self->vdpau ); self->vdpau = NULL; } static int vdpau_init( producer_avformat self ) { if ( !vdpau_supported ) return 0; mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_init\n" ); int success = 0; mlt_properties properties = MLT_PRODUCER_PROPERTIES( self->parent ); Display *display = XOpenDisplay( NULL ); if ( !display || mlt_properties_get_int( properties, "novdpau" ) || ( getenv( "MLT_NO_VDPAU" ) && strcmp( getenv( "MLT_NO_VDPAU" ), "1" ) == 0 ) ) return success; void *object = NULL; if ( !vdpau_init_done ) { int flags = RTLD_NOW; object = dlopen( "/usr/lib/libvdpau.so", flags ); #ifdef ARCH_X86_64 if ( !object ) object = dlopen( "/usr/lib64/libvdpau.so", flags ); if ( !object ) object = dlopen( "/usr/lib/x86_64-linux-gnu/libvdpau.so.1", flags ); #elif ARCH_X86 if ( !object ) object = dlopen( "/usr/lib/i386-linux-gnu/libvdpau.so.1", flags ); #endif if ( !object ) object = dlopen( "/usr/local/lib/libvdpau.so", flags ); if ( object ) vdpau_device_create_x11 = dlsym( object, "vdp_device_create_x11" ); else { mlt_log( MLT_PRODUCER_SERVICE(self->parent), MLT_LOG_WARNING, "%s: failed to dlopen libvdpau.so\n (%s)\n", __FUNCTION__, dlerror() ); // Don't try again. vdpau_supported = 0; return success; } } if ( vdpau_device_create_x11 ) { int screen = mlt_properties_get_int( properties, "x11_screen" ); self->vdpau = calloc( 1, sizeof( *self->vdpau ) ); self->vdpau->device = VDP_INVALID_HANDLE; self->vdpau->decoder = VDP_INVALID_HANDLE; mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "X11 Display = %p\n", display ); if ( VDP_STATUS_OK == vdpau_device_create_x11( display, screen, &self->vdpau->device, &vdp_get_proc_address ) ) { if ( !vdpau_init_done ) { vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_GET_ERROR_STRING, (void**) &vdp_get_error_string ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_GET_API_VERSION, (void**) &vdp_get_api_version ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_GET_INFORMATION_STRING, (void**) &vdp_get_information_string ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_CREATE, (void**) &vdp_surface_create ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_DESTROY, (void**) &vdp_surface_destroy ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR, (void**) &vdp_surface_get_bits ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DECODER_CREATE, (void**) &vdp_decoder_create ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DECODER_DESTROY, (void**) &vdp_decoder_destroy ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DECODER_RENDER, (void**) &vdp_decoder_render ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DEVICE_DESTROY, (void**) &vdp_device_destroy ); vdpau_init_done = 1; } success = 1; } } if ( !success ) { mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "VDPAU failed to initialize device\n" ); if ( object ) dlclose( object ); if ( self->vdpau ) free( self->vdpau ); self->vdpau = NULL; } return success; } static enum PixelFormat vdpau_get_format( struct AVCodecContext *s, const enum PixelFormat *fmt ) { return PIX_FMT_VDPAU_H264; } static int vdpau_get_buffer( AVCodecContext *codec_context, AVFrame *frame ) { int error = 0; producer_avformat self = codec_context->opaque; mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_get_buffer\n" ); if ( self->vdpau && mlt_deque_count( self->vdpau->deque ) ) { struct vdpau_render_state *render = mlt_deque_pop_front( self->vdpau->deque ); if ( render ) { frame->data[0] = (uint8_t*) render; frame->data[1] = (uint8_t*) render; frame->data[2] = (uint8_t*) render; frame->linesize[0] = 0; frame->linesize[1] = 0; frame->linesize[2] = 0; frame->type = FF_BUFFER_TYPE_USER; render->state = FF_VDPAU_STATE_USED_FOR_REFERENCE; frame->reordered_opaque = codec_context->reordered_opaque; if ( frame->reference ) { self->vdpau->ip_age[0] = self->vdpau->ip_age[1] + 1; self->vdpau->ip_age[1] = 1; self->vdpau->b_age++; } else { self->vdpau->ip_age[0] ++; self->vdpau->ip_age[1] ++; self->vdpau->b_age = 1; } } else { mlt_log_warning( MLT_PRODUCER_SERVICE(self->parent), "VDPAU surface underrun\n" ); error = -1; } } else { mlt_log_warning( MLT_PRODUCER_SERVICE(self->parent), "VDPAU surface underrun\n" ); error = -1; } return error; } static void vdpau_release_buffer( AVCodecContext *codec_context, AVFrame *frame ) { producer_avformat self = codec_context->opaque; if ( self->vdpau ) { struct vdpau_render_state *render = (struct vdpau_render_state*) frame->data[0]; mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_release_buffer (%x)\n", render->surface ); int i; render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE; for ( i = 0; i < 4; i++ ) frame->data[i] = NULL; mlt_deque_push_back( self->vdpau->deque, render ); } } static void vdpau_draw_horiz( AVCodecContext *codec_context, const AVFrame *frame, int offset[4], int y, int type, int height ) { producer_avformat self = codec_context->opaque; if ( self->vdpau ) { struct vdpau_render_state *render = (struct vdpau_render_state*) frame->data[0]; VdpVideoSurface surface = render->surface; VdpStatus status = vdp_decoder_render( self->vdpau->decoder, surface, (void*) &render->info, render->bitstream_buffers_used, render->bitstream_buffers ); if ( status != VDP_STATUS_OK ) { self->vdpau->is_decoded = 0; mlt_log_warning( MLT_PRODUCER_SERVICE(self->parent), "VDPAU failed to decode (%s)\n", vdp_get_error_string( status ) ); } else { self->vdpau->is_decoded = 1; } } } static int vdpau_decoder_init( producer_avformat self ) { mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_decoder_init\n" ); int success = 1; self->video_codec->opaque = self; self->video_codec->get_format = vdpau_get_format; self->video_codec->get_buffer = vdpau_get_buffer; self->video_codec->release_buffer = vdpau_release_buffer; self->video_codec->draw_horiz_band = vdpau_draw_horiz; self->video_codec->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD; self->video_codec->pix_fmt = PIX_FMT_VDPAU_H264; VdpDecoderProfile profile = VDP_DECODER_PROFILE_H264_HIGH; uint32_t max_references = self->video_codec->refs; pthread_mutex_lock( &mlt_sdl_mutex ); VdpStatus status = vdp_decoder_create( self->vdpau->device, profile, self->video_codec->width, self->video_codec->height, max_references, &self->vdpau->decoder ); pthread_mutex_unlock( &mlt_sdl_mutex ); if ( status == VDP_STATUS_OK ) { int i, n = FFMIN( self->video_codec->refs + 2, MAX_VDPAU_SURFACES ); self->vdpau->deque = mlt_deque_init(); for ( i = 0; i < n; i++ ) { if ( VDP_STATUS_OK == vdp_surface_create( self->vdpau->device, VDP_CHROMA_TYPE_420, self->video_codec->width, self->video_codec->height, &self->vdpau->render_states[i].surface ) ) { mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "successfully created VDPAU surface %x\n", self->vdpau->render_states[i].surface ); mlt_deque_push_back( self->vdpau->deque, &self->vdpau->render_states[i] ); } else { mlt_log_info( MLT_PRODUCER_SERVICE(self->parent), "failed to create VDPAU surface %dx%d\n", self->video_codec->width, self->video_codec->height ); while ( mlt_deque_count( self->vdpau->deque ) ) { struct vdpau_render_state *render = mlt_deque_pop_front( self->vdpau->deque ); vdp_surface_destroy( render->surface ); } mlt_deque_close( self->vdpau->deque ); success = 0; break; } } if ( self->vdpau ) self->vdpau->b_age = self->vdpau->ip_age[0] = self->vdpau->ip_age[1] = 256*256*256*64; // magic from Avidemux } else { success = 0; self->vdpau->decoder = VDP_INVALID_HANDLE; mlt_log_error( MLT_PRODUCER_SERVICE(self->parent), "VDPAU failed to initialize decoder (%s)\n", vdp_get_error_string( status ) ); } return success; } static void vdpau_producer_close( producer_avformat self ) { if ( self->vdpau ) { mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_producer_close\n" ); int i; for ( i = 0; i < MAX_VDPAU_SURFACES; i++ ) { if ( self->vdpau->render_states[i].surface != VDP_INVALID_HANDLE ) vdp_surface_destroy( self->vdpau->render_states[i].surface ); self->vdpau->render_states[i].surface = VDP_INVALID_HANDLE; } mlt_deque_close( self->vdpau->deque ); if ( self->vdpau->buffer ) mlt_pool_release( self->vdpau->buffer ); self->vdpau->buffer = NULL; vdpau_fini( self ); } } mlt-0.9.0/src/modules/avsync/000077500000000000000000000000001215300731300160515ustar00rootroot00000000000000mlt-0.9.0/src/modules/avsync/Makefile000066400000000000000000000012701215300731300175110ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lm -lpthread include ../../../config.mak TARGET = ../libmltavsync$(LIBSUF) OBJS = factory.o \ producer_blipflash.o \ consumer_blipflash.o ASM_OBJS = SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(ASM_OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(ASM_OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(ASM_OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/avsync" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/avsync" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/avsync/consumer_blipflash.c000066400000000000000000000265301215300731300221020ustar00rootroot00000000000000/* * consumer_blipflash.c -- a consumer to measure A/V sync from a blip/flash * source * Copyright (C) 2013 Brian Matherly * Author: Brian Matherly * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // mlt Header files #include #include #include // System header files #include #include #include #include #include // Private constants #define SAMPLE_FREQ 48000 #define FLASH_LUMA_THRESHOLD 150 #define BLIP_THRESHOLD 0.5 // Private types typedef struct { int64_t flash_history[2]; int flash_history_count; int64_t blip_history[2]; int blip_history_count; int blip_in_progress; int samples_since_blip; int blip; int flash; int sample_offset; FILE* out_file; int report_frames; } avsync_stats; // Forward references. static int consumer_start( mlt_consumer consumer ); static int consumer_stop( mlt_consumer consumer ); static int consumer_is_stopped( mlt_consumer consumer ); static void *consumer_thread( void *arg ); static void consumer_close( mlt_consumer consumer ); /** Initialize the consumer. */ mlt_consumer consumer_blipflash_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Allocate the consumer mlt_consumer consumer = mlt_consumer_new( profile ); mlt_properties consumer_properties = MLT_CONSUMER_PROPERTIES( consumer ); avsync_stats* stats = NULL; // If memory allocated and initializes without error if ( consumer != NULL ) { // Set up start/stop/terminated callbacks consumer->close = consumer_close; consumer->start = consumer_start; consumer->stop = consumer_stop; consumer->is_stopped = consumer_is_stopped; stats = mlt_pool_alloc( sizeof( avsync_stats ) ); stats->flash_history_count = 0; stats->blip_history_count = 0; stats->blip_in_progress = 0; stats->samples_since_blip = 0; stats->blip = 0; stats->flash = 0; stats->sample_offset = INT_MAX; stats->report_frames = 0; stats->out_file = stdout; if ( arg != NULL ) { FILE* out_file = fopen( arg, "w" ); if ( out_file != NULL ) stats->out_file = out_file; } mlt_properties_set_data( consumer_properties, "_stats", stats, 0, NULL, NULL ); mlt_properties_set( consumer_properties, "report", "blip" ); } // Return this return consumer; } /** Start the consumer. */ static int consumer_start( mlt_consumer consumer ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Check that we're not already running if ( !mlt_properties_get_int( properties, "_running" ) ) { // Allocate a thread pthread_t *thread = calloc( 1, sizeof( pthread_t ) ); // Assign the thread to properties mlt_properties_set_data( properties, "_thread", thread, sizeof( pthread_t ), free, NULL ); // Set the running state mlt_properties_set_int( properties, "_running", 1 ); // Create the thread pthread_create( thread, NULL, consumer_thread, consumer ); } return 0; } /** Stop the consumer. */ static int consumer_stop( mlt_consumer consumer ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Check that we're running if ( mlt_properties_get_int( properties, "_running" ) ) { // Get the thread pthread_t *thread = mlt_properties_get_data( properties, "_thread", NULL ); // Stop the thread mlt_properties_set_int( properties, "_running", 0 ); // Wait for termination if ( thread ) pthread_join( *thread, NULL ); } return 0; } /** Determine if the consumer is stopped. */ static int consumer_is_stopped( mlt_consumer consumer ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); return !mlt_properties_get_int( properties, "_running" ); } static void detect_flash( mlt_frame frame, mlt_position pos, double fps, avsync_stats* stats ) { int width = 0; int height = 0; mlt_image_format format = mlt_image_yuv422; uint8_t* image = NULL; int error = mlt_frame_get_image( frame, &image, &format, &width, &height, 0 ); if ( !error && format == mlt_image_yuv422 && image != NULL ) { int i, j = 0; int y_accumulator = 0; // Add up the luma values from 4 samples in 4 different quadrants. for( i = 1; i < 3; i++ ) { int x = ( width / 3 ) * i; x = x - x % 2; // Make sure this is a luma sample for( j = 1; j < 3; j++ ) { int y = ( height / 3 ) * j; y_accumulator += image[ y * height * 2 + x * 2 ]; } } // If the average luma value is > 150, assume it is a flash. stats->flash = ( y_accumulator / 4 ) > FLASH_LUMA_THRESHOLD; } if( stats->flash ) { stats->flash_history[1] = stats->flash_history[0]; stats->flash_history[0] = mlt_sample_calculator_to_now( fps, SAMPLE_FREQ, pos ); if( stats->flash_history_count < 2 ) { stats->flash_history_count++; } } } static void detect_blip( mlt_frame frame, mlt_position pos, double fps, avsync_stats* stats ) { int frequency = SAMPLE_FREQ; int channels = 1; int samples = mlt_sample_calculator( fps, frequency, pos ); mlt_audio_format format = mlt_audio_float; float* buffer = NULL; int error = mlt_frame_get_audio( frame, (void**) &buffer, &format, &frequency, &channels, &samples ); if ( !error && format == mlt_audio_float && buffer != NULL ) { int i = 0; for( i = 0; i < samples; i++ ) { if( !stats->blip_in_progress ) { if( buffer[i] > BLIP_THRESHOLD || buffer[i] < -BLIP_THRESHOLD ) { // This sample must start a blip stats->blip_in_progress = 1; stats->samples_since_blip = 0; stats->blip_history[1] = stats->blip_history[0]; stats->blip_history[0] = mlt_sample_calculator_to_now( fps, SAMPLE_FREQ, pos ); stats->blip_history[0] += i; if( stats->blip_history_count < 2 ) { stats->blip_history_count++; } stats->blip = 1; } } else { if( buffer[i] > -BLIP_THRESHOLD && buffer[i] < BLIP_THRESHOLD ) { if( ++stats->samples_since_blip > frequency / 1000 ) { // One ms of silence means the blip is over stats->blip_in_progress = 0; stats->samples_since_blip = 0; } } else { stats->samples_since_blip = 0; } } } } } static void calculate_sync( avsync_stats* stats ) { if( stats->blip || stats->flash ) { if( stats->flash_history_count > 0 && stats->blip_history_count > 0 && stats->blip_history[0] == stats->flash_history[0] ) { // The flash and blip occurred at the same time. stats->sample_offset = 0; } if( stats->flash_history_count > 1 && stats->blip_history_count > 0 && stats->blip_history[0] <= stats->flash_history[0] && stats->blip_history[0] >= stats->flash_history[1] ) { // The latest blip occurred between two flashes if( stats->flash_history[0] - stats->blip_history[0] > stats->blip_history[0] - stats->flash_history[1] ) { // Blip is closer to the previous flash. // F1---B0--------F0 // ^----^ // Video leads audio (negative number). stats->sample_offset = (int)(stats->flash_history[1] - stats->blip_history[0] ); } else { // Blip is closer to the current flash. // F1--------B0---F0 // ^----^ // Audio leads video (positive number). stats->sample_offset = (int)(stats->flash_history[0] - stats->blip_history[0]); } } else if( stats->blip_history_count > 1 && stats->flash_history_count > 0 && stats->flash_history[0] <= stats->blip_history[0] && stats->flash_history[0] >= stats->blip_history[1] ) { // The latest flash occurred between two blips if( stats->blip_history[0] - stats->flash_history[0] > stats->flash_history[0] - stats->blip_history[1] ) { // Flash is closer to the previous blip. // B1---F0--------B0 // ^----^ // Audio leads video (positive number). stats->sample_offset = (int)(stats->flash_history[0] - stats->blip_history[1]); } else { // Flash is closer to the latest blip. // B1--------F0---B0 // ^----^ // Video leads audio (negative number). stats->sample_offset = (int)(stats->flash_history[0] - stats->blip_history[0] ); } } } } static void report_results( avsync_stats* stats, mlt_position pos ) { if( stats->report_frames || stats->blip ) { if( stats->sample_offset == INT_MAX ) { fprintf( stats->out_file, MLT_POSITION_FMT "\t??\n", pos ); } else { // Convert to milliseconds. double ms_offset = (double)stats->sample_offset * 1000.0 / (double)SAMPLE_FREQ; fprintf( stats->out_file, MLT_POSITION_FMT "\t%02.02f\n", pos, ms_offset ); } } stats->blip = 0; stats->flash = 0; } /** The main thread - the argument is simply the consumer. */ static void *consumer_thread( void *arg ) { // Map the argument to the object mlt_consumer consumer = arg; // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Convenience functionality int terminate_on_pause = mlt_properties_get_int( properties, "terminate_on_pause" ); int terminated = 0; // Frame and size mlt_frame frame = NULL; // Loop while running while( !terminated && mlt_properties_get_int( properties, "_running" ) ) { // Get the frame frame = mlt_consumer_rt_frame( consumer ); // Check for termination if ( terminate_on_pause && frame != NULL ) terminated = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0; // Check that we have a frame to work with if ( frame ) { avsync_stats* stats = mlt_properties_get_data( properties, "_stats", NULL ); double fps = mlt_properties_get_double( properties, "fps" ); mlt_position pos = mlt_frame_get_position( frame ); if( !strcmp( mlt_properties_get( properties, "report" ), "frame" ) ) { stats->report_frames = 1; } else { stats->report_frames = 0; } detect_flash( frame, pos, fps, stats ); detect_blip( frame, pos, fps, stats ); calculate_sync( stats ); report_results( stats, pos ); // Close the frame mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); mlt_frame_close( frame ); } } // Indicate that the consumer is stopped mlt_properties_set_int( properties, "_running", 0 ); mlt_consumer_stopped( consumer ); return NULL; } /** Close the consumer. */ static void consumer_close( mlt_consumer consumer ) { mlt_properties consumer_properties = MLT_CONSUMER_PROPERTIES( consumer ); avsync_stats* stats = mlt_properties_get_data( consumer_properties, "_stats", NULL ); // Stop the consumer mlt_consumer_stop( consumer ); // Close the file if( stats->out_file != stdout ) { fclose( stats->out_file ); } // Clean up memory mlt_pool_release( stats ); // Close the parent mlt_consumer_close( consumer ); // Free the memory free( consumer ); } mlt-0.9.0/src/modules/avsync/consumer_blipflash.yml000066400000000000000000000014361215300731300224570ustar00rootroot00000000000000schema_version: 0.1 type: consumer identifier: blipflash title: Blip Flash version: 1 copyright: Brian Matherly creator: Brian Matherly license: LGPLv2.1 language: en tags: - Video - Audio description: > Calculate the A/V sync for a blip flash source. Sync can be recalculated whenever a blip or a flash is detected. parameters: - identifier: argument title: Report File type: string description: > The file to report the results to. If empty, the results will be reported to standard out. required: no widget: filesave - identifier: report title: Report Style type: string description: > When to report sync - every frame or only when blips occur. default: blip values: - blip - frame mutable: yes widget: combo mlt-0.9.0/src/modules/avsync/factory.c000066400000000000000000000033511215300731300176660ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2013 Brian Matherly * Author: Brian Matherly * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include extern mlt_consumer consumer_blipflash_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_blipflash_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/avsync/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( consumer_type, "blipflash", consumer_blipflash_init ); MLT_REGISTER( producer_type, "blipflash", producer_blipflash_init ); MLT_REGISTER_METADATA( consumer_type, "blipflash", metadata, "consumer_blipflash.yml" ); MLT_REGISTER_METADATA( producer_type, "blipflash", metadata, "producer_blipflash.yml" ); } mlt-0.9.0/src/modules/avsync/producer_blipflash.c000066400000000000000000000212671215300731300220740ustar00rootroot00000000000000/* * producer_blipflash.c -- blip/flash generating producer * Copyright (C) 2013 Brian Matherly * Author: Brian Matherly * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include /** Fill an audio buffer with 1kHz "blip" samples. */ static void fill_blip( mlt_properties producer_properties, float* buffer, int frequency, int channels, int samples ) { int new_size = samples * channels * sizeof( float ); int old_size = 0; float* blip = mlt_properties_get_data( producer_properties, "_blip", &old_size ); if( !blip || new_size > old_size ) { blip = mlt_pool_alloc( new_size ); // Fill the blip buffer if ( blip != NULL ) { int s = 0; int c = 0; for( s = 0; s < samples; s++ ) { float f = 1000.0; float t = (float)s/(float)frequency; // Add 90 deg so the blip always starts at 1 for easy detection. float phase = M_PI / 2; float value = sin( 2*M_PI*f*t + phase ); for( c = 0; c < channels; c++ ) { float* sample_ptr = ((float*) blip) + (c * samples) + s; *sample_ptr = value; } } } // Cache the audio blip to save from regenerating it with every blip. mlt_properties_set_data( producer_properties, "_blip", blip, new_size, mlt_pool_release, NULL ); }; if( blip ) memcpy( buffer, blip, new_size ); } static int producer_get_audio( mlt_frame frame, int16_t** buffer, mlt_audio_format* format, int* frequency, int* channels, int* samples ) { mlt_producer producer = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "_producer_blipflash", NULL ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); int size = *samples * *channels * sizeof( float ); double fps = mlt_producer_get_fps( producer ); int frames = mlt_frame_get_position( frame ) + mlt_properties_get_int( producer_properties, "offset" ); int seconds = frames / fps; // Correct the returns if necessary *format = mlt_audio_float; *frequency = *frequency <= 0 ? 48000 : *frequency; *channels = *channels <= 0 ? 2 : *channels; *samples = *samples <= 0 ? mlt_sample_calculator( fps, *frequency, frames ) : *samples; // Allocate the buffer *buffer = mlt_pool_alloc( size ); // Determine if this should be a blip or silence. frames = frames % lrint( fps ); seconds = seconds % mlt_properties_get_int( producer_properties, "period" ); if( seconds == 0 && frames == 0 ) { fill_blip( producer_properties, (float*)*buffer, *frequency, *channels, *samples ); } else { // Fill silence. memset( *buffer, 0, size ); } // Set the buffer for destruction mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); return 0; } /** Fill an image buffer with either white (flash) or black as requested. */ static void fill_image( mlt_properties producer_properties, char* color, uint8_t* buffer, mlt_image_format format, int width, int height ) { int new_size = mlt_image_format_size( format, width, height, NULL ); int old_size = 0; uint8_t* image = mlt_properties_get_data( producer_properties, color, &old_size ); if( !image || new_size > old_size ) { // Need to create a new cached image. image = mlt_pool_alloc( new_size ); if ( image != NULL ) { uint8_t r, g, b; uint8_t* p = image; if( !strcmp( color, "_flash" ) ) { r = g = b = 255; // White } else { r = g = b = 0; // Black } switch( format ) { default: case mlt_image_yuv422: { int uneven = width % 2; int count = ( width - uneven ) / 2 + 1; uint8_t y, u, v; RGB2YUV_601_SCALED( r, g, b, y, u, v ); int i = height + 1; while ( --i ) { int j = count; while ( --j ) { *p ++ = y; *p ++ = u; *p ++ = y; *p ++ = v; } if ( uneven ) { *p ++ = y; *p ++ = u; } } break; } case mlt_image_rgb24: { int i = width * height + 1; while ( --i ) { *p ++ = r; *p ++ = g; *p ++ = b; } break; } case mlt_image_rgb24a: { int i = width * height + 1; while ( --i ) { *p ++ = r; *p ++ = g; *p ++ = b; *p ++ = 255; // alpha } break; } } // Cache the image to save from regenerating it with every frame. mlt_properties_set_data( producer_properties, color, image, new_size, mlt_pool_release, NULL ); } } if( image ) memcpy( buffer, image, new_size ); } static int producer_get_image( mlt_frame frame, uint8_t** buffer, mlt_image_format* format, int* width, int* height, int writable ) { mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_producer producer = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "_producer_blipflash", NULL ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); int size = 0; double fps = mlt_producer_get_fps( producer ); int frames = mlt_frame_get_position( frame ); int seconds = frames / fps; mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); // Correct the returns if necessary if( *format != mlt_image_yuv422 && *format != mlt_image_rgb24 && *format != mlt_image_rgb24a ) *format = mlt_image_yuv422; if( *width <= 0 ) *width = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->width; if ( *height <= 0 ) *height = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->height; // Allocate the buffer size = mlt_image_format_size( *format, *width, *height, NULL ); *buffer = mlt_pool_alloc( size ); // Determine if this should be a flash or black. frames = frames % lrint( fps ); seconds = seconds % mlt_properties_get_int( producer_properties, "period" ); if( seconds == 0 && frames == 0 ) { fill_image( producer_properties, "_flash", *buffer, *format, *width, *height ); } else { fill_image( producer_properties, "_black", *buffer, *format, *width, *height ); } mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); // Create the alpha channel int alpha_size = *width * *height; uint8_t *alpha = mlt_pool_alloc( alpha_size ); if ( alpha ) memset( alpha, 255, alpha_size ); // Update the frame mlt_frame_set_image( frame, *buffer, size, mlt_pool_release ); mlt_frame_set_alpha( frame, alpha, alpha_size, mlt_pool_release ); mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_properties, "aspect_ratio" ) ); mlt_properties_set_int( properties, "progressive", 1 ); mlt_properties_set_int( properties, "meta.media.width", *width ); mlt_properties_set_int( properties, "meta.media.height", *height ); return 0; } static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL ) { // Obtain properties of frame mlt_properties frame_properties = MLT_FRAME_PROPERTIES( *frame ); // Save the producer to be used later mlt_properties_set_data( frame_properties, "_producer_blipflash", producer, 0, NULL, NULL ); // Update time code on the frame mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Configure callbacks mlt_frame_push_get_image( *frame, producer_get_image ); mlt_frame_push_audio( *frame, producer_get_audio ); } // Calculate the next time code mlt_producer_prepare_next( producer ); return 0; } static void producer_close( mlt_producer this ) { this->close = NULL; mlt_producer_close( this ); free( this ); } /** Initialize. */ mlt_producer producer_blipflash_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create a new producer object mlt_producer producer = mlt_producer_new( profile ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); // Initialize the producer if ( producer ) { mlt_properties_set_int( producer_properties, "period", 1 ); mlt_properties_set_int( producer_properties, "offset", 0 ); // Callback registration producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )producer_close; } return producer; } mlt-0.9.0/src/modules/avsync/producer_blipflash.yml000066400000000000000000000015521215300731300224460ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: blipflash title: Blip Flash version: 1 copyright: Brian Matherly creator: Brian Matherly license: LGPLv2.1 language: en tags: - Audio - Video description: > Generate periodic synchronized audio blips and video flashes. Blips are a 1kHz tone and last the duration of the flash frame. parameters: - identifier: period title: Flash Period type: integer description: > The period between flashes in seconds. default: 1 readonly: no mutable: yes widget: spinner - identifier: offset title: Audio Offset type: integer description: > The number of frames to offset the audio. A positive number results in audio earlier than video. An negative number results in audio later than video. default: 0 readonly: no mutable: yes widget: spinner mlt-0.9.0/src/modules/configure000077500000000000000000000016501215300731300164570ustar00rootroot00000000000000#!/bin/sh # Clean up disables if not in help mode [ "$help" != "1" ] && rm -f disable-* producers.dat filters.dat transitions.dat consumers.dat # Create the make.inc file echo SUBDIRS = `find . -maxdepth 1 -type d | grep -v .svn | grep -v "^.$" | sed 's/\.\///'` > make.inc # Iterate through arguments for i in "$@" do case $i in --disable-* ) touch disable-${i#--disable-} ;; esac done # Iterate through each of the components for i in * do if [ -d $i -a \( "$help" = "1" -o ! -f disable-$i \) ] then if [ "$gpl" = "true" -o ! -f $i/gpl -o "$help" = "1" ] then [ -f $i/Makefile -a "$help" = "0" ] && echo "Configuring modules/$i:" if [ -x $i/configure ] then olddir2=`pwd` cd $i ./configure "$@" [ $? != 0 ] && exit 1 cd $olddir2 elif [ -f $i/configure ] then echo " configure script is not set executable!" fi elif [ "$help" = "0" ] then touch disable-$i fi fi done mlt-0.9.0/src/modules/core/000077500000000000000000000000001215300731300154765ustar00rootroot00000000000000mlt-0.9.0/src/modules/core/Makefile000066400000000000000000000036451215300731300171460ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lm -lpthread include ../../../config.mak TARGET = ../libmltcore$(LIBSUF) OBJS = factory.o \ producer_colour.o \ producer_consumer.o \ producer_hold.o \ producer_loader.o \ producer_melt.o \ producer_noise.o \ producer_ppm.o \ filter_audiochannels.o \ filter_audioconvert.o \ filter_audiowave.o \ filter_brightness.o \ filter_channelcopy.o \ filter_crop.o \ filter_data_feed.o \ filter_data_show.o \ filter_fieldorder.o \ filter_gamma.o \ filter_greyscale.o \ filter_imageconvert.o \ filter_luma.o \ filter_mirror.o \ filter_mono.o \ filter_obscure.o \ filter_panner.o \ filter_region.o \ filter_rescale.o \ filter_resize.o \ filter_transition.o \ filter_watermark.o \ transition_composite.o \ transition_luma.o \ transition_mix.o \ transition_region.o \ consumer_multi.o \ consumer_null.o ifdef SSE2_FLAGS ifdef ARCH_X86_64 OBJS += composite_line_yuv_sse2_simple.o endif endif ASM_OBJS = SRCS := $(OBJS:.o=.c) ifeq ($(targetos), MinGW) CFLAGS += -I../../win32 OBJS += ../../win32/fnmatch.o SRCS += ../../win32/fnmatch.c endif all: $(TARGET) $(TARGET): $(OBJS) $(ASM_OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(ASM_OBJS) $(LDFLAGS) composite_line_yuv_mmx.o: composite_line_yuv_mmx.S $(CC) -o $@ -c composite_line_yuv_mmx.S depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(ASM_OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/core" install -m 644 data_fx.properties "$(DESTDIR)$(mltdatadir)/core" install -m 644 loader.dict "$(DESTDIR)$(mltdatadir)/core" install -m 644 loader.ini "$(DESTDIR)$(mltdatadir)/core" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/core" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/core/composite_line_yuv_mmx.S000066400000000000000000000066661215300731300224350ustar00rootroot00000000000000 .file "composite_line_yuv_mmx" .version "01.01" gcc2_compiled.: .data .text .align 16 #if !defined(__MINGW32__) && !defined(__CYGWIN__) .globl composite_line_yuv_mmx .type composite_line_yuv_mmx,@function composite_line_yuv_mmx: #else .globl _composite_line_yuv_mmx _composite_line_yuv_mmx: #endif /* * Arguments * * dest: 8(%ebp) %esi * src: 12(%ebp) * width_src: 16(%ebp) * alpha: 20(%ebp) * weight: 24(%ebp) * luma: 28(%ebp) * softness: 32(%ebp) */ /* * Function call entry */ pushl %ebp movl %esp,%ebp subl $28,%esp pushl %edi pushl %esi pushl %ebx /* Initialise */ movl 8(%ebp), %esi # get dest movl $0, %edx # j = 0 .loop: movl $0xffff, %ecx # a = 255 cmpl $0, 20(%ebp) # if alpha == NULL je .noalpha movl 20(%ebp), %edi # a = alpha[ j ] movb (%edi,%edx), %cl .noalpha: movl %ecx, -24(%ebp) # save ecx movl 24(%ebp), %eax # mix = weight cmpl $0, 28(%ebp) # if luma == NULL je .noluma movl 28(%ebp), %edi # mix = ... movl %edx, %ebx sall $1, %ebx movw (%edi,%ebx), %bx # luma[ j*2 ] cmpl %ebx, %eax jl .luma0 movl %ebx, %ecx addl 32(%ebp), %ecx # + softness cmpl %ecx, %eax jge .luma1 /* TODO: linear interpolate between edges */ subw %bx, %ax sall $8, %eax subw %bx, %cx movl %edx, %ebx divw %cx movl %ebx, %edx jmp .noluma .luma0: movl $0, %eax jmp .noluma .luma1: movl $0xffff, %eax .noluma: shrl $8, %eax movl %edx, %ebx # edx will be destroyed by mulw movl -24(%ebp), %ecx # restore ecx mull %ecx # mix = mix * a... movl %ebx, %edx # restore edx shrl $8, %eax # >>8 andl $0xff, %eax /* put alpha and (1-alpha) into mm0 */ /* 0 aa 0 1-a 0 aa 0 1-a */ /* duplicate word */ movl %eax, %ecx shll $16, %ecx orl %eax, %ecx movd %ecx, %mm1 /* (1 << 16) - mix */ movl $0x000000ff, %ecx subl %eax, %ecx andl $0xff, %ecx /* duplicate word */ movl %ecx, %eax shll $16, %eax orl %eax, %ecx movd %ecx, %mm0 /* unpack words into double words */ punpcklwd %mm1, %mm0 /* put src yuv and dest yuv into mm1 */ /* 0 UVs 0 UVd 0 Ys 0 Yd */ movl 12(%ebp), %edi # get src movb (%edi), %cl shll $8, %ecx movb 1(%edi), %al shll $24, %eax orl %eax, %ecx movb (%esi), %al # get dest orl %eax, %ecx movb 1(%esi), %al shll $16, %eax orl %eax, %ecx movd %ecx, %mm1 punpcklbw %mm4, %mm1 /* alpha composite */ pmaddwd %mm1, %mm0 psrld $8, %mm0 /* store result */ movd %mm0, %eax movb %al, (%esi) pextrw $2, %mm0, %eax movl $128, %eax movb %al, 1(%esi) /* for..next */ addl $1, %edx # j++ cmpl 16(%ebp), %edx # if ( j == width_src ) jge .out addl $2, %esi addl $2, 12(%ebp) jmp .loop .out: emms leal -40(%ebp),%esp popl %ebx popl %esi popl %edi movl %ebp,%esp popl %ebp ret /********************************************/ .align 8 #if !defined(__MINGW32__) && !defined(__CYGWIN__) .globl composite_have_mmx .type composite_have_mmx,@function composite_have_mmx: #else .globl _composite_have_mmx _composite_have_mmx: #endif push %ebx # Check if bit 21 in flags word is writeable pushfl popl %eax movl %eax,%ebx xorl $0x00200000, %eax pushl %eax popfl pushfl popl %eax cmpl %eax, %ebx je .notfound # OK, we have CPUID movl $1, %eax cpuid test $0x00800000, %edx jz .notfound movl $1, %eax jmp .out2 .notfound: movl $0, %eax .out2: popl %ebx ret mlt-0.9.0/src/modules/core/composite_line_yuv_sse2_simple.c000066400000000000000000000157051215300731300240730ustar00rootroot00000000000000/* * composite_line_yuv_sse2_simple.c * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Maksym Veremeyenko * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include void composite_line_yuv_sse2_simple(uint8_t *dest, uint8_t *src, int width, uint8_t *alpha_b, uint8_t *alpha_a, int weight) { const static unsigned char const1[] = { 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00 }; __asm__ volatile ( "pxor %%xmm0, %%xmm0 \n\t" /* clear zero register */ "movdqu (%4), %%xmm9 \n\t" /* load const1 */ "movd %0, %%xmm1 \n\t" /* load weight and decompose */ "movlhps %%xmm1, %%xmm1 \n\t" "pshuflw $0, %%xmm1, %%xmm1 \n\t" "pshufhw $0, %%xmm1, %%xmm1 \n\t" /* xmm1 (weight) 00 W 00 W 00 W 00 W 00 W 00 W 00 W 00 W */ "loop_start: \n\t" "movq (%1), %%xmm2 \n\t" /* load source alpha */ "punpcklbw %%xmm0, %%xmm2 \n\t" /* unpack alpha 8 8-bits alphas to 8 16-bits values */ /* xmm2 (src alpha) xmm3 (dst alpha) 00 A8 00 A7 00 A6 00 A5 00 A4 00 A3 00 A2 00 A1 */ "pmullw %%xmm1, %%xmm2 \n\t" /* premultiply source alpha */ "psrlw $8, %%xmm2 \n\t" /* xmm2 (premultiplied) 00 A8 00 A7 00 A6 00 A5 00 A4 00 A3 00 A2 00 A1 */ /* DSTa = DSTa + (SRCa * (0xFF - DSTa)) >> 8 */ "movq (%5), %%xmm3 \n\t" /* load dst alpha */ "punpcklbw %%xmm0, %%xmm3 \n\t" /* unpack dst 8 8-bits alphas to 8 16-bits values */ "movdqa %%xmm9, %%xmm4 \n\t" "psubw %%xmm3, %%xmm4 \n\t" "pmullw %%xmm2, %%xmm4 \n\t" "psrlw $8, %%xmm4 \n\t" "paddw %%xmm4, %%xmm3 \n\t" "packuswb %%xmm0, %%xmm3 \n\t" "movq %%xmm3, (%5) \n\t" /* save dst alpha */ "movdqu (%2), %%xmm3 \n\t" /* load src */ "movdqu (%3), %%xmm4 \n\t" /* load dst */ "movdqa %%xmm3, %%xmm5 \n\t" /* dub src */ "movdqa %%xmm4, %%xmm6 \n\t" /* dub dst */ /* xmm3 (src) xmm4 (dst) xmm5 (src) xmm6 (dst) U8 V8 U7 V7 U6 V6 U5 V5 U4 V4 U3 V3 U2 V2 U1 V1 */ "punpcklbw %%xmm0, %%xmm5 \n\t" /* unpack src low */ "punpcklbw %%xmm0, %%xmm6 \n\t" /* unpack dst low */ "punpckhbw %%xmm0, %%xmm3 \n\t" /* unpack src high */ "punpckhbw %%xmm0, %%xmm4 \n\t" /* unpack dst high */ /* xmm5 (src_l) xmm6 (dst_l) 00 U4 00 V4 00 U3 00 V3 00 U2 00 V2 00 U1 00 V1 xmm3 (src_u) xmm4 (dst_u) 00 U8 00 V8 00 U7 00 V7 00 U6 00 V6 00 U5 00 V5 */ "movdqa %%xmm2, %%xmm7 \n\t" /* dub alpha */ "movdqa %%xmm2, %%xmm8 \n\t" /* dub alpha */ "movlhps %%xmm7, %%xmm7 \n\t" /* dub low */ "movhlps %%xmm8, %%xmm8 \n\t" /* dub high */ /* xmm7 (src alpha) 00 A4 00 A3 00 A2 00 A1 00 A4 00 A3 00 A2 00 A1 xmm8 (src alpha) 00 A8 00 A7 00 A6 00 A5 00 A8 00 A7 00 A6 00 A5 */ "pshuflw $0x50, %%xmm7, %%xmm7 \n\t" "pshuflw $0x50, %%xmm8, %%xmm8 \n\t" "pshufhw $0xFA, %%xmm7, %%xmm7 \n\t" "pshufhw $0xFA, %%xmm8, %%xmm8 \n\t" /* xmm7 (src alpha lower) 00 A4 00 A4 00 A3 00 A3 00 A2 00 A2 00 A1 00 A1 xmm8 (src alpha upper) 00 A8 00 A8 00 A7 00 A7 00 A6 00 A6 00 A5 00 A5 */ /* DST = SRC * ALPHA + DST * (0xFF - ALPHA) SRC * ALPHA + DST * 0xFF - DST * ALPHA (SRC - DST) * ALPHA + DST * 0xFF */ "psubw %%xmm4, %%xmm3 \n\t" /* src = src - dst */ "psubw %%xmm6, %%xmm5 \n\t" "pmullw %%xmm8, %%xmm3 \n\t" /* src = src * alpha */ "pmullw %%xmm7, %%xmm5 \n\t" "pmullw %%xmm9, %%xmm4 \n\t" /* dst = dst * 0xFF */ "pmullw %%xmm9, %%xmm6 \n\t" "paddw %%xmm3, %%xmm4 \n\t" /* dst = dst + src */ "paddw %%xmm5, %%xmm6 \n\t" "psrlw $8, %%xmm4 \n\t" /* dst = dst >> 8 */ "psrlw $8, %%xmm6 \n\t" // "pminsw %%xmm9, %%xmm4 \n\t" /* clamp values */ // "pminsw %%xmm9, %%xmm6 \n\t" /* xmm6 (dst_l) 00 U4 00 V4 00 U3 00 V3 00 U2 00 V2 00 U1 00 V1 xmm4 (dst_u) 00 U8 00 V8 00 U7 00 V7 00 U6 00 V6 00 U5 00 V5 */ "packuswb %%xmm4, %%xmm6 \n\t" /* xmm6 (dst) U8 V8 U7 V7 U6 V6 U5 V5 U4 V4 U3 V3 U2 V2 U1 V1 */ "movdqu %%xmm6, (%3) \n\t" /* store dst */ /* increment pointers */ "add $0x08, %1 \n\t" "add $0x08, %5 \n\t" "add $0x10, %2 \n\t" "add $0x10, %3 \n\t" "dec %6 \n\t" "jnz loop_start \n\t" : : "r" (weight >> 8), "r" (alpha_b), "r" (src), "r" (dest), "r" (const1) , "r" (alpha_a), "r" (width / 8) //: "xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7","xmm8","xmm9", "memory" ); }; mlt-0.9.0/src/modules/core/consumer_multi.c000066400000000000000000000447641215300731300207260ustar00rootroot00000000000000/* * Copyright (C) 2011 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include // Forward references static int start( mlt_consumer consumer ); static int stop( mlt_consumer consumer ); static int is_stopped( mlt_consumer consumer ); static void *consumer_thread( void *arg ); static void consumer_close( mlt_consumer consumer ); static void purge( mlt_consumer consumer ); static mlt_properties normalisers = NULL; /** Initialise the consumer. */ mlt_consumer consumer_multi_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_consumer consumer = mlt_consumer_new( profile ); if ( consumer ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer); // Set defaults mlt_properties_set( properties, "resource", arg ); mlt_properties_set_int( properties, "real_time", -1 ); mlt_properties_set_int( properties, "terminate_on_pause", 1 ); // Init state mlt_properties_set_int( properties, "joined", 1 ); // Assign callbacks consumer->close = consumer_close; consumer->start = start; consumer->stop = stop; consumer->is_stopped = is_stopped; consumer->purge = purge; } return consumer; } static mlt_consumer create_consumer( mlt_profile profile, char *id, char *arg ) { char *myid = id ? strdup( id ) : NULL; char *myarg = ( myid && !arg ) ? strchr( myid, ':' ) : NULL; if ( myarg ) *myarg ++ = '\0'; else myarg = arg; mlt_consumer consumer = mlt_factory_consumer( profile, myid, myarg ); if ( myid ) free( myid ); return consumer; } static void create_filter( mlt_profile profile, mlt_service service, char *effect, int *created ) { char *id = strdup( effect ); char *arg = strchr( id, ':' ); if ( arg != NULL ) *arg ++ = '\0'; // We cannot use GLSL-based filters here. if ( strncmp( effect, "movit.", 6 ) && strncmp( effect, "glsl.", 5 ) ) { mlt_filter filter; // The swscale and avcolor_space filters require resolution as arg to test compatibility if ( strncmp( effect, "swscale", 7 ) == 0 || strncmp( effect, "avcolo", 6 ) == 0 ) { int width = mlt_properties_get_int( MLT_SERVICE_PROPERTIES( service ), "meta.media.width" ); filter = mlt_factory_filter( profile, id, &width ); } else { filter = mlt_factory_filter( profile, id, arg ); } if ( filter ) { mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "_loader", 1 ); mlt_service_attach( service, filter ); mlt_filter_close( filter ); *created = 1; } } free( id ); } static void attach_normalisers( mlt_profile profile, mlt_service service ) { // Loop variable int i; // Tokeniser mlt_tokeniser tokeniser = mlt_tokeniser_init( ); // We only need to load the normalising properties once if ( normalisers == NULL ) { char temp[ 1024 ]; snprintf( temp, sizeof(temp), "%s/core/loader.ini", mlt_environment( "MLT_DATA" ) ); normalisers = mlt_properties_load( temp ); mlt_factory_register_for_clean_up( normalisers, ( mlt_destructor )mlt_properties_close ); } // Apply normalisers for ( i = 0; i < mlt_properties_count( normalisers ); i ++ ) { int j = 0; int created = 0; char *value = mlt_properties_get_value( normalisers, i ); mlt_tokeniser_parse_new( tokeniser, value, "," ); for ( j = 0; !created && j < mlt_tokeniser_count( tokeniser ); j ++ ) create_filter( profile, service, mlt_tokeniser_get_string( tokeniser, j ), &created ); } // Close the tokeniser mlt_tokeniser_close( tokeniser ); // Attach the audio and video format converters int created = 0; // movit.convert skips setting the frame->convert_image pointer if GLSL cannot be used. mlt_filter filter = mlt_factory_filter( profile, "movit.convert", NULL ); if ( filter != NULL ) { mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "_loader", 1 ); mlt_service_attach( service, filter ); mlt_filter_close( filter ); created = 1; } // avcolor_space and imageconvert only set frame->convert_image if it has not been set. create_filter( profile, service, "avcolor_space", &created ); if ( !created ) create_filter( profile, service, "imageconvert", &created ); create_filter( profile, service, "audioconvert", &created ); } static void on_frame_show( void *dummy, mlt_properties properties, mlt_frame frame ) { mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); } static mlt_consumer generate_consumer( mlt_consumer consumer, mlt_properties props, int index ) { mlt_profile profile = NULL; if ( mlt_properties_get( props, "mlt_profile" ) ) profile = mlt_profile_init( mlt_properties_get( props, "mlt_profile" ) ); if ( !profile ) profile = mlt_profile_clone( mlt_service_profile( MLT_CONSUMER_SERVICE(consumer) ) ); mlt_consumer nested = create_consumer( profile, mlt_properties_get( props, "mlt_service" ), mlt_properties_get( props, "target" ) ); if ( nested ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer); mlt_properties nested_props = MLT_CONSUMER_PROPERTIES(nested); char key[30]; snprintf( key, sizeof(key), "%d.consumer", index ); mlt_properties_set_data( properties, key, nested, 0, (mlt_destructor) mlt_consumer_close, NULL ); snprintf( key, sizeof(key), "%d.profile", index ); mlt_properties_set_data( properties, key, profile, 0, (mlt_destructor) mlt_profile_close, NULL ); mlt_properties_set_int( nested_props, "put_mode", 1 ); mlt_properties_pass_list( nested_props, properties, "terminate_on_pause" ); mlt_properties_set( props, "consumer", NULL ); // set mlt_profile before other properties to facilitate presets mlt_properties_pass_list( nested_props, props, "mlt_profile" ); mlt_properties_inherit( nested_props, props ); attach_normalisers( profile, MLT_CONSUMER_SERVICE(nested) ); // Relay the first available consumer-frame-show event mlt_event event = mlt_properties_get_data( properties, "frame-show-event", NULL ); if ( !event ) { event = mlt_events_listen( nested_props, properties, "consumer-frame-show", (mlt_listener) on_frame_show ); mlt_properties_set_data( properties, "frame-show-event", event, 0, /*mlt_event_close*/ NULL, NULL ); } } else { mlt_profile_close( profile ); } return nested; } static void foreach_consumer_init( mlt_consumer consumer ) { const char *resource = mlt_properties_get( MLT_CONSUMER_PROPERTIES(consumer), "resource" ); mlt_properties properties = mlt_properties_parse_yaml( resource ); char key[20]; int index = 0; if ( mlt_properties_get_data( MLT_CONSUMER_PROPERTIES(consumer), "0", NULL ) ) { // Properties set directly by application mlt_properties p; if ( properties ) mlt_properties_close( properties ); properties = MLT_CONSUMER_PROPERTIES(consumer); do { snprintf( key, sizeof(key), "%d", index ); if ( ( p = mlt_properties_get_data( properties, key, NULL ) ) ) generate_consumer( consumer, p, index++ ); } while ( p ); } else if ( properties && mlt_properties_get_data( properties, "0", NULL ) ) { // YAML file supplied mlt_properties p; do { snprintf( key, sizeof(key), "%d", index ); if ( ( p = mlt_properties_get_data( properties, key, NULL ) ) ) generate_consumer( consumer, p, index++ ); } while ( p ); mlt_properties_close( properties ); } else { // properties file supplied or properties on this consumer const char *s; if ( properties ) mlt_properties_close( properties ); if ( resource ) properties = mlt_properties_load( resource ); else properties = MLT_CONSUMER_PROPERTIES( consumer ); do { snprintf( key, sizeof(key), "%d", index ); if ( ( s = mlt_properties_get( properties, key ) ) ) { mlt_properties p = mlt_properties_new(); int i, count; if ( !p ) break; mlt_properties_set( p, "mlt_service", mlt_properties_get( properties, key ) ); snprintf( key, sizeof(key), "%d.", index ); count = mlt_properties_count( properties ); for ( i = 0; i < count; i++ ) { char *name = mlt_properties_get_name( properties, i ); if ( !strncmp( name, key, strlen(key) ) ) mlt_properties_set( p, name + strlen(key), mlt_properties_get_value( properties, i ) ); } generate_consumer( consumer, p, index++ ); mlt_properties_close( p ); } } while ( s ); if ( resource ) mlt_properties_close( properties ); } } static void foreach_consumer_start( mlt_consumer consumer ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_consumer nested = NULL; char key[30]; int index = 0; do { snprintf( key, sizeof(key), "%d.consumer", index++ ); nested = mlt_properties_get_data( properties, key, NULL ); if ( nested ) { mlt_properties nested_props = MLT_CONSUMER_PROPERTIES(nested); mlt_properties_set_position( nested_props, "_multi_position", 0 ); mlt_properties_set_data( nested_props, "_multi_audio", NULL, 0, NULL, NULL ); mlt_properties_set_int( nested_props, "_multi_samples", 0 ); mlt_consumer_start( nested ); } } while ( nested ); } static void foreach_consumer_refresh( mlt_consumer consumer ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_consumer nested = NULL; char key[30]; int index = 0; do { snprintf( key, sizeof(key), "%d.consumer", index++ ); nested = mlt_properties_get_data( properties, key, NULL ); if ( nested ) mlt_properties_set_int( MLT_CONSUMER_PROPERTIES(nested), "refresh", 1 ); } while ( nested ); } static void foreach_consumer_put( mlt_consumer consumer, mlt_frame frame ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_consumer nested = NULL; char key[30]; int index = 0; do { snprintf( key, sizeof(key), "%d.consumer", index++ ); nested = mlt_properties_get_data( properties, key, NULL ); if ( nested ) { mlt_properties nested_props = MLT_CONSUMER_PROPERTIES(nested); double self_fps = mlt_properties_get_double( properties, "fps" ); double nested_fps = mlt_properties_get_double( nested_props, "fps" ); mlt_position nested_pos = mlt_properties_get_position( nested_props, "_multi_position" ); mlt_position self_pos = mlt_frame_get_position( frame ); double self_time = self_pos / self_fps; double nested_time = nested_pos / nested_fps; // get the audio for the current frame uint8_t *buffer = NULL; mlt_audio_format format = mlt_audio_s16; int channels = mlt_properties_get_int( properties, "channels" ); int frequency = mlt_properties_get_int( properties, "frequency" ); int current_samples = mlt_sample_calculator( self_fps, frequency, self_pos ); mlt_frame_get_audio( frame, (void**) &buffer, &format, &frequency, &channels, ¤t_samples ); int current_size = mlt_audio_format_size( format, current_samples, channels ); // get any leftover audio int prev_size = 0; uint8_t *prev_buffer = mlt_properties_get_data( nested_props, "_multi_audio", &prev_size ); uint8_t *new_buffer = NULL; if ( prev_size > 0 ) { new_buffer = mlt_pool_alloc( prev_size + current_size ); memcpy( new_buffer, prev_buffer, prev_size ); memcpy( new_buffer + prev_size, buffer, current_size ); buffer = new_buffer; } current_size += prev_size; current_samples += mlt_properties_get_int( nested_props, "_multi_samples" ); while ( nested_time <= self_time ) { // put ideal number of samples into cloned frame int deeply = index > 1 ? 1 : 0; mlt_frame clone_frame = mlt_frame_clone( frame, deeply ); int nested_samples = mlt_sample_calculator( nested_fps, frequency, nested_pos ); // -10 is an optimization to avoid tiny amounts of leftover samples nested_samples = nested_samples > current_samples - 10 ? current_samples : nested_samples; int nested_size = mlt_audio_format_size( format, nested_samples, channels ); if ( nested_size > 0 ) { prev_buffer = mlt_pool_alloc( nested_size ); memcpy( prev_buffer, buffer, nested_size ); } else { prev_buffer = NULL; nested_size = 0; } mlt_frame_set_audio( clone_frame, prev_buffer, format, nested_size, mlt_pool_release ); mlt_properties_set_int( MLT_FRAME_PROPERTIES(clone_frame), "audio_samples", nested_samples ); mlt_properties_set_int( MLT_FRAME_PROPERTIES(clone_frame), "audio_frequency", frequency ); mlt_properties_set_int( MLT_FRAME_PROPERTIES(clone_frame), "audio_channels", channels ); // chomp the audio current_samples -= nested_samples; current_size -= nested_size; buffer += nested_size; // send frame to nested consumer mlt_consumer_put_frame( nested, clone_frame ); mlt_properties_set_position( nested_props, "_multi_position", ++nested_pos ); nested_time = nested_pos / nested_fps; } // save any remaining audio if ( current_size > 0 ) { prev_buffer = mlt_pool_alloc( current_size ); memcpy( prev_buffer, buffer, current_size ); } else { prev_buffer = NULL; current_size = 0; } mlt_pool_release( new_buffer ); mlt_properties_set_data( nested_props, "_multi_audio", prev_buffer, current_size, mlt_pool_release, NULL ); mlt_properties_set_int( nested_props, "_multi_samples", current_samples ); } } while ( nested ); } static void foreach_consumer_stop( mlt_consumer consumer ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_consumer nested = NULL; char key[30]; int index = 0; struct timespec tm = { 0, 1000 * 1000 }; do { snprintf( key, sizeof(key), "%d.consumer", index++ ); nested = mlt_properties_get_data( properties, key, NULL ); if ( nested ) { // Let consumer with terminate_on_pause stop on their own if ( mlt_properties_get_int( MLT_CONSUMER_PROPERTIES(nested), "terminate_on_pause" ) ) { // Send additional dummy frame to unlatch nested consumer's threads mlt_consumer_put_frame( nested, mlt_frame_init( MLT_CONSUMER_SERVICE(consumer) ) ); // wait for stop while ( !mlt_consumer_is_stopped( nested ) ) nanosleep( &tm, NULL ); } else { mlt_consumer_stop( nested ); } } } while ( nested ); } /** Start the consumer. */ static int start( mlt_consumer consumer ) { // Check that we're not already running if ( is_stopped( consumer ) ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); pthread_t *thread = calloc( 1, sizeof( pthread_t ) ); // Assign the thread to properties with automatic dealloc mlt_properties_set_data( properties, "thread", thread, sizeof( pthread_t ), free, NULL ); // Set the running state mlt_properties_set_int( properties, "running", 1 ); mlt_properties_set_int( properties, "joined", 0 ); // Construct and start nested consumers if ( !mlt_properties_get_data( properties, "0.consumer", NULL ) ) foreach_consumer_init( consumer ); foreach_consumer_start( consumer ); // Create the thread pthread_create( thread, NULL, consumer_thread, consumer ); } return 0; } /** Stop the consumer. */ static int stop( mlt_consumer consumer ) { // Check that we're running if ( !mlt_properties_get_int( MLT_CONSUMER_PROPERTIES(consumer), "joined" ) ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); pthread_t *thread = mlt_properties_get_data( properties, "thread", NULL ); // Stop the thread mlt_properties_set_int( properties, "running", 0 ); // Wait for termination if ( thread ) { foreach_consumer_refresh( consumer ); pthread_join( *thread, NULL ); } mlt_properties_set_int( properties, "joined", 1 ); // Stop nested consumers foreach_consumer_stop( consumer ); } return 0; } /** Determine if the consumer is stopped. */ static int is_stopped( mlt_consumer consumer ) { return !mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( consumer ), "running" ); } /** Purge each of the child consumers. */ static void purge( mlt_consumer consumer ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); if ( mlt_properties_get_int( properties, "running" ) ) { mlt_consumer nested = NULL; char key[30]; int index = 0; do { snprintf( key, sizeof(key), "%d.consumer", index++ ); nested = mlt_properties_get_data( properties, key, NULL ); if ( nested ) mlt_consumer_purge( nested ); } while ( nested ); } } /** The main thread - the argument is simply the consumer. */ static void *consumer_thread( void *arg ) { mlt_consumer consumer = arg; mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_frame frame = NULL; // Determine whether to stop at end-of-media int terminate_on_pause = mlt_properties_get_int( properties, "terminate_on_pause" ); int terminated = 0; // Loop while running while ( !terminated && !is_stopped( consumer ) ) { // Get the next frame frame = mlt_consumer_rt_frame( consumer ); // Check for termination if ( terminate_on_pause && frame ) terminated = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0; // Check that we have a frame to work with if ( frame && !terminated && !is_stopped( consumer ) ) { if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES(frame), "rendered" ) ) { if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES(frame), "_speed" ) == 0 ) foreach_consumer_refresh( consumer ); foreach_consumer_put( consumer, frame ); } else { int dropped = mlt_properties_get_int( properties, "_dropped" ); mlt_log_info( MLT_CONSUMER_SERVICE(consumer), "dropped frame %d\n", ++dropped ); mlt_properties_set_int( properties, "_dropped", dropped ); } mlt_frame_close( frame ); } else { if ( frame && terminated ) { // Send this termination frame to nested consumers for their cancellation foreach_consumer_put( consumer, frame ); } if ( frame ) mlt_frame_close( frame ); terminated = 1; } } // Indicate that the consumer is stopped mlt_consumer_stopped( consumer ); return NULL; } /** Close the consumer. */ static void consumer_close( mlt_consumer consumer ) { mlt_consumer_stop( consumer ); // Close the parent mlt_consumer_close( consumer ); free( consumer ); } mlt-0.9.0/src/modules/core/consumer_multi.yml000066400000000000000000000026561215300731300212770ustar00rootroot00000000000000schema_version: 0.1 type: consumer identifier: multi title: Multiple outputs version: 1 copyright: Copyright (C) 2011 Ushodaya Enterprises Limited license: LGPL language: en creator: Dan Dennedy tags: - Audio - Video description: Use multiple consumers with the same producer. notes: | There are a few ways of defining each of the outputs and their properties. One form is a flat set of properties on this consumer that follows the pattern: = [.=]* For example, 0=sdl 0.rescale=bilinear 1=avformat 1.target=foo.dv ... To change the profile for a particular output set the property "mlt_profile." You can put these into a MLT properties file and supply that to this consumer. Another way is to create a separate properties list for each output and set that on the consumer with a numeric name starting with zero: = ... In this format, to specify the service, use the property name "mlt_service" and, again, to specify the profile, use "mlt_profile." You can put these into a YAML Tiny file and supply that to this consumer. This is also the recommended way for applications to interact with this consumer, which is how melt and the XML producer support multiple consumers. parameters: - identifier: argument title: File type: string description: > A properties or YAML file specifying multiple consumers and their properties. required: no mlt-0.9.0/src/modules/core/consumer_null.c000066400000000000000000000112061215300731300205270ustar00rootroot00000000000000/* * consumer_null.c -- a null consumer * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // mlt Header files #include #include // System header files #include #include #include #include // Forward references. static int consumer_start( mlt_consumer this ); static int consumer_stop( mlt_consumer this ); static int consumer_is_stopped( mlt_consumer this ); static void *consumer_thread( void *arg ); static void consumer_close( mlt_consumer this ); /** Initialise the dv consumer. */ mlt_consumer consumer_null_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Allocate the consumer mlt_consumer this = mlt_consumer_new( profile ); // If memory allocated and initialises without error if ( this != NULL ) { // Assign close callback this->close = consumer_close; // Set up start/stop/terminated callbacks this->start = consumer_start; this->stop = consumer_stop; this->is_stopped = consumer_is_stopped; } // Return this return this; } /** Start the consumer. */ static int consumer_start( mlt_consumer this ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); // Check that we're not already running if ( !mlt_properties_get_int( properties, "running" ) ) { // Allocate a thread pthread_t *thread = calloc( 1, sizeof( pthread_t ) ); // Assign the thread to properties mlt_properties_set_data( properties, "thread", thread, sizeof( pthread_t ), free, NULL ); // Set the running state mlt_properties_set_int( properties, "running", 1 ); mlt_properties_set_int( properties, "joined", 0 ); // Create the thread pthread_create( thread, NULL, consumer_thread, this ); } return 0; } /** Stop the consumer. */ static int consumer_stop( mlt_consumer this ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); // Check that we're running if ( !mlt_properties_get_int( properties, "joined" ) ) { // Get the thread pthread_t *thread = mlt_properties_get_data( properties, "thread", NULL ); // Stop the thread mlt_properties_set_int( properties, "running", 0 ); mlt_properties_set_int( properties, "joined", 1 ); // Wait for termination if ( thread ) pthread_join( *thread, NULL ); } return 0; } /** Determine if the consumer is stopped. */ static int consumer_is_stopped( mlt_consumer this ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); return !mlt_properties_get_int( properties, "running" ); } /** The main thread - the argument is simply the consumer. */ static void *consumer_thread( void *arg ) { // Map the argument to the object mlt_consumer this = arg; // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); // Convenience functionality int terminate_on_pause = mlt_properties_get_int( properties, "terminate_on_pause" ); int terminated = 0; // Frame and size mlt_frame frame = NULL; // Loop while running while( !terminated && mlt_properties_get_int( properties, "running" ) ) { // Get the frame frame = mlt_consumer_rt_frame( this ); // Check for termination if ( terminate_on_pause && frame != NULL ) terminated = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0; // Check that we have a frame to work with if ( frame != NULL ) { // Close the frame mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); mlt_frame_close( frame ); } } // Indicate that the consumer is stopped mlt_properties_set_int( properties, "running", 0 ); mlt_consumer_stopped( this ); return NULL; } /** Close the consumer. */ static void consumer_close( mlt_consumer this ) { // Stop the consumer mlt_consumer_stop( this ); // Close the parent mlt_consumer_close( this ); // Free the memory free( this ); } mlt-0.9.0/src/modules/core/data_fx.properties000066400000000000000000000174101215300731300212250ustar00rootroot00000000000000# This properties file describes the fx available to the data_send and # data_show filters # # Syntax is as follows: # # name= # name.description= # name.properties.= # name.=value # etc # # Typically, the is a 'region' and additional filters are # included as properties using the normal region filter syntax. # # # The titles filter definition # titles=region .description=Titles .properties.markup=filter[1].producer.markup .type.markup=text .period=2 .properties.length[0]=filter[0].composite.out .properties.length[1]=filter[1].composite.out .composite.geometry=5%,70%:90%x20% .filter[0]=watermark .filter[0].resource=colour:0x000000 .filter[0].composite.geometry=0%,0%:100%x100%:0;5=0%,0%:100%x100%:40 .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup=Shotcut .filter[1].composite.geometry=0%,0%:100%x100%:0;8=0%,0%:100%x100%:100 .filter[1].composite.titles=1 # # The top titles filter definition # top-titles=region .description=Top Titles .properties.markup=filter[1].producer.markup .type.markup=text .period=2 .properties.length[0]=filter[0].composite.out .properties.length[1]=filter[1].composite.out .composite.geometry=5%,5%:90%x20% .filter[0]=watermark .filter[0].resource=colour:0x000000 .filter[0].composite.geometry=0%,0%:100%x100%:0;5=0%,0%:100%x100%:40 .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup=Shotcut .filter[1].composite.geometry=0%,0%:100%x100%:0;8=0%,0%:100%x100%:100 .filter[1].composite.halign=centre .filter[1].composite.titles=1 # # OK - Silly example... # tickertape=region .description=Tickertape .properties.markup=filter[1].producer.markup .type.markup=text .properties.length[0]=filter[1].composite.out .composite.geometry=0%,93%:100%x7% .filter[0]=watermark .filter[0].resource=colour:0x000000 .filter[0].composite.geometry=0%,0%:100%x100%:100 .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup=Shotcut .filter[1].composite.geometry=100%,0%:300%x100%:100;-1=-300%,0%:300%x100%:100 .filter[1].producer.family=San .filter[1].producer.size=32 .filter[1].composite.titles=1 # # ETV Location # location=region .description=Titles .properties.markup=filter[1].producer.markup .type.markup=text .period=2 .properties.length[0]=filter[0].composite.out .properties.length[1]=filter[1].composite.out .composite.geometry=0,80:230x30 .filter[0]=watermark .filter[0].resource=colour:0x6c010100 .filter[0].composite.geometry=-100%,0%:100%x100%:100;25=0%,0%:100%x100%:100 .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup= .filter[1].producer.family=San .filter[1].producer.size=24 .filter[1].composite.geometry=0%,0%:100%x100%:0;24=0%,0%:100%x100%:0;49=0%,0%:100%x100%:100 .filter[1].composite.titles=1 .filter[1].composite.halign=right .filter[1].composite.valign=center courtesy=region .description=Titles .properties.markup=filter[1].producer.markup .type.markup=text .period=2 .properties.length[0]=filter[0].composite.out .properties.length[1]=filter[1].composite.out .composite.geometry=0,115:230x30 .filter[0]=watermark .filter[0].resource=colour:0x6c010100 .filter[0].composite.geometry=-100%,0%:100%x100%:0;12=-100%,0%:100%x100%:0;37=0%,0%:100%x100%:100 .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup=ETV Exclusive .filter[1].producer.family=San .filter[1].producer.size=24 .filter[1].composite.geometry=0%,0%:100%x100%:0;37=0%,0%:100%x100%:0;61=0%,0%:100%x100%:100 .filter[1].composite.titles=1 .filter[1].composite.halign=right .filter[1].composite.valign=right exclusive=region .description=Exclusive .period=2 .properties.length[0]=filter[0].composite.out .properties.length[1]=filter[1].composite.out .composite.geometry=0,115:230x30 .filter[0]=watermark .filter[0].resource=colour:0x6c010100 .filter[0].composite.geometry=0%,0%:100%x100%:10;25=0%,0%:100%x100%:100 .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup=ETV Exclusive .filter[1].producer.family=San .filter[1].producer.size=24 .filter[1].composite.geometry=0%,0%:100%x100%:10;25=0%,0%:100%x100%:100 .filter[1].composite.titles=1 .filter[1].composite.halign=right .filter[1].composite.valign=right file_shot=region .description=Titles .period=2 .properties.length[0]=filter[0].composite.out .properties.length[1]=filter[1].composite.out .composite.geometry=590,160:80x25 .filter[0]=watermark .filter[0].resource=colour:0x6c010100 .filter[0].composite.geometry=0%,0%:100%x100%:10;25=0%,0%:100%x100%:100 .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup=File Shot .filter[1].producer.family=San .filter[1].producer.size=18 .filter[1].composite.geometry=0%,0%:100%x100%:15;25=0%,0%:100%x100%:100 .filter[1].composite.titles=0 .filter[1].composite.halign=centre .filter[1].composite.valign=centre special=region .description=Titles .period=2 .properties.length[0]=filter[0].composite.out .properties.length[1]=filter[1].composite.out .composite.geometry=465,375:255x35 .filter[0]=watermark .filter[0].resource=colour:0x6c010100 .filter[0].composite.geometry=100%,0%:100%x100%:0;49=100%,0%:100%x100%:0;74=0%,0%:100%x100%:100 .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup=Special .filter[1].producer.family=San .filter[1].producer.size=24 .filter[1].composite.geometry=100%,0%:100%x100%:0;49=100%,0%:100%x100%:0;74=0%,0%:100%x100%:100 .filter[1].composite.titles=1 .filter[1].composite.halign=centre .filter[1].composite.valign=centre ticker=region .description=Tickertape .properties.markup=filter[1].producer.markup .type.markup=text .properties.length[0]=filter[1].composite.out .composite.geometry=0,500:722x75 .filter[0]=watermark .filter[0].resource=colour:0x6c010100 .filter[0].composite.geometry=0%,0%:100%x100%:100 .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup=Ticker - provided for reference .filter[1].composite.geometry=0%,0%:100%x100%:100 .filter[1].composite.titles=0 .filter[1].producer.family=San .filter[1].producer.size=24 .filter[1].composite.halign=centre .filter[1].composite.titles=1 .filter[1].composite.valign=centre super=region .description=Transcription .properties.0=filter[1].producer.markup .properties.1=filter[2].producer.markup .properties.align=filter[1].composite.valign .properties.length[0]=filter[0].composite.out .properties.length[1]=filter[1].composite.out .properties.length[2]=filter[2].composite.out .period=2 .composite.geometry=0,410:720x90 .filter[0]=watermark .filter[0].resource=colour:0xbbbbbb00 .filter[0].composite.geometry=0%,0%:100%x100%:10;25=0%,0%:100%x100%:100 .filter[0].composite.titles=1 .filter[0].composite.luma=%luma18.pgm .filter[0].composite.out=25 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup= .filter[1].producer.family=San .filter[1].producer.size=32 .filter[1].producer.fgcolour=0x6c0101ff .filter[1].composite.geometry=0%,0%:100%x100%:10;25=0%,0%:100%x100%:100 .filter[1].composite.titles=1 .filter[1].composite.halign=centre .filter[1].composite.valign=top .filter[2]=watermark .filter[2].resource=pango: .filter[2].producer.markup= .filter[1].producer.family=San .filter[1].producer.size=32 .filter[2].producer.fgcolour=0x6c0101ff .filter[2].composite.geometry=0%,0%:100%x100%:10;25=0%,0%:100%x100%:100 .filter[2].composite.titles=1 .filter[2].composite.halign=centre .filter[2].composite.valign=bottom obscure=region .description=Obscure .properties.geometry=composite.geometry .properties.resource=resource .properties.length[0]=composite.out .composite.geometry= .resource=rectangle .composite.refresh=1 .filter[0]=obscure .filter[0].start=0,0:100%x100% mlt-0.9.0/src/modules/core/factory.c000066400000000000000000000242701215300731300173160ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include extern mlt_consumer consumer_multi_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_consumer consumer_null_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_audiochannels_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_audioconvert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_audiowave_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_brightness_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_channelcopy_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_crop_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_data_feed_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_data_show_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_fieldorder_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_gamma_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_greyscale_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_imageconvert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_luma_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_mirror_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_mono_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_obscure_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_panner_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_region_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_rescale_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_resize_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_transition_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_watermark_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_colour_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_consumer_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_hold_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_loader_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_melt_file_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_melt_init( mlt_profile profile, mlt_service_type type, const char *id, char **argv ); extern mlt_producer producer_noise_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_ppm_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); #include "transition_composite.h" extern mlt_transition transition_luma_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_transition transition_mix_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); #include "transition_region.h" static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/core/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( consumer_type, "multi", consumer_multi_init ); MLT_REGISTER( consumer_type, "null", consumer_null_init ); MLT_REGISTER( filter_type, "audiochannels", filter_audiochannels_init ); MLT_REGISTER( filter_type, "audioconvert", filter_audioconvert_init ); MLT_REGISTER( filter_type, "audiowave", filter_audiowave_init ); MLT_REGISTER( filter_type, "brightness", filter_brightness_init ); MLT_REGISTER( filter_type, "channelcopy", filter_channelcopy_init ); MLT_REGISTER( filter_type, "channelswap", filter_channelcopy_init ); MLT_REGISTER( filter_type, "crop", filter_crop_init ); MLT_REGISTER( filter_type, "data_feed", filter_data_feed_init ); MLT_REGISTER( filter_type, "data_show", filter_data_show_init ); MLT_REGISTER( filter_type, "fieldorder", filter_fieldorder_init ); MLT_REGISTER( filter_type, "gamma", filter_gamma_init ); MLT_REGISTER( filter_type, "greyscale", filter_greyscale_init ); MLT_REGISTER( filter_type, "grayscale", filter_greyscale_init ); MLT_REGISTER( filter_type, "imageconvert", filter_imageconvert_init ); MLT_REGISTER( filter_type, "luma", filter_luma_init ); MLT_REGISTER( filter_type, "mirror", filter_mirror_init ); MLT_REGISTER( filter_type, "mono", filter_mono_init ); MLT_REGISTER( filter_type, "obscure", filter_obscure_init ); MLT_REGISTER( filter_type, "panner", filter_panner_init ); MLT_REGISTER( filter_type, "region", filter_region_init ); MLT_REGISTER( filter_type, "rescale", filter_rescale_init ); MLT_REGISTER( filter_type, "resize", filter_resize_init ); MLT_REGISTER( filter_type, "transition", filter_transition_init ); MLT_REGISTER( filter_type, "watermark", filter_watermark_init ); MLT_REGISTER( producer_type, "abnormal", producer_loader_init ); MLT_REGISTER( producer_type, "color", producer_colour_init ); MLT_REGISTER( producer_type, "colour", producer_colour_init ); MLT_REGISTER( producer_type, "consumer", producer_consumer_init ); MLT_REGISTER( producer_type, "hold", producer_hold_init ); MLT_REGISTER( producer_type, "loader", producer_loader_init ); MLT_REGISTER( producer_type, "melt", producer_melt_init ); MLT_REGISTER( producer_type, "melt_file", producer_melt_file_init ); MLT_REGISTER( producer_type, "noise", producer_noise_init ); MLT_REGISTER( producer_type, "ppm", producer_ppm_init ); MLT_REGISTER( transition_type, "composite", transition_composite_init ); MLT_REGISTER( transition_type, "luma", transition_luma_init ); MLT_REGISTER( transition_type, "mix", transition_mix_init ); MLT_REGISTER( transition_type, "region", transition_region_init ); MLT_REGISTER_METADATA( consumer_type, "multi", metadata, "consumer_multi.yml" ); MLT_REGISTER_METADATA( filter_type, "audiowave", metadata, "filter_audiowave.yml" ); MLT_REGISTER_METADATA( filter_type, "brightness", metadata, "filter_brightness.yml" ); MLT_REGISTER_METADATA( filter_type, "channelcopy", metadata, "filter_channelcopy.yml" ); MLT_REGISTER_METADATA( filter_type, "channelswap", metadata, "filter_channelcopy.yml" ); MLT_REGISTER_METADATA( filter_type, "crop", metadata, "filter_crop.yml" ); MLT_REGISTER_METADATA( filter_type, "data_show", metadata, "filter_data_show.yml" ); MLT_REGISTER_METADATA( filter_type, "fieldorder", metadata, "filter_fieldorder.yml" ); MLT_REGISTER_METADATA( filter_type, "gamma", metadata, "filter_gamma.yml" ); MLT_REGISTER_METADATA( filter_type, "greyscale", metadata, "filter_greyscale.yml" ); MLT_REGISTER_METADATA( filter_type, "grayscale", metadata, "filter_greyscale.yml" ); MLT_REGISTER_METADATA( filter_type, "luma", metadata, "filter_luma.yml" ); MLT_REGISTER_METADATA( filter_type, "mirror", metadata, "filter_mirror.yml" ); MLT_REGISTER_METADATA( filter_type, "mono", metadata, "filter_mono.yml" ); MLT_REGISTER_METADATA( filter_type, "obscure", metadata, "filter_obscure.yml" ); MLT_REGISTER_METADATA( filter_type, "region", metadata, "filter_region.yml" ); MLT_REGISTER_METADATA( filter_type, "rescale", metadata, "filter_rescale.yml" ); MLT_REGISTER_METADATA( filter_type, "resize", metadata, "filter_resize.yml" ); MLT_REGISTER_METADATA( filter_type, "transition", metadata, "filter_transition.yml" ); MLT_REGISTER_METADATA( filter_type, "watermark", metadata, "filter_watermark.yml" ); MLT_REGISTER_METADATA( producer_type, "colour", metadata, "producer_colour.yml" ); MLT_REGISTER_METADATA( producer_type, "color", metadata, "producer_colour.yml" ); MLT_REGISTER_METADATA( producer_type, "consumer", metadata, "producer_consumer.yml" ); MLT_REGISTER_METADATA( producer_type, "hold", metadata, "producer_hold.yml" ); MLT_REGISTER_METADATA( producer_type, "loader", metadata, "producer_loader.yml" ); MLT_REGISTER_METADATA( producer_type, "melt", metadata, "producer_melt.yml" ); MLT_REGISTER_METADATA( producer_type, "melt_file", metadata, "producer_melt_file.yml" ); MLT_REGISTER_METADATA( producer_type, "noise", metadata, "producer_noise.yml" ); MLT_REGISTER_METADATA( transition_type, "composite", metadata, "transition_composite.yml" ); MLT_REGISTER_METADATA( transition_type, "luma", metadata, "transition_luma.yml" ); MLT_REGISTER_METADATA( transition_type, "mix", metadata, "transition_mix.yml" ); MLT_REGISTER_METADATA( transition_type, "region", metadata, "transition_region.yml" ); } mlt-0.9.0/src/modules/core/filter_audiochannels.c000066400000000000000000000103101215300731300220170ustar00rootroot00000000000000/* * filter_audiochannels.c -- convert from one audio format to another * Copyright (C) 2009-2012 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Used to return number of channels in the source int channels_avail = *channels; // Get the producer's audio int error = mlt_frame_get_audio( frame, buffer, format, frequency, &channels_avail, samples ); if ( error ) return error; if ( channels_avail < *channels ) { int size = mlt_audio_format_size( *format, *samples, *channels ); int16_t *new_buffer = mlt_pool_alloc( size ); // Duplicate the existing channels if ( *format == mlt_audio_s16 ) { int i, j, k = 0; for ( i = 0; i < *samples; i++ ) { for ( j = 0; j < *channels; j++ ) { new_buffer[ ( i * *channels ) + j ] = ((int16_t*)(*buffer))[ ( i * channels_avail ) + k ]; k = ( k + 1 ) % channels_avail; } } } else if ( *format == mlt_audio_s32le || *format == mlt_audio_f32le ) { int32_t *p = (int32_t*) new_buffer; int i, j, k = 0; for ( i = 0; i < *samples; i++ ) { for ( j = 0; j < *channels; j++ ) { p[ ( i * *channels ) + j ] = ((int32_t*)(*buffer))[ ( i * channels_avail ) + k ]; k = ( k + 1 ) % channels_avail; } } } else if ( *format == mlt_audio_u8 ) { uint8_t *p = (uint8_t*) new_buffer; int i, j, k = 0; for ( i = 0; i < *samples; i++ ) { for ( j = 0; j < *channels; j++ ) { p[ ( i * *channels ) + j ] = ((uint8_t*)(*buffer))[ ( i * channels_avail ) + k ]; k = ( k + 1 ) % channels_avail; } } } else { // non-interleaved - s32 or float int size_avail = mlt_audio_format_size( *format, *samples, channels_avail ); int32_t *p = (int32_t*) new_buffer; int i = *channels / channels_avail; while ( i-- ) { memcpy( p, *buffer, size_avail ); p += size_avail / sizeof(*p); } i = *channels % channels_avail; if ( i ) { size_avail = mlt_audio_format_size( *format, *samples, i ); memcpy( p, *buffer, size_avail ); } } // Update the audio buffer now - destroys the old mlt_frame_set_audio( frame, new_buffer, *format, size, mlt_pool_release ); *buffer = new_buffer; } else if ( channels_avail > *channels ) { int size = mlt_audio_format_size( *format, *samples, *channels ); int16_t *new_buffer = mlt_pool_alloc( size ); // Drop all but the first *channels if ( *format == mlt_audio_s16 ) { int i, j; for ( i = 0; i < *samples; i++ ) for ( j = 0; j < *channels; j++ ) new_buffer[ ( i * *channels ) + j ] = ((int16_t*)(*buffer))[ ( i * channels_avail ) + j ]; } else { // non-interleaved memcpy( new_buffer, *buffer, size ); } // Update the audio buffer now - destroys the old mlt_frame_set_audio( frame, new_buffer, *format, size, mlt_pool_release ); *buffer = new_buffer; } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { mlt_frame_push_audio( frame, filter_get_audio ); return frame; } /** Constructor for the filter. */ mlt_filter filter_audiochannels_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = mlt_filter_new(); if ( filter ) filter->process = filter_process; return filter; } mlt-0.9.0/src/modules/core/filter_audioconvert.c000066400000000000000000000316541215300731300217220ustar00rootroot00000000000000/* * filter_audioconvert.c -- convert from one audio format to another * Copyright (C) 2009-2012 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include static int convert_audio( mlt_frame frame, void **audio, mlt_audio_format *format, mlt_audio_format requested_format ) { int error = 1; mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); int channels = mlt_properties_get_int( properties, "audio_channels" ); int samples = mlt_properties_get_int( properties, "audio_samples" ); int size = mlt_audio_format_size( requested_format, samples, channels ); if ( *format != requested_format ) { mlt_log_debug( NULL, "[filter audioconvert] %s -> %s %d channels %d samples\n", mlt_audio_format_name( *format ), mlt_audio_format_name( requested_format ), channels, samples ); switch ( *format ) { case mlt_audio_s16: switch ( requested_format ) { case mlt_audio_s32: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; int c; for ( c = 0; c < channels; c++ ) { int16_t *q = (int16_t*) *audio + c; int i = samples + 1; while ( --i ) { *p++ = (int32_t) *q << 16; q += channels; } } *audio = buffer; error = 0; break; } case mlt_audio_float: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; int c; for ( c = 0; c < channels; c++ ) { int16_t *q = (int16_t*) *audio + c; int i = samples + 1; while ( --i ) { *p++ = (float)( *q ) / 32768.0; q += channels; } } *audio = buffer; error = 0; break; } case mlt_audio_s32le: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; int16_t *q = (int16_t*) *audio; int i = samples * channels + 1; while ( --i ) *p++ = (int32_t) *q++ << 16; *audio = buffer; error = 0; break; } case mlt_audio_f32le: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; int16_t *q = (int16_t*) *audio; int i = samples * channels + 1; while ( --i ) { float f = (float)( *q++ ) / 32768.0; f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = f; } *audio = buffer; error = 0; break; } case mlt_audio_u8: { uint8_t *buffer = mlt_pool_alloc( size ); uint8_t *p = buffer; int16_t *q = (int16_t*) *audio; int i = samples * channels + 1; while ( --i ) *p++ = ( *q++ >> 8 ) + 128; *audio = buffer; error = 0; break; } default: break; } break; case mlt_audio_s32: switch ( requested_format ) { case mlt_audio_s16: { int16_t *buffer = mlt_pool_alloc( size ); int16_t *p = buffer; int32_t *q = (int32_t*) *audio; int s, c; for ( s = 0; s < samples; s++ ) for ( c = 0; c < channels; c++ ) *p++ = *( q + c * samples + s ) >> 16; *audio = buffer; error = 0; break; } case mlt_audio_float: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; int32_t *q = (int32_t*) *audio; int i = samples * channels + 1; while ( --i ) *p++ = (float)( *q++ ) / 2147483648.0; *audio = buffer; error = 0; break; } case mlt_audio_s32le: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; int32_t *q = (int32_t*) *audio; int s, c; for ( s = 0; s < samples; s++ ) for ( c = 0; c < channels; c++ ) *p++ = *( q + c * samples + s ); *audio = buffer; error = 0; break; } case mlt_audio_f32le: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; int32_t *q = (int32_t*) *audio; int s, c; for ( s = 0; s < samples; s++ ) for ( c = 0; c < channels; c++ ) { float f = (float)( *( q + c * samples + s ) ) / 2147483648.0; f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = f; } *audio = buffer; error = 0; break; } case mlt_audio_u8: { uint8_t *buffer = mlt_pool_alloc( size ); uint8_t *p = buffer; int32_t *q = (int32_t*) *audio; int s, c; for ( s = 0; s < samples; s++ ) for ( c = 0; c < channels; c++ ) *p++ = ( q[c * samples + s] >> 24 ) + 128; *audio = buffer; error = 0; break; } default: break; } break; case mlt_audio_float: switch ( requested_format ) { case mlt_audio_s16: { int16_t *buffer = mlt_pool_alloc( size ); int16_t *p = buffer; float *q = (float*) *audio; int s, c; for ( s = 0; s < samples; s++ ) for ( c = 0; c < channels; c++ ) { float f = *( q + c * samples + s ); f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = 32767 * f; } *audio = buffer; error = 0; break; } case mlt_audio_s32: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; float *q = (float*) *audio; int i = samples * channels + 1; while ( --i ) { float f = *q++; f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = ( f > 0 ? 2147483647LL : 2147483648LL ) * f; } *audio = buffer; error = 0; break; } case mlt_audio_s32le: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; float *q = (float*) *audio; int s, c; for ( s = 0; s < samples; s++ ) for ( c = 0; c < channels; c++ ) { float f = *( q + c * samples + s ); f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = ( f > 0 ? 2147483647LL : 2147483648LL ) * f; } *audio = buffer; error = 0; break; } case mlt_audio_f32le: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; float *q = (float*) *audio; int s, c; for ( s = 0; s < samples; s++ ) for ( c = 0; c < channels; c++ ) *p++ = *( q + c * samples + s ); *audio = buffer; error = 0; break; } case mlt_audio_u8: { uint8_t *buffer = mlt_pool_alloc( size ); uint8_t *p = buffer; float *q = (float*) *audio; int s, c; for ( s = 0; s < samples; s++ ) for ( c = 0; c < channels; c++ ) { float f = *( q + c * samples + s ); f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = ( 127 * f ) + 128; } *audio = buffer; error = 0; break; } default: break; } break; case mlt_audio_s32le: switch ( requested_format ) { case mlt_audio_s16: { int16_t *buffer = mlt_pool_alloc( size ); int16_t *p = buffer; int32_t *q = (int32_t*) *audio; int i = samples * channels + 1; while ( --i ) *p++ = *q++ >> 16; *audio = buffer; error = 0; break; } case mlt_audio_s32: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; int c; for ( c = 0; c < channels; c++ ) { int32_t *q = (int32_t*) *audio + c; int i = samples + 1; while ( --i ) { *p++ = *q; q += channels; } } *audio = buffer; error = 0; break; } case mlt_audio_float: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; int c; for ( c = 0; c < channels; c++ ) { int32_t *q = (int32_t*) *audio + c; int i = samples + 1; while ( --i ) { *p++ = (float)( *q ) / 2147483648.0; q += channels; } } *audio = buffer; error = 0; break; } case mlt_audio_f32le: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; int32_t *q = (int32_t*) *audio; int i = samples * channels + 1; while ( --i ) *p++ = (float)( *q++ ) / 2147483648.0; *audio = buffer; error = 0; break; } case mlt_audio_u8: { uint8_t *buffer = mlt_pool_alloc( size ); uint8_t *p = buffer; int32_t *q = (int32_t*) *audio; int i = samples * channels + 1; while ( --i ) *p++ = ( *q++ >> 24 ) + 128; *audio = buffer; error = 0; break; } default: break; } break; case mlt_audio_f32le: switch ( requested_format ) { case mlt_audio_s16: { int16_t *buffer = mlt_pool_alloc( size ); int16_t *p = buffer; float *q = (float*) *audio; int i = samples * channels + 1; while ( --i ) { float f = *q++; f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = 32767 * f; } *audio = buffer; error = 0; break; } case mlt_audio_float: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; int c; for ( c = 0; c < channels; c++ ) { float *q = (float*) *audio + c; int i = samples + 1; while ( --i ) { *p++ = *q; q += channels; } } *audio = buffer; error = 0; break; } case mlt_audio_s32: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; int c; for ( c = 0; c < channels; c++ ) { float *q = (float*) *audio + c; int i = samples + 1; while ( --i ) { float f = *q; f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = ( f > 0 ? 2147483647LL : 2147483648LL ) * f; q += channels; } } *audio = buffer; error = 0; break; } case mlt_audio_s32le: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; float *q = (float*) *audio; int i = samples * channels + 1; while ( --i ) { float f = *q++; f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = ( f > 0 ? 2147483647LL : 2147483648LL ) * f; } *audio = buffer; error = 0; break; } case mlt_audio_u8: { uint8_t *buffer = mlt_pool_alloc( size ); uint8_t *p = buffer; float *q = (float*) *audio; int i = samples * channels + 1; while ( --i ) { float f = *q++; f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = ( 127 * f ) + 128; } *audio = buffer; error = 0; break; } default: break; } break; case mlt_audio_u8: switch ( requested_format ) { case mlt_audio_s32: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; int c; for ( c = 0; c < channels; c++ ) { uint8_t *q = (uint8_t*) *audio + c; int i = samples + 1; while ( --i ) { *p++ = ( (int32_t) *q - 128 ) << 24; q += channels; } } *audio = buffer; error = 0; break; } case mlt_audio_float: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; int c; for ( c = 0; c < channels; c++ ) { uint8_t *q = (uint8_t*) *audio + c; int i = samples + 1; while ( --i ) { *p++ = ( (float) *q - 128 ) / 256.0f; q += channels; } } *audio = buffer; error = 0; break; } case mlt_audio_s16: { int16_t *buffer = mlt_pool_alloc( size ); int16_t *p = buffer; uint8_t *q = (uint8_t*) *audio; int i = samples * channels + 1; while ( --i ) *p++ = ( (int16_t) *q++ - 128 ) << 8; *audio = buffer; error = 0; break; } case mlt_audio_s32le: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; uint8_t *q = (uint8_t*) *audio; int i = samples * channels + 1; while ( --i ) *p++ = ( (int32_t) *q++ - 128 ) << 24; *audio = buffer; error = 0; break; } case mlt_audio_f32le: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; uint8_t *q = (uint8_t*) *audio; int i = samples * channels + 1; while ( --i ) { float f = ( (float) *q++ - 128 ) / 256.0f; f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = f; } *audio = buffer; error = 0; break; } default: break; } break; default: break; } } if ( !error ) { mlt_frame_set_audio( frame, *audio, requested_format, size, mlt_pool_release ); *format = requested_format; } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { frame->convert_audio = convert_audio; return frame; } /** Constructor for the filter. */ mlt_filter filter_audioconvert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = calloc( 1, sizeof( struct mlt_filter_s ) ); if ( mlt_filter_init( this, this ) == 0 ) this->process = filter_process; return this; } mlt-0.9.0/src/modules/core/filter_audiowave.c000066400000000000000000000037101215300731300211740ustar00rootroot00000000000000/* * filter_audiowave.c -- display audio waveform * Copyright (C) 2010 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include /** Do it :-). */ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int size = *width * *height * 2; *format = mlt_image_yuv422; *image = mlt_pool_alloc( size ); mlt_frame_set_image( this, *image, size, mlt_pool_release ); uint8_t *wave = mlt_frame_get_waveform( this, *width, *height ); if ( wave ) { uint8_t *p = *image; uint8_t *q = *image + *width * *height * 2; uint8_t *s = wave; while ( p != q ) { *p ++ = *s ++; *p ++ = 128; } } return ( wave == NULL ); } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_audiowave_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) this->process = filter_process; return this; } mlt-0.9.0/src/modules/core/filter_audiowave.yml000066400000000000000000000007521215300731300215560ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: audiowave title: Audio Waveform version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en description: Generate audio waveforms. tags: - Video bugs: - > This does not work alone on audio-only clips. It must have video to overwrite. A workaround is to apply this to a multitrack with a color generator. - The quality of the waveforms is not so good especially for high definition video. mlt-0.9.0/src/modules/core/filter_brightness.c000066400000000000000000000060041215300731300213570ustar00rootroot00000000000000/* * filter_brightness.c -- gamma filter * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #define CLAMP( x, min, max ) (x) < (min) ? (min) : (x) > (max) ? (max) : (x) /** Do it :-). */ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the image *format = mlt_image_yuv422; int error = mlt_frame_get_image( this, image, format, width, height, 1 ); // Only process if we have no error and a valid colour space if ( error == 0 ) { // Get the brightness level double level = mlt_properties_get_double( MLT_FRAME_PROPERTIES( this ), "brightness" ); // Only process if level is something other than 1 if ( level != 1.0 ) { int i = *width * *height + 1; uint8_t *p = *image; int32_t m = level * ( 1 << 16 ); int32_t n = 128 * ( ( 1 << 16 ) - m ); while ( --i ) { p[0] = CLAMP( (p[0] * m) >> 16, 16, 235 ); p[1] = CLAMP( (p[1] * m + n) >> 16, 16, 240 ); p += 2; } } } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Get the starting brightness level double level = fabs( mlt_properties_get_double( MLT_FILTER_PROPERTIES( this ), "start" ) ); // If there is an end adjust gain to the range if ( mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "end" ) != NULL ) { // Determine the time position of this frame in the transition duration double end = fabs( mlt_properties_get_double( MLT_FILTER_PROPERTIES( this ), "end" ) ); level += ( end - level ) * mlt_filter_get_progress( this, frame ); } // Push the frame filter mlt_properties_set_double( MLT_FRAME_PROPERTIES( frame ), "brightness", level ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_brightness_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "start", arg == NULL ? "1" : arg ); } return this; } mlt-0.9.0/src/modules/core/filter_brightness.yml000066400000000000000000000011261215300731300217360ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: brightness title: Brightness version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en description: Adjust the brightness value of the image. tags: - Video parameters: - identifier: argument title: Start level type: float minimum: 0.0 maximum: 15.0 default: 1.0 - identifier: start title: Start level type: float minimum: 0.0 maximum: 15.0 default: 1.0 - identifier: end title: End level type: float minimum: 0.0 maximum: 15.0 default: 1.0 mlt-0.9.0/src/modules/core/filter_channelcopy.c000066400000000000000000000121101215300731300215050ustar00rootroot00000000000000/* * filter_channelcopy.c -- copy one audio channel to another * Copyright (C) 2003-2012 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include /** Get the audio. */ static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the properties of the a frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); int from = mlt_properties_get_int( properties, "channelcopy.from" ); int to = mlt_properties_get_int( properties, "channelcopy.to" ); int swap = mlt_properties_get_int( properties, "channelcopy.swap" ); // Get the producer's audio mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); // Copy channels as necessary if ( from != to) switch ( *format ) { case mlt_audio_u8: { uint8_t *f = (uint8_t*) *buffer + from; uint8_t *t = (uint8_t*) *buffer + to; uint8_t x; int i; if ( swap ) for ( i = 0; i < *samples; i++, f += *channels, t += *channels ) { x = *t; *t = *f; *f = x; } else for ( i = 0; i < *samples; i++, f += *channels, t += *channels ) *t = *f; break; } case mlt_audio_s16: { int16_t *f = (int16_t*) *buffer + from; int16_t *t = (int16_t*) *buffer + to; int16_t x; int i; if ( swap ) for ( i = 0; i < *samples; i++, f += *channels, t += *channels ) { x = *t; *t = *f; *f = x; } else for ( i = 0; i < *samples; i++, f += *channels, t += *channels ) *t = *f; break; } case mlt_audio_s32: { int32_t *f = (int32_t*) *buffer + from * *samples; int32_t *t = (int32_t*) *buffer + to * *samples; if ( swap ) { int32_t *x = malloc( *samples * sizeof(int32_t) ); memcpy( x, t, *samples * sizeof(int32_t) ); memcpy( t, f, *samples * sizeof(int32_t) ); memcpy( f, x, *samples * sizeof(int32_t) ); free( x ); } else { memcpy( t, f, *samples * sizeof(int32_t) ); } break; } case mlt_audio_s32le: case mlt_audio_f32le: { int32_t *f = (int32_t*) *buffer + from; int32_t *t = (int32_t*) *buffer + to; int32_t x; int i; if ( swap ) for ( i = 0; i < *samples; i++, f += *channels, t += *channels ) { x = *t; *t = *f; *f = x; } else for ( i = 0; i < *samples; i++, f += *channels, t += *channels ) *t = *f; break; } case mlt_audio_float: { float *f = (float*) *buffer + from * *samples; float *t = (float*) *buffer + to * *samples; if ( swap ) { float *x = malloc( *samples * sizeof(float) ); memcpy( x, t, *samples * sizeof(float) ); memcpy( t, f, *samples * sizeof(float) ); memcpy( f, x, *samples * sizeof(float) ); free( x ); } else { memcpy( t, f, *samples * sizeof(float) ); } break; } default: mlt_log_error( MLT_FILTER_SERVICE( filter ), "Invalid audio format\n" ); break; } return 0; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { mlt_properties properties = MLT_FILTER_PROPERTIES( this ); mlt_properties frame_props = MLT_FRAME_PROPERTIES( frame ); // Propogate the parameters mlt_properties_set_int( frame_props, "channelcopy.to", mlt_properties_get_int( properties, "to" ) ); mlt_properties_set_int( frame_props, "channelcopy.from", mlt_properties_get_int( properties, "from" ) ); mlt_properties_set_int( frame_props, "channelcopy.swap", mlt_properties_get_int( properties, "swap" ) ); // Override the get_audio method mlt_frame_push_audio( frame, this ); mlt_frame_push_audio( frame, filter_get_audio ); return frame; } /** Constructor for the filter. */ mlt_filter filter_channelcopy_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; if ( arg != NULL ) mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "to", atoi( arg ) ); else mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "to", 1 ); if ( strcmp(id, "channelswap") == 0 ) mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "swap", 1 ); } return this; } mlt-0.9.0/src/modules/core/filter_channelcopy.yml000066400000000000000000000013711215300731300220730ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: channelcopy title: Copy Channels version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Audio description: Copy one audio channel to another. parameters: - identifier: argument title: To type: integer minimum: 0 maximum: 15 default: 1 - identifier: to title: To type: integer minimum: 0 maximum: 15 default: 1 - identifier: from title: From type: integer minimum: 0 maximum: 15 default: 0 - identifier: swap title: Swap description: Swap the two channels instead of duplicating the source channel. type: integer minimum: 0 maximum: 1 default: 0 widget: checkbox mlt-0.9.0/src/modules/core/filter_crop.c000066400000000000000000000173251215300731300201620ustar00rootroot00000000000000/* * filter_crop.c -- cropping filter * Copyright (C) 2009 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include static void crop( uint8_t *src, uint8_t *dest, int bpp, int width, int height, int left, int right, int top, int bottom ) { int src_stride = ( width ) * bpp; int dest_stride = ( width - left - right ) * bpp; int y = height - top - bottom + 1; src += top * src_stride + left * bpp; while ( --y ) { memcpy( dest, src, dest_stride ); dest += dest_stride; src += src_stride; } } /** Do it :-). */ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; mlt_profile profile = mlt_frame_pop_service( frame ); // Get the properties from the frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Correct Width/height if necessary if ( *width == 0 || *height == 0 ) { *width = profile->width; *height = profile->height; } int left = mlt_properties_get_int( properties, "crop.left" ); int right = mlt_properties_get_int( properties, "crop.right" ); int top = mlt_properties_get_int( properties, "crop.top" ); int bottom = mlt_properties_get_int( properties, "crop.bottom" ); // Request the image at its original resolution if ( left || right || top || bottom ) { mlt_properties_set_int( properties, "rescale_width", mlt_properties_get_int( properties, "crop.original_width" ) ); mlt_properties_set_int( properties, "rescale_height", mlt_properties_get_int( properties, "crop.original_height" ) ); } // Now get the image error = mlt_frame_get_image( frame, image, format, width, height, writable ); int owidth = *width - left - right; int oheight = *height - top - bottom; owidth = owidth < 0 ? 0 : owidth; oheight = oheight < 0 ? 0 : oheight; if ( ( owidth != *width || oheight != *height ) && error == 0 && *image != NULL && owidth > 0 && oheight > 0 ) { int bpp; // Subsampled YUV is messy and less precise. if ( *format == mlt_image_yuv422 && frame->convert_image ) { mlt_image_format requested_format = mlt_image_rgb24; frame->convert_image( frame, image, format, requested_format ); } mlt_log_debug( NULL, "[filter crop] %s %dx%d -> %dx%d\n", mlt_image_format_name(*format), *width, *height, owidth, oheight); if ( top % 2 ) mlt_properties_set_int( properties, "top_field_first", !mlt_properties_get_int( properties, "top_field_first" ) ); // Create the output image int size = mlt_image_format_size( *format, owidth, oheight, &bpp ); uint8_t *output = mlt_pool_alloc( size ); if ( output ) { // Call the generic resize crop( *image, output, bpp, *width, *height, left, right, top, bottom ); // Now update the frame mlt_frame_set_image( frame, output, size, mlt_pool_release ); *image = output; } // We should resize the alpha too uint8_t *alpha = mlt_frame_get_alpha_mask( frame ); int alpha_size = 0; mlt_properties_get_data( properties, "alpha", &alpha_size ); if ( alpha && alpha_size >= ( *width * *height ) ) { uint8_t *newalpha = mlt_pool_alloc( owidth * oheight ); if ( newalpha ) { crop( alpha, newalpha, 1, *width, *height, left, right, top, bottom ); mlt_frame_set_alpha( frame, newalpha, owidth * oheight, mlt_pool_release ); } } *width = owidth; *height = oheight; } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { if ( mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "active" ) ) { // Push the get_image method on to the stack mlt_frame_push_service( frame, mlt_service_profile( MLT_FILTER_SERVICE( filter ) ) ); mlt_frame_push_get_image( frame, filter_get_image ); } else { mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter ); mlt_properties frame_props = MLT_FRAME_PROPERTIES( frame ); int left = mlt_properties_get_int( filter_props, "left" ); int right = mlt_properties_get_int( filter_props, "right" ); int top = mlt_properties_get_int( filter_props, "top" ); int bottom = mlt_properties_get_int( filter_props, "bottom" ); int width = mlt_properties_get_int( frame_props, "meta.media.width" ); int height = mlt_properties_get_int( frame_props, "meta.media.height" ); int use_profile = mlt_properties_get_int( filter_props, "use_profile" ); mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); if ( use_profile ) { top = top * height / profile->height; bottom = bottom * height / profile->height; left = left * width / profile->width; right = right * width / profile->width; } if ( mlt_properties_get_int( filter_props, "center" ) ) { double aspect_ratio = mlt_frame_get_aspect_ratio( frame ); if ( aspect_ratio == 0.0 ) aspect_ratio = mlt_profile_sar( profile ); double input_ar = aspect_ratio * width / height; double output_ar = mlt_profile_dar( mlt_service_profile( MLT_FILTER_SERVICE(filter) ) ); int bias = mlt_properties_get_int( filter_props, "center_bias" ); if ( input_ar > output_ar ) { left = right = ( width - rint( output_ar * height / aspect_ratio ) ) / 2; if ( abs(bias) > left ) bias = bias < 0 ? -left : left; else if ( use_profile ) bias = bias * width / profile->width; left -= bias; right += bias; } else { top = bottom = ( height - rint( aspect_ratio * width / output_ar ) ) / 2; if ( abs(bias) > top ) bias = bias < 0 ? -top : top; else if ( use_profile ) bias = bias * height / profile->height; top -= bias; bottom += bias; } } // Coerce the output to an even width because subsampled YUV with odd widths is too // risky for downstream processing to handle correctly. left += ( width - left - right ) & 1; if ( width - left - right < 8 ) left = right = 0; if ( height - top - bottom < 8 ) top = bottom = 0; mlt_properties_set_int( frame_props, "crop.left", left ); mlt_properties_set_int( frame_props, "crop.right", right ); mlt_properties_set_int( frame_props, "crop.top", top ); mlt_properties_set_int( frame_props, "crop.bottom", bottom ); mlt_properties_set_int( frame_props, "crop.original_width", width ); mlt_properties_set_int( frame_props, "crop.original_height", height ); mlt_properties_set_int( frame_props, "meta.media.width", width - left - right ); mlt_properties_set_int( frame_props, "meta.media.height", height - top - bottom ); } return frame; } /** Constructor for the filter. */ mlt_filter filter_crop_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = calloc( 1, sizeof( struct mlt_filter_s ) ); if ( mlt_filter_init( filter, filter ) == 0 ) { filter->process = filter_process; if ( arg ) mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "active", atoi( arg ) ); } return filter; } mlt-0.9.0/src/modules/core/filter_crop.yml000066400000000000000000000036551215300731300205420ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: crop title: Crop version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en description: Remove pixels from the edges of the video. tags: - Video notes: > This filter is meant to be included as a normalizing filter attached automatically by the loader so that cropping occurs early in the processing stack and can request the full resolution of the source image. Then, a second instance of the filter may be applied to set the parameters of the crop operation. parameters: - identifier: argument title: Active description: Whether to do the processing (1) or simply set the parameters. type: integer minimum: 0 maximum: 1 default: 0 - identifier: left title: Left type: integer minimum: 0 default: 0 unit: pixels - identifier: right title: Right type: integer minimum: 0 default: 0 unit: pixels - identifier: top title: Top type: integer minimum: 0 default: 0 unit: pixels - identifier: bottom title: Bottom type: integer minimum: 0 default: 0 unit: pixels - identifier: center title: Center crop description: Whether to automatically crop whatever is needed to fill the output frame and prevent padding. type: integer minimum: 0 maximum: 1 default: 0 widget: checkbox - identifier: center_bias title: Center balance description: When center crop is enabled, offset the center point. type: integer minimum: 0 default: 0 unit: pixels - identifier: use_profile title: Use profile resolution description: > This is useful for proxy editing. Normally all crop values are expressed in terms of pixels of the source footage, but this option makes them relative to the profile resolution. type: integer minimum: 0 maximum: 1 default: 0 widget: checkbox mlt-0.9.0/src/modules/core/filter_data_feed.c000066400000000000000000000133211215300731300211030ustar00rootroot00000000000000/* * filter_data_feed.c -- data feed filter * Copyright (C) 2004-2005 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include /** This filter should be used in conjuction with the data_show filter. The concept of the data_feed is that it can be used to pass titles or images to render on the frame, but doesn't actually do it itself. data_feed imposes few rules on what's passed on and the validity is confirmed in data_show before use. */ /** Data queue destructor. */ static void destroy_data_queue( void *arg ) { if ( arg != NULL ) { // Assign the correct type mlt_deque queue = arg; // Iterate through each item and destroy them while ( mlt_deque_peek_front( queue ) != NULL ) mlt_properties_close( mlt_deque_pop_back( queue ) ); // Close the deque mlt_deque_close( queue ); } } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( this ); // Get the frame properties mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); // Get the data queue mlt_deque data_queue = mlt_properties_get_data( frame_properties, "data_queue", NULL ); // Get the type of the data feed char *type = mlt_properties_get( filter_properties, "type" ); // Get the in and out points of this filter int in = mlt_filter_get_in( this ); int out = mlt_filter_get_out( this ); // Create the data queue if it doesn't exist if ( data_queue == NULL ) { // Create the queue data_queue = mlt_deque_init( ); // Assign it to the frame with the destructor mlt_properties_set_data( frame_properties, "data_queue", data_queue, 0, destroy_data_queue, NULL ); } // Now create the data feed if ( data_queue != NULL && type != NULL && !strcmp( type, "attr_check" ) ) { int i = 0; int count = mlt_properties_count( frame_properties ); for ( i = 0; i < count; i ++ ) { char *name = mlt_properties_get_name( frame_properties, i ); // Only deal with meta.attr.name values here - these should have a value of 1 to be considered // Additional properties of the form are meta.attr.name.property are passed down on the feed if ( !strncmp( name, "meta.attr.", 10 ) && strchr( name + 10, '.' ) == NULL && mlt_properties_get_int( frame_properties, name ) == 1 ) { // Temp var to hold name + '.' for pass method char temp[ 132 ]; // Create a new data feed mlt_properties feed = mlt_properties_new( ); // Assign it the base properties mlt_properties_set( feed, "id", mlt_properties_get( filter_properties, "_unique_id" ) ); mlt_properties_set( feed, "type", strrchr( name, '.' ) + 1 ); mlt_properties_set_position( feed, "position", mlt_frame_get_position( frame ) ); // Assign in/out of service we're connected to mlt_properties_set_position( feed, "in", mlt_properties_get_position( frame_properties, "in" ) ); mlt_properties_set_position( feed, "out", mlt_properties_get_position( frame_properties, "out" ) ); // Pass all meta properties sprintf( temp, "%s.", name ); mlt_properties_pass( feed, frame_properties, temp ); // Push it on to the queue mlt_deque_push_back( data_queue, feed ); // Make sure this attribute only gets processed once mlt_properties_set_int( frame_properties, name, 0 ); } } } else if ( data_queue != NULL ) { // Create a new data feed mlt_properties feed = mlt_properties_new( ); // Assign it the base properties mlt_properties_set( feed, "id", mlt_properties_get( filter_properties, "_unique_id" ) ); mlt_properties_set( feed, "type", type ); mlt_properties_set_position( feed, "position", mlt_frame_get_position( frame ) ); // Assign in/out of service we're connected to mlt_properties_set_position( feed, "in", mlt_properties_get_position( frame_properties, "in" ) ); mlt_properties_set_position( feed, "out", mlt_properties_get_position( frame_properties, "out" ) ); // Correct in/out to the filter if specified if ( in != 0 ) mlt_properties_set_position( feed, "in", in ); if ( out != 0 ) mlt_properties_set_position( feed, "out", out ); // Pass the properties which start with a "feed." prefix // Note that 'feed.text' in the filter properties becomes 'text' on the feed mlt_properties_pass( feed, filter_properties, "feed." ); // Push it on to the queue mlt_deque_push_back( data_queue, feed ); } return frame; } /** Constructor for the filter. */ mlt_filter filter_data_feed_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create the filter mlt_filter this = mlt_filter_new( ); // Initialise it if ( this != NULL ) { // Get the properties mlt_properties properties = MLT_FILTER_PROPERTIES( this ); // Assign the argument (default to titles) mlt_properties_set( properties, "type", arg == NULL ? "titles" : arg ); // Specify the processing method this->process = filter_process; } return this; } mlt-0.9.0/src/modules/core/filter_data_show.c000066400000000000000000000255501215300731300211670ustar00rootroot00000000000000/* * filter_data_show.c -- data feed filter * Copyright (C) 2004-2005 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include /** Handle the profile. */ static mlt_filter obtain_filter( mlt_filter filter, char *type ) { // Result to return mlt_filter result = NULL; // Miscelaneous variable int i = 0; int type_len = strlen( type ); // Get the properties of the data show filter mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); // Get the profile properties mlt_properties profile_properties = mlt_properties_get_data( filter_properties, "profile_properties", NULL ); // Obtain the profile_properties if we haven't already if ( profile_properties == NULL ) { char temp[ 512 ]; // Get the profile requested char *profile = mlt_properties_get( filter_properties, "resource" ); // If none is specified, pick up the default for this normalisation if ( profile == NULL ) sprintf( temp, "%s/feeds/%s/data_fx.properties", mlt_environment( "MLT_DATA" ), mlt_environment( "MLT_NORMALISATION" ) ); else if ( strchr( profile, '%' ) ) sprintf( temp, "%s/feeds/%s/%s", mlt_environment( "MLT_DATA" ), mlt_environment( "MLT_NORMALISATION" ), strchr( profile, '%' ) + 1 ); else { strncpy( temp, profile, sizeof( temp ) ); temp[ sizeof( temp ) - 1 ] = '\0'; } // Load the specified profile or use the default profile_properties = mlt_properties_load( temp ); // Store for later retrieval mlt_properties_set_data( filter_properties, "profile_properties", profile_properties, 0, ( mlt_destructor )mlt_properties_close, NULL ); } if ( profile_properties != NULL ) { for ( i = 0; i < mlt_properties_count( profile_properties ); i ++ ) { char *name = mlt_properties_get_name( profile_properties, i ); char *value = mlt_properties_get_value( profile_properties, i ); if ( result == NULL && !strcmp( name, type ) && result == NULL ) result = mlt_factory_filter( mlt_service_profile( MLT_FILTER_SERVICE( filter ) ), value, NULL ); else if ( result != NULL && !strncmp( name, type, type_len ) && name[ type_len ] == '.' ) mlt_properties_set( MLT_FILTER_PROPERTIES( result ), name + type_len + 1, value ); else if ( result != NULL ) break; } } return result; } /** Retrieve medatata value */ char* metadata_value(mlt_properties properties, char* name) { if (name == NULL) return NULL; char *meta = malloc( strlen(name) + 18 ); sprintf( meta, "meta.attr.%s.markup", name); char *result = mlt_properties_get( properties, meta); free(meta); return result; } /** Convert frames to Timecode */ char* frame_to_timecode( int frames, double fps) { if (fps == 0) return strdup("-"); char *res = malloc(12); int seconds = frames / fps; frames = frames % lrint( fps ); int minutes = seconds / 60; seconds = seconds % 60; int hours = minutes / 60; minutes = minutes % 60; sprintf(res, "%.2d:%.2d:%.2d:%.2d", hours, minutes, seconds, frames); return res; } /** Process the frame for the requested type */ static int process_feed( mlt_properties feed, mlt_filter filter, mlt_frame frame ) { // Error return int error = 1; // Get the properties of the data show filter mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); // Get the type requested by the feeding filter char *type = mlt_properties_get( feed, "type" ); // Fetch the filter associated to this type mlt_filter requested = mlt_properties_get_data( filter_properties, type, NULL ); // If it doesn't exist, then create it now if ( requested == NULL ) { // Source filter from profile requested = obtain_filter( filter, type ); // Store it on the properties for subsequent retrieval/destruction mlt_properties_set_data( filter_properties, type, requested, 0, ( mlt_destructor )mlt_filter_close, NULL ); } // If we have one, then process it now... if ( requested != NULL ) { int i = 0; mlt_properties properties = MLT_FILTER_PROPERTIES( requested ); static const char *prefix = "properties."; int len = strlen( prefix ); // Determine if this is an absolute or relative feed int absolute = mlt_properties_get_int( feed, "absolute" ); // Make do with what we have int length = !absolute ? mlt_properties_get_int( feed, "out" ) - mlt_properties_get_int( feed, "in" ) + 1 : mlt_properties_get_int( feed, "out" ) + 1; // Repeat period int period = mlt_properties_get_int( properties, "period" ); period = period == 0 ? 1 : period; // Pass properties from feed into requested for ( i = 0; i < mlt_properties_count( properties ); i ++ ) { char *name = mlt_properties_get_name( properties, i ); char *key = mlt_properties_get_value( properties, i ); if ( !strncmp( name, prefix, len ) ) { if ( !strncmp( name + len, "length[", 7 ) ) { mlt_properties_set_position( properties, key, ( length - period ) / period ); } else { char *value = mlt_properties_get( feed, name + len ); if ( value != NULL ) { // check for metadata keywords in metadata markup if user requested so if ( mlt_properties_get_int( filter_properties, "dynamic" ) == 1 && !strcmp( name + strlen( name ) - 6, "markup") ) { // Find keywords which should be surrounded by '#', like: #title# char* keywords = strtok( value, "#" ); char result[512] = ""; // XXX: how much is enough? int ct = 0; int fromStart = ( value[0] == '#' ) ? 1 : 0; while ( keywords != NULL ) { if ( ct % 2 == fromStart ) { // backslash in front of # suppresses substitution if ( keywords[ strlen( keywords ) -1 ] == '\\' ) { // keep characters except backslash strncat( result, keywords, strlen( keywords ) -1 ); strcat( result, "#" ); ct++; } else { strcat( result, keywords ); } } else if ( !strcmp( keywords, "timecode" ) ) { // special case: replace #timecode# with current frame timecode int pos = mlt_properties_get_int( feed, "position" ); char *tc = frame_to_timecode( pos, mlt_profile_fps( mlt_service_profile( MLT_FILTER_SERVICE( filter ) ) ) ); strncat( result, tc, sizeof( result ) - strlen( result ) - 1 ); free( tc ); } else if ( !strcmp( keywords, "frame" ) ) { // special case: replace #frame# with current frame number int pos = mlt_properties_get_int( feed, "position" ); char s[12]; snprintf( s, sizeof(s) - 1, "%d", pos ); s[sizeof( s ) - 1] = '\0'; strcat( result, s ); } else { // replace keyword with metadata value char *metavalue = metadata_value( MLT_FRAME_PROPERTIES( frame ), keywords ); strncat( result, metavalue ? metavalue : "-", sizeof( result ) - strlen( result ) -1 ); } keywords = strtok( NULL, "#" ); ct++; } mlt_properties_set( properties, key, (char*) result ); } else mlt_properties_set( properties, key, value ); } } } } // Set the original position on the frame if ( absolute == 0 ) mlt_frame_set_position( frame, mlt_properties_get_int( feed, "position" ) - mlt_properties_get_int( feed, "in" ) ); else mlt_frame_set_position( frame, mlt_properties_get_int( feed, "position" ) ); // Process the filter mlt_filter_process( requested, frame ); // Should be ok... error = 0; } return error; } void process_queue( mlt_deque data_queue, mlt_frame frame, mlt_filter filter ) { if ( data_queue != NULL ) { // Create a new queue for those that we can't handle mlt_deque temp_queue = mlt_deque_init( ); // Iterate through each entry on the queue while ( mlt_deque_peek_front( data_queue ) != NULL ) { // Get the data feed mlt_properties feed = mlt_deque_pop_front( data_queue ); if ( mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "debug" ) != NULL ) mlt_properties_debug( feed, mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "debug" ), stderr ); // Process the data feed... if ( process_feed( feed, filter, frame ) == 0 ) mlt_properties_close( feed ); else mlt_deque_push_back( temp_queue, feed ); } // Now put the unprocessed feeds back on the stack while ( mlt_deque_peek_front( temp_queue ) ) { // Get the data feed mlt_properties feed = mlt_deque_pop_front( temp_queue ); // Put it back on the data queue mlt_deque_push_back( data_queue, feed ); } // Close the temporary queue mlt_deque_close( temp_queue ); } } /** Get the image. */ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Pop the service mlt_filter filter = mlt_frame_pop_service( frame ); // Get the frame properties mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); // Track specific process_queue( mlt_properties_get_data( frame_properties, "data_queue", NULL ), frame, filter ); // Global process_queue( mlt_properties_get_data( frame_properties, "global_queue", NULL ), frame, filter ); mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); // Need to get the image return mlt_frame_get_image( frame, image, format, width, height, 1 ); } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Push the filter mlt_frame_push_service( frame, this ); // Register the get image method mlt_frame_push_get_image( frame, filter_get_image ); // Return the frame return frame; } /** Constructor for the filter. */ mlt_filter filter_data_show_init( mlt_profile profile, mlt_service_type type, const char *id, void *arg ) { // Create the filter mlt_filter this = mlt_filter_new( ); // Initialise it if ( this != NULL ) { // Get the properties mlt_properties properties = MLT_FILTER_PROPERTIES( this ); // Assign the argument (default to titles) mlt_properties_set( properties, "resource", arg == NULL ? NULL : arg ); // Specify the processing method this->process = filter_process; } return this; } mlt-0.9.0/src/modules/core/filter_data_show.yml000066400000000000000000000030351215300731300215400ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: data_show title: Template version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video description: Show data based on properties of the producer. notes: | The data show filter uses data provided by the data feed filter. The producer properties must supply: > * The keyword text to be inserted in the form of: meta.attr.[keyword].markup=[text to insert] * The name of the properties to be used from the feed file in the form of: meta.attr.[name]=1 * The text to be displayed in the form of: meta.attr.[name].markup=[some text #keyword#] (Keyword text is enclosed between #s.) e.g. melt file.dv meta.attr.sometext.markup="this is some text" meta.attr.titles=1 meta.attr.titles.markup=#sometext# -filter data_show dynamic=1 > Two special keywords exist * #timecode# shows the frame position as a timecode. * #frame# shows the frame position as an integer. e.g. melt file.dv meta.attr.timecode=1 meta.attr.timecode.markup=#timecode# -attach data_feed:attr_check -attach data_show:custom_file.properties dynamic=1 (where the file "custom_file" contains a filter definition by the name of "timecode") parameters: - identifier: argument title: Feed Properties File type: string required: no readonly: no default: data_fx.properties widget: fileopen - identifier: dynamic title: Dynamic type: integer default: 0 minimum: 0 maximum: 1 widget: checkbox mlt-0.9.0/src/modules/core/filter_fieldorder.c000066400000000000000000000100661215300731300213310ustar00rootroot00000000000000/* * filter_fieldorder.c -- change field dominance * Copyright (C) 2011 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the properties from the frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Get the input image, width and height int error = mlt_frame_get_image( frame, image, format, width, height, writable ); if ( !error && *image ) { int tff = mlt_properties_get_int( properties, "consumer_tff" ); // Provides a manual override for misreported field order if ( mlt_properties_get( properties, "meta.top_field_first" ) ) mlt_properties_set_int( properties, "top_field_first", mlt_properties_get_int( properties, "meta.top_field_first" ) ); mlt_log_debug( NULL, "TFF in %d out %d\n", mlt_properties_get_int( properties, "top_field_first" ), tff ); if ( mlt_properties_get_int( properties, "meta.swap_fields" ) && mlt_properties_get( properties, "progressive" ) && mlt_properties_get_int( properties, "progressive" ) == 0 ) { // We only work with non-planar formats if ( *format == mlt_image_yuv420p && frame->convert_image ) error = frame->convert_image( frame, image, format, mlt_image_yuv422 ); // Make a new image int bpp; int size = mlt_image_format_size( *format, *width, *height, &bpp ); uint8_t *new_image = mlt_pool_alloc( size ); int stride = *width * bpp; int i = *height + 1; uint8_t *src = *image; // Set the new image mlt_frame_set_image( frame, new_image, size, mlt_pool_release ); *image = new_image; while ( --i ) { memcpy( new_image, src + stride * !(i % 2), stride ); new_image += stride; src += stride * (i % 2) * 2; } } // Correct field order if needed if ( tff != -1 && mlt_properties_get_int( properties, "top_field_first" ) != tff && mlt_properties_get( properties, "progressive" ) && mlt_properties_get_int( properties, "progressive" ) == 0 ) { // We only work with non-planar formats if ( *format == mlt_image_yuv420p ) { *format = mlt_image_yuv422; mlt_frame_get_image( frame, image, format, width, height, writable ); } // Shift the entire image down by one line int bpp; int size = mlt_image_format_size( *format, *width, *height, &bpp ); uint8_t *new_image = mlt_pool_alloc( size ); uint8_t *ptr = new_image + *width * bpp; memcpy( new_image, *image, *width * bpp ); memcpy( ptr, *image, *width * ( *height - 1 ) * bpp ); // Set the new image mlt_frame_set_image( frame, new_image, size, mlt_pool_release ); *image = new_image; // Set the normalised field order mlt_properties_set_int( properties, "top_field_first", tff ); mlt_properties_set_int( properties, "meta.top_field_first", tff ); } } return error; } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { mlt_frame_push_get_image( frame, get_image ); return frame; } mlt_filter filter_fieldorder_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = calloc( 1, sizeof( *filter ) ); if ( mlt_filter_init( filter, NULL ) == 0 ) { filter->process = process; } return filter; } mlt-0.9.0/src/modules/core/filter_fieldorder.yml000066400000000000000000000014071215300731300217070ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: fieldorder title: Field order description: Correct the field order of interlaced video. version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Video - Hidden notes: > This filter is automatically invoked by the loader as part of image normalisation. It compares the frame property top_field_first to the consumer property with the same name to determine if correction is needed. It performs field order correction by shifting the image down by one line. If you set the property meta.swap_fields=1 on the producer, then this filter swaps the fields of an interlaced frame in addition to any field order correction by shifting the image. mlt-0.9.0/src/modules/core/filter_gamma.c000066400000000000000000000047011215300731300202730ustar00rootroot00000000000000/* * filter_gamma.c -- gamma filter * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include /** Do it :-). */ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { *format = mlt_image_yuv422; int error = mlt_frame_get_image( this, image, format, width, height, 1 ); if ( error == 0 ) { // Get the gamma value double gamma = mlt_properties_get_double( MLT_FRAME_PROPERTIES( this ), "gamma" ); if ( gamma != 1.0 ) { uint8_t *p = *image; uint8_t *q = *image + *width * *height * 2; // Calculate the look up table double exp = 1 / gamma; uint8_t lookup[ 256 ]; int i; for( i = 0; i < 256; i ++ ) lookup[ i ] = ( uint8_t )( pow( ( double )i / 255.0, exp ) * 255 ); while ( p != q ) { *p = lookup[ *p ]; p += 2; } } } return 0; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { double gamma = mlt_properties_get_double( MLT_FILTER_PROPERTIES( this ), "gamma" ); gamma = gamma <= 0 ? 1 : gamma; mlt_properties_set_double( MLT_FRAME_PROPERTIES( frame ), "gamma", gamma ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_gamma_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "gamma", arg == NULL ? "1" : arg ); } return this; } mlt-0.9.0/src/modules/core/filter_gamma.yml000066400000000000000000000010131215300731300206430ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: gamma title: Gamma version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video description: Adjust image luma using a non-linear power-law curve. parameters: - identifier: argument title: Gamma type: float description: The exponential factor of the power-law curve default: 1.0 - identifier: gamma title: Gamma type: float description: See "argument" mutable: yes default: 1.0 mlt-0.9.0/src/modules/core/filter_greyscale.c000066400000000000000000000034471215300731300211750ustar00rootroot00000000000000/* * filter_greyscale.c -- greyscale filter * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include /** Do it :-). */ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { *format = mlt_image_yuv422; int error = mlt_frame_get_image( this, image, format, width, height, 1 ); if ( error == 0 ) { uint8_t *p = *image; uint8_t *q = *image + *width * *height * 2; while ( p ++ != q ) *p ++ = 128; } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_greyscale_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) this->process = filter_process; return this; } mlt-0.9.0/src/modules/core/filter_greyscale.yml000066400000000000000000000003601215300731300215430ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: greyscale title: Greyscale version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video description: Convert colour image to greyscale mlt-0.9.0/src/modules/core/filter_imageconvert.c000066400000000000000000000223501215300731300216740ustar00rootroot00000000000000/* * filter_imageconvert.c -- colorspace and pixel format converter * Copyright (C) 2009 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include /** This macro converts a YUV value to the RGB color space. */ #define RGB2YUV_601_UNSCALED(r, g, b, y, u, v)\ y = (299*r + 587*g + 114*b) >> 10;\ u = ((-169*r - 331*g + 500*b) >> 10) + 128;\ v = ((500*r - 419*g - 81*b) >> 10) + 128;\ y = y < 16 ? 16 : y;\ u = u < 16 ? 16 : u;\ v = v < 16 ? 16 : v;\ y = y > 235 ? 235 : y;\ u = u > 240 ? 240 : u;\ v = v > 240 ? 240 : v /** This macro scales YUV up into the full gamut of the RGB color space. */ #define YUV2RGB_601_SCALED( y, u, v, r, g, b ) \ r = ((1192 * ( y - 16 ) + 1634 * ( v - 128 ) ) >> 10 ); \ g = ((1192 * ( y - 16 ) - 832 * ( v - 128 ) - 401 * ( u - 128 ) ) >> 10 ); \ b = ((1192 * ( y - 16 ) + 2066 * ( u - 128 ) ) >> 10 ); \ r = r < 0 ? 0 : r > 255 ? 255 : r; \ g = g < 0 ? 0 : g > 255 ? 255 : g; \ b = b < 0 ? 0 : b > 255 ? 255 : b; /** This macro converts a YUV value to the RGB color space. */ #define YUV2RGB_601_UNSCALED( y, u, v, r, g, b ) \ r = ((1024 * y + 1404 * ( v - 128 ) ) >> 10 ); \ g = ((1024 * y - 715 * ( v - 128 ) - 345 * ( u - 128 ) ) >> 10 ); \ b = ((1024 * y + 1774 * ( u - 128 ) ) >> 10 ); \ r = r < 0 ? 0 : r > 255 ? 255 : r; \ g = g < 0 ? 0 : g > 255 ? 255 : g; \ b = b < 0 ? 0 : b > 255 ? 255 : b; #define SCALED 1 #if SCALED #define RGB2YUV_601 RGB2YUV_601_SCALED #define YUV2RGB_601 YUV2RGB_601_SCALED #else #define RGB2YUV_601 RGB2YUV_601_UNSCALED #define YUV2RGB_601 YUV2RGB_601_UNSCALED #endif static int convert_yuv422_to_rgb24a( uint8_t *yuv, uint8_t *rgba, uint8_t *alpha, int width, int height ) { int ret = 0; int yy, uu, vv; int r,g,b; int total = width * height / 2 + 1; while ( --total ) { yy = yuv[0]; uu = yuv[1]; vv = yuv[3]; YUV2RGB_601( yy, uu, vv, r, g, b ); rgba[0] = r; rgba[1] = g; rgba[2] = b; rgba[3] = *alpha++; yy = yuv[2]; YUV2RGB_601( yy, uu, vv, r, g, b ); rgba[4] = r; rgba[5] = g; rgba[6] = b; rgba[7] = *alpha++; yuv += 4; rgba += 8; } return ret; } static int convert_yuv422_to_rgb24( uint8_t *yuv, uint8_t *rgb, uint8_t *alpha, int width, int height ) { int ret = 0; int yy, uu, vv; int r,g,b; int total = width * height / 2 + 1; while ( --total ) { yy = yuv[0]; uu = yuv[1]; vv = yuv[3]; YUV2RGB_601( yy, uu, vv, r, g, b ); rgb[0] = r; rgb[1] = g; rgb[2] = b; yy = yuv[2]; YUV2RGB_601( yy, uu, vv, r, g, b ); rgb[3] = r; rgb[4] = g; rgb[5] = b; yuv += 4; rgb += 6; } return ret; } static int convert_rgb24a_to_yuv422( uint8_t *rgba, uint8_t *yuv, uint8_t *alpha, int width, int height ) { int ret = 0; int stride = width * 4; int y0, y1, u0, u1, v0, v1; int r, g, b; uint8_t *s, *d = yuv; int i, j, n = width / 2 + 1; if ( alpha ) for ( i = 0; i < height; i++ ) { s = rgba + ( stride * i ); j = n; while ( --j ) { r = *s++; g = *s++; b = *s++; *alpha++ = *s++; RGB2YUV_601( r, g, b, y0, u0 , v0 ); r = *s++; g = *s++; b = *s++; *alpha++ = *s++; RGB2YUV_601( r, g, b, y1, u1 , v1 ); *d++ = y0; *d++ = (u0+u1) >> 1; *d++ = y1; *d++ = (v0+v1) >> 1; } if ( width % 2 ) { r = *s++; g = *s++; b = *s++; *alpha++ = *s++; RGB2YUV_601( r, g, b, y0, u0 , v0 ); *d++ = y0; *d++ = u0; } } else for ( i = 0; i < height; i++ ) { s = rgba + ( stride * i ); j = n; while ( --j ) { r = *s++; g = *s++; b = *s++; s++; RGB2YUV_601( r, g, b, y0, u0 , v0 ); r = *s++; g = *s++; b = *s++; s++; RGB2YUV_601( r, g, b, y1, u1 , v1 ); *d++ = y0; *d++ = (u0+u1) >> 1; *d++ = y1; *d++ = (v0+v1) >> 1; } if ( width % 2 ) { r = *s++; g = *s++; b = *s++; s++; RGB2YUV_601( r, g, b, y0, u0 , v0 ); *d++ = y0; *d++ = u0; } } return ret; } static int convert_rgb24_to_yuv422( uint8_t *rgb, uint8_t *yuv, uint8_t *alpha, int width, int height ) { int ret = 0; int stride = width * 3; int y0, y1, u0, u1, v0, v1; int r, g, b; uint8_t *s, *d = yuv; int i, j, n = width / 2 + 1; for ( i = 0; i < height; i++ ) { s = rgb + ( stride * i ); j = n; while ( --j ) { r = *s++; g = *s++; b = *s++; RGB2YUV_601( r, g, b, y0, u0 , v0 ); r = *s++; g = *s++; b = *s++; RGB2YUV_601( r, g, b, y1, u1 , v1 ); *d++ = y0; *d++ = (u0+u1) >> 1; *d++ = y1; *d++ = (v0+v1) >> 1; } if ( width % 2 ) { r = *s++; g = *s++; b = *s++; RGB2YUV_601( r, g, b, y0, u0 , v0 ); *d++ = y0; *d++ = u0; } } return ret; } static int convert_yuv420p_to_yuv422( uint8_t *yuv420p, uint8_t *yuv, uint8_t *alpha, int width, int height ) { int ret = 0; int i, j; int half = width >> 1; uint8_t *Y = yuv420p; uint8_t *U = Y + width * height; uint8_t *V = U + width * height / 4; uint8_t *d = yuv; for ( i = 0; i < height; i++ ) { uint8_t *u = U + ( i / 2 ) * ( half ); uint8_t *v = V + ( i / 2 ) * ( half ); j = half + 1; while ( --j ) { *d ++ = *Y ++; *d ++ = *u ++; *d ++ = *Y ++; *d ++ = *v ++; } } return ret; } static int convert_rgb24_to_rgb24a( uint8_t *rgb, uint8_t *rgba, uint8_t *alpha, int width, int height ) { uint8_t *s = rgb; uint8_t *d = rgba; int total = width * height + 1; while ( --total ) { *d++ = s[0]; *d++ = s[1]; *d++ = s[2]; *d++ = 0xff; s += 3; } return 0; } static int convert_rgb24a_to_rgb24( uint8_t *rgba, uint8_t *rgb, uint8_t *alpha, int width, int height ) { uint8_t *s = rgba; uint8_t *d = rgb; int total = width * height + 1; while ( --total ) { *d++ = s[0]; *d++ = s[1]; *d++ = s[2]; *alpha++ = s[3]; s += 4; } return 0; } typedef int ( *conversion_function )( uint8_t *yuv, uint8_t *rgba, uint8_t *alpha, int width, int height ); static conversion_function conversion_matrix[5][5] = { { NULL, convert_rgb24_to_rgb24a, convert_rgb24_to_yuv422, NULL, convert_rgb24_to_rgb24a }, { convert_rgb24a_to_rgb24, NULL, convert_rgb24a_to_yuv422, NULL, NULL }, { convert_yuv422_to_rgb24, convert_yuv422_to_rgb24a, NULL, NULL, convert_yuv422_to_rgb24a }, { NULL, NULL, convert_yuv420p_to_yuv422, NULL, NULL }, { convert_rgb24a_to_rgb24, NULL, convert_rgb24a_to_yuv422, NULL, NULL }, }; static uint8_t bpp_table[4] = { 3, 4, 2, 0 }; static int convert_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, mlt_image_format requested_format ) { int error = 0; mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); int width = mlt_properties_get_int( properties, "width" ); int height = mlt_properties_get_int( properties, "height" ); if ( *format != requested_format ) { conversion_function converter = conversion_matrix[ *format - 1 ][ requested_format - 1 ]; mlt_log_debug( NULL, "[filter imageconvert] %s -> %s @ %dx%d\n", mlt_image_format_name( *format ), mlt_image_format_name( requested_format ), width, height ); if ( converter ) { int size = width * height * bpp_table[ requested_format - 1 ]; int alpha_size = width * height; uint8_t *image = mlt_pool_alloc( size ); uint8_t *alpha = ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) ? mlt_pool_alloc( width * height ) : NULL; if ( requested_format == mlt_image_rgb24a || requested_format == mlt_image_opengl ) { if ( alpha ) mlt_pool_release( alpha ); alpha = mlt_frame_get_alpha_mask( frame ); mlt_properties_get_data( properties, "alpha", &alpha_size ); } if ( !( error = converter( *buffer, image, alpha, width, height ) ) ) { mlt_frame_set_image( frame, image, size, mlt_pool_release ); if ( alpha && ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) ) mlt_frame_set_alpha( frame, alpha, alpha_size, mlt_pool_release ); *buffer = image; *format = requested_format; } else { mlt_pool_release( image ); if ( alpha ) mlt_pool_release( alpha ); } } else { error = 1; } } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { if ( !frame->convert_image ) frame->convert_image = convert_image; return frame; } /** Constructor for the filter. */ mlt_filter filter_imageconvert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = calloc( 1, sizeof( struct mlt_filter_s ) ); if ( mlt_filter_init( this, this ) == 0 ) { this->process = filter_process; } return this; } mlt-0.9.0/src/modules/core/filter_luma.c000066400000000000000000000125161215300731300201520ustar00rootroot00000000000000/* * filter_luma.c -- luma filter * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include /** Do it :-). */ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; mlt_filter filter = mlt_frame_pop_service( this ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); mlt_transition luma = mlt_properties_get_data( properties, "luma", NULL ); mlt_frame b_frame = mlt_properties_get_data( properties, "frame", NULL ); mlt_properties b_frame_props = b_frame ? MLT_FRAME_PROPERTIES( b_frame ) : NULL; int out = mlt_properties_get_int( properties, "period" ); int cycle = mlt_properties_get_int( properties, "cycle" ); int duration = mlt_properties_get_int( properties, "duration" ); mlt_position position = mlt_filter_get_position( filter, this ); out = out? out + 1 : 25; if ( cycle ) out = cycle; if ( duration < 1 || duration > out ) duration = out; *format = mlt_image_yuv422; if ( b_frame == NULL || mlt_properties_get_int( b_frame_props, "width" ) != *width || mlt_properties_get_int( b_frame_props, "height" ) != *height ) { b_frame = mlt_frame_init( MLT_FILTER_SERVICE( filter ) ); mlt_properties_set_data( properties, "frame", b_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); } if ( luma == NULL ) { char *resource = mlt_properties_get( properties, "resource" ); mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); luma = mlt_factory_transition( profile, "luma", resource ); if ( luma != NULL ) { mlt_properties luma_properties = MLT_TRANSITION_PROPERTIES( luma ); mlt_properties_set_int( luma_properties, "in", 0 ); mlt_properties_set_int( luma_properties, "out", duration - 1 ); mlt_properties_set_int( luma_properties, "reverse", 1 ); mlt_properties_set_data( properties, "luma", luma, 0, ( mlt_destructor )mlt_transition_close, NULL ); } } mlt_position modulo_pos = MLT_POSITION_MOD(position, out); mlt_log_debug( MLT_FILTER_SERVICE(filter), "pos " MLT_POSITION_FMT " mod period " MLT_POSITION_FMT "\n", position, modulo_pos ); if ( luma != NULL && ( mlt_properties_get( properties, "blur" ) != NULL || ( position >= duration && modulo_pos < duration - 1 ) ) ) { mlt_properties luma_properties = MLT_TRANSITION_PROPERTIES( luma ); mlt_properties_pass( luma_properties, properties, "luma." ); int in = position / out * out + mlt_frame_get_position( this ) - position; mlt_properties_set_int( luma_properties, "in", in ); mlt_properties_set_int( luma_properties, "out", in + duration - 1 ); mlt_transition_process( luma, this, b_frame ); } error = mlt_frame_get_image( this, image, format, width, height, 1 ); // We only need a copy of the last frame in the cycle, but we could miss it // with realtime frame-dropping, so we copy the last several frames of the cycle. if ( error == 0 && modulo_pos > out - duration ) { mlt_properties a_props = MLT_FRAME_PROPERTIES( this ); int size = 0; uint8_t *src = mlt_properties_get_data( a_props, "image", &size ); uint8_t *dst = mlt_pool_alloc( size ); if ( dst != NULL ) { mlt_log_debug( MLT_FILTER_SERVICE(filter), "copying frame " MLT_POSITION_FMT "\n", modulo_pos ); mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); memcpy( dst, src, size ); mlt_frame_set_image( b_frame, dst, size, mlt_pool_release ); mlt_properties_set_int( b_props, "width", *width ); mlt_properties_set_int( b_props, "height", *height ); mlt_properties_set_int( b_props, "format", *format ); } } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Push the filter on to the stack mlt_frame_push_service( frame, this ); // Push the get_image on to the stack mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_luma_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { mlt_properties properties = MLT_FILTER_PROPERTIES( this ); this->process = filter_process; if ( arg != NULL ) mlt_properties_set( properties, "resource", arg ); } return this; } mlt-0.9.0/src/modules/core/filter_luma.yml000066400000000000000000000021051215300731300205220ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: luma title: Wipe version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video description: > Applies a luma transition between the current and next frames. Useful for transitions from a slideshow created using producer pixbuf. parameters: - identifier: argument title: File type: string description: The luma map file to be used for the transition - identifier: cycle title: Period type: integer description: > The duration between iterations of the transition. For best results set this to a multiple of ttl used in pixbuf. mutable: yes default: 25 - identifier: duration title: Duration type: integer description: The length of the transition. mutable: yes default: 25 - identifier: luma.* title: Luma Properties description: > All properties beginning with "luma." are passed to the encapsulated luma transition. For example, luma.out controls the duration of the wipe. mutable: yes mlt-0.9.0/src/modules/core/filter_mirror.c000066400000000000000000000167621215300731300205350ustar00rootroot00000000000000/* * filter_mirror.c -- mirror filter * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include /** Do it :-). */ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Pop the mirror filter from the stack mlt_filter this = mlt_frame_pop_service( frame ); // Get the mirror type mlt_properties properties = MLT_FILTER_PROPERTIES( this ); // Get the properties char *mirror = mlt_properties_get( properties, "mirror" ); // Determine if reverse is required int reverse = mlt_properties_get_int( properties, "reverse" ); // Get the image *format = mlt_image_yuv422; int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); // Get the alpha uint8_t *alpha = mlt_frame_get_alpha_mask( frame ); // If we have an image of the right colour space if ( error == 0 ) { // We'll KISS here int hh = *height / 2; if ( !strcmp( mirror, "horizontal" ) ) { uint8_t *p = NULL; uint8_t *q = NULL; uint8_t *a = NULL; uint8_t *b = NULL; int i; int uneven_w = ( *width % 2 ) * 2; for ( i = 0; i < *height; i ++ ) { p = ( uint8_t * )*image + i * *width * 2; q = p + *width * 2; a = alpha + i * *width; b = a + *width - 1; if ( !reverse ) { while ( p < q ) { *p ++ = *( q - 2 ); *p ++ = *( q - 3 - uneven_w ); *p ++ = *( q - 4 ); *p ++ = *( q - 1 - uneven_w ); q -= 4; *a ++ = *b --; *a ++ = *b --; } } else { while ( p < q ) { *( q - 2 ) = *p ++; *( q - 3 - uneven_w ) = *p ++; *( q - 4 ) = *p ++; *( q - 1 - uneven_w ) = *p ++; q -= 4; *b -- = *a ++; *b -- = *a ++; } } } } else if ( !strcmp( mirror, "vertical" ) ) { uint16_t *end = ( uint16_t *)*image + *width * *height; uint16_t *p = NULL; uint16_t *q = NULL; uint8_t *a = NULL; uint8_t *b = NULL; int i; int j; for ( i = 0; i < hh; i ++ ) { p = ( uint16_t * )*image + i * *width; q = end - ( i + 1 ) * *width; j = *width; a = alpha + i * *width; b = alpha + ( *height - i - 1 ) * *width; if ( !reverse ) { while ( j -- ) { *p ++ = *q ++; *a ++ = *b ++; } } else { while ( j -- ) { *q ++ = *p ++; *b ++ = *a ++; } } } } else if ( !strcmp( mirror, "diagonal" ) ) { uint8_t *end = ( uint8_t *)*image + *width * *height * 2; uint8_t *p = NULL; uint8_t *q = NULL; uint8_t *a = NULL; uint8_t *b = NULL; int i; int j; int uneven_w = ( *width % 2 ) * 2; for ( i = 0; i < *height; i ++ ) { p = ( uint8_t * )*image + i * *width * 2; q = end - i * *width * 2; j = ( ( *width * ( *height - i ) ) / *height ) / 2; a = alpha + i * *width; b = alpha + ( *height - i - 1 ) * *width; if ( !reverse ) { while ( j -- ) { *p ++ = *( q - 2 ); *p ++ = *( q - 3 - uneven_w ); *p ++ = *( q - 4 ); *p ++ = *( q - 1 - uneven_w ); q -= 4; *a ++ = *b --; *a ++ = *b --; } } else { while ( j -- ) { *( q - 2 ) = *p ++; *( q - 3 - uneven_w ) = *p ++; *( q - 4 ) = *p ++; *( q - 1 - uneven_w ) = *p ++; q -= 4; *b -- = *a ++; *b -- = *a ++; } } } } else if ( !strcmp( mirror, "xdiagonal" ) ) { uint8_t *end = ( uint8_t *)*image + *width * *height * 2; uint8_t *p = NULL; uint8_t *q = NULL; int i; int j; uint8_t *a = NULL; uint8_t *b = NULL; int uneven_w = ( *width % 2 ) * 2; for ( i = 0; i < *height; i ++ ) { p = ( uint8_t * )*image + ( i + 1 ) * *width * 2; q = end - ( i + 1 ) * *width * 2; j = ( ( *width * ( *height - i ) ) / *height ) / 2; a = alpha + ( i + 1 ) * *width - 1; b = alpha + ( *height - i - 1 ) * *width; if ( !reverse ) { while ( j -- ) { *q ++ = *( p - 2 ); *q ++ = *( p - 3 - uneven_w ); *q ++ = *( p - 4 ); *q ++ = *( p - 1 - uneven_w ); p -= 4; *b ++ = *a --; *b ++ = *a --; } } else { while ( j -- ) { *( p - 2 ) = *q ++; *( p - 3 - uneven_w ) = *q ++; *( p - 4 ) = *q ++; *( p - 1 - uneven_w ) = *q ++; p -= 4; *a -- = *b ++; *a -- = *b ++; } } } } else if ( !strcmp( mirror, "flip" ) ) { uint8_t t[ 4 ]; uint8_t *p = NULL; uint8_t *q = NULL; int i; uint8_t *a = NULL; uint8_t *b = NULL; uint8_t c; int uneven_w = ( *width % 2 ) * 2; for ( i = 0; i < *height; i ++ ) { p = ( uint8_t * )*image + i * *width * 2; q = p + *width * 2; a = alpha + i * *width; b = a + *width - 1; while ( p < q ) { t[ 0 ] = p[ 0 ]; t[ 1 ] = p[ 1 + uneven_w ]; t[ 2 ] = p[ 2 ]; t[ 3 ] = p[ 3 + uneven_w ]; *p ++ = *( q - 2 ); *p ++ = *( q - 3 - uneven_w ); *p ++ = *( q - 4 ); *p ++ = *( q - 1 - uneven_w ); *( -- q ) = t[ 3 ]; *( -- q ) = t[ 0 ]; *( -- q ) = t[ 1 ]; *( -- q ) = t[ 2 ]; c = *a; *a ++ = *b; *b -- = c; c = *a; *a ++ = *b; *b -- = c; } } } else if ( !strcmp( mirror, "flop" ) ) { uint16_t *end = ( uint16_t *)*image + *width * *height; uint16_t *p = NULL; uint16_t *q = NULL; uint16_t t; uint8_t *a = NULL; uint8_t *b = NULL; uint8_t c; int i; int j; for ( i = 0; i < hh; i ++ ) { p = ( uint16_t * )*image + i * *width; q = end - ( i + 1 ) * *width; a = alpha + i * *width; b = alpha + ( *height - i - 1 ) * *width; j = *width; while ( j -- ) { t = *p; *p ++ = *q; *q ++ = t; c = *a; *a ++ = *b; *b ++ = c; } } } } // Return the error return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Push the service on to the stack mlt_frame_push_service( frame, this ); // Push the filter method on to the stack mlt_frame_push_service( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_mirror_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Construct a new filter mlt_filter this = mlt_filter_new( ); // If we have a filter, initialise it if ( this != NULL ) { // Get the properties mlt_properties properties = MLT_FILTER_PROPERTIES( this ); // Set the default mirror type mlt_properties_set_or_default( properties, "mirror", arg, "horizontal" ); // Assign the process method this->process = filter_process; } // Return the filter return this; } mlt-0.9.0/src/modules/core/filter_mirror.yml000066400000000000000000000011711215300731300211000ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: mirror title: Mirror version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video description: > Provides various mirror and image reversing effects. parameters: - identifier: argument title: File type: string description: Choose the type of mirror operation. values: - horizontal - vertical - diagonal - xdiagonal - flip - flop - identifier: reverse title: Reverse type: integer mutable: no default: 0 minimum: 0 maximum: 1 widget: checkbox mlt-0.9.0/src/modules/core/filter_mono.c000066400000000000000000000120471215300731300201630ustar00rootroot00000000000000/* * filter_mono.c -- mix all channels to a mono signal across n channels * Copyright (C) 2003-2012 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include /** Get the audio. */ static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the properties of the a frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); int channels_out = mlt_properties_get_int( properties, "mono.channels" ); int i, j, size; // Get the producer's audio mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); if ( channels_out == -1 ) channels_out = *channels; size = mlt_audio_format_size( *format, *samples, channels_out ); switch ( *format ) { case mlt_audio_u8: { uint8_t *new_buffer = mlt_pool_alloc( size ); for ( i = 0; i < *samples; i++ ) { uint8_t mixdown = 0; for ( j = 0; j < *channels; j++ ) mixdown += ((uint8_t*) *buffer)[ ( i * *channels ) + j ] / *channels; for ( j = 0; j < channels_out; j++ ) new_buffer[ ( i * channels_out ) + j ] = mixdown; } *buffer = new_buffer; break; } case mlt_audio_s16: { int16_t *new_buffer = mlt_pool_alloc( size ); for ( i = 0; i < *samples; i++ ) { int16_t mixdown = 0; for ( j = 0; j < *channels; j++ ) mixdown += ((int16_t*) *buffer)[ ( i * *channels ) + j ] / *channels; for ( j = 0; j < channels_out; j++ ) new_buffer[ ( i * channels_out ) + j ] = mixdown; } *buffer = new_buffer; break; } case mlt_audio_s32le: { int32_t *new_buffer = mlt_pool_alloc( size ); for ( i = 0; i < *samples; i++ ) { int32_t mixdown = 0; for ( j = 0; j < *channels; j++ ) mixdown += ((int32_t*) *buffer)[ ( i * *channels ) + j ] / *channels; for ( j = 0; j < channels_out; j++ ) new_buffer[ ( i * channels_out ) + j ] = mixdown; } *buffer = new_buffer; break; } case mlt_audio_f32le: { float *new_buffer = mlt_pool_alloc( size ); for ( i = 0; i < *samples; i++ ) { float mixdown = 0; for ( j = 0; j < *channels; j++ ) mixdown += ((float*) *buffer)[ ( i * *channels ) + j ] / *channels; for ( j = 0; j < channels_out; j++ ) new_buffer[ ( i * channels_out ) + j ] = mixdown; } *buffer = new_buffer; break; } case mlt_audio_s32: { int32_t *new_buffer = mlt_pool_alloc( size ); for ( i = 0; i < *samples; i++ ) { int32_t mixdown = 0; for ( j = 0; j < *channels; j++ ) mixdown += ((int32_t*) *buffer)[ ( j * *channels ) + i ] / *channels; for ( j = 0; j < channels_out; j++ ) new_buffer[ ( j * *samples ) + i ] = mixdown; } *buffer = new_buffer; break; } case mlt_audio_float: { float *new_buffer = mlt_pool_alloc( size ); for ( i = 0; i < *samples; i++ ) { float mixdown = 0; for ( j = 0; j < *channels; j++ ) mixdown += ((float*) *buffer)[ ( j * *channels ) + i ] / *channels; for ( j = 0; j < channels_out; j++ ) new_buffer[ ( j * *samples ) + i ] = mixdown; } *buffer = new_buffer; break; } default: mlt_log_error( NULL, "[filter mono] Invalid audio format\n" ); break; } if ( size > *samples * channels_out ) { mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); *channels = channels_out; } return 0; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { mlt_properties properties = MLT_FILTER_PROPERTIES( this ); mlt_properties frame_props = MLT_FRAME_PROPERTIES( frame ); // Propogate the parameters mlt_properties_set_int( frame_props, "mono.channels", mlt_properties_get_int( properties, "channels" ) ); // Override the get_audio method mlt_frame_push_audio( frame, filter_get_audio ); return frame; } /** Constructor for the filter. */ mlt_filter filter_mono_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; if ( arg != NULL ) mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "channels", atoi( arg ) ); else mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "channels", -1 ); } return this; } mlt-0.9.0/src/modules/core/filter_mono.yml000066400000000000000000000007641215300731300205450ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: mono title: Mixdown version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Audio description: > Mix all channels of audio into a mono signal and output it as N channels. parameters: - identifier: argument title: channels type: integer description: > Set the number of output channels. The default is automatic based on consumer request. required: no minimum: 1 mlt-0.9.0/src/modules/core/filter_obscure.c000066400000000000000000000161141215300731300206540ustar00rootroot00000000000000/* * filter_obscure.c -- obscure filter * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include /** Geometry struct. */ struct geometry_s { int nw; int nh; float x; float y; float w; float h; int mask_w; int mask_h; }; /** Parse a value from a geometry string. */ static inline float parse_value( char **ptr, int normalisation, char delim, float defaults ) { float value = defaults; if ( *ptr != NULL && **ptr != '\0' ) { char *end = NULL; value = strtod( *ptr, &end ); if ( end != NULL ) { if ( *end == '%' ) value = ( value / 100.0 ) * normalisation; while ( *end == delim || *end == '%' || ( delim == ',' && *end == '/' ) ) end ++; } *ptr = end; } return value; } /** Parse a geometry property string. */ static void geometry_parse( struct geometry_s *geometry, struct geometry_s *defaults, char *property, int nw, int nh ) { // Assign normalised width and height geometry->nw = nw; geometry->nh = nh; // Assign from defaults if available if ( defaults != NULL ) { geometry->x = defaults->x; geometry->y = defaults->y; geometry->w = defaults->w; geometry->h = defaults->h; geometry->mask_w = defaults->mask_w; geometry->mask_h = defaults->mask_h; } else { geometry->x = 0; geometry->y = 0; geometry->w = nw; geometry->h = nh; geometry->mask_w = 20; geometry->mask_h = 20; } // Parse the geomtry string if ( property != NULL ) { char *ptr = property; geometry->x = parse_value( &ptr, nw, ',', geometry->x ); geometry->y = parse_value( &ptr, nh, ':', geometry->y ); geometry->w = parse_value( &ptr, nw, 'x', geometry->w ); geometry->h = parse_value( &ptr, nh, ':', geometry->h ); geometry->mask_w = parse_value( &ptr, nw, 'x', geometry->mask_w ); geometry->mask_h = parse_value( &ptr, nh, ' ', geometry->mask_h ); } } /** A Timism but not as clean ;-). */ static float lerp( float value, float lower, float upper ) { if ( value < lower ) return lower; else if ( upper > lower && value > upper ) return upper; return value; } /** Calculate real geometry. */ static void geometry_calculate( struct geometry_s *output, struct geometry_s *in, struct geometry_s *out, float position, int ow, int oh ) { // Calculate this frames geometry output->x = lerp( ( in->x + ( out->x - in->x ) * position ) / ( float )out->nw * ow, 0, ow ); output->y = lerp( ( in->y + ( out->y - in->y ) * position ) / ( float )out->nh * oh, 0, oh ); output->w = lerp( ( in->w + ( out->w - in->w ) * position ) / ( float )out->nw * ow, 0, ow - output->x ); output->h = lerp( ( in->h + ( out->h - in->h ) * position ) / ( float )out->nh * oh, 0, oh - output->y ); output->mask_w = lerp( in->mask_w + ( out->mask_w - in->mask_w ) * position, 1, -1 ); output->mask_h = lerp( in->mask_h + ( out->mask_h - in->mask_h ) * position, 1, -1 ); } /** The averaging function... */ static inline void obscure_average( uint8_t *start, int width, int height, int stride ) { register int y; register int x; register int Y = ( *start + *( start + 2 ) ) / 2; register int U = *( start + 1 ); register int V = *( start + 3 ); register uint8_t *p; register int components = width >> 1; y = height; while( y -- ) { p = start; x = components; while( x -- ) { Y = ( Y + *p ++ ) >> 1; U = ( U + *p ++ ) >> 1; Y = ( Y + *p ++ ) >> 1; V = ( V + *p ++ ) >> 1; } start += stride; } start -= height * stride; y = height; while( y -- ) { p = start; x = components; while( x -- ) { *p ++ = Y; *p ++ = U; *p ++ = Y; *p ++ = V; } start += stride; } } /** The obscurer rendering function... */ static void obscure_render( uint8_t *image, int width, int height, struct geometry_s result ) { int area_x = result.x; int area_y = result.y; int area_w = result.w; int area_h = result.h; int mw = result.mask_w; int mh = result.mask_h; int w; int h; int aw; int ah; uint8_t *p = image + area_y * width * 2 + area_x * 2; for ( w = 0; w < area_w; w += mw ) { for ( h = 0; h < area_h; h += mh ) { aw = w + mw > area_w ? mw - ( w + mw - area_w ) : mw; ah = h + mh > area_h ? mh - ( h + mh - area_h ) : mh; if ( aw > 1 && ah > 1 ) obscure_average( p + h * ( width << 1 ) + ( w << 1 ), aw, ah, width << 1 ); } } } /** Do it :-). */ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Pop the top of stack now mlt_filter filter = mlt_frame_pop_service( frame ); // Get the image from the frame *format = mlt_image_yuv422; int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); // Get the image from the frame if ( error == 0 ) { if ( filter != NULL ) { // Get the filter properties mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); // Structures for geometry struct geometry_s result; struct geometry_s start; struct geometry_s end; // Retrieve the position float position = mlt_filter_get_progress( filter, frame ); // Now parse the geometries geometry_parse( &start, NULL, mlt_properties_get( properties, "start" ), profile->width, profile->height ); geometry_parse( &end, &start, mlt_properties_get( properties, "end" ), profile->width, profile->height ); // Do the calculation geometry_calculate( &result, &start, &end, position, *width, *height ); // Now actually render it obscure_render( *image, *width, *height, result ); } } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { // Push this on to the service stack mlt_frame_push_service( frame, filter ); // Push the get image call mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_obscure_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = mlt_filter_new( ); if ( filter != NULL ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); filter->process = filter_process; mlt_properties_set( properties, "start", arg != NULL ? arg : "0%/0%:100%x100%" ); mlt_properties_set( properties, "end", "" ); } return filter; } mlt-0.9.0/src/modules/core/filter_obscure.yml000066400000000000000000000012121215300731300212240ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: obscure title: Obscure version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video description: > Obscuring filter. parameters: - identifier: argument title: Start type: string description: > The starting rectangle is given in the format X/Y:WxH[:PWxPY] where PWxPY is the size of the averaging region in pixels. - identifier: end title: End type: string description: > The ending rectangle is given in the format X/Y:WxH[:PWxPY] where PWxPY is the size of the averaging region in pixels. mlt-0.9.0/src/modules/core/filter_panner.c000066400000000000000000000243261215300731300205010ustar00rootroot00000000000000/* * filter_panner.c --pan/balance audio channels * Copyright (C) 2010 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include /** Get the audio. */ static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { mlt_properties properties = mlt_frame_pop_audio( frame ); mlt_filter filter = mlt_frame_pop_audio( frame ); mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter ); mlt_properties frame_props = MLT_FRAME_PROPERTIES( frame ); // We can only mix s16 *format = mlt_audio_s16; mlt_frame_get_audio( frame, (void**) buffer, format, frequency, channels, samples ); // Apply silence int silent = mlt_properties_get_int( frame_props, "silent_audio" ); mlt_properties_set_int( frame_props, "silent_audio", 0 ); if ( silent ) memset( *buffer, 0, *samples * *channels * sizeof( int16_t ) ); int src_size = 0; int16_t *src = mlt_properties_get_data( filter_props, "scratch_buffer", &src_size ); int16_t *dest = *buffer; double v; // sample accumulator int i, out, in; double factors[6][6]; // mixing weights [in][out] double mix_start = 0.5, mix_end = 0.5; if ( mlt_properties_get( properties, "previous_mix" ) != NULL ) mix_start = mlt_properties_get_double( properties, "previous_mix" ); if ( mlt_properties_get( properties, "mix" ) != NULL ) mix_end = mlt_properties_get_double( properties, "mix" ); double weight = mix_start; double weight_step = ( mix_end - mix_start ) / *samples; int active_channel = mlt_properties_get_int( properties, "channel" ); int gang = mlt_properties_get_int( properties, "gang" ) ? 2 : 1; // Use an inline low-pass filter to help avoid clipping double Fc = 0.5; double B = exp(-2.0 * M_PI * Fc); double A = 1.0 - B; double vp[6]; // Setup or resize a scratch buffer if ( !src || src_size < *samples * *channels * sizeof(int16_t) ) { // We allocate 4 more samples than we need to deal with jitter in the sample count per frame. src_size = ( *samples + 4 ) * *channels * sizeof(int16_t); src = mlt_pool_alloc( src_size ); if ( !src ) return 0; mlt_properties_set_data( filter_props, "scratch_buffer", src, src_size, mlt_pool_release, NULL ); } // We must use a pristine copy as the source memcpy( src, *buffer, *samples * *channels * sizeof(int16_t) ); // Initialize the mix factors for ( i = 0; i < 6; i++ ) for ( out = 0; out < 6; out++ ) factors[i][out] = 0.0; for ( out = 0; out < *channels; out++ ) vp[out] = (double) dest[out]; for ( i = 0; i < *samples; i++ ) { // Recompute the mix factors switch ( active_channel ) { case -1: // Front L/R balance case -2: // Rear L/R balance { // Gang front/rear balance if requested int g, active = active_channel; for ( g = 0; g < gang; g++, active-- ) { int left = active == -1 ? 0 : 2; int right = left + 1; if ( weight < 0.0 ) { factors[left][left] = 1.0; factors[right][right] = weight + 1.0 < 0.0 ? 0.0 : weight + 1.0; } else { factors[left][left] = 1.0 - weight < 0.0 ? 0.0 : 1.0 - weight; factors[right][right] = 1.0; } } break; } case -3: // Left fade case -4: // right fade { // Gang left/right fade if requested int g, active = active_channel; for ( g = 0; g < gang; g++, active-- ) { int front = active == -3 ? 0 : 1; int rear = front + 2; if ( weight < 0.0 ) { factors[front][front] = 1.0; factors[rear][rear] = weight + 1.0 < 0.0 ? 0.0 : weight + 1.0; } else { factors[front][front] = 1.0 - weight < 0.0 ? 0.0 : 1.0 - weight; factors[rear][rear] = 1.0; } } break; } case 0: // left case 2: { int left = active_channel; int right = left + 1; factors[right][right] = 1.0; if ( weight < 0.0 ) // output left toward left { factors[left][left] = 0.5 - weight * 0.5; factors[left][right] = ( 1.0 + weight ) * 0.5; } else // output left toward right { factors[left][left] = ( 1.0 - weight ) * 0.5; factors[left][right] = 0.5 + weight * 0.5; } break; } case 1: // right case 3: { int right = active_channel; int left = right - 1; factors[left][left] = 1.0; if ( weight < 0.0 ) // output right toward left { factors[right][left] = 0.5 - weight * 0.5; factors[right][right] = ( 1.0 + weight ) * 0.5; } else // output right toward right { factors[right][left] = ( 1.0 - weight ) * 0.5; factors[right][right] = 0.5 + weight * 0.5; } break; } } // Do the mixing for ( out = 0; out < *channels && out < 6; out++ ) { v = 0; for ( in = 0; in < *channels && in < 6; in++ ) v += factors[in][out] * src[ i * *channels + in ]; // dest[ i * *channels + out ] = (int16_t) ( v < -32767 ? -32767 : v > 32768 ? 32768 : v ); v = v < -32767 ? -32767 : v > 32768 ? 32768 : v; vp[out] = dest[ i * *channels + out ] = (int16_t) ( v * A + vp[ out ] * B ); } weight += weight_step; } return 0; } /** Pan filter processing. */ static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties frame_props = MLT_FRAME_PROPERTIES( frame ); mlt_properties instance_props = mlt_properties_new(); // Only if mix is specified, otherwise a producer may set the mix if ( mlt_properties_get( properties, "start" ) != NULL ) { // Determine the time position of this frame in the filter duration mlt_properties props = mlt_properties_get_data( frame_props, "_producer", NULL ); int always_active = mlt_properties_get_int( properties, "always_active" ); mlt_position in = !always_active ? mlt_filter_get_in( filter ) : mlt_properties_get_int( props, "in" ); mlt_position out = !always_active ? mlt_filter_get_out( filter ) : mlt_properties_get_int( props, "out" ); int length = mlt_properties_get_int( properties, "length" ); mlt_position time = !always_active ? mlt_frame_get_position( frame ) : mlt_properties_get_int( props, "_frame" ); double mix = ( double )( time - in ) / ( double )( out - in + 1 ); if ( length == 0 ) { // If there is an end mix level adjust mix to the range if ( mlt_properties_get( properties, "end" ) != NULL ) { double start = mlt_properties_get_double( properties, "start" ); double end = mlt_properties_get_double( properties, "end" ); mix = start + ( end - start ) * mix; } // Use constant mix level if only start else if ( mlt_properties_get( properties, "start" ) != NULL ) { mix = mlt_properties_get_double( properties, "start" ); } // Convert it from [0, 1] to [-1, 1] mix = mix * 2.0 - 1.0; // Finally, set the mix property on the frame mlt_properties_set_double( instance_props, "mix", mix ); // Initialise filter previous mix value to prevent an inadvertant jump from 0 mlt_position last_position = mlt_properties_get_position( properties, "_last_position" ); mlt_position current_position = mlt_frame_get_position( frame ); mlt_properties_set_position( properties, "_last_position", current_position ); if ( mlt_properties_get( properties, "_previous_mix" ) == NULL || current_position != last_position + 1 ) mlt_properties_set_double( properties, "_previous_mix", mix ); // Tell the frame what the previous mix level was mlt_properties_set_double( instance_props, "previous_mix", mlt_properties_get_double( properties, "_previous_mix" ) ); // Save the current mix level for the next iteration mlt_properties_set_double( properties, "_previous_mix", mix ); } else { double level = mlt_properties_get_double( properties, "start" ); double mix_start = level; double mix_end = mix_start; double mix_increment = 1.0 / length; if ( time - in < length ) { mix_start *= ( double )( time - in ) / length; mix_end = mix_start + mix_increment; } else if ( time > out - length ) { mix_end = mix_start * ( ( double )( out - time - in ) / length ); mix_start = mix_end - mix_increment; } mix_start = mix_start < 0 ? 0 : mix_start > level ? level : mix_start; mix_end = mix_end < 0 ? 0 : mix_end > level ? level : mix_end; mlt_properties_set_double( instance_props, "previous_mix", mix_start ); mlt_properties_set_double( instance_props, "mix", mix_end ); } mlt_properties_set_int( instance_props, "channel", mlt_properties_get_int( properties, "channel" ) ); mlt_properties_set_int( instance_props, "gang", mlt_properties_get_int( properties, "gang" ) ); } mlt_properties_set_data( frame_props, mlt_properties_get( properties, "_unique_id" ), instance_props, 0, (mlt_destructor) mlt_properties_close, NULL ); // Override the get_audio method mlt_frame_push_audio( frame, filter ); mlt_frame_push_audio( frame, instance_props ); mlt_frame_push_audio( frame, filter_get_audio ); return frame; } /** Constructor for the filter. */ mlt_filter filter_panner_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = calloc( 1, sizeof( struct mlt_filter_s ) ); if ( filter != NULL && mlt_filter_init( filter, NULL ) == 0 ) { filter->process = filter_process; if ( arg != NULL ) mlt_properties_set_double( MLT_FILTER_PROPERTIES( filter ), "start", atof( arg ) ); mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "channel", -1 ); } return filter; } mlt-0.9.0/src/modules/core/filter_region.c000066400000000000000000000066041215300731300205000ustar00rootroot00000000000000/* * filter_region.c -- region filter * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "transition_region.h" #include #include #include #include #include /** Filter processing. */ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter mlt_filter filter = mlt_frame_pop_service( frame ); // Get the properties of the filter mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); // Get the region transition mlt_transition transition = mlt_properties_get_data( properties, "_transition", NULL ); // Create the transition if not available if ( transition == NULL ) { // Create the transition mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); transition = mlt_factory_transition( profile, "region", NULL ); // Register with the filter mlt_properties_set_data( properties, "_transition", transition, 0, ( mlt_destructor )mlt_transition_close, NULL ); // Pass a reference to this filter down mlt_properties_set_data( MLT_TRANSITION_PROPERTIES( transition ), "_region_filter", filter, 0, NULL, NULL ); } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); // Pass all properties down mlt_properties_inherit( MLT_TRANSITION_PROPERTIES( transition ), properties ); // Make the frame's position relative to this filter's in point mlt_frame_set_position( frame, mlt_filter_get_position( filter, frame ) ); // Process the frame mlt_transition_process( transition, frame, NULL ); return mlt_frame_get_image( frame, image, format, width, height, writable ); } static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { mlt_frame_push_service( frame, this ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_region_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create a new filter mlt_filter this = mlt_filter_new( ); // Further initialisation if ( this != NULL ) { // Get the properties from the filter mlt_properties properties = MLT_FILTER_PROPERTIES( this ); // Assign the filter process method this->process = filter_process; // Resource defines the shape of the region mlt_properties_set( properties, "resource", arg == NULL ? "rectangle" : arg ); // Ensure that attached filters are handled privately mlt_properties_set_int( properties, "_filter_private", 1 ); } // Return the filter return this; } mlt-0.9.0/src/modules/core/filter_region.yml000066400000000000000000000016221215300731300210520ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: region title: Regionalize version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video description: > Apply one or more filters to a region of the video image. The region can be shaped as well using the alpha channel of another producer. bugs: - Circle is unpredictable in the absence of the librsvg pixbuf loader. parameters: - identifier: argument title: File type: string description: > A file whose alpha channel will "shape" the region. The string "circle" is a shortcut but it requires pixbuf with the librsvg loader. The circle is automatically stretched to the region to create an ellipse. - identifier: region.* title: Region description: > Properties may be set on the encapsulated region transition. See "region" transition for details. mlt-0.9.0/src/modules/core/filter_rescale.c000066400000000000000000000215651215300731300206360ustar00rootroot00000000000000/* * filter_rescale.c -- scale the producer video frame size to match the consumer * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include /** virtual function declaration for an image scaler * * image scaler implementations are expected to support the following in and out formats: * yuv422 -> yuv422 * rgb24 -> rgb24 * rgb24a -> rgb24a * rgb24 -> yuv422 * rgb24a -> yuv422 */ typedef int ( *image_scaler )( mlt_frame frame, uint8_t **image, mlt_image_format *format, int iwidth, int iheight, int owidth, int oheight ); static int filter_scale( mlt_frame frame, uint8_t **image, mlt_image_format *format, int iwidth, int iheight, int owidth, int oheight ) { // Create the output image uint8_t *output = mlt_pool_alloc( owidth * ( oheight + 1 ) * 2 ); // Calculate strides int istride = iwidth * 2; int ostride = owidth * 2; iwidth = iwidth - ( iwidth % 4 ); // Derived coordinates int dy, dx; // Calculate ranges int out_x_range = owidth / 2; int out_y_range = oheight / 2; int in_x_range = iwidth / 2; int in_y_range = iheight / 2; // Output pointers register uint8_t *out_line = output; register uint8_t *out_ptr; // Calculate a middle pointer uint8_t *in_middle = *image + istride * in_y_range + in_x_range * 2; uint8_t *in_line; // Generate the affine transform scaling values register int scale_width = ( iwidth << 16 ) / owidth; register int scale_height = ( iheight << 16 ) / oheight; register int base = 0; int outer = out_x_range * scale_width; int bottom = out_y_range * scale_height; // Loop for the entirety of our output height. for ( dy = - bottom; dy < bottom; dy += scale_height ) { // Start at the beginning of the line out_ptr = out_line; // Pointer to the middle of the input line in_line = in_middle + ( dy >> 16 ) * istride; // Loop for the entirety of our output row. for ( dx = - outer; dx < outer; dx += scale_width ) { base = dx >> 15; base &= 0xfffffffe; *out_ptr ++ = *( in_line + base ); base &= 0xfffffffc; *out_ptr ++ = *( in_line + base + 1 ); dx += scale_width; base = dx >> 15; base &= 0xfffffffe; *out_ptr ++ = *( in_line + base ); base &= 0xfffffffc; *out_ptr ++ = *( in_line + base + 3 ); } // Move to next output line out_line += ostride; } // Now update the frame mlt_frame_set_image( frame, output, owidth * ( oheight + 1 ) * 2, mlt_pool_release ); *image = output; return 0; } static void scale_alpha( mlt_frame frame, int iwidth, int iheight, int owidth, int oheight ) { // Scale the alpha uint8_t *output = NULL; uint8_t *input = mlt_frame_get_alpha_mask( frame ); if ( input != NULL ) { uint8_t *out_line, *in_line; register int i, j, x, y; register int ox = ( iwidth << 16 ) / owidth; register int oy = ( iheight << 16 ) / oheight; output = mlt_pool_alloc( owidth * oheight ); out_line = output; // Loop for the entirety of our output height. for ( i = 0, y = (oy >> 1); i < oheight; i++, y += oy ) { in_line = &input[ (y >> 16) * iwidth ]; for ( j = 0, x = (ox >> 1); j < owidth; j++, x += ox ) *out_line ++ = in_line[ x >> 16 ]; } // Set it back on the frame mlt_frame_set_alpha( frame, output, owidth * oheight, mlt_pool_release ); } } /** Do it :-). */ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; // Get the frame properties mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Get the filter from the stack mlt_filter filter = mlt_frame_pop_service( frame ); // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); // Get the image scaler method image_scaler scaler_method = mlt_properties_get_data( filter_properties, "method", NULL ); // Correct Width/height if necessary if ( *width == 0 || *height == 0 ) { mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); *width = profile->width; *height = profile->height; } // There can be problems with small images - avoid them (by hacking - gah) if ( *width >= 6 && *height >= 6 ) { int iwidth = *width; int iheight = *height; double factor = mlt_properties_get_double( filter_properties, "factor" ); factor = factor > 0 ? factor : 1.0; int owidth = *width * factor; int oheight = *height * factor; char *interps = mlt_properties_get( properties, "rescale.interp" ); // Default from the scaler if not specifed on the frame if ( interps == NULL ) { interps = mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "interpolation" ); mlt_properties_set( properties, "rescale.interp", interps ); } // If meta.media.width/height exist, we want that as minimum information if ( mlt_properties_get_int( properties, "meta.media.width" ) ) { iwidth = mlt_properties_get_int( properties, "meta.media.width" ); iheight = mlt_properties_get_int( properties, "meta.media.height" ); } // Let the producer know what we are actually requested to obtain if ( strcmp( interps, "none" ) ) { mlt_properties_set_int( properties, "rescale_width", *width ); mlt_properties_set_int( properties, "rescale_height", *height ); } else { // When no scaling is requested, revert the requested dimensions if possible mlt_properties_set_int( properties, "rescale_width", iwidth ); mlt_properties_set_int( properties, "rescale_height", iheight ); } // Deinterlace if height is changing to prevent fields mixing on interpolation // One exception: non-interpolated, integral scaling if ( iheight != oheight && ( strcmp( interps, "nearest" ) || ( iheight % oheight != 0 ) ) ) mlt_properties_set_int( properties, "consumer_deinterlace", 1 ); // Convert the image to yuv422 when using the local scaler if ( scaler_method == filter_scale ) *format = mlt_image_yuv422; // Get the image as requested mlt_frame_get_image( frame, image, format, &iwidth, &iheight, writable ); // Get rescale interpretation again, in case the producer wishes to override scaling interps = mlt_properties_get( properties, "rescale.interp" ); if ( *image && strcmp( interps, "none" ) && ( iwidth != owidth || iheight != oheight ) ) { mlt_log_debug( MLT_FILTER_SERVICE( filter ), "%dx%d -> %dx%d (%s) %s\n", iwidth, iheight, owidth, oheight, mlt_image_format_name( *format ), interps ); // If valid colorspace if ( *format == mlt_image_yuv422 || *format == mlt_image_rgb24 || *format == mlt_image_rgb24a || *format == mlt_image_opengl ) { // Call the virtual function scaler_method( frame, image, format, iwidth, iheight, owidth, oheight ); *width = owidth; *height = oheight; } // Scale the alpha channel only if exists and not correct size int alpha_size = 0; mlt_properties_get_data( properties, "alpha", &alpha_size ); if ( alpha_size > 0 && alpha_size != ( owidth * oheight ) && alpha_size != ( owidth * ( oheight + 1 ) ) ) scale_alpha( frame, iwidth, iheight, owidth, oheight ); } else { *width = iwidth; *height = iheight; } } else { error = 1; } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { // Push the filter mlt_frame_push_service( frame, filter ); // Push the get image method mlt_frame_push_service( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_rescale_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create a new scaler mlt_filter filter = mlt_filter_new( ); // If successful, then initialise it if ( filter != NULL ) { // Get the properties mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); // Set the process method filter->process = filter_process; // Set the inerpolation mlt_properties_set( properties, "interpolation", arg == NULL ? "bilinear" : arg ); // Set the method mlt_properties_set_data( properties, "method", filter_scale, 0, NULL, NULL ); } return filter; } mlt-0.9.0/src/modules/core/filter_rescale.yml000066400000000000000000000016761215300731300212160ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: rescale title: Rescale version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Video - Hidden description: > Scale the producer video frame size to match the consumer. This filter is designed for use as a normaliser for the loader producer. notes: > If a property "consumer_aspect_ratio" exists on the frame, then rescaler normalises the producer's aspect ratio and maximises the size of the frame, but may not produce the consumer's requested dimension. Therefore, this option works best in conjunction with the resize filter. This behavior can be disabled by another service by either removing the property, setting it to zero, or setting frame property "distort" to 1. bugs: - > It only implements a nearest neighbour scaling - it is used as the base class for the gtkrescale and mcrescale filters. mlt-0.9.0/src/modules/core/filter_resize.c000066400000000000000000000220031215300731300205050ustar00rootroot00000000000000/* * filter_resize.c -- resizing filter * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include static uint8_t *resize_alpha( uint8_t *input, int owidth, int oheight, int iwidth, int iheight, uint8_t alpha_value ) { uint8_t *output = NULL; if ( input != NULL && ( iwidth != owidth || iheight != oheight ) && ( owidth > 6 && oheight > 6 ) ) { uint8_t *out_line; int offset_x = ( owidth - iwidth ) / 2; int offset_y = ( oheight - iheight ) / 2; int iused = iwidth; output = mlt_pool_alloc( owidth * oheight ); memset( output, alpha_value, owidth * oheight ); offset_x -= offset_x % 2; out_line = output + offset_y * owidth; out_line += offset_x; // Loop for the entirety of our output height. while ( iheight -- ) { // We're in the input range for this row. memcpy( out_line, input, iused ); // Move to next input line input += iwidth; // Move to next output line out_line += owidth; } } return output; } static void resize_image( uint8_t *output, int owidth, int oheight, uint8_t *input, int iwidth, int iheight, int bpp ) { // Calculate strides int istride = iwidth * bpp; int ostride = owidth * bpp; int offset_x = ( owidth - iwidth ) / 2 * bpp; int offset_y = ( oheight - iheight ) / 2; uint8_t *in_line = input; uint8_t *out_line; int size = owidth * oheight; uint8_t *p = output; // Optimisation point if ( output == NULL || input == NULL || ( owidth <= 6 || oheight <= 6 || iwidth <= 6 || oheight <= 6 ) ) { return; } else if ( iwidth == owidth && iheight == oheight ) { memcpy( output, input, iheight * istride ); return; } if ( bpp == 2 ) { while( size -- ) { *p ++ = 16; *p ++ = 128; } offset_x -= offset_x % 4; } else { size *= bpp; while ( size-- ) *p ++ = 0; } out_line = output + offset_y * ostride; out_line += offset_x; // Loop for the entirety of our output height. while ( iheight -- ) { // We're in the input range for this row. memcpy( out_line, in_line, istride ); // Move to next input line in_line += istride; // Move to next output line out_line += ostride; } } /** A padding function for frames - this does not rescale, but simply resizes. */ static uint8_t *frame_resize_image( mlt_frame frame, int owidth, int oheight, int bpp ) { // Get properties mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Get the input image, width and height uint8_t *input = mlt_properties_get_data( properties, "image", NULL ); uint8_t *alpha = mlt_frame_get_alpha_mask( frame ); int alpha_size = 0; mlt_properties_get_data( properties, "alpha", &alpha_size ); int iwidth = mlt_properties_get_int( properties, "width" ); int iheight = mlt_properties_get_int( properties, "height" ); // If width and height are correct, don't do anything if ( iwidth < owidth || iheight < oheight ) { uint8_t alpha_value = mlt_properties_get_int( properties, "resize_alpha" ); // Create the output image uint8_t *output = mlt_pool_alloc( owidth * ( oheight + 1 ) * bpp ); // Call the generic resize resize_image( output, owidth, oheight, input, iwidth, iheight, bpp ); // Now update the frame mlt_frame_set_image( frame, output, owidth * ( oheight + 1 ) * bpp, mlt_pool_release ); // We should resize the alpha too if ( alpha && alpha_size >= iwidth * iheight ) { alpha = resize_alpha( alpha, owidth, oheight, iwidth, iheight, alpha_value ); if ( alpha ) mlt_frame_set_alpha( frame, alpha, owidth * oheight, mlt_pool_release ); } // Return the output return output; } // No change, return input return input; } /** Do it :-). */ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; // Get the properties from the frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Pop the top of stack now mlt_filter filter = mlt_frame_pop_service( frame ); mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); // Retrieve the aspect ratio double aspect_ratio = mlt_deque_pop_back_double( MLT_FRAME_IMAGE_STACK( frame ) ); double consumer_aspect = mlt_profile_sar( mlt_service_profile( MLT_FILTER_SERVICE( filter ) ) ); // Correct Width/height if necessary if ( *width == 0 || *height == 0 ) { *width = profile->width; *height = profile->height; } // Assign requested width/height from our subordinate int owidth = *width; int oheight = *height; // Check for the special case - no aspect ratio means no problem :-) if ( aspect_ratio == 0.0 ) aspect_ratio = consumer_aspect; // Reset the aspect ratio mlt_properties_set_double( properties, "aspect_ratio", aspect_ratio ); // XXX: This is a hack, but it forces the force_full_luma to apply by doing a RGB // conversion because range scaling only occurs on YUV->RGB. And we do it here, // after the deinterlace filter, which only operates in YUV to avoid a YUV->RGB->YUV->?. // Instead, it will go YUV->RGB->?. if ( mlt_properties_get_int( properties, "force_full_luma" ) ) *format = mlt_image_rgb24a; // Hmmm... char *rescale = mlt_properties_get( properties, "rescale.interp" ); if ( rescale != NULL && !strcmp( rescale, "none" ) ) return mlt_frame_get_image( frame, image, format, width, height, writable ); if ( mlt_properties_get_int( properties, "distort" ) == 0 ) { // Normalise the input and out display aspect int normalised_width = profile->width; int normalised_height = profile->height; int real_width = mlt_properties_get_int( properties, "meta.media.width" ); int real_height = mlt_properties_get_int( properties, "meta.media.height" ); if ( real_width == 0 ) real_width = mlt_properties_get_int( properties, "width" ); if ( real_height == 0 ) real_height = mlt_properties_get_int( properties, "height" ); double input_ar = aspect_ratio * real_width / real_height; double output_ar = consumer_aspect * owidth / oheight; // fprintf( stderr, "real %dx%d normalised %dx%d output %dx%d sar %f in-dar %f out-dar %f\n", // real_width, real_height, normalised_width, normalised_height, owidth, oheight, aspect_ratio, input_ar, output_ar); // Optimised for the input_ar > output_ar case (e.g. widescreen on standard) int scaled_width = rint( ( input_ar * normalised_width ) / output_ar ); int scaled_height = normalised_height; // Now ensure that our images fit in the output frame if ( scaled_width > normalised_width ) { scaled_width = normalised_width; scaled_height = rint( ( output_ar * normalised_height ) / input_ar ); } // Now calculate the actual image size that we want owidth = rint( scaled_width * owidth / normalised_width ); oheight = rint( scaled_height * oheight / normalised_height ); // Tell frame we have conformed the aspect to the consumer mlt_frame_set_aspect_ratio( frame, consumer_aspect ); } mlt_properties_set_int( properties, "distort", 0 ); // Now pass on the calculations down the line mlt_properties_set_int( properties, "resize_width", *width ); mlt_properties_set_int( properties, "resize_height", *height ); // Now get the image if ( *format == mlt_image_yuv422 ) owidth -= owidth % 2; error = mlt_frame_get_image( frame, image, format, &owidth, &oheight, writable ); if ( error == 0 && *image ) { int bpp; mlt_image_format_size( *format, owidth, oheight, &bpp ); *image = frame_resize_image( frame, *width, *height, bpp ); } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { // Store the aspect ratio reported by the source mlt_deque_push_back_double( MLT_FRAME_IMAGE_STACK( frame ), mlt_frame_get_aspect_ratio( frame ) ); // Push this on to the service stack mlt_frame_push_service( frame, filter ); // Push the get_image method on to the stack mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_resize_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = calloc( 1, sizeof( struct mlt_filter_s ) ); if ( mlt_filter_init( filter, filter ) == 0 ) { filter->process = filter_process; } return filter; } mlt-0.9.0/src/modules/core/filter_resize.yml000066400000000000000000000011031215300731300210620ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: resize title: Pad version: 2 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video - Hidden description: Pad an image with black to fulfill the requested image size. notes: > Normally resize is used to pad the producer's output to what the consumer has requested after an upstream rescale filter first scales the image to maximise usage of the image area. This filter is automatically invoked by the loader as part of image normalisation. mlt-0.9.0/src/modules/core/filter_transition.c000066400000000000000000000105161215300731300214040ustar00rootroot00000000000000/* * filter_transition.c -- Convert any transition into a filter * Copyright (C) 2005 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include /** Get the image via the transition. NB: Not all transitions will accept a and b frames being the same... */ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_transition transition = mlt_frame_pop_service( this ); if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "image_count" ) >= 1 ) mlt_transition_process( transition, this, this ); return mlt_frame_get_image( this, image, format, width, height, writable ); } /** Get the audio via the transition. NB: Not all transitions will accept a and b frames being the same... */ static int filter_get_audio( mlt_frame this, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Obtain the transition instance mlt_transition transition = mlt_frame_pop_audio( this ); mlt_transition_process( transition, this, this ); return mlt_frame_get_audio( this, buffer, format, frequency, channels, samples ); } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Obtain the transition instance mlt_transition transition = mlt_properties_get_data( MLT_FILTER_PROPERTIES( this ), "instance", NULL ); // If we haven't created the instance, do it now if ( transition == NULL ) { char *name = mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "transition" ); mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) ); transition = mlt_factory_transition( profile, name, NULL ); mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "instance", transition, 0, ( mlt_destructor )mlt_transition_close, NULL ); } // We may still not have a transition... if ( transition != NULL ) { // Get the transition type int type = mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( transition ), "_transition_type" ); // Set the basic info mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "in", mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "in" ) ); mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "out", mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "out" ) ); // Refresh with current user values mlt_properties_pass( MLT_TRANSITION_PROPERTIES( transition ), MLT_FILTER_PROPERTIES( this ), "transition." ); if ( type & 1 && !mlt_frame_is_test_card( frame ) && !( mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "hide" ) & 1 ) ) { mlt_frame_push_service( frame, transition ); mlt_frame_push_get_image( frame, filter_get_image ); } if ( type & 2 && !mlt_frame_is_test_audio( frame ) && !( mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "hide" ) & 2 ) ) { mlt_frame_push_audio( frame, transition ); mlt_frame_push_audio( frame, filter_get_audio ); } if ( type == 0 ) mlt_properties_debug( MLT_TRANSITION_PROPERTIES( transition ), "unknown transition type", stderr ); } else { mlt_properties_debug( MLT_FILTER_PROPERTIES( this ), "no transition", stderr ); } return frame; } /** Constructor for the filter. */ mlt_filter filter_transition_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "transition", arg ); this->process = filter_process; } return this; } mlt-0.9.0/src/modules/core/filter_transition.yml000066400000000000000000000003151215300731300217570ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: transition title: Transition as Filter version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/core/filter_watermark.c000066400000000000000000000216341215300731300212120ustar00rootroot00000000000000/* * filter_watermark.c -- watermark filter * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include /** Do it :-). */ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Error we will return int error = 0; // Get the watermark filter object mlt_filter this = mlt_frame_pop_service( frame ); // Get the properties of the filter mlt_properties properties = MLT_FILTER_PROPERTIES( this ); mlt_service_lock( MLT_FILTER_SERVICE( this ) ); // Get the producer from the filter mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL ); // Get the composite from the filter mlt_transition composite = mlt_properties_get_data( properties, "composite", NULL ); // Get the resource to use char *resource = mlt_properties_get( properties, "resource" ); // Get the old resource char *old_resource = mlt_properties_get( properties, "_old_resource" ); // Create a composite if we don't have one if ( composite == NULL ) { // Create composite via the factory mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) ); composite = mlt_factory_transition( profile, "composite", NULL ); // Register the composite for reuse/destruction if ( composite != NULL ) mlt_properties_set_data( properties, "composite", composite, 0, ( mlt_destructor )mlt_transition_close, NULL ); } // If we have one if ( composite != NULL ) { // Get the properties mlt_properties composite_properties = MLT_TRANSITION_PROPERTIES( composite ); // Pass all the composite. properties on the filter down mlt_properties_pass( composite_properties, properties, "composite." ); if ( mlt_properties_get( properties, "composite.out" ) == NULL ) mlt_properties_set_int( composite_properties, "out", mlt_properties_get_int( properties, "_out" ) ); // Force a refresh mlt_properties_set_int( composite_properties, "refresh", 1 ); } // Create a producer if don't have one if ( producer == NULL || ( old_resource != NULL && strcmp( resource, old_resource ) ) ) { // Get the factory producer service char *factory = mlt_properties_get( properties, "factory" ); // Create the producer mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) ); producer = mlt_factory_producer( profile, factory, resource ); // If we have one if ( producer != NULL ) { // Register the producer for reuse/destruction mlt_properties_set_data( properties, "producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); // Ensure that we loop mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "loop" ); // Set the old resource mlt_properties_set( properties, "_old_resource", resource ); } } if ( producer != NULL ) { // Get the producer properties mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); // Now pass all producer. properties on the filter down mlt_properties_pass( producer_properties, properties, "producer." ); } mlt_service_unlock( MLT_FILTER_SERVICE( this ) ); // Only continue if we have both producer and composite if ( composite != NULL && producer != NULL ) { // Get the service of the producer mlt_service service = MLT_PRODUCER_SERVICE( producer ); // We will get the 'b frame' from the producer mlt_frame b_frame = NULL; // Get the original producer position mlt_position position = mlt_filter_get_position( this, frame ); // Make sure the producer is in the correct position mlt_producer_seek( producer, position ); // Resetting position to appease the composite transition mlt_frame_set_position( frame, position ); // Get the b frame and process with composite if successful if ( mlt_service_get_frame( service, &b_frame, 0 ) == 0 ) { // Get the a and b frame properties mlt_properties a_props = MLT_FRAME_PROPERTIES( frame ); mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); mlt_profile profile = mlt_service_profile( service ); // Set the b frame to be in the same position and have same consumer requirements mlt_frame_set_position( b_frame, position ); mlt_properties_set_int( b_props, "consumer_deinterlace", mlt_properties_get_int( a_props, "consumer_deinterlace" ) || mlt_properties_get_int( properties, "deinterlace" ) ); // Check for the special case - no aspect ratio means no problem :-) if ( mlt_frame_get_aspect_ratio( b_frame ) == 0 ) mlt_frame_set_aspect_ratio( b_frame, mlt_profile_sar( profile ) ); if ( mlt_frame_get_aspect_ratio( frame ) == 0 ) mlt_frame_set_aspect_ratio( frame, mlt_profile_sar( profile ) ); if ( mlt_properties_get_int( properties, "distort" ) ) { mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( composite ), "distort", 1 ); mlt_properties_set_int( a_props, "distort", 1 ); mlt_properties_set_int( b_props, "distort", 1 ); } *format = mlt_image_yuv422; if ( mlt_properties_get_int( properties, "reverse" ) == 0 ) { // Apply all filters that are attached to this filter to the b frame mlt_service_apply_filters( MLT_FILTER_SERVICE( this ), b_frame, 0 ); // Process the frame mlt_transition_process( composite, frame, b_frame ); // Get the image error = mlt_frame_get_image( frame, image, format, width, height, 1 ); } else { char temp[ 132 ]; int count = 0; uint8_t *alpha = NULL; const char *rescale = mlt_properties_get( a_props, "rescale.interp" ); if ( rescale == NULL || !strcmp( rescale, "none" ) ) rescale = "hyper"; mlt_transition_process( composite, b_frame, frame ); mlt_properties_set_int( a_props, "consumer_deinterlace", 1 ); mlt_properties_set_int( b_props, "consumer_deinterlace", 1 ); mlt_properties_set( a_props, "rescale.interp", rescale ); mlt_properties_set( b_props, "rescale.interp", rescale ); mlt_service_apply_filters( MLT_FILTER_SERVICE( this ), b_frame, 0 ); error = mlt_frame_get_image( b_frame, image, format, width, height, 1 ); alpha = mlt_frame_get_alpha_mask( b_frame ); mlt_frame_set_image( frame, *image, *width * *height * 2, NULL ); mlt_frame_set_alpha( frame, alpha, *width * *height, NULL ); mlt_properties_set_int( a_props, "width", *width ); mlt_properties_set_int( a_props, "height", *height ); mlt_properties_set_int( a_props, "progressive", 1 ); mlt_properties_inc_ref( b_props ); strcpy( temp, "_b_frame" ); while( mlt_properties_get_data( a_props, temp, NULL ) != NULL ) sprintf( temp, "_b_frame%d", count ++ ); mlt_properties_set_data( a_props, temp, b_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); } } // Close the b frame mlt_frame_close( b_frame ); } else { // Get the image from the frame without running fx error = mlt_frame_get_image( frame, image, format, width, height, 1 ); } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Get the properties of the frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Assign the frame out point to the filter (just in case we need it later) mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "_out", mlt_properties_get_int( properties, "out" ) ); // Push the filter on to the stack mlt_frame_push_service( frame, this ); // Push the get_image on to the stack mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_watermark_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { mlt_properties properties = MLT_FILTER_PROPERTIES( this ); this->process = filter_process; mlt_properties_set( properties, "factory", mlt_environment( "MLT_PRODUCER" ) ); if ( arg != NULL ) mlt_properties_set( properties, "resource", arg ); // Ensure that attached filters are handled privately mlt_properties_set_int( properties, "_filter_private", 1 ); } return this; } mlt-0.9.0/src/modules/core/filter_watermark.yml000066400000000000000000000042341215300731300215660ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: watermark title: Overlay version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video description: Overlay text or images onto the video notes: > The watermark filter combines a frame producer and a composite transition to overlay the specified text or image onto the video. Supplying a filename with extension ".txt" causes the loader to load a pango producer. Supplying a file name with an extension supported by gtk-pixbuf causes the loader to load a pixbuf producer. See the pango and pixbuf producers for details. Note: If the filename begins with "+" the pango producer interprets the filename as pango text. Text Example: melt colour:red -filter watermark:"+First Line~Second Line.txt" composite.progressive=1 producer.align=centre composite.valign=c composite.halign=c Image Example: melt clip.dv -filter watermark:logo.png parameters: - identifier: argument title: File/URL type: string description: The file to overlay. required: no readonly: no default: unset widget: fileopen - identifier: distort title: Allow distorted scaling type: integer default: 0 minimum: 0 maximum: 1 widget: checkbox - identifier: producer.* title: Producer description: | Properties may be set on the encapsulated producer. e.g.: producer.align=centre See "pango" and "pixbuf" producers for details. readonly: no - identifier: composite.* title: Composite description: | Properties may be set on the encapsulated composite. e.g.: composite.valign=c See "composite" transition for details. readonly: no - identifier: reverse title: Reverse type: integer description: Overlay the video to which the filter is applied atop the supplied file. minimum: 0 maximum: 1 mutable: yes widget: checkbox - identifier: deinterlace description: Force the supplied file to be be deinterlaced if it is interlaced. type: integer description: minimum: 0 maximum: 1 mutable: yes widget: checkbox mlt-0.9.0/src/modules/core/loader.dict000066400000000000000000000016541215300731300176170ustar00rootroot00000000000000http://*=avformat,webvfx:plain: https://*=webvfx:plain: plain:http://*=webvfx:plain: plain:https://*=webvfx:plain: * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include typedef struct { uint8_t r, g, b, a; } rgba_color; static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ); static void producer_close( mlt_producer parent ); mlt_producer producer_colour_init( mlt_profile profile, mlt_service_type type, const char *id, char *colour ) { mlt_producer producer = calloc( 1, sizeof( struct mlt_producer_s ) ); if ( producer != NULL && mlt_producer_init( producer, NULL ) == 0 ) { // Get the properties interface mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); // Callback registration producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )producer_close; // Set the default properties mlt_properties_set( properties, "resource", ( !colour || !strcmp( colour, "" ) ) ? "0x000000ff" : colour ); mlt_properties_set( properties, "_resource", "" ); mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) ); return producer; } free( producer ); return NULL; } rgba_color parse_color( char *color, unsigned int color_int ) { rgba_color result = { 0xff, 0xff, 0xff, 0xff }; if ( !strcmp( color, "red" ) ) { result.r = 0xff; result.g = 0x00; result.b = 0x00; } else if ( !strcmp( color, "green" ) ) { result.r = 0x00; result.g = 0xff; result.b = 0x00; } else if ( !strcmp( color, "blue" ) ) { result.r = 0x00; result.g = 0x00; result.b = 0xff; } else if ( !strcmp( color, "black" ) ) { result.r = 0x00; result.g = 0x00; result.b = 0x00; } else if ( strcmp( color, "white" ) ) { result.r = ( color_int >> 24 ) & 0xff; result.g = ( color_int >> 16 ) & 0xff; result.b = ( color_int >> 8 ) & 0xff; result.a = ( color_int ) & 0xff; } return result; } static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { // Obtain properties of frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Obtain the producer for this frame mlt_producer producer = mlt_properties_get_data( properties, "producer_colour", NULL ); mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); // Obtain properties of producer mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Get the current and previous colour strings char *now = mlt_properties_get( producer_props, "resource" ); char *then = mlt_properties_get( producer_props, "_resource" ); // Get the current image and dimensions cached in the producer int size = 0; uint8_t *image = mlt_properties_get_data( producer_props, "image", &size ); int current_width = mlt_properties_get_int( producer_props, "_width" ); int current_height = mlt_properties_get_int( producer_props, "_height" ); mlt_image_format current_format = mlt_properties_get_int( producer_props, "_format" ); // Parse the colour if ( now && strchr( now, '/' ) ) { now = strdup( strrchr( now, '/' ) + 1 ); mlt_properties_set( producer_props, "resource", now ); free( now ); now = mlt_properties_get( producer_props, "resource" ); } rgba_color color = parse_color( now, mlt_properties_get_int( producer_props, "resource" ) ); // Choose suitable out values if nothing specific requested if ( *format == mlt_image_none ) *format = mlt_image_rgb24a; if ( *width <= 0 ) *width = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->width; if ( *height <= 0 ) *height = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->height; // See if we need to regenerate if ( strcmp( now, then ) || *width != current_width || *height != current_height || *format != current_format ) { // Color the image int i = *width * *height + 1; int bpp; // Allocate the image size = mlt_image_format_size( *format, *width, *height, &bpp ); uint8_t *p = image = mlt_pool_alloc( size ); // Update the producer mlt_properties_set_data( producer_props, "image", image, size, mlt_pool_release, NULL ); mlt_properties_set_int( producer_props, "_width", *width ); mlt_properties_set_int( producer_props, "_height", *height ); mlt_properties_set_int( producer_props, "_format", *format ); mlt_properties_set( producer_props, "_resource", now ); mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); switch ( *format ) { case mlt_image_yuv422: { int uneven = *width % 2; int count = ( *width - uneven ) / 2 + 1; uint8_t y, u, v; RGB2YUV_601_SCALED( color.r, color.g, color.b, y, u, v ); i = *height + 1; while ( --i ) { int j = count; while ( --j ) { *p ++ = y; *p ++ = u; *p ++ = y; *p ++ = v; } if ( uneven ) { *p ++ = y; *p ++ = u; } } break; } case mlt_image_rgb24: while ( --i ) { *p ++ = color.r; *p ++ = color.g; *p ++ = color.b; } break; default: while ( --i ) { *p ++ = color.r; *p ++ = color.g; *p ++ = color.b; *p ++ = color.a; } break; } } else { mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); } // Create the alpha channel int alpha_size = *width * *height; uint8_t *alpha = mlt_pool_alloc( alpha_size ); // Initialise the alpha if ( alpha ) memset( alpha, color.a, alpha_size ); // Clone our image *buffer = mlt_pool_alloc( size ); memcpy( *buffer, image, size ); // Now update properties so we free the copy after mlt_frame_set_image( frame, *buffer, size, mlt_pool_release ); mlt_frame_set_alpha( frame, alpha, alpha_size, mlt_pool_release ); mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_props, "aspect_ratio" ) ); mlt_properties_set_int( properties, "meta.media.width", *width ); mlt_properties_set_int( properties, "meta.media.height", *height ); return 0; } static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL ) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Obtain properties of producer mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Set the producer on the frame properties mlt_properties_set_data( properties, "producer_colour", producer, 0, NULL, NULL ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Set producer-specific frame properties mlt_properties_set_int( properties, "progressive", 1 ); mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) ); // colour is an alias for resource if ( mlt_properties_get( producer_props, "colour" ) != NULL ) mlt_properties_set( producer_props, "resource", mlt_properties_get( producer_props, "colour" ) ); // Push the get_image method mlt_frame_push_get_image( *frame, producer_get_image ); } // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; } static void producer_close( mlt_producer producer ) { producer->close = NULL; mlt_producer_close( producer ); free( producer ); } mlt-0.9.0/src/modules/core/producer_colour.yml000066400000000000000000000011561215300731300214320ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: colour title: Color version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Video description: A simple color generator. parameters: - identifier: argument title: Color description: > A color value is a hexadecimal representation of RGB plus alpha channel as 0xrrggbbaa. Colors can also be the words: white, black, red, green, or blue. You can also use a HTML-style color values #rrggbb or #aarrggbb. type: string required: no readonly: no default: black widget: color mlt-0.9.0/src/modules/core/producer_consumer.c000066400000000000000000000215731215300731300214100ustar00rootroot00000000000000/* * producer_consumer.c -- produce as a consumer of an encapsulated producer * Copyright (C) 2008 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include struct context_s { mlt_producer this; mlt_producer producer; mlt_consumer consumer; mlt_profile profile; int64_t audio_counter; mlt_position audio_position; }; typedef struct context_s *context; static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { context cx = mlt_frame_pop_service( frame ); mlt_frame nested_frame = mlt_frame_pop_service( frame ); *width = cx->profile->width; *height = cx->profile->height; int result = mlt_frame_get_image( nested_frame, image, format, width, height, writable ); // Allocate the image int size = mlt_image_format_size( *format, *width, *height, NULL ); uint8_t *new_image = mlt_pool_alloc( size ); // Update the frame mlt_properties properties = mlt_frame_properties( frame ); mlt_frame_set_image( frame, new_image, size, mlt_pool_release ); memcpy( new_image, *image, size ); mlt_properties_set( properties, "progressive", mlt_properties_get( MLT_FRAME_PROPERTIES(nested_frame), "progressive" ) ); *image = new_image; // Copy the alpha channel uint8_t *alpha = mlt_properties_get_data( MLT_FRAME_PROPERTIES( nested_frame ), "alpha", &size ); if ( alpha && size > 0 ) { new_image = mlt_pool_alloc( size ); memcpy( new_image, alpha, size ); mlt_frame_set_alpha( frame, new_image, size, mlt_pool_release ); } return result; } static int get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { context cx = mlt_frame_pop_audio( frame ); mlt_frame nested_frame = mlt_frame_pop_audio( frame ); int result = 0; // if not repeating last frame if ( mlt_frame_get_position( nested_frame ) != cx->audio_position ) { double fps = mlt_profile_fps( cx->profile ); if ( mlt_producer_get_fps( cx->this ) < fps ) fps = mlt_producer_get_fps( cx->this ); *samples = mlt_sample_calculator( fps, *frequency, cx->audio_counter++ ); result = mlt_frame_get_audio( nested_frame, buffer, format, frequency, channels, samples ); int size = mlt_audio_format_size( *format, *samples, *channels ); int16_t *new_buffer = mlt_pool_alloc( size ); mlt_frame_set_audio( frame, new_buffer, *format, size, mlt_pool_release ); memcpy( new_buffer, *buffer, size ); *buffer = new_buffer; cx->audio_position = mlt_frame_get_position( nested_frame ); } else { // otherwise return no samples *samples = 0; *buffer = NULL; } return result; } static int get_frame( mlt_producer this, mlt_frame_ptr frame, int index ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES(this); context cx = mlt_properties_get_data( properties, "context", NULL ); if ( !cx ) { // Allocate and initialize our context cx = mlt_pool_alloc( sizeof( struct context_s ) ); memset( cx, 0, sizeof( *cx ) ); mlt_properties_set_data( properties, "context", cx, 0, mlt_pool_release, NULL ); cx->this = this; char *profile_name = mlt_properties_get( properties, "profile" ); if ( !profile_name ) profile_name = mlt_properties_get( properties, "mlt_profile" ); mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( this ) ); if ( profile_name ) { cx->profile = mlt_profile_init( profile_name ); cx->profile->is_explicit = 1; } else { cx->profile = mlt_profile_clone( profile ); cx->profile->is_explicit = 0; } // Encapsulate a real producer for the resource cx->producer = mlt_factory_producer( cx->profile, NULL, mlt_properties_get( properties, "resource" ) ); if ( ( profile_name && !strcmp( profile_name, "auto" ) ) || mlt_properties_get_int( properties, "autoprofile" ) ) { mlt_profile_from_producer( cx->profile, cx->producer ); mlt_producer_close( cx->producer ); cx->producer = mlt_factory_producer( cx->profile, NULL, mlt_properties_get( properties, "resource" ) ); } // Since we control the seeking, prevent it from seeking on its own mlt_producer_set_speed( cx->producer, 0 ); cx->audio_position = -1; // We will encapsulate a consumer cx->consumer = mlt_consumer_new( cx->profile ); // Do not use _pass_list on real_time so that it defaults to 0 in the absence of // an explicit real_time property. mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( cx->consumer ), "real_time", mlt_properties_get_int( properties, "real_time" ) ); mlt_properties_pass_list( MLT_CONSUMER_PROPERTIES( cx->consumer ), properties, "buffer, prefill, deinterlace_method, rescale" ); // Connect it all together mlt_consumer_connect( cx->consumer, MLT_PRODUCER_SERVICE( cx->producer ) ); mlt_consumer_start( cx->consumer ); } // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( this ) ); if ( *frame ) { // Seek the producer to the correct place // Calculate our positions double actual_position = (double) mlt_producer_frame( this ); if ( mlt_producer_get_speed( this ) != 0 ) actual_position *= mlt_producer_get_speed( this ); mlt_position need_first = floor( actual_position ); mlt_producer_seek( cx->producer, lrint( need_first * mlt_profile_fps( cx->profile ) / mlt_producer_get_fps( this ) ) ); // Get the nested frame mlt_frame nested_frame = mlt_consumer_rt_frame( cx->consumer ); // Stack the producer and our methods on the nested frame mlt_frame_push_service( *frame, nested_frame ); mlt_frame_push_service( *frame, cx ); mlt_frame_push_get_image( *frame, get_image ); mlt_frame_push_audio( *frame, nested_frame ); mlt_frame_push_audio( *frame, cx ); mlt_frame_push_audio( *frame, get_audio ); // Give the returned frame temporal identity mlt_frame_set_position( *frame, mlt_producer_position( this ) ); // Store the nested frame on the produced frame for destruction mlt_properties frame_props = MLT_FRAME_PROPERTIES( *frame ); mlt_properties_set_data( frame_props, "_producer_consumer.frame", nested_frame, 0, (mlt_destructor) mlt_frame_close, NULL ); // Inform the normalizers about our video properties mlt_properties_set_double( frame_props, "aspect_ratio", mlt_profile_sar( cx->profile ) ); mlt_properties_set_int( frame_props, "width", cx->profile->width ); mlt_properties_set_int( frame_props, "height", cx->profile->height ); mlt_properties_set_int( frame_props, "meta.media.width", cx->profile->width ); mlt_properties_set_int( frame_props, "meta.media.height", cx->profile->height ); mlt_properties_set_int( frame_props, "progressive", cx->profile->progressive ); } // Calculate the next timecode mlt_producer_prepare_next( this ); return 0; } static void producer_close( mlt_producer this ) { context cx = mlt_properties_get_data( MLT_PRODUCER_PROPERTIES( this ), "context", NULL ); // Shut down all the encapsulated services if ( cx ) { mlt_consumer_stop( cx->consumer ); mlt_consumer_close( cx->consumer ); mlt_producer_close( cx->producer ); mlt_profile_close( cx->profile ); } this->close = NULL; mlt_producer_close( this ); free( this ); } mlt_producer producer_consumer_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_producer this = mlt_producer_new( profile ); // Encapsulate the real producer mlt_profile temp_profile = mlt_profile_clone( profile ); temp_profile->is_explicit = 0; mlt_producer real_producer = mlt_factory_producer( temp_profile, NULL, arg ); if ( this && real_producer ) { // Override some producer methods this->close = ( mlt_destructor )producer_close; this->get_frame = get_frame; // Get the properties of this producer mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); mlt_properties_set( properties, "resource", arg ); mlt_properties_pass_list( properties, MLT_PRODUCER_PROPERTIES( real_producer ), "out, length" ); // Done with the producer - will re-open later when we have the profile property mlt_producer_close( real_producer ); } else { if ( this ) mlt_producer_close( this ); if ( real_producer ) mlt_producer_close( real_producer ); this = NULL; } mlt_profile_close( temp_profile ); return this; } mlt-0.9.0/src/modules/core/producer_consumer.yml000066400000000000000000000015311215300731300217570ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: consumer title: Consumer as Producer version: 2 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Audio - Video parameters: - identifier: argument title: File/URL type: string description: A file name, URL, or producer name. required: yes - identifier: profile title: Profile type: string description: > The name of a MLT profile with which to load the resource. This defaults to the composition's profile, but could be overridden by the profile in MLT XML. Also, the value "auto" triggers profile detection. - identifier: autoprofile title: Auto-profile type: integer description: Generate a new, custom profile from the encapsulated resource. minimum: 0 maximum: 1 default: 0 mlt-0.9.0/src/modules/core/producer_hold.c000066400000000000000000000153331215300731300205000ustar00rootroot00000000000000/* * producer_hold.c -- frame holding producer * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include // Forward references static int producer_get_frame( mlt_producer this, mlt_frame_ptr frame, int index ); static void producer_close( mlt_producer this ); /** Constructor for the frame holding producer. Basically, all this producer does is provide a producer wrapper for the requested producer, allows the specifcation of the frame required and will then repeatedly obtain that frame for each get_frame and get_image requested. */ mlt_producer producer_hold_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Construct a new holding producer mlt_producer this = mlt_producer_new( profile ); // Construct the requested producer via loader mlt_producer producer = mlt_factory_producer( profile, NULL, arg ); // Initialise the frame holding capabilities if ( this != NULL && producer != NULL ) { // Get the properties of this producer mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); // Store the producer mlt_properties_set_data( properties, "producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); // Set frame, in, out and length for this producer mlt_properties_set_position( properties, "frame", 0 ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", 25 ); mlt_properties_set_position( properties, "length", 15000 ); mlt_properties_set( properties, "resource", arg ); mlt_properties_set( properties, "method", "onefield" ); // Override the get_frame method this->get_frame = producer_get_frame; this->close = ( mlt_destructor )producer_close; } else { // Clean up (not sure which one failed, can't be bothered to find out, so close both) if ( this ) mlt_producer_close( this ); if ( producer ) mlt_producer_close( producer ); // Make sure we return NULL this = NULL; } // Return this producer return this; } static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { // Get the properties of the frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Obtain the real frame mlt_frame real_frame = mlt_frame_pop_service( frame ); // Get the image from the real frame int size = 0; *buffer = mlt_properties_get_data( MLT_FRAME_PROPERTIES( real_frame ), "image", &size ); *width = mlt_properties_get_int( MLT_FRAME_PROPERTIES( real_frame ), "width" ); *height = mlt_properties_get_int( MLT_FRAME_PROPERTIES( real_frame ), "height" ); // If this is the first time, get it from the producer if ( *buffer == NULL ) { mlt_properties_pass( MLT_FRAME_PROPERTIES( real_frame ), properties, "" ); // We'll deinterlace on the downstream deinterlacer mlt_properties_set_int( MLT_FRAME_PROPERTIES( real_frame ), "consumer_deinterlace", 1 ); // We want distorted to ensure we don't hit the resize filter twice mlt_properties_set_int( MLT_FRAME_PROPERTIES( real_frame ), "distort", 1 ); // Get the image mlt_frame_get_image( real_frame, buffer, format, width, height, writable ); // Make sure we get the size *buffer = mlt_properties_get_data( MLT_FRAME_PROPERTIES( real_frame ), "image", &size ); } mlt_properties_pass( properties, MLT_FRAME_PROPERTIES( real_frame ), "" ); // Set the values obtained on the frame if ( *buffer != NULL ) { uint8_t *image = mlt_pool_alloc( size ); memcpy( image, *buffer, size ); *buffer = image; mlt_frame_set_image( frame, *buffer, size, mlt_pool_release ); } else { // Pass the current image as is mlt_frame_set_image( frame, *buffer, size, NULL ); } // Make sure that no further scaling is done mlt_properties_set( properties, "rescale.interps", "none" ); mlt_properties_set( properties, "scale", "off" ); // All done return 0; } static int producer_get_frame( mlt_producer this, mlt_frame_ptr frame, int index ) { // Get the properties of this producer mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); // Construct a new frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( this ) ); // If we have a frame, then stack the producer itself and the get_image method if ( *frame != NULL ) { // Define the real frame mlt_frame real_frame = mlt_properties_get_data( properties, "real_frame", NULL ); // Obtain real frame if we don't have it if ( real_frame == NULL ) { // Get the producer mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL ); // Get the frame position requested mlt_position position = mlt_properties_get_position( properties, "frame" ); // Seek the producer to the correct place mlt_producer_seek( producer, position ); // Get the real frame mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &real_frame, index ); // Ensure that the real frame gets wiped eventually mlt_properties_set_data( properties, "real_frame", real_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); } else { // Temporary fix - ensure that we aren't seen as a test frame uint8_t *image = mlt_properties_get_data( MLT_FRAME_PROPERTIES( real_frame ), "image", NULL ); mlt_frame_set_image( *frame, image, 0, NULL ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_image", 0 ); } // Stack the real frame and method mlt_frame_push_service( *frame, real_frame ); mlt_frame_push_service( *frame, producer_get_image ); // Ensure that the consumer sees what the real frame has mlt_properties_pass( MLT_FRAME_PROPERTIES( *frame ), MLT_FRAME_PROPERTIES( real_frame ), "" ); mlt_properties_set( MLT_FRAME_PROPERTIES( real_frame ), "deinterlace_method", mlt_properties_get( properties, "method" ) ); } // Move to the next position mlt_producer_prepare_next( this ); return 0; } static void producer_close( mlt_producer this ) { this->close = NULL; mlt_producer_close( this ); free( this ); } mlt-0.9.0/src/modules/core/producer_hold.yml000066400000000000000000000002721215300731300210530ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: hold title: Still version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/core/producer_loader.c000066400000000000000000000201731215300731300210160ustar00rootroot00000000000000/* * producer_loader.c -- auto-load producer by file name extension * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include static mlt_properties dictionary = NULL; static mlt_properties normalisers = NULL; static mlt_producer create_from( mlt_profile profile, char *file, char *services ) { mlt_producer producer = NULL; char *temp = strdup( services ); char *service = temp; do { char *p = strchr( service, ',' ); if ( p != NULL ) *p ++ = '\0'; // If the service name has a colon as field delimiter, then treat the // second field as a prefix for the file/url. char *prefix = strchr( service, ':' ); if ( prefix ) { *prefix ++ = '\0'; char* prefix_file = calloc( 1, strlen( file ) + strlen( prefix ) + 1 ); strcpy( prefix_file, prefix ); strcat( prefix_file, file ); producer = mlt_factory_producer( profile, service, prefix_file ); free( prefix_file ); } else { producer = mlt_factory_producer( profile, service, file ); } service = p; } while ( producer == NULL && service != NULL ); free( temp ); return producer; } static mlt_producer create_producer( mlt_profile profile, char *file ) { mlt_producer result = NULL; // 1st Line - check for service:resource handling // And ignore drive letters on Win32 - no single char services supported. if ( strchr( file, ':' ) > file + 1 ) { char *temp = strdup( file ); char *service = temp; char *resource = strchr( temp, ':' ); *resource ++ = '\0'; result = mlt_factory_producer( profile, service, resource ); free( temp ); } // 2nd Line preferences if ( result == NULL ) { int i = 0; char *lookup = strdup( file ); char *p = lookup; // Make backup of profile for determining if we need to use 'consumer' producer. mlt_profile backup_profile = mlt_profile_clone( profile ); // We only need to load the dictionary once if ( dictionary == NULL ) { char temp[ 1024 ]; sprintf( temp, "%s/core/loader.dict", mlt_environment( "MLT_DATA" ) ); dictionary = mlt_properties_load( temp ); mlt_factory_register_for_clean_up( dictionary, ( mlt_destructor )mlt_properties_close ); } // Convert the lookup string to lower case while ( *p ) { *p = tolower( *p ); p ++; } // Chop off the query string p = strrchr( lookup, '?' ); if ( p ) p[0] = '\0'; // Strip file:// prefix p = lookup; if ( strncmp( lookup, "file://", 7 ) == 0 ) p += 7; // Iterate through the dictionary for ( i = 0; result == NULL && i < mlt_properties_count( dictionary ); i ++ ) { char *name = mlt_properties_get_name( dictionary, i ); if ( fnmatch( name, p, 0 ) == 0 ) result = create_from( profile, file, mlt_properties_get_value( dictionary, i ) ); } // Check if the producer changed the profile - xml does this. // The consumer producer does not handle frame rate differences. if ( result && backup_profile->is_explicit && ( profile->width != backup_profile->width || profile->height != backup_profile->height || profile->sample_aspect_num != backup_profile->sample_aspect_num || profile->sample_aspect_den != backup_profile->sample_aspect_den || profile->colorspace != backup_profile->colorspace ) ) { // Restore the original profile attributes. profile->display_aspect_den = backup_profile->display_aspect_den; profile->display_aspect_num = backup_profile->display_aspect_num; profile->frame_rate_den = backup_profile->frame_rate_den; profile->frame_rate_num = backup_profile->frame_rate_num; profile->height = backup_profile->height; profile->progressive = backup_profile->progressive; profile->sample_aspect_den = backup_profile->sample_aspect_den; profile->sample_aspect_num = backup_profile->sample_aspect_num; profile->width = backup_profile->width; // Use the 'consumer' producer. mlt_producer_close( result ); result = mlt_factory_producer( profile, "consumer", file ); } mlt_profile_close( backup_profile ); free( lookup ); } // Finally, try just loading as service if ( result == NULL ) result = mlt_factory_producer( profile, file, NULL ); return result; } static void create_filter( mlt_profile profile, mlt_producer producer, char *effect, int *created ) { mlt_filter filter; char *id = strdup( effect ); char *arg = strchr( id, ':' ); if ( arg != NULL ) *arg ++ = '\0'; // The swscale and avcolor_space filters require resolution as arg to test compatibility if ( strncmp( effect, "swscale", 7 ) == 0 || strncmp( effect, "avcolo", 6 ) == 0 ) { int width = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( producer ), "meta.media.width" ); filter = mlt_factory_filter( profile, id, &width ); } else { filter = mlt_factory_filter( profile, id, arg ); } if ( filter ) { mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "_loader", 1 ); mlt_producer_attach( producer, filter ); mlt_filter_close( filter ); *created = 1; } free( id ); } static void attach_normalisers( mlt_profile profile, mlt_producer producer ) { // Loop variable int i; // Tokeniser mlt_tokeniser tokeniser = mlt_tokeniser_init( ); // We only need to load the normalising properties once if ( normalisers == NULL ) { char temp[ 1024 ]; sprintf( temp, "%s/core/loader.ini", mlt_environment( "MLT_DATA" ) ); normalisers = mlt_properties_load( temp ); mlt_factory_register_for_clean_up( normalisers, ( mlt_destructor )mlt_properties_close ); } // Apply normalisers for ( i = 0; i < mlt_properties_count( normalisers ); i ++ ) { int j = 0; int created = 0; char *value = mlt_properties_get_value( normalisers, i ); mlt_tokeniser_parse_new( tokeniser, value, "," ); for ( j = 0; !created && j < mlt_tokeniser_count( tokeniser ); j ++ ) create_filter( profile, producer, mlt_tokeniser_get_string( tokeniser, j ), &created ); } // Close the tokeniser mlt_tokeniser_close( tokeniser ); } mlt_producer producer_loader_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create the producer mlt_producer producer = NULL; mlt_properties properties = NULL; if ( arg != NULL ) producer = create_producer( profile, arg ); if ( producer != NULL ) properties = MLT_PRODUCER_PROPERTIES( producer ); // Attach filters if we have a producer and it isn't already xml'd :-) if ( producer && strcmp( id, "abnormal" ) && strncmp( arg, "abnormal:", 9 ) && mlt_properties_get( properties, "xml" ) == NULL && mlt_properties_get( properties, "_xml" ) == NULL && mlt_properties_get( properties, "loader_normalised" ) == NULL ) attach_normalisers( profile, producer ); if ( producer ) { // Always let the image and audio be converted int created = 0; // movit.convert skips setting the frame->convert_image pointer if GLSL cannot be used. create_filter( profile, producer, "movit.convert", &created ); // avcolor_space and imageconvert only set frame->convert_image if it has not been set. create_filter( profile, producer, "avcolor_space", &created ); if ( !created ) create_filter( profile, producer, "imageconvert", &created ); create_filter( profile, producer, "audioconvert", &created ); } // Now make sure we don't lose our identity if ( properties != NULL ) mlt_properties_set_int( properties, "_mlt_service_hidden", 1 ); // Return the producer return producer; } mlt-0.9.0/src/modules/core/producer_loader.yml000066400000000000000000000014421215300731300213730ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: loader title: Loader version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Audio - Video - Hidden description: > This producer has two roles: 1. it handles the mappings of all file names to the other producers; 2. it attaches normalising filters (rescale, resize and resample) to the producers (when necessary). This producer simplifies many aspects of use. Essentially, it ensures that a consumer will receive images and audio precisely as they request them. parameters: - identifier: argument title: File/URL type: string description: The file for the producer to be based on. required: no readonly: no default: unset widget: fileopenmlt-0.9.0/src/modules/core/producer_melt.c000066400000000000000000000414601215300731300205130ustar00rootroot00000000000000/* * producer_melt.c -- load from melt command line syntax * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include mlt_producer producer_melt_init( mlt_profile profile, mlt_service_type type, const char *id, char **argv ); mlt_producer producer_melt_file_init( mlt_profile profile, mlt_service_type type, const char *id, char *file ) { FILE *input = fopen( file, "r" ); char **args = calloc( sizeof( char * ), 1000 ); int count = 0; char temp[ 2048 ]; if ( input != NULL ) { while( fgets( temp, 2048, input ) ) { temp[ strlen( temp ) - 1 ] = '\0'; if ( strcmp( temp, "" ) ) args[ count ++ ] = strdup( temp ); } fclose( input ); } mlt_producer result = producer_melt_init( profile, type, id, args ); if ( result != NULL ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( result ); mlt_properties_set( properties, "resource", file ); } while( count -- ) free( args[ count ] ); free( args ); return result; } static void track_service( mlt_field field, void *service, mlt_destructor destructor ) { mlt_properties properties = mlt_field_properties( field ); int registered = mlt_properties_get_int( properties, "registered" ); char *key = mlt_properties_get( properties, "registered" ); mlt_properties_set_data( properties, key, service, 0, destructor, NULL ); mlt_properties_set_int( properties, "registered", ++ registered ); } static mlt_producer create_producer( mlt_profile profile, mlt_field field, char *file ) { mlt_producer result = mlt_factory_producer( profile, NULL, file ); if ( result != NULL ) track_service( field, result, ( mlt_destructor )mlt_producer_close ); return result; } static mlt_filter create_attach( mlt_profile profile, mlt_field field, char *id, int track ) { char *temp = strdup( id ); char *arg = strchr( temp, ':' ); if ( arg != NULL ) *arg ++ = '\0'; mlt_filter filter = mlt_factory_filter( profile, temp, arg ); if ( filter != NULL ) track_service( field, filter, ( mlt_destructor )mlt_filter_close ); free( temp ); return filter; } static mlt_filter create_filter( mlt_profile profile, mlt_field field, char *id, int track ) { char *temp = strdup( id ); char *arg = strchr( temp, ':' ); if ( arg != NULL ) *arg ++ = '\0'; mlt_filter filter = mlt_factory_filter( profile, temp, arg ); if ( filter != NULL ) { mlt_field_plant_filter( field, filter, track ); track_service( field, filter, ( mlt_destructor )mlt_filter_close ); } free( temp ); return filter; } static mlt_transition create_transition( mlt_profile profile, mlt_field field, char *id, int track ) { char *arg = strchr( id, ':' ); if ( arg != NULL ) *arg ++ = '\0'; mlt_transition transition = mlt_factory_transition( profile, id, arg ); if ( transition != NULL ) { mlt_field_plant_transition( field, transition, track, track + 1 ); track_service( field, transition, ( mlt_destructor )mlt_transition_close ); } return transition; } mlt_producer producer_melt_init( mlt_profile profile, mlt_service_type type, const char *id, char **argv ) { int i; int track = 0; mlt_producer producer = NULL; mlt_tractor mix = NULL; mlt_playlist playlist = mlt_playlist_new( profile ); mlt_properties group = mlt_properties_new( ); mlt_tractor tractor = mlt_tractor_new( ); mlt_properties properties = MLT_TRACTOR_PROPERTIES( tractor ); mlt_field field = mlt_tractor_field( tractor ); mlt_properties field_properties = mlt_field_properties( field ); mlt_multitrack multitrack = mlt_tractor_multitrack( tractor ); char *title = NULL; // Assistance for template construction (allows -track usage to specify the first track) mlt_properties_set_int( MLT_PLAYLIST_PROPERTIES( playlist ), "_melt_first", 1 ); // We need to track the number of registered filters mlt_properties_set_int( field_properties, "registered", 0 ); // Parse the arguments if ( argv ) for ( i = 0; argv[ i ] != NULL; i ++ ) { if ( argv[ i + 1 ] == NULL && ( !strcmp( argv[ i ], "-attach" ) || !strcmp( argv[ i ], "-attach-cut" ) || !strcmp( argv[ i ], "-attach-track" ) || !strcmp( argv[ i ], "-attach-clip" ) || !strcmp( argv[ i ], "-repeat" ) || !strcmp( argv[ i ], "-split" ) || !strcmp( argv[ i ], "-join" ) || !strcmp( argv[ i ], "-mixer" ) || !strcmp( argv[ i ], "-mix" ) || !strcmp( argv[ i ], "-filter" ) || !strcmp( argv[ i ], "-transition" ) || !strcmp( argv[ i ], "-blank" ) ) ) { fprintf( stderr, "Argument missing for %s.\n", argv[ i ] ); break; } if ( !strcmp( argv[ i ], "-group" ) ) { if ( mlt_properties_count( group ) != 0 ) { mlt_properties_close( group ); group = mlt_properties_new( ); } if ( group != NULL ) properties = group; } else if ( !strcmp( argv[ i ], "-attach" ) || !strcmp( argv[ i ], "-attach-cut" ) || !strcmp( argv[ i ], "-attach-track" ) || !strcmp( argv[ i ], "-attach-clip" ) ) { int type = !strcmp( argv[ i ], "-attach" ) ? 0 : !strcmp( argv[ i ], "-attach-cut" ) ? 1 : !strcmp( argv[ i ], "-attach-track" ) ? 2 : 3; mlt_filter filter = create_attach( profile, field, argv[ ++ i ], track ); if ( producer != NULL && !mlt_producer_is_cut( producer ) ) { mlt_playlist_clip_info info; mlt_playlist_append( playlist, producer ); mlt_playlist_get_clip_info( playlist, &info, mlt_playlist_count( playlist ) - 1 ); producer = info.cut; } if ( type == 1 || type == 2 ) { mlt_playlist_clip_info info; mlt_playlist_get_clip_info( playlist, &info, mlt_playlist_count( playlist ) - 1 ); producer = info.cut; } if ( filter != NULL && mlt_playlist_count( playlist ) > 0 ) { if ( type == 0 ) mlt_service_attach( ( mlt_service )properties, filter ); else if ( type == 1 ) mlt_service_attach( ( mlt_service )producer, filter ); else if ( type == 2 ) mlt_service_attach( ( mlt_service )playlist, filter ); else if ( type == 3 ) mlt_service_attach( ( mlt_service )mlt_producer_cut_parent( producer ), filter ); properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties_inherit( properties, group ); } else if ( filter != NULL ) { mlt_service_attach( ( mlt_service )playlist, filter ); properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties_inherit( properties, group ); } } else if ( !strcmp( argv[ i ], "-repeat" ) ) { int repeat = atoi( argv[ ++ i ] ); if ( producer != NULL && !mlt_producer_is_cut( producer ) ) mlt_playlist_append( playlist, producer ); producer = NULL; if ( mlt_playlist_count( playlist ) > 0 ) { mlt_playlist_clip_info info; mlt_playlist_repeat_clip( playlist, mlt_playlist_count( playlist ) - 1, repeat ); mlt_playlist_get_clip_info( playlist, &info, mlt_playlist_count( playlist ) - 1 ); producer = info.cut; properties = MLT_PRODUCER_PROPERTIES( producer ); } } else if ( !strcmp( argv[ i ], "-split" ) ) { int split = atoi( argv[ ++ i ] ); if ( producer != NULL && !mlt_producer_is_cut( producer ) ) mlt_playlist_append( playlist, producer ); producer = NULL; if ( mlt_playlist_count( playlist ) > 0 ) { mlt_playlist_clip_info info; mlt_playlist_get_clip_info( playlist, &info, mlt_playlist_count( playlist ) - 1 ); split = split < 0 ? info.frame_out + split : split; mlt_playlist_split( playlist, mlt_playlist_count( playlist ) - 1, split ); mlt_playlist_get_clip_info( playlist, &info, mlt_playlist_count( playlist ) - 1 ); producer = info.cut; properties = MLT_PRODUCER_PROPERTIES( producer ); } } else if ( !strcmp( argv[ i ], "-swap" ) ) { if ( producer != NULL && !mlt_producer_is_cut( producer ) ) mlt_playlist_append( playlist, producer ); producer = NULL; if ( mlt_playlist_count( playlist ) >= 2 ) { mlt_playlist_clip_info info; mlt_playlist_move( playlist, mlt_playlist_count( playlist ) - 2, mlt_playlist_count( playlist ) - 1 ); mlt_playlist_get_clip_info( playlist, &info, mlt_playlist_count( playlist ) - 1 ); producer = info.cut; properties = MLT_PRODUCER_PROPERTIES( producer ); } } else if ( !strcmp( argv[ i ], "-join" ) ) { int clips = atoi( argv[ ++ i ] ); if ( producer != NULL && !mlt_producer_is_cut( producer ) ) mlt_playlist_append( playlist, producer ); producer = NULL; if ( mlt_playlist_count( playlist ) > 0 ) { mlt_playlist_clip_info info; int clip = clips <= 0 ? 0 : mlt_playlist_count( playlist ) - clips - 1; if ( clip < 0 ) clip = 0; if ( clip >= mlt_playlist_count( playlist ) ) clip = mlt_playlist_count( playlist ) - 2; if ( clips < 0 ) clips = mlt_playlist_count( playlist ) - 1; mlt_playlist_join( playlist, clip, clips, 0 ); mlt_playlist_get_clip_info( playlist, &info, mlt_playlist_count( playlist ) - 1 ); producer = info.cut; properties = MLT_PRODUCER_PROPERTIES( producer ); } } else if ( !strcmp( argv[ i ], "-remove" ) ) { if ( producer != NULL && !mlt_producer_is_cut( producer ) ) mlt_playlist_append( playlist, producer ); producer = NULL; if ( mlt_playlist_count( playlist ) > 0 ) { mlt_playlist_clip_info info; mlt_playlist_remove( playlist, mlt_playlist_count( playlist ) - 1 ); mlt_playlist_get_clip_info( playlist, &info, mlt_playlist_count( playlist ) - 1 ); producer = info.cut; properties = MLT_PRODUCER_PROPERTIES( producer ); } } else if ( !strcmp( argv[ i ], "-mix" ) ) { int length = atoi( argv[ ++ i ] ); if ( producer != NULL && !mlt_producer_is_cut( producer ) ) mlt_playlist_append( playlist, producer ); producer = NULL; if ( mlt_playlist_count( playlist ) >= 2 ) { if ( mlt_playlist_mix( playlist, mlt_playlist_count( playlist ) - 2, length, NULL ) == 0 ) { mlt_playlist_clip_info info; mlt_playlist_get_clip_info( playlist, &info, mlt_playlist_count( playlist ) - 1 ); if ( mlt_properties_get_data( ( mlt_properties )info.producer, "mlt_mix", NULL ) == NULL ) mlt_playlist_get_clip_info( playlist, &info, mlt_playlist_count( playlist ) - 2 ); mix = ( mlt_tractor )mlt_properties_get_data( ( mlt_properties )info.producer, "mlt_mix", NULL ); properties = NULL; } else { fprintf( stderr, "Mix failed?\n" ); } } else { fprintf( stderr, "Invalid position for a mix...\n" ); } } else if ( !strcmp( argv[ i ], "-mixer" ) ) { if ( mix != NULL ) { char *id = strdup( argv[ ++ i ] ); char *arg = strchr( id, ':' ); mlt_field field = mlt_tractor_field( mix ); mlt_transition transition = NULL; if ( arg != NULL ) *arg ++ = '\0'; transition = mlt_factory_transition( profile, id, arg ); if ( transition != NULL ) { properties = MLT_TRANSITION_PROPERTIES( transition ); mlt_properties_inherit( properties, group ); mlt_field_plant_transition( field, transition, 0, 1 ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", mlt_producer_get_out( ( mlt_producer )mix ) ); mlt_transition_close( transition ); } free( id ); } else { fprintf( stderr, "Invalid mixer...\n" ); } } else if ( !strcmp( argv[ i ], "-filter" ) ) { mlt_filter filter = create_filter( profile, field, argv[ ++ i ], track ); if ( filter != NULL ) { properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties_inherit( properties, group ); } } else if ( !strcmp( argv[ i ], "-transition" ) ) { mlt_transition transition = create_transition( profile, field, argv[ ++ i ], track - 1 ); if ( transition != NULL ) { properties = MLT_TRANSITION_PROPERTIES( transition ); mlt_properties_inherit( properties, group ); } } else if ( !strcmp( argv[ i ], "-blank" ) ) { if ( producer != NULL && !mlt_producer_is_cut( producer ) ) mlt_playlist_append( playlist, producer ); producer = NULL; if ( strchr( argv[ i + 1 ], ':' ) ) mlt_playlist_blank_time( playlist, argv[ ++ i ] ); else // support for legacy where plain int is an out point instead of length mlt_playlist_blank( playlist, atof( argv[ ++ i ] ) ); } else if ( !strcmp( argv[ i ], "-track" ) || !strcmp( argv[ i ], "-null-track" ) || !strcmp( argv[ i ], "-video-track" ) || !strcmp( argv[ i ], "-audio-track" ) || !strcmp( argv[ i ], "-hide-track" ) || !strcmp( argv[ i ], "-hide-video" ) || !strcmp( argv[ i ], "-hide-audio" ) ) { if ( producer != NULL && !mlt_producer_is_cut( producer ) ) mlt_playlist_append( playlist, producer ); producer = NULL; if ( !mlt_properties_get_int( MLT_PLAYLIST_PROPERTIES( playlist ), "_melt_first" ) || mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( playlist ) ) > 0 ) { mlt_multitrack_connect( multitrack, MLT_PLAYLIST_PRODUCER( playlist ), track ++ ); track_service( field, playlist, ( mlt_destructor )mlt_playlist_close ); playlist = mlt_playlist_new( profile ); } if ( playlist != NULL ) { properties = MLT_PLAYLIST_PROPERTIES( playlist ); if ( !strcmp( argv[ i ], "-null-track" ) || !strcmp( argv[ i ], "-hide-track" ) ) mlt_properties_set_int( properties, "hide", 3 ); else if ( !strcmp( argv[ i ], "-audio-track" ) || !strcmp( argv[ i ], "-hide-video" ) ) mlt_properties_set_int( properties, "hide", 1 ); else if ( !strcmp( argv[ i ], "-video-track" ) || !strcmp( argv[ i ], "-hide-audio" ) ) mlt_properties_set_int( properties, "hide", 2 ); } } else if ( strchr( argv[ i ], '=' ) && strstr( argv[ i ], " strchr( argv[ i ], '=' ) ) ) { mlt_properties_parse( properties, argv[ i ] ); } else if ( argv[ i ][ 0 ] != '-' ) { if ( producer != NULL && !mlt_producer_is_cut( producer ) ) mlt_playlist_append( playlist, producer ); if ( title == NULL && strstr( argv[ i ], " strchr( argv[ i ], '=' ) ) ) { i ++; backtrack = 1; } if ( backtrack ) i --; } } // Connect last producer to playlist if ( producer != NULL && !mlt_producer_is_cut( producer ) ) mlt_playlist_append( playlist, producer ); // Track the last playlist too track_service( field, playlist, ( mlt_destructor )mlt_playlist_close ); // We must have a playlist to connect if ( playlist && ( !mlt_properties_get_int( MLT_PLAYLIST_PROPERTIES( playlist ), "_melt_first" ) || mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( playlist ) ) > 0 ) ) mlt_multitrack_connect( multitrack, MLT_PLAYLIST_PRODUCER( playlist ), track ); mlt_producer prod = MLT_TRACTOR_PRODUCER( tractor ); mlt_producer_optimise( prod ); mlt_properties props = MLT_TRACTOR_PROPERTIES( tractor ); mlt_properties_set_data( props, "group", group, 0, ( mlt_destructor )mlt_properties_close, NULL ); mlt_properties_set_position( props, "length", mlt_producer_get_out( MLT_MULTITRACK_PRODUCER( multitrack ) ) + 1 ); mlt_producer_set_in_and_out( prod, 0, mlt_producer_get_out( MLT_MULTITRACK_PRODUCER( multitrack ) ) ); if ( title != NULL ) mlt_properties_set( props, "title", strchr( title, '/' ) ? strrchr( title, '/' ) + 1 : title ); // If the last producer has a consumer property connect it tractor if ( producer ) { mlt_consumer consumer = mlt_properties_get_data( MLT_PRODUCER_PROPERTIES(producer), "consumer", NULL ); if ( consumer ) mlt_consumer_connect( consumer, MLT_PRODUCER_SERVICE(prod) ); } return prod; } mlt-0.9.0/src/modules/core/producer_melt.yml000066400000000000000000000003531215300731300210660ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: melt title: Melt description: Process melt command line. version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Audio - Video mlt-0.9.0/src/modules/core/producer_melt_file.yml000066400000000000000000000004071215300731300220650ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: melt_file title: Melt description: Process file containing melt command line syntax. version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Audio - Video mlt-0.9.0/src/modules/core/producer_noise.c000066400000000000000000000117241215300731300206670ustar00rootroot00000000000000/* * producer_noise.c -- noise generating producer * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include /** Random number generator */ static unsigned int seed_x = 521288629; static unsigned int seed_y = 362436069; static inline unsigned int fast_rand( ) { static unsigned int a = 18000, b = 30903; seed_x = a * ( seed_x & 65535 ) + ( seed_x >> 16 ); seed_y = b * ( seed_y & 65535 ) + ( seed_y >> 16 ); return ( ( seed_x << 16 ) + ( seed_y & 65535 ) ); } // Foward declarations static int producer_get_frame( mlt_producer this, mlt_frame_ptr frame, int index ); static void producer_close( mlt_producer this ); /** Initialise. */ mlt_producer producer_noise_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create a new producer object mlt_producer this = mlt_producer_new( profile ); // Initialise the producer if ( this != NULL ) { // Callback registration this->get_frame = producer_get_frame; this->close = ( mlt_destructor )producer_close; } return this; } static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { // Choose suitable out values if nothing specific requested if ( *width <= 0 ) *width = mlt_service_profile( MLT_PRODUCER_SERVICE( mlt_frame_get_original_producer( frame ) ) )->width; if ( *height <= 0 ) *height = mlt_service_profile( MLT_PRODUCER_SERVICE( mlt_frame_get_original_producer( frame ) ) )->height; // Calculate the size of the image int size = *width * *height * 2; // Set the format being returned *format = mlt_image_yuv422; // Allocate the image *buffer = mlt_pool_alloc( size ); // Update the frame mlt_frame_set_image( frame, *buffer, size, mlt_pool_release ); // Before we write to the image, make sure we have one if ( *buffer != NULL ) { // Calculate the end of the buffer uint8_t *p = *buffer + *width * *height * 2; // Value to hold a random number uint32_t value; // Generate random noise while ( p != *buffer ) { value = fast_rand( ) & 0xff; *( -- p ) = 128; *( -- p ) = value < 16 ? 16 : value > 240 ? 240 : value; } } return 0; } static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { int size = 0; // Correct the returns if necessary *samples = *samples <= 0 ? 1920 : *samples; *channels = *channels <= 0 ? 2 : *channels; *frequency = *frequency <= 0 ? 48000 : *frequency; *format = mlt_audio_s16; // Calculate the size of the buffer size = *samples * *channels * sizeof( int16_t ); // Allocate the buffer *buffer = mlt_pool_alloc( size ); // Make sure we got one and fill it if ( *buffer != NULL ) { int16_t *p = *buffer + size / 2; while ( p != *buffer ) *( -- p ) = fast_rand( ) & 0x0f00; } // Set the buffer for destruction mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); return 0; } static int producer_get_frame( mlt_producer this, mlt_frame_ptr frame, int index ) { // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( this ) ); // Check that we created a frame and initialise it if ( *frame != NULL ) { // Obtain properties of frame mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Aspect ratio is whatever it needs to be mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( this ) ); mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) ); // Set producer-specific frame properties mlt_properties_set_int( properties, "progressive", 1 ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( this ) ); // Push the get_image method mlt_frame_push_get_image( *frame, producer_get_image ); // Specify the audio mlt_frame_push_audio( *frame, producer_get_audio ); } // Calculate the next timecode mlt_producer_prepare_next( this ); return 0; } static void producer_close( mlt_producer this ) { this->close = NULL; mlt_producer_close( this ); free( this ); } mlt-0.9.0/src/modules/core/producer_noise.yml000066400000000000000000000003471215300731300212450ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: noise title: Noise version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Audio - Video description: White noise producer mlt-0.9.0/src/modules/core/producer_ppm.c000066400000000000000000000157451215300731300203550ustar00rootroot00000000000000/* * producer_ppm.c -- simple ppm test case * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include typedef struct producer_ppm_s *producer_ppm; struct producer_ppm_s { struct mlt_producer_s parent; char *command; FILE *video; FILE *audio; uint64_t expected; }; static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ); static void producer_close( mlt_producer parent ); mlt_producer producer_ppm_init( mlt_profile profile, mlt_service_type type, const char *id, char *command ) { producer_ppm this = calloc( 1, sizeof( struct producer_ppm_s ) ); if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 ) { mlt_producer producer = &this->parent; mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )producer_close; if ( command != NULL ) { mlt_properties_set( properties, "resource", command ); this->command = strdup( command ); } else { mlt_properties_set( properties, "resource", "ppm test" ); } return producer; } free( this ); return NULL; } static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { // Get the frames properties mlt_properties properties = MLT_FRAME_PROPERTIES( this ); if ( mlt_properties_get_int( properties, "has_image" ) ) { // Get the RGB image *buffer = mlt_properties_get_data( properties, "image", NULL ); *width = mlt_properties_get_int( properties, "width" ); *height = mlt_properties_get_int( properties, "height" ); *format = mlt_image_rgb24; } else { mlt_frame_get_image( this, buffer, format, width, height, writable ); } return 0; } FILE *producer_ppm_run_video( producer_ppm this ) { if ( this->video == NULL ) { if ( this->command == NULL ) { this->video = popen( "image2raw -k -r 25 -ppm /usr/share/pixmaps/*.png", "r" ); } else { char command[ 1024 ]; float fps = mlt_producer_get_fps( &this->parent ); float position = mlt_producer_position( &this->parent ); sprintf( command, "ffmpeg -i \"%s\" -ss %f -f image2pipe -r %f -vcodec ppm - 2>/dev/null", this->command, position, fps ); this->video = popen( command, "r" ); } } return this->video; } FILE *producer_ppm_run_audio( producer_ppm this ) { if ( this->audio == NULL ) { if ( this->command != NULL ) { char command[ 1024 ]; float position = mlt_producer_position( &this->parent ); sprintf( command, "ffmpeg -i \"%s\" -ss %f -f s16le -ar 48000 -ac 2 - 2>/dev/null", this->command, position ); this->audio = popen( command, "r" ); } } return this->audio; } static void producer_ppm_position( producer_ppm this, uint64_t requested ) { if ( requested != this->expected ) { if ( this->video != NULL ) pclose( this->video ); this->video = NULL; if ( this->audio != NULL ) pclose( this->audio ); this->audio = NULL; } // This is the next frame we expect this->expected = mlt_producer_frame( &this->parent ) + 1; // Open the pipe this->video = producer_ppm_run_video( this ); // Open the audio pipe this->audio = producer_ppm_run_audio( this ); } static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the frames properties mlt_properties properties = MLT_FRAME_PROPERTIES( this ); FILE *pipe = mlt_properties_get_data( properties, "audio.pipe", NULL ); *frequency = 48000; *channels = 2; *samples = 1920; // Size int size = *samples * *channels * 2; // Allocate an image *buffer = malloc( size ); // Read it if ( pipe != NULL ) size = fread( *buffer, size, 1, pipe ); else memset( *buffer, 0, size ); // Pass the data on the frame properties mlt_frame_set_audio( this, *buffer, *format, size, free ); return 0; } static int read_ppm_header( FILE *video, int *width, int *height ) { int count = 0; { char temp[ 132 ]; char *ignore = fgets( temp, 132, video ); ignore = fgets( temp, 132, video ); count += sscanf( temp, "%d %d", width, height ); ignore = fgets( temp, 132, video ); } return count; } static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { producer_ppm this = producer->child; int width; int height; // Construct a test frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); // Are we at the position expected? producer_ppm_position( this, mlt_producer_frame( producer ) ); // Get the frames properties mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); FILE *video = this->video; FILE *audio = this->audio; // Read the video if ( video != NULL && read_ppm_header( video, &width, &height ) == 2 ) { // Allocate an image uint8_t *image = mlt_pool_alloc( width * ( height + 1 ) * 3 ); // Read it size_t ignore; ignore = fread( image, width * height * 3, 1, video ); // Pass the data on the frame properties mlt_frame_set_image( *frame, image, width * ( height + 1 ) * 3, mlt_pool_release ); mlt_properties_set_int( properties, "width", width ); mlt_properties_set_int( properties, "height", height ); mlt_properties_set_int( properties, "has_image", 1 ); mlt_properties_set_int( properties, "progressive", 1 ); mlt_properties_set_double( properties, "aspect_ratio", 1 ); // Push the image callback mlt_frame_push_get_image( *frame, producer_get_image ); } else { // Push the image callback mlt_frame_push_get_image( *frame, producer_get_image ); } // Set the audio pipe mlt_properties_set_data( properties, "audio.pipe", audio, 0, NULL, NULL ); // Hmm - register audio callback mlt_frame_push_audio( *frame, producer_get_audio ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; } static void producer_close( mlt_producer parent ) { producer_ppm this = parent->child; if ( this->video ) pclose( this->video ); if ( this->audio ) pclose( this->audio ); free( this->command ); parent->close = NULL; mlt_producer_close( parent ); free( this ); } mlt-0.9.0/src/modules/core/transition_composite.c000066400000000000000000001237271215300731300221320ustar00rootroot00000000000000/* * transition_composite.c -- compose one image over another using alpha channel * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "transition_composite.h" #include #include #include #include #include #include typedef void ( *composite_line_fn )( uint8_t *dest, uint8_t *src, int width_src, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int softness, uint32_t step ); /** Geometry struct. */ struct geometry_s { struct mlt_geometry_item_s item; int nw; // normalised width int nh; // normalised height int sw; // scaled width, not including consumer scale based upon w/nw int sh; // scaled height, not including consumer scale based upon h/nh int halign; // horizontal alignment: 0=left, 1=center, 2=right int valign; // vertical alignment: 0=top, 1=middle, 2=bottom int x_src; int y_src; }; /** Parse the alignment properties into the geometry. */ static int alignment_parse( char* align ) { int ret = 0; if ( align == NULL ); else if ( isdigit( align[ 0 ] ) ) ret = atoi( align ); else if ( align[ 0 ] == 'c' || align[ 0 ] == 'm' ) ret = 1; else if ( align[ 0 ] == 'r' || align[ 0 ] == 'b' ) ret = 2; return ret; } /** Calculate real geometry. */ static void geometry_calculate( mlt_transition self, struct geometry_s *output, double position ) { mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); mlt_geometry geometry = mlt_properties_get_data( properties, "geometries", NULL ); int mirror_off = mlt_properties_get_int( properties, "mirror_off" ); int repeat_off = mlt_properties_get_int( properties, "repeat_off" ); int length = mlt_geometry_get_length( geometry ); // Allow wrapping if ( !repeat_off && position >= length && length != 0 ) { int section = position / length; position -= section * length; if ( !mirror_off && section % 2 == 1 ) position = length - position; } // Fetch the key for the position mlt_geometry_fetch( geometry, &output->item, position ); } static mlt_geometry transition_parse_keys( mlt_transition self, int normalised_width, int normalised_height ) { // Loop variable for property interrogation int i = 0; // Get the properties of the transition mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); // Create an empty geometries object mlt_geometry geometry = mlt_geometry_init( ); // Get the duration mlt_position length = mlt_transition_get_length( self ); double cycle = mlt_properties_get_double( properties, "cycle" ); // Get the new style geometry string char *property = mlt_properties_get( properties, "geometry" ); // Allow a geometry repeat cycle if ( cycle >= 1 ) length = cycle; else if ( cycle > 0 ) length *= cycle; // Parse the geometry if we have one mlt_geometry_parse( geometry, property, length, normalised_width, normalised_height ); // Check if we're using the old style geometry if ( property == NULL ) { // DEPRECATED: Multiple keys for geometry information is inefficient and too rigid for // practical use - while deprecated, it has been slightly extended too - keys can now // be specified out of order, and can be blanked or NULL to simulate removal // Structure to use for parsing and inserting struct mlt_geometry_item_s item; // Parse the start property item.frame = 0; if ( mlt_geometry_parse_item( geometry, &item, mlt_properties_get( properties, "start" ) ) == 0 ) mlt_geometry_insert( geometry, &item ); // Parse the keys in between for ( i = 0; i < mlt_properties_count( properties ); i ++ ) { // Get the name of the property char *name = mlt_properties_get_name( properties, i ); // Check that it's valid if ( !strncmp( name, "key[", 4 ) ) { // Get the value of the property char *value = mlt_properties_get_value( properties, i ); // Determine the frame number item.frame = atoi( name + 4 ); // Parse and add to the list if ( mlt_geometry_parse_item( geometry, &item, value ) == 0 ) mlt_geometry_insert( geometry, &item ); else fprintf( stderr, "Invalid Key - skipping %s = %s\n", name, value ); } } // Parse the end item.frame = -1; if ( mlt_geometry_parse_item( geometry, &item, mlt_properties_get( properties, "end" ) ) == 0 ) mlt_geometry_insert( geometry, &item ); mlt_geometry_interpolate( geometry ); } return geometry; } /** Adjust position according to scaled size and alignment properties. */ static void alignment_calculate( struct geometry_s *geometry ) { geometry->item.x += ( geometry->item.w - geometry->sw ) * geometry->halign / 2; geometry->item.y += ( geometry->item.h - geometry->sh ) * geometry->valign / 2; } /** Calculate the position for this frame. */ static int position_calculate( mlt_transition self, mlt_position position ) { // Get the in and out position mlt_position in = mlt_transition_get_in( self ); // Now do the calcs return position - in; } /** Calculate the field delta for this frame - position between two frames. */ static int get_value( mlt_properties properties, const char *preferred, const char *fallback ) { int value = mlt_properties_get_int( properties, preferred ); if ( value == 0 ) value = mlt_properties_get_int( properties, fallback ); return value; } /** A linear threshold determination function. */ static inline int32_t linearstep( int32_t edge1, int32_t edge2, int32_t a ) { if ( a < edge1 ) return 0; if ( a >= edge2 ) return 0x10000; return ( ( a - edge1 ) << 16 ) / ( edge2 - edge1 ); } /** A smoother, non-linear threshold determination function. */ static inline int32_t smoothstep( int32_t edge1, int32_t edge2, uint32_t a ) { if ( a < edge1 ) return 0; if ( a >= edge2 ) return 0x10000; a = ( ( a - edge1 ) << 16 ) / ( edge2 - edge1 ); return ( ( ( a * a ) >> 16 ) * ( ( 3 << 16 ) - ( 2 * a ) ) ) >> 16; } /** Load the luma map from PGM stream. */ static void luma_read_pgm( FILE *f, uint16_t **map, int *width, int *height ) { uint8_t *data = NULL; while (1) { char line[128]; char comment[128]; int i = 2; int maxval; int bpp; uint16_t *p; line[127] = '\0'; // get the magic code if ( fgets( line, 127, f ) == NULL ) break; // skip comments while ( sscanf( line, " #%s", comment ) > 0 ) if ( fgets( line, 127, f ) == NULL ) break; if ( line[0] != 'P' || line[1] != '5' ) break; // skip white space and see if a new line must be fetched for ( i = 2; i < 127 && line[i] != '\0' && isspace( line[i] ); i++ ); if ( ( line[i] == '\0' || line[i] == '#' ) && fgets( line, 127, f ) == NULL ) break; // skip comments while ( sscanf( line, " #%s", comment ) > 0 ) if ( fgets( line, 127, f ) == NULL ) break; // get the dimensions if ( line[0] == 'P' ) i = sscanf( line, "P5 %d %d %d", width, height, &maxval ); else i = sscanf( line, "%d %d %d", width, height, &maxval ); // get the height value, if not yet if ( i < 2 ) { if ( fgets( line, 127, f ) == NULL ) break; // skip comments while ( sscanf( line, " #%s", comment ) > 0 ) if ( fgets( line, 127, f ) == NULL ) break; i = sscanf( line, "%d", height ); if ( i == 0 ) break; else i = 2; } // get the maximum gray value, if not yet if ( i < 3 ) { if ( fgets( line, 127, f ) == NULL ) break; // skip comments while ( sscanf( line, " #%s", comment ) > 0 ) if ( fgets( line, 127, f ) == NULL ) break; i = sscanf( line, "%d", &maxval ); if ( i == 0 ) break; } // determine if this is one or two bytes per pixel bpp = maxval > 255 ? 2 : 1; // allocate temporary storage for the raw data data = mlt_pool_alloc( *width * *height * bpp ); if ( data == NULL ) break; // read the raw data if ( fread( data, *width * *height * bpp, 1, f ) != 1 ) break; // allocate the luma bitmap *map = p = (uint16_t*)mlt_pool_alloc( *width * *height * sizeof( uint16_t ) ); if ( *map == NULL ) break; // proces the raw data into the luma bitmap for ( i = 0; i < *width * *height * bpp; i += bpp ) { if ( bpp == 1 ) *p++ = data[ i ] << 8; else *p++ = ( data[ i ] << 8 ) + data[ i + 1 ]; } break; } if ( data != NULL ) mlt_pool_release( data ); } /** Generate a luma map from any YUV image. */ static void luma_read_yuv422( uint8_t *image, uint16_t **map, int width, int height ) { int i; // allocate the luma bitmap uint16_t *p = *map = ( uint16_t* )mlt_pool_alloc( width * height * sizeof( uint16_t ) ); if ( *map == NULL ) return; // proces the image data into the luma bitmap for ( i = 0; i < width * height * 2; i += 2 ) *p++ = ( image[ i ] - 16 ) * 299; // 299 = 65535 / 219 } static inline int calculate_mix( uint16_t *luma, int j, int softness, int weight, int alpha, uint32_t step ) { return ( ( luma ? smoothstep( luma[ j ], luma[ j ] + softness, step ) : weight ) * ( alpha + 1 ) ) >> 8; } static inline uint8_t sample_mix( uint8_t dest, uint8_t src, int mix ) { return ( src * mix + dest * ( ( 1 << 16 ) - mix ) ) >> 16; } /** Composite a source line over a destination line */ #if defined(USE_SSE) && defined(ARCH_X86_64) void composite_line_yuv_sse2_simple(uint8_t *dest, uint8_t *src, int width, uint8_t *alpha_b, uint8_t *alpha_a, int weight); #endif void composite_line_yuv( uint8_t *dest, uint8_t *src, int width, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int soft, uint32_t step ) { register int j = 0; register int mix; #if defined(USE_SSE) && defined(ARCH_X86_64) if ( !luma && width > 7 ) { composite_line_yuv_sse2_simple(dest, src, width, alpha_b, alpha_a, weight); j = width - width % 8; dest += j * 2; src += j * 2; alpha_a += j; alpha_b += j; } #endif for ( ; j < width; j ++ ) { mix = calculate_mix( luma, j, soft, weight, *alpha_b ++, step ); *dest = sample_mix( *dest, *src++, mix ); dest++; *dest = sample_mix( *dest, *src++, mix ); dest++; *alpha_a = ( mix >> 8 ) | *alpha_a; alpha_a ++; } } static void composite_line_yuv_or( uint8_t *dest, uint8_t *src, int width, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int soft, uint32_t step ) { register int j; register int mix; for ( j = 0; j < width; j ++ ) { mix = calculate_mix( luma, j, soft, weight, *alpha_b ++ | *alpha_a, step ); *dest = sample_mix( *dest, *src++, mix ); dest++; *dest = sample_mix( *dest, *src++, mix ); dest++; *alpha_a ++ = mix >> 8; } } static void composite_line_yuv_and( uint8_t *dest, uint8_t *src, int width, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int soft, uint32_t step ) { register int j; register int mix; for ( j = 0; j < width; j ++ ) { mix = calculate_mix( luma, j, soft, weight, *alpha_b ++ & *alpha_a, step ); *dest = sample_mix( *dest, *src++, mix ); dest++; *dest = sample_mix( *dest, *src++, mix ); dest++; *alpha_a ++ = mix >> 8; } } static void composite_line_yuv_xor( uint8_t *dest, uint8_t *src, int width, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int soft, uint32_t step ) { register int j; register int mix; for ( j = 0; j < width; j ++ ) { mix = calculate_mix( luma, j, soft, weight, *alpha_b ++ ^ *alpha_a, step ); *dest = sample_mix( *dest, *src++, mix ); dest++; *dest = sample_mix( *dest, *src++, mix ); dest++; *alpha_a ++ = mix >> 8; } } /** Composite function. */ static int composite_yuv( uint8_t *p_dest, int width_dest, int height_dest, uint8_t *p_src, int width_src, int height_src, uint8_t *alpha_b, uint8_t *alpha_a, struct geometry_s geometry, int field, uint16_t *p_luma, double softness, composite_line_fn line_fn ) { int ret = 0; int i; int x_src = -geometry.x_src, y_src = -geometry.y_src; int uneven_x_src = ( x_src % 2 ); int step = ( field > -1 ) ? 2 : 1; int bpp = 2; int stride_src = geometry.sw * bpp; int stride_dest = width_dest * bpp; int i_softness = ( 1 << 16 ) * softness; int weight = ( ( 1 << 16 ) * geometry.item.mix + 50 ) / 100; uint32_t luma_step = ( ( ( 1 << 16 ) - 1 ) * geometry.item.mix + 50 ) / 100 * ( 1.0 + softness ); // Adjust to consumer scale int x = rint( geometry.item.x * width_dest / geometry.nw ); int y = rint( geometry.item.y * height_dest / geometry.nh ); int uneven_x = ( x % 2 ); // optimization points - no work to do if ( width_src <= 0 || height_src <= 0 || y_src >= height_src || x_src >= width_src ) return ret; if ( ( x < 0 && -x >= width_src ) || ( y < 0 && -y >= height_src ) ) return ret; // cropping affects the source width if ( x_src > 0 ) { width_src -= x_src; // and it implies cropping if ( width_src > geometry.item.w ) width_src = geometry.item.w; } // cropping affects the source height if ( y_src > 0 ) { height_src -= y_src; // and it implies cropping if ( height_src > geometry.item.h ) height_src = geometry.item.h; } // crop overlay off the left edge of frame if ( x < 0 ) { x_src = -x; width_src -= x_src; x = 0; } // crop overlay beyond right edge of frame if ( x + width_src > width_dest ) width_src = width_dest - x; // crop overlay off the top edge of the frame if ( y < 0 ) { y_src = -y; height_src -= y_src; y = 0; } // crop overlay below bottom edge of frame if ( y + height_src > height_dest ) height_src = height_dest - y; // offset pointer into overlay buffer based on cropping p_src += x_src * bpp + y_src * stride_src; // offset pointer into frame buffer based upon positive coordinates only! p_dest += x * bpp + y * stride_dest; // offset pointer into alpha channel based upon cropping alpha_b += x_src + y_src * stride_src / bpp; alpha_a += x + y * stride_dest / bpp; // offset pointer into luma channel based upon cropping if ( p_luma ) p_luma += x_src + y_src * stride_src / bpp; // Assuming lower field first // Special care is taken to make sure the b_frame is aligned to the correct field. // field 0 = lower field and y should be odd (y is 0-based). // field 1 = upper field and y should be even. if ( ( field > -1 ) && ( y % 2 == field ) ) { if ( ( field == 1 && y < height_dest - 1 ) || ( field == 0 && y == 0 ) ) p_dest += stride_dest; else p_dest -= stride_dest; } // On the second field, use the other lines from b_frame if ( field == 1 ) { p_src += stride_src; alpha_b += stride_src / bpp; alpha_a += stride_dest / bpp; height_src--; } stride_src *= step; stride_dest *= step; int alpha_b_stride = stride_src / bpp; int alpha_a_stride = stride_dest / bpp; // Align chroma of source and destination if ( uneven_x != uneven_x_src ) { p_src += 2; alpha_b += 1; } // now do the compositing only to cropped extents for ( i = 0; i < height_src; i += step ) { line_fn( p_dest, p_src, width_src, alpha_b, alpha_a, weight, p_luma, i_softness, luma_step ); p_src += stride_src; p_dest += stride_dest; alpha_b += alpha_b_stride; alpha_a += alpha_a_stride; if ( p_luma ) p_luma += alpha_b_stride; } return ret; } /** Scale 16bit greyscale luma map using nearest neighbor. */ static inline void scale_luma ( uint16_t *dest_buf, int dest_width, int dest_height, const uint16_t *src_buf, int src_width, int src_height, int invert ) { register int i, j; register int x_step = ( src_width << 16 ) / dest_width; register int y_step = ( src_height << 16 ) / dest_height; register int x, y = 0; for ( i = 0; i < dest_height; i++ ) { const uint16_t *src = src_buf + ( y >> 16 ) * src_width; x = 0; for ( j = 0; j < dest_width; j++ ) { *dest_buf++ = src[ x >> 16 ] ^ invert; x += x_step; } y += y_step; } } static uint16_t* get_luma( mlt_transition self, mlt_properties properties, int width, int height ) { // The cached luma map information int luma_width = mlt_properties_get_int( properties, "_luma.width" ); int luma_height = mlt_properties_get_int( properties, "_luma.height" ); uint16_t *luma_bitmap = mlt_properties_get_data( properties, "_luma.bitmap", NULL ); int invert = mlt_properties_get_int( properties, "luma_invert" ); // If the filename property changed, reload the map char *resource = mlt_properties_get( properties, "luma" ); char temp[ 512 ]; if ( luma_width == 0 || luma_height == 0 ) { luma_width = width; luma_height = height; } if ( resource && resource[0] && strchr( resource, '%' ) ) { // TODO: Clean up quick and dirty compressed/existence check FILE *test; sprintf( temp, "%s/lumas/%s/%s", mlt_environment( "MLT_DATA" ), mlt_environment( "MLT_NORMALISATION" ), strchr( resource, '%' ) + 1 ); test = fopen( temp, "r" ); if ( test == NULL ) strcat( temp, ".png" ); else fclose( test ); resource = temp; } if ( resource && resource[0] ) { char *old_luma = mlt_properties_get( properties, "_luma" ); int old_invert = mlt_properties_get_int( properties, "_luma_invert" ); if ( invert != old_invert || ( old_luma && old_luma[0] && strcmp( resource, old_luma ) ) ) { mlt_properties_set_data( properties, "_luma.orig_bitmap", NULL, 0, NULL, NULL ); luma_bitmap = NULL; } } else { char *old_luma = mlt_properties_get( properties, "_luma" ); if ( old_luma && old_luma[0] ) { mlt_properties_set_data( properties, "_luma.orig_bitmap", NULL, 0, NULL, NULL ); luma_bitmap = NULL; mlt_properties_set( properties, "_luma", NULL); } } if ( resource && resource[0] && ( luma_bitmap == NULL || luma_width != width || luma_height != height ) ) { uint16_t *orig_bitmap = mlt_properties_get_data( properties, "_luma.orig_bitmap", NULL ); luma_width = mlt_properties_get_int( properties, "_luma.orig_width" ); luma_height = mlt_properties_get_int( properties, "_luma.orig_height" ); // Load the original luma once if ( orig_bitmap == NULL ) { char *extension = strrchr( resource, '.' ); // See if it is a PGM if ( extension != NULL && strcmp( extension, ".pgm" ) == 0 ) { // Open PGM FILE *f = fopen( resource, "r" ); if ( f != NULL ) { // Load from PGM luma_read_pgm( f, &orig_bitmap, &luma_width, &luma_height ); fclose( f ); // Remember the original size for subsequent scaling mlt_properties_set_data( properties, "_luma.orig_bitmap", orig_bitmap, luma_width * luma_height * 2, mlt_pool_release, NULL ); mlt_properties_set_int( properties, "_luma.orig_width", luma_width ); mlt_properties_set_int( properties, "_luma.orig_height", luma_height ); } } else { // Get the factory producer service char *factory = mlt_properties_get( properties, "factory" ); // Create the producer mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( self ) ); mlt_producer producer = mlt_factory_producer( profile, factory, resource ); // If we have one if ( producer != NULL ) { // Get the producer properties mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); // Ensure that we loop mlt_properties_set( producer_properties, "eof", "loop" ); // Now pass all producer. properties on the transition down mlt_properties_pass( producer_properties, properties, "luma." ); // We will get the alpha frame from the producer mlt_frame luma_frame = NULL; // Get the luma frame if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &luma_frame, 0 ) == 0 ) { uint8_t *luma_image; mlt_image_format luma_format = mlt_image_yuv422; // Get image from the luma producer mlt_properties_set( MLT_FRAME_PROPERTIES( luma_frame ), "rescale.interp", "none" ); mlt_frame_get_image( luma_frame, &luma_image, &luma_format, &luma_width, &luma_height, 0 ); // Generate the luma map if ( luma_image != NULL && luma_format == mlt_image_yuv422 ) luma_read_yuv422( luma_image, &orig_bitmap, luma_width, luma_height ); // Remember the original size for subsequent scaling mlt_properties_set_data( properties, "_luma.orig_bitmap", orig_bitmap, luma_width * luma_height * 2, mlt_pool_release, NULL ); mlt_properties_set_int( properties, "_luma.orig_width", luma_width ); mlt_properties_set_int( properties, "_luma.orig_height", luma_height ); // Cleanup the luma frame mlt_frame_close( luma_frame ); } // Cleanup the luma producer mlt_producer_close( producer ); } } } // Scale luma map luma_bitmap = mlt_pool_alloc( width * height * sizeof( uint16_t ) ); scale_luma( luma_bitmap, width, height, orig_bitmap, luma_width, luma_height, invert * ( ( 1 << 16 ) - 1 ) ); // Remember the scaled luma size to prevent unnecessary scaling mlt_properties_set_int( properties, "_luma.width", width ); mlt_properties_set_int( properties, "_luma.height", height ); mlt_properties_set_data( properties, "_luma.bitmap", luma_bitmap, width * height * 2, mlt_pool_release, NULL ); mlt_properties_set( properties, "_luma", resource ); mlt_properties_set_int( properties, "_luma_invert", invert ); } return luma_bitmap; } /** Get the properly sized image from b_frame. */ static int get_b_frame_image( mlt_transition self, mlt_frame b_frame, uint8_t **image, int *width, int *height, struct geometry_s *geometry ) { int ret = 0; mlt_image_format format = mlt_image_yuv422; // Get the properties objects mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); uint8_t resize_alpha = mlt_properties_get_int( b_props, "resize_alpha" ); double output_ar = mlt_profile_sar( mlt_service_profile( MLT_TRANSITION_SERVICE(self) ) ); // Do not scale if we are cropping - the compositing rectangle can crop the b image // TODO: Use the animatable w and h of the crop geometry to scale independently of crop rectangle if ( mlt_properties_get( properties, "crop" ) ) { int real_width = get_value( b_props, "meta.media.width", "width" ); int real_height = get_value( b_props, "meta.media.height", "height" ); double input_ar = mlt_properties_get_double( b_props, "aspect_ratio" ); int scaled_width = rint( ( input_ar == 0.0 ? output_ar : input_ar ) / output_ar * real_width ); int scaled_height = real_height; geometry->sw = scaled_width; geometry->sh = scaled_height; } // Normalise aspect ratios and scale preserving aspect ratio else if ( mlt_properties_get_int( properties, "aligned" ) && mlt_properties_get_int( properties, "distort" ) == 0 && mlt_properties_get_int( b_props, "distort" ) == 0 && geometry->item.distort == 0 ) { // Adjust b_frame pixel aspect int normalised_width = geometry->item.w; int normalised_height = geometry->item.h; int real_width = get_value( b_props, "meta.media.width", "width" ); int real_height = get_value( b_props, "meta.media.height", "height" ); double input_ar = mlt_properties_get_double( b_props, "aspect_ratio" ); int scaled_width = rint( ( input_ar == 0.0 ? output_ar : input_ar ) / output_ar * real_width ); int scaled_height = real_height; // fprintf(stderr, "%s: scaled %dx%d norm %dx%d real %dx%d output_ar %f\n", __FILE__, // scaled_width, scaled_height, normalised_width, normalised_height, real_width, real_height, // output_ar); // Now ensure that our images fit in the normalised frame if ( scaled_width > normalised_width ) { scaled_height = rint( scaled_height * normalised_width / scaled_width ); scaled_width = normalised_width; } if ( scaled_height > normalised_height ) { scaled_width = rint( scaled_width * normalised_height / scaled_height ); scaled_height = normalised_height; } // Honour the fill request - this will scale the image to fill width or height while maintaining a/r // ????: Shouln't this be the default behaviour? if ( mlt_properties_get_int( properties, "fill" ) && scaled_width > 0 && scaled_height > 0 ) { if ( scaled_height < normalised_height && scaled_width * normalised_height / scaled_height <= normalised_width ) { scaled_width = rint( scaled_width * normalised_height / scaled_height ); scaled_height = normalised_height; } else if ( scaled_width < normalised_width && scaled_height * normalised_width / scaled_width < normalised_height ) { scaled_height = rint( scaled_height * normalised_width / scaled_width ); scaled_width = normalised_width; } } // Save the new scaled dimensions geometry->sw = scaled_width; geometry->sh = scaled_height; } else { geometry->sw = geometry->item.w; geometry->sh = geometry->item.h; } // We want to ensure that we bypass resize now... if ( resize_alpha == 0 ) mlt_properties_set_int( b_props, "distort", mlt_properties_get_int( properties, "distort" ) ); // If we're not aligned, we want a non-transparent background if ( mlt_properties_get_int( properties, "aligned" ) == 0 ) mlt_properties_set_int( b_props, "resize_alpha", 255 ); // Take into consideration alignment for optimisation (titles are a special case) if ( !mlt_properties_get_int( properties, "titles" ) && mlt_properties_get( properties, "crop" ) == NULL ) alignment_calculate( geometry ); // Adjust to consumer scale *width = rint( geometry->sw * *width / geometry->nw ); *width -= *width % 2; // coerce to even width for yuv422 *height = rint( geometry->sh * *height / geometry->nh ); // fprintf(stderr, "%s: scaled %dx%d norm %dx%d resize %dx%d\n", __FILE__, // geometry->sw, geometry->sh, geometry->nw, geometry->nh, *width, *height); ret = mlt_frame_get_image( b_frame, image, &format, width, height, 1 ); // composite_yuv uses geometry->sw to determine source stride, which // should equal the image width if not using crop property. if ( !mlt_properties_get( properties, "crop" ) ) geometry->sw = *width; // Set the frame back mlt_properties_set_int( b_props, "resize_alpha", resize_alpha ); return ret && image != NULL; } static void crop_calculate( mlt_transition self, mlt_properties properties, struct geometry_s *result, double position ) { // Initialize panning info result->x_src = 0; result->y_src = 0; if ( mlt_properties_get( properties, "crop" ) ) { mlt_geometry crop = mlt_properties_get_data( properties, "crop_geometry", NULL ); if ( !crop ) { crop = mlt_geometry_init(); mlt_position length = mlt_transition_get_length( self ); double cycle = mlt_properties_get_double( properties, "cycle" ); // Allow a geometry repeat cycle if ( cycle >= 1 ) length = cycle; else if ( cycle > 0 ) length *= cycle; mlt_geometry_parse( crop, mlt_properties_get( properties, "crop" ), length, result->sw, result->sh ); mlt_properties_set_data( properties, "crop_geometry", crop, 0, (mlt_destructor)mlt_geometry_close, NULL ); } // Repeat processing int length = mlt_geometry_get_length( crop ); int mirror_off = mlt_properties_get_int( properties, "mirror_off" ); int repeat_off = mlt_properties_get_int( properties, "repeat_off" ); if ( !repeat_off && position >= length && length != 0 ) { int section = position / length; position -= section * length; if ( !mirror_off && section % 2 == 1 ) position = length - position; } // Compute the pan struct mlt_geometry_item_s crop_item; mlt_geometry_fetch( crop, &crop_item, position ); result->x_src = rint( crop_item.x ); result->y_src = rint( crop_item.y ); } } static mlt_geometry composite_calculate( mlt_transition self, struct geometry_s *result, mlt_frame a_frame, double position ) { // Get the properties from the transition mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); // Get the properties from the frame mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); // Structures for geometry mlt_geometry start = mlt_properties_get_data( properties, "geometries", NULL ); // Obtain the normalised width and height from the a_frame mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( self ) ); int normalised_width = profile->width; int normalised_height = profile->height; char *name = mlt_properties_get( properties, "_unique_id" ); char key[ 256 ]; sprintf( key, "%s.in", name ); if ( mlt_properties_get( a_props, key ) ) { sscanf( mlt_properties_get( a_props, key ), "%f %f %f %f %f %d %d", &result->item.x, &result->item.y, &result->item.w, &result->item.h, &result->item.mix, &result->nw, &result->nh ); } else { // Now parse the geometries if ( start == NULL ) { // Parse the transitions properties start = transition_parse_keys( self, normalised_width, normalised_height ); // Assign to properties to ensure we get destroyed mlt_properties_set_data( properties, "geometries", start, 0, ( mlt_destructor )mlt_geometry_close, NULL ); } else { mlt_position length = mlt_transition_get_length( self ); double cycle = mlt_properties_get_double( properties, "cycle" ); if ( cycle > 1 ) length = cycle; else if ( cycle > 0 ) length *= cycle; mlt_geometry_refresh( start, mlt_properties_get( properties, "geometry" ), length, normalised_width, normalised_height ); } // Do the calculation geometry_calculate( self, result, position ); // Assign normalised info result->nw = normalised_width; result->nh = normalised_height; } // Now parse the alignment result->halign = alignment_parse( mlt_properties_get( properties, "halign" ) ); result->valign = alignment_parse( mlt_properties_get( properties, "valign" ) ); crop_calculate( self, properties, result, position ); return start; } mlt_frame composite_copy_region( mlt_transition self, mlt_frame a_frame, mlt_position frame_position ) { // Create a frame to return mlt_frame b_frame = mlt_frame_init( MLT_TRANSITION_SERVICE( self ) ); // Get the properties of the a frame mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); // Get the properties of the b frame mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); // Get the position int position = position_calculate( self, frame_position ); // Get the unique id of the transition char *name = mlt_properties_get( MLT_TRANSITION_PROPERTIES( self ), "_unique_id" ); char key[ 256 ]; // Destination image uint8_t *dest = NULL; // Get the image and dimensions uint8_t *image = NULL; int width = mlt_properties_get_int( a_props, "width" ); int height = mlt_properties_get_int( a_props, "height" ); mlt_image_format format = mlt_image_yuv422; mlt_frame_get_image( a_frame, &image, &format, &width, &height, 0 ); if ( !image ) return b_frame; // Pointers for copy operation uint8_t *p; // Coordinates int w = 0; int h = 0; int x = 0; int y = 0; int ss = 0; int ds = 0; // Will need to know region to copy struct geometry_s result; // Calculate the region now composite_calculate( self, &result, a_frame, position ); // Need to scale down to actual dimensions x = rint( result.item.x * width / result.nw ); y = rint( result.item.y * height / result.nh ); w = rint( result.item.w * width / result.nw ); h = rint( result.item.h * height / result.nh ); if ( x % 2 ) { x --; w ++; } // Store the key sprintf( key, "%s.in=%d %d %d %d %f %d %d", name, x, y, w, h, result.item.mix, width, height ); mlt_properties_parse( a_props, key ); sprintf( key, "%s.out=%d %d %d %d %f %d %d", name, x, y, w, h, result.item.mix, width, height ); mlt_properties_parse( a_props, key ); ds = w * 2; ss = width * 2; // Now we need to create a new destination image dest = mlt_pool_alloc( w * h * 2 ); // Assign to the new frame mlt_frame_set_image( b_frame, dest, w * h * 2, mlt_pool_release ); mlt_properties_set_int( b_props, "width", w ); mlt_properties_set_int( b_props, "height", h ); mlt_properties_set_int( b_props, "format", format ); if ( y < 0 ) { dest += ( ds * -y ); h += y; y = 0; } if ( y + h > height ) h -= ( y + h - height ); if ( x < 0 ) { dest += -x * 2; w += x; x = 0; } if ( w > 0 && h > 0 ) { // Copy the region of the image p = image + y * ss + x * 2; while ( h -- ) { memcpy( dest, p, w * 2 ); dest += ds; p += ss; } } // Assign this position to the b frame mlt_frame_set_position( b_frame, frame_position ); mlt_properties_set_int( b_props, "distort", 1 ); // Return the frame return b_frame; } /** Get the image. */ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the b frame from the stack mlt_frame b_frame = mlt_frame_pop_frame( a_frame ); // Get the transition from the a frame mlt_transition self = mlt_frame_pop_service( a_frame ); // Get in and out double position = mlt_deque_pop_back_double( MLT_FRAME_IMAGE_STACK( a_frame ) ); int out = mlt_frame_pop_service_int( a_frame ); int in = mlt_frame_pop_service_int( a_frame ); // Get the properties from the transition mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); // TODO: clean up always_active behaviour if ( mlt_properties_get_int( properties, "always_active" ) ) { mlt_events_block( properties, properties ); mlt_properties_set_int( properties, "in", in ); mlt_properties_set_int( properties, "out", out ); mlt_events_unblock( properties, properties ); } // This compositer is yuv422 only *format = mlt_image_yuv422; if ( b_frame != NULL ) { // Get the properties of the a frame mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); // Get the properties of the b frame mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); // Structures for geometry struct geometry_s result; // Calculate the position double delta = mlt_transition_get_progress_delta( self, a_frame ); mlt_position length = mlt_transition_get_length( self ); // Get the image from the b frame uint8_t *image_b = NULL; mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( self ) ); int width_b = *width > 0 ? *width : profile->width; int height_b = *height > 0 ? *height : profile->height; // Vars for alphas uint8_t *alpha_a = NULL; uint8_t *alpha_b = NULL; // Do the calculation // NB: Locks needed here since the properties are being modified int invert = mlt_properties_get_int( properties, "invert" ); mlt_service_lock( MLT_TRANSITION_SERVICE( self ) ); composite_calculate( self, &result, invert ? b_frame : a_frame, position ); mlt_service_unlock( MLT_TRANSITION_SERVICE( self ) ); // Manual option to deinterlace if ( mlt_properties_get_int( properties, "deinterlace" ) ) { mlt_properties_set_int( a_props, "consumer_deinterlace", 1 ); mlt_properties_set_int( b_props, "consumer_deinterlace", 1 ); } // TODO: Dangerous/temporary optimisation - if nothing to do, then do nothing if ( mlt_properties_get_int( properties, "no_alpha" ) && result.item.x == 0 && result.item.y == 0 && result.item.w == *width && result.item.h == *height && result.item.mix == 100 ) { mlt_frame_get_image( b_frame, image, format, width, height, 1 ); if ( !mlt_frame_is_test_card( a_frame ) ) mlt_frame_replace_image( a_frame, *image, *format, *width, *height ); return 0; } if ( a_frame == b_frame ) { double aspect_ratio = mlt_frame_get_aspect_ratio( b_frame ); get_b_frame_image( self, b_frame, &image_b, &width_b, &height_b, &result ); alpha_b = mlt_frame_get_alpha_mask( b_frame ); mlt_properties_set_double( a_props, "aspect_ratio", aspect_ratio ); } // Get the image from the a frame mlt_frame_get_image( a_frame, invert ? &image_b : image, format, width, height, 1 ); alpha_a = mlt_frame_get_alpha_mask( a_frame ); // Optimisation - no compositing required if ( result.item.mix == 0 || ( result.item.w == 0 && result.item.h == 0 ) ) return 0; // Need to keep the width/height of the a_frame on the b_frame for titling if ( mlt_properties_get( a_props, "dest_width" ) == NULL ) { mlt_properties_set_int( a_props, "dest_width", *width ); mlt_properties_set_int( a_props, "dest_height", *height ); mlt_properties_set_int( b_props, "dest_width", *width ); mlt_properties_set_int( b_props, "dest_height", *height ); } else { mlt_properties_set_int( b_props, "dest_width", mlt_properties_get_int( a_props, "dest_width" ) ); mlt_properties_set_int( b_props, "dest_height", mlt_properties_get_int( a_props, "dest_height" ) ); } // Special case for titling... if ( mlt_properties_get_int( properties, "titles" ) ) { if ( mlt_properties_get( b_props, "rescale.interp" ) == NULL ) mlt_properties_set( b_props, "rescale.interp", "hyper" ); width_b = mlt_properties_get_int( a_props, "dest_width" ); height_b = mlt_properties_get_int( a_props, "dest_height" ); } if ( *image != image_b && ( ( invert ? 0 : image_b ) || get_b_frame_image( self, b_frame, invert ? image : &image_b, &width_b, &height_b, &result ) == 0 ) ) { uint8_t *dest = *image; uint8_t *src = image_b; int progressive = mlt_properties_get_int( a_props, "consumer_deinterlace" ) || mlt_properties_get_int( properties, "progressive" ); int field; double luma_softness = mlt_properties_get_double( properties, "softness" ); mlt_service_lock( MLT_TRANSITION_SERVICE( self ) ); uint16_t *luma_bitmap = get_luma( self, properties, width_b, height_b ); mlt_service_unlock( MLT_TRANSITION_SERVICE( self ) ); char *operator = mlt_properties_get( properties, "operator" ); alpha_b = alpha_b == NULL ? mlt_frame_get_alpha_mask( b_frame ) : alpha_b; composite_line_fn line_fn = composite_line_yuv; // Replacement and override if ( operator != NULL ) { if ( !strcmp( operator, "or" ) ) line_fn = composite_line_yuv_or; if ( !strcmp( operator, "and" ) ) line_fn = composite_line_yuv_and; if ( !strcmp( operator, "xor" ) ) line_fn = composite_line_yuv_xor; } // Allow the user to completely obliterate the alpha channels from both frames if ( mlt_properties_get( properties, "alpha_a" ) ) memset( alpha_a, mlt_properties_get_int( properties, "alpha_a" ), *width * *height ); if ( mlt_properties_get( properties, "alpha_b" ) ) memset( alpha_b, mlt_properties_get_int( properties, "alpha_b" ), width_b * height_b ); for ( field = 0; field < ( progressive ? 1 : 2 ); field++ ) { // Assume lower field (0) first double field_position = position + field * delta * length; // Do the calculation if we need to // NB: Locks needed here since the properties are being modified mlt_service_lock( MLT_TRANSITION_SERVICE( self ) ); composite_calculate( self, &result, invert ? b_frame : a_frame, field_position ); mlt_service_unlock( MLT_TRANSITION_SERVICE( self ) ); if ( mlt_properties_get_int( properties, "titles" ) ) { result.item.w = rint( *width * ( result.item.w / result.nw ) ); result.nw = result.item.w; result.item.h = rint( *height * ( result.item.h / result.nh ) ); result.nh = *height; result.sw = width_b; result.sh = height_b; } // Enforce cropping if ( mlt_properties_get( properties, "crop" ) ) { if ( result.x_src == 0 ) width_b = width_b > result.item.w ? result.item.w : width_b; if ( result.y_src == 0 ) height_b = height_b > result.item.h ? result.item.h : height_b; } else { // Otherwise, align alignment_calculate( &result ); } // Composite the b_frame on the a_frame if ( invert ) composite_yuv( dest, width_b, height_b, src, *width, *height, alpha_a, alpha_b, result, progressive ? -1 : field, luma_bitmap, luma_softness, line_fn ); else composite_yuv( dest, *width, *height, src, width_b, height_b, alpha_b, alpha_a, result, progressive ? -1 : field, luma_bitmap, luma_softness, line_fn ); } } } else { mlt_frame_get_image( a_frame, image, format, width, height, 1 ); } return 0; } /** Composition transition processing. */ static mlt_frame composite_process( mlt_transition self, mlt_frame a_frame, mlt_frame b_frame ) { // UGH - this is a TODO - find a more reliable means of obtaining in/out for the always_active case if ( mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( self ), "always_active" ) == 0 ) { mlt_frame_push_service_int( a_frame, mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( self ), "in" ) ); mlt_frame_push_service_int( a_frame, mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( self ), "out" ) ); mlt_deque_push_back_double( MLT_FRAME_IMAGE_STACK( a_frame ), position_calculate( self, mlt_frame_get_position( a_frame ) ) ); } else { mlt_properties props = mlt_properties_get_data( MLT_FRAME_PROPERTIES( b_frame ), "_producer", NULL ); mlt_frame_push_service_int( a_frame, mlt_properties_get_int( props, "in" ) ); mlt_frame_push_service_int( a_frame, mlt_properties_get_int( props, "out" ) ); mlt_deque_push_back_double( MLT_FRAME_IMAGE_STACK( a_frame ), mlt_properties_get_int( props, "_frame" ) - mlt_properties_get_int( props, "in" ) ); } mlt_frame_push_service( a_frame, self ); mlt_frame_push_frame( a_frame, b_frame ); mlt_frame_push_get_image( a_frame, transition_get_image ); return a_frame; } /** Constructor for the filter. */ mlt_transition transition_composite_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_transition self = calloc( 1, sizeof( struct mlt_transition_s ) ); if ( self != NULL && mlt_transition_init( self, NULL ) == 0 ) { mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); self->process = composite_process; // Default starting motion and zoom mlt_properties_set( properties, "start", arg != NULL ? arg : "0/0:100%x100%" ); // Default factory mlt_properties_set( properties, "factory", mlt_environment( "MLT_PRODUCER" ) ); // Use alignment (and hence alpha of b frame) mlt_properties_set_int( properties, "aligned", 1 ); // Default to progressive rendering mlt_properties_set_int( properties, "progressive", 1 ); // Inform apps and framework that this is a video only transition mlt_properties_set_int( properties, "_transition_type", 1 ); } return self; } mlt-0.9.0/src/modules/core/transition_composite.h000066400000000000000000000027311215300731300221260ustar00rootroot00000000000000/* * transition_composite.h -- compose one image over another using alpha channel * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _TRANSITION_COMPOSITE_H_ #define _TRANSITION_COMPOSITE_H_ #include extern mlt_transition transition_composite_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); // Courtesy functionality - allows regionalised filtering extern mlt_frame composite_copy_region( mlt_transition, mlt_frame, mlt_position ); extern void composite_line_yuv( uint8_t *dest, uint8_t *src, int width, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int soft, uint32_t step ); #endif mlt-0.9.0/src/modules/core/transition_composite.yml000066400000000000000000000073151215300731300225030ustar00rootroot00000000000000schema_version: 0.1 type: transition identifier: composite title: Composite version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Video description: > A key-framable alpha-channel compositor for two frames. notes: > Performs dissolves and luma wipes in addition to alpha compositing. By default, the aspect ratio of the B frame is respected and the size portion of the geometry specification simply defines a bounding rectangle. This performs field-based rendering unless the A frame property "progressive" or "consumer_progressive" or the transition property "progressive" is set to 1. bugs: - Assumes lower field first during field rendering. parameters: - identifier: factory title: Factory type: string description: > The name of a factory service used as a non-PGM producer loader. default: loader - identifier: geometry title: Geometry type: geometry description: > Key frame specification. This is a ";" delimited form of the deprecated start, key[n], end properties. mutable: yes - identifier: progressive title: Progressive description: > Enable or disable field-based rendering. type: integer minimum: 0 maximum: 1 mutable: yes widget: checkbox - identifier: distort title: Allow distorted scaling description: > When set, causes the B frame image to fill the WxH completely with no regard to B's aspect ratio. type: integer default: 0 minimum: 0 maximum: 1 mutable: yes widget: checkbox - identifier: halign title: Horizontal alignment description: > When not distorting, set the horizontal alignment of B within the geometry rectangle. type: string default: left values: - left - centre - right mutable: yes widget: combo - identifier: valign title: Vertical alignment description: > When not distorting, set the vertical alignment of B within the geometry rectangle. type: string default: top values: - top - middle - bottom mutable: yes widget: combo - identifier: luma title: Luma map description: > The luma map file name. If not supplied, a dissolve. type: string default: unset mutable: yes widget: fileopen - identifier: softness title: Softness description: > Only when using a luma map, how soft to make the edges between A and B. type: float default: 0.0 minimum: 0.0 maximum: 1.0 mutable: yes - identifier: luma.* title: Luma producer description: > Properties may be set on the encapsulated producer. Any property starting with "luma." is passed to the non-PGM luma producer. readonly: no mutable: yes - identifier: start title: Start geometry description: > (deprecated) A geometry specification as X/Y:WxH[!][:mix] X, Y, W, H are assumed to pixel units unless they have the suffix '%'. '!' is a shortcut to specify distort. Mix is always a 2 digit percentage, defaults to 100. type: geometry default: "0%/0%:100%x100%" readonly: no mutable: yes - identifier: end title: End geometry description: > (deprecated) X/Y:WxH[:mix] - The end geometry specification (see "start"). type: geometry readonly: no mutable: yes - identifier: key[F] title: Key frame geometry description: > (deprecated) X/Y:WxH[:mix] - set a key frame for geometry between the in and out. F is a frame number and can be negative to make it relative to the out point. type: geometry readonly: no mutable: yes mlt-0.9.0/src/modules/core/transition_luma.c000066400000000000000000000370111215300731300210540ustar00rootroot00000000000000/* * transition_luma.c -- a generic dissolve/wipe processor * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * Adapted from Kino Plugin Timfx, which is * Copyright (C) 2002 Timothy M. Shead * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include "transition_composite.h" static inline int dissolve_yuv( mlt_frame this, mlt_frame that, float weight, int width, int height ) { int ret = 0; int i = height + 1; int width_src = width, height_src = height; mlt_image_format format = mlt_image_yuv422; uint8_t *p_src, *p_dest; uint8_t *alpha_src; uint8_t *alpha_dst; int mix = weight * ( 1 << 16 ); if ( mlt_properties_get( &this->parent, "distort" ) ) mlt_properties_set( &that->parent, "distort", mlt_properties_get( &this->parent, "distort" ) ); mlt_frame_get_image( this, &p_dest, &format, &width, &height, 1 ); alpha_dst = mlt_frame_get_alpha_mask( this ); mlt_frame_get_image( that, &p_src, &format, &width_src, &height_src, 0 ); alpha_src = mlt_frame_get_alpha_mask( that ); // Pick the lesser of two evils ;-) width_src = width_src > width ? width : width_src; height_src = height_src > height ? height : height_src; while ( --i ) { composite_line_yuv( p_dest, p_src, width_src, alpha_src, alpha_dst, mix, NULL, 0, 0 ); p_src += width_src << 1; p_dest += width << 1; alpha_src += width_src; alpha_dst += width; } return ret; } // image processing functions static inline int32_t smoothstep( int32_t edge1, int32_t edge2, uint32_t a ) { if ( a < edge1 ) return 0; if ( a >= edge2 ) return 0x10000; a = ( ( a - edge1 ) << 16 ) / ( edge2 - edge1 ); return ( ( ( a * a ) >> 16 ) * ( ( 3 << 16 ) - ( 2 * a ) ) ) >> 16; } /** powerful stuff \param field_order -1 = progressive, 0 = lower field first, 1 = top field first */ static void luma_composite( mlt_frame a_frame, mlt_frame b_frame, int luma_width, int luma_height, uint16_t *luma_bitmap, float pos, float frame_delta, float softness, int field_order, int *width, int *height ) { int width_src = *width, height_src = *height; int width_dest = *width, height_dest = *height; mlt_image_format format_src = mlt_image_yuv422, format_dest = mlt_image_yuv422; uint8_t *p_src, *p_dest; int i, j; int stride_src; int stride_dest; uint16_t weight = 0; if ( mlt_properties_get( &a_frame->parent, "distort" ) ) mlt_properties_set( &b_frame->parent, "distort", mlt_properties_get( &a_frame->parent, "distort" ) ); mlt_frame_get_image( a_frame, &p_dest, &format_dest, &width_dest, &height_dest, 1 ); mlt_frame_get_image( b_frame, &p_src, &format_src, &width_src, &height_src, 0 ); if ( *width == 0 || *height == 0 ) return; // Pick the lesser of two evils ;-) width_src = width_src > width_dest ? width_dest : width_src; height_src = height_src > height_dest ? height_dest : height_src; stride_src = width_src * 2; stride_dest = width_dest * 2; // Offset the position based on which field we're looking at ... int32_t field_pos[ 2 ]; field_pos[ 0 ] = ( pos + ( ( field_order == 0 ? 1 : 0 ) * frame_delta * 0.5 ) ) * ( 1 << 16 ) * ( 1.0 + softness ); field_pos[ 1 ] = ( pos + ( ( field_order == 0 ? 0 : 1 ) * frame_delta * 0.5 ) ) * ( 1 << 16 ) * ( 1.0 + softness ); register uint8_t *p; register uint8_t *q; register uint8_t *o; uint16_t *l; uint32_t value; int32_t x_diff = ( luma_width << 16 ) / *width; int32_t y_diff = ( luma_height << 16 ) / *height; int32_t x_offset = 0; int32_t y_offset = 0; uint8_t *p_row; uint8_t *q_row; int32_t i_softness = softness * ( 1 << 16 ); int field_count = field_order < 0 ? 1 : 2; int field_stride_src = field_count * stride_src; int field_stride_dest = field_count * stride_dest; int field = 0; // composite using luma map while ( field < field_count ) { p_row = p_src + field * stride_src; q_row = p_dest + field * stride_dest; y_offset = field << 16; i = field; while ( i < height_src ) { p = p_row; q = q_row; o = q; l = luma_bitmap + ( y_offset >> 16 ) * ( luma_width * field_count ); x_offset = 0; j = width_src; while( j -- ) { weight = l[ x_offset >> 16 ]; value = smoothstep( weight, i_softness + weight, field_pos[ field ] ); *o ++ = ( *p ++ * value + *q++ * ( ( 1 << 16 ) - value ) ) >> 16; *o ++ = ( *p ++ * value + *q++ * ( ( 1 << 16 ) - value ) ) >> 16; x_offset += x_diff; } y_offset += y_diff; i += field_count; p_row += field_stride_src; q_row += field_stride_dest; } field ++; } } /** Load the luma map from PGM stream. */ static void luma_read_pgm( FILE *f, uint16_t **map, int *width, int *height ) { uint8_t *data = NULL; while (1) { char line[128]; char comment[128]; int i = 2; int maxval; int bpp; uint16_t *p; line[127] = '\0'; // get the magic code if ( fgets( line, 127, f ) == NULL ) break; // skip comments while ( sscanf( line, " #%s", comment ) > 0 ) if ( fgets( line, 127, f ) == NULL ) break; if ( line[0] != 'P' || line[1] != '5' ) break; // skip white space and see if a new line must be fetched for ( i = 2; i < 127 && line[i] != '\0' && isspace( line[i] ); i++ ); if ( ( line[i] == '\0' || line[i] == '#' ) && fgets( line, 127, f ) == NULL ) break; // skip comments while ( sscanf( line, " #%s", comment ) > 0 ) if ( fgets( line, 127, f ) == NULL ) break; // get the dimensions if ( line[0] == 'P' ) i = sscanf( line, "P5 %d %d %d", width, height, &maxval ); else i = sscanf( line, "%d %d %d", width, height, &maxval ); // get the height value, if not yet if ( i < 2 ) { if ( fgets( line, 127, f ) == NULL ) break; // skip comments while ( sscanf( line, " #%s", comment ) > 0 ) if ( fgets( line, 127, f ) == NULL ) break; i = sscanf( line, "%d", height ); if ( i == 0 ) break; else i = 2; } // get the maximum gray value, if not yet if ( i < 3 ) { if ( fgets( line, 127, f ) == NULL ) break; // skip comments while ( sscanf( line, " #%s", comment ) > 0 ) if ( fgets( line, 127, f ) == NULL ) break; i = sscanf( line, "%d", &maxval ); if ( i == 0 ) break; } // determine if this is one or two bytes per pixel bpp = maxval > 255 ? 2 : 1; // allocate temporary storage for the raw data data = mlt_pool_alloc( *width * *height * bpp ); if ( data == NULL ) break; // read the raw data if ( fread( data, *width * *height * bpp, 1, f ) != 1 ) break; // allocate the luma bitmap *map = p = (uint16_t*)mlt_pool_alloc( *width * *height * sizeof( uint16_t ) ); if ( *map == NULL ) break; // proces the raw data into the luma bitmap for ( i = 0; i < *width * *height * bpp; i += bpp ) { if ( bpp == 1 ) *p++ = data[ i ] << 8; else *p++ = ( data[ i ] << 8 ) + data[ i+1 ]; } break; } if ( data != NULL ) mlt_pool_release( data ); } /** Generate a luma map from an RGB image. */ static void luma_read_yuv422( uint8_t *image, uint16_t **map, int width, int height ) { int i; int size = width * height * 2; // allocate the luma bitmap uint16_t *p = *map = ( uint16_t* )mlt_pool_alloc( width * height * sizeof( uint16_t ) ); if ( *map == NULL ) return; // proces the image data into the luma bitmap for ( i = 0; i < size; i += 2 ) *p++ = ( image[ i ] - 16 ) * 299; // 299 = 65535 / 219 } /** Get the image. */ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the b frame from the stack mlt_frame b_frame = mlt_frame_pop_frame( a_frame ); // Get the transition object mlt_transition transition = mlt_frame_pop_service( a_frame ); // Get the properties of the transition mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); // Get the properties of the a frame mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); // Get the properties of the b frame mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); // This compositer is yuv422 only *format = mlt_image_yuv422; mlt_service_lock( MLT_TRANSITION_SERVICE( transition ) ); // The cached luma map information int luma_width = mlt_properties_get_int( properties, "width" ); int luma_height = mlt_properties_get_int( properties, "height" ); uint16_t *luma_bitmap = mlt_properties_get_data( properties, "bitmap", NULL ); char *current_resource = mlt_properties_get( properties, "_resource" ); // If the filename property changed, reload the map char *resource = mlt_properties_get( properties, "resource" ); // Correct width/height if not specified if ( luma_width == 0 || luma_height == 0 ) { luma_width = *width; luma_height = *height; } if ( resource && ( !current_resource || strcmp( resource, current_resource ) ) ) { char temp[ 512 ]; char *extension = strrchr( resource, '.' ); char *orig_resource = resource; if ( strchr( resource, '%' ) ) { FILE *test; sprintf( temp, "%s/lumas/%s/%s", mlt_environment( "MLT_DATA" ), mlt_environment( "MLT_NORMALISATION" ), strchr( resource, '%' ) + 1 ); test = fopen( temp, "r" ); if ( test == NULL ) strcat( temp, ".png" ); else fclose( test ); resource = temp; extension = strrchr( resource, '.' ); } // See if it is a PGM if ( extension != NULL && strcmp( extension, ".pgm" ) == 0 ) { // Open PGM FILE *f = fopen( resource, "r" ); if ( f != NULL ) { // Load from PGM luma_read_pgm( f, &luma_bitmap, &luma_width, &luma_height ); fclose( f ); // Set the transition properties mlt_properties_set_int( properties, "width", luma_width ); mlt_properties_set_int( properties, "height", luma_height ); mlt_properties_set( properties, "_resource", orig_resource ); mlt_properties_set_data( properties, "bitmap", luma_bitmap, luma_width * luma_height * 2, mlt_pool_release, NULL ); } } else if (!*resource) { luma_bitmap = NULL; mlt_properties_set( properties, "_resource", NULL ); mlt_properties_set_data( properties, "bitmap", luma_bitmap, 0, mlt_pool_release, NULL ); } else { // Get the factory producer service char *factory = mlt_properties_get( properties, "factory" ); // Create the producer mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) ); mlt_producer producer = mlt_factory_producer( profile, factory, resource ); // If we have one if ( producer != NULL ) { // Get the producer properties mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); // Ensure that we loop mlt_properties_set( producer_properties, "eof", "loop" ); // Now pass all producer. properties on the transition down mlt_properties_pass( producer_properties, properties, "producer." ); // We will get the alpha frame from the producer mlt_frame luma_frame = NULL; // Get the luma frame if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &luma_frame, 0 ) == 0 ) { uint8_t *luma_image = NULL; mlt_image_format luma_format = mlt_image_yuv422; // Get image from the luma producer mlt_properties_set( MLT_FRAME_PROPERTIES( luma_frame ), "rescale.interp", "nearest" ); mlt_frame_get_image( luma_frame, &luma_image, &luma_format, &luma_width, &luma_height, 0 ); // Generate the luma map if ( luma_image != NULL ) luma_read_yuv422( luma_image, &luma_bitmap, luma_width, luma_height ); // Set the transition properties mlt_properties_set_int( properties, "width", luma_width ); mlt_properties_set_int( properties, "height", luma_height ); mlt_properties_set( properties, "_resource", orig_resource); mlt_properties_set_data( properties, "bitmap", luma_bitmap, luma_width * luma_height * 2, mlt_pool_release, NULL ); // Cleanup the luma frame mlt_frame_close( luma_frame ); } // Cleanup the luma producer mlt_producer_close( producer ); } } } // Arbitrary composite defaults float mix = mlt_transition_get_progress( transition, a_frame ); float frame_delta = mlt_transition_get_progress_delta( transition, a_frame ); float luma_softness = mlt_properties_get_double( properties, "softness" ); int progressive = mlt_properties_get_int( a_props, "consumer_deinterlace" ) || mlt_properties_get_int( properties, "progressive" ) || mlt_properties_get_int( b_props, "luma.progressive" ); int top_field_first = mlt_properties_get_int( b_props, "top_field_first" ); int reverse = mlt_properties_get_int( properties, "reverse" ); int invert = mlt_properties_get_int( properties, "invert" ); // Honour the reverse here if ( mix >= 1.0 ) mix -= floor( mix ); if ( mlt_properties_get( properties, "fixed" ) ) mix = mlt_properties_get_double( properties, "fixed" ); if ( luma_width > 0 && luma_height > 0 && luma_bitmap != NULL ) { reverse = invert ? !reverse : reverse; mix = reverse ? 1 - mix : mix; frame_delta *= reverse ? -1.0 : 1.0; // Composite the frames using a luma map luma_composite( !invert ? a_frame : b_frame, !invert ? b_frame : a_frame, luma_width, luma_height, luma_bitmap, mix, frame_delta, luma_softness, progressive ? -1 : top_field_first, width, height ); } else { mix = ( reverse || invert ) ? 1 - mix : mix; invert = 0; // Dissolve the frames using the time offset for mix value dissolve_yuv( a_frame, b_frame, mix, *width, *height ); } mlt_service_unlock( MLT_TRANSITION_SERVICE( transition ) ); // Extract the a_frame image info *width = mlt_properties_get_int( !invert ? a_props : b_props, "width" ); *height = mlt_properties_get_int( !invert ? a_props : b_props, "height" ); *image = mlt_properties_get_data( !invert ? a_props : b_props, "image", NULL ); return 0; } /** Luma transition processing. */ static mlt_frame transition_process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ) { // Push the transition on to the frame mlt_frame_push_service( a_frame, transition ); // Push the b_frame on to the stack mlt_frame_push_frame( a_frame, b_frame ); // Push the transition method mlt_frame_push_get_image( a_frame, transition_get_image ); return a_frame; } /** Constructor for the filter. */ mlt_transition transition_luma_init( mlt_profile profile, mlt_service_type type, const char *id, char *lumafile ) { mlt_transition transition = mlt_transition_new( ); if ( transition != NULL ) { // Set the methods transition->process = transition_process; // Default factory mlt_properties_set( MLT_TRANSITION_PROPERTIES( transition ), "factory", mlt_environment( "MLT_PRODUCER" ) ); // Set the main property mlt_properties_set( MLT_TRANSITION_PROPERTIES( transition ), "resource", lumafile ); // Inform apps and framework that this is a video only transition mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "_transition_type", 1 ); return transition; } return NULL; } mlt-0.9.0/src/modules/core/transition_luma.yml000066400000000000000000000034201215300731300214300ustar00rootroot00000000000000schema_version: 0.1 type: transition identifier: luma title: Wipe version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Video description: > A generic dissolve and wipe transition processor. "luma" gets its name from how it uses a grayscale "map" file. As the luma value varies over time, a threshold filter is applied to the map to determine what parts of frame A vs. frame B to show. It reads PGM files up to 16 bits! Alternatively, it can use the first frame from any producer that outputs yuv, but it will be limited to the luma gamut of 220 values. This performs field-based rendering unless the A frame property "progressive" or "consumer_progressive" or the transition property "progressive" is set to 1. bugs: - Assumes lower field first output. parameters: - identifier: argument title: Luma map file type: string description: > Either PGM or any other producable video. If not supplied, performs a dissolve. - identifier: factory title: Factory type: string description: > The name of a factory service used as a non-PGM producer loader. default: loader - identifier: softness title: Softness type: float mutable: yes description: > Only when using a luma map, how soft to make the edges between A and B. 0.0 = no softness. 1.0 = too soft. - identifier: reverse title: Reverse type: integer mutable: yes description: > Reverse the direction of the transition. default: 0 - identifier: producer.* title: Producer mutable: yes description: > Properties may be set on the encapsulated producer. Any property starting with "producer." is passed to the non-PGM luma producer. readonly: no mlt-0.9.0/src/modules/core/transition_mix.c000066400000000000000000000254701215300731300207210ustar00rootroot00000000000000/* * transition_mix.c -- mix two audio streams * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include static int mix_audio( mlt_frame this, mlt_frame that, float weight_start, float weight_end, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { int ret = 0; int16_t *src, *dest; int frequency_src = *frequency, frequency_dest = *frequency; int channels_src = *channels, channels_dest = *channels; int samples_src = *samples, samples_dest = *samples; int i, j; double d = 0, s = 0; mlt_frame_get_audio( that, (void**) &src, format, &frequency_src, &channels_src, &samples_src ); mlt_frame_get_audio( this, (void**) &dest, format, &frequency_dest, &channels_dest, &samples_dest ); int silent = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "silent_audio" ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "silent_audio", 0 ); if ( silent ) memset( dest, 0, samples_dest * channels_dest * sizeof( int16_t ) ); silent = mlt_properties_get_int( MLT_FRAME_PROPERTIES( that ), "silent_audio" ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( that ), "silent_audio", 0 ); if ( silent ) memset( src, 0, samples_src * channels_src * sizeof( int16_t ) ); if ( channels_src > 6 ) channels_src = 0; if ( channels_dest > 6 ) channels_dest = 0; if ( samples_src > 4000 ) samples_src = 0; if ( samples_dest > 4000 ) samples_dest = 0; // determine number of samples to process *samples = samples_src < samples_dest ? samples_src : samples_dest; *channels = channels_src < channels_dest ? channels_src : channels_dest; *buffer = dest; *frequency = frequency_dest; // Compute a smooth ramp over start to end float weight = weight_start; float weight_step = ( weight_end - weight_start ) / *samples; if ( src == dest ) { *samples = samples_src; *channels = channels_src; *buffer = src; *frequency = frequency_src; return ret; } // Mixdown for ( i = 0; i < *samples; i++ ) { for ( j = 0; j < *channels; j++ ) { if ( j < channels_dest ) d = (double) dest[ i * channels_dest + j ]; if ( j < channels_src ) s = (double) src[ i * channels_src + j ]; dest[ i * channels_dest + j ] = s * weight + d * ( 1.0 - weight ); } weight += weight_step; } return ret; } // Replacement for broken mlt_frame_audio_mix - this filter uses an inline low pass filter // to allow mixing without volume hacking static int combine_audio( mlt_frame this, mlt_frame that, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { int ret = 0; int16_t *src, *dest; int frequency_src = *frequency, frequency_dest = *frequency; int channels_src = *channels, channels_dest = *channels; int samples_src = *samples, samples_dest = *samples; int i, j; double vp[ 6 ]; double b_weight = 1.0; if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "meta.mixdown" ) ) b_weight = 1.0 - mlt_properties_get_double( MLT_FRAME_PROPERTIES( this ), "meta.volume" ); mlt_frame_get_audio( that, (void**) &src, format, &frequency_src, &channels_src, &samples_src ); mlt_frame_get_audio( this, (void**) &dest, format, &frequency_dest, &channels_dest, &samples_dest ); int silent = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "silent_audio" ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "silent_audio", 0 ); if ( silent ) memset( dest, 0, samples_dest * channels_dest * sizeof( int16_t ) ); silent = mlt_properties_get_int( MLT_FRAME_PROPERTIES( that ), "silent_audio" ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( that ), "silent_audio", 0 ); if ( silent ) memset( src, 0, samples_src * channels_src * sizeof( int16_t ) ); if ( src == dest ) { *samples = samples_src; *channels = channels_src; *buffer = src; *frequency = frequency_src; return ret; } // determine number of samples to process *samples = samples_src < samples_dest ? samples_src : samples_dest; *channels = channels_src < channels_dest ? channels_src : channels_dest; *buffer = dest; *frequency = frequency_dest; for ( j = 0; j < *channels; j++ ) vp[ j ] = ( double )dest[ j ]; double Fc = 0.5; double B = exp(-2.0 * M_PI * Fc); double A = 1.0 - B; double v; for ( i = 0; i < *samples; i++ ) { for ( j = 0; j < *channels; j++ ) { v = ( double )( b_weight * dest[ i * channels_dest + j ] + src[ i * channels_src + j ] ); v = v < -32767 ? -32767 : v > 32768 ? 32768 : v; vp[ j ] = dest[ i * channels_dest + j ] = ( int16_t )( v * A + vp[ j ] * B ); } } return ret; } /** Get the audio. */ static int transition_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the b frame from the stack mlt_frame b_frame = mlt_frame_pop_audio( frame ); // Get the effect mlt_transition effect = mlt_frame_pop_audio( frame ); // Get the properties of the b frame mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); // We can only mix s16 *format = mlt_audio_s16; if ( mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( effect ), "combine" ) == 0 ) { double mix_start = 0.5, mix_end = 0.5; if ( mlt_properties_get( b_props, "audio.previous_mix" ) != NULL ) mix_start = mlt_properties_get_double( b_props, "audio.previous_mix" ); if ( mlt_properties_get( b_props, "audio.mix" ) != NULL ) mix_end = mlt_properties_get_double( b_props, "audio.mix" ); if ( mlt_properties_get_int( b_props, "audio.reverse" ) ) { mix_start = 1 - mix_start; mix_end = 1 - mix_end; } mix_audio( frame, b_frame, mix_start, mix_end, buffer, format, frequency, channels, samples ); } else { combine_audio( frame, b_frame, buffer, format, frequency, channels, samples ); } return 0; } /** Mix transition processing. */ static mlt_frame transition_process( mlt_transition this, mlt_frame a_frame, mlt_frame b_frame ) { mlt_properties properties = MLT_TRANSITION_PROPERTIES( this ); mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); // Only if mix is specified, otherwise a producer may set the mix if ( mlt_properties_get( properties, "start" ) != NULL ) { // Determine the time position of this frame in the transition duration mlt_properties props = mlt_properties_get_data( MLT_FRAME_PROPERTIES( b_frame ), "_producer", NULL ); mlt_position in = mlt_properties_get_int( props, "in" ); mlt_position out = mlt_properties_get_int( props, "out" ); int length = mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( this ), "length" ); mlt_position time = mlt_properties_get_int( props, "_frame" ); double mix = mlt_transition_get_progress( this, b_frame ); if ( mlt_properties_get_int( properties, "always_active" ) ) mix = ( double ) ( time - in ) / ( double ) ( out - in + 1 ); // TODO: Check the logic here - shouldn't we be computing current and next mixing levels in all cases? if ( length == 0 ) { // If there is an end mix level adjust mix to the range if ( mlt_properties_get( properties, "end" ) != NULL ) { double start = mlt_properties_get_double( properties, "start" ); double end = mlt_properties_get_double( properties, "end" ); mix = start + ( end - start ) * mix; } // A negative means total crossfade (uses position) else if ( mlt_properties_get_double( properties, "start" ) >= 0 ) { // Otherwise, start/constructor is a constant mix level mix = mlt_properties_get_double( properties, "start" ); } // Finally, set the mix property on the frame mlt_properties_set_double( b_props, "audio.mix", mix ); // Initialise transition previous mix value to prevent an inadvertant jump from 0 mlt_position last_position = mlt_properties_get_position( properties, "_last_position" ); mlt_position current_position = mlt_frame_get_position( b_frame ); mlt_properties_set_position( properties, "_last_position", current_position ); if ( mlt_properties_get( properties, "_previous_mix" ) == NULL || current_position != last_position + 1 ) mlt_properties_set_double( properties, "_previous_mix", mix ); // Tell b frame what the previous mix level was mlt_properties_set_double( b_props, "audio.previous_mix", mlt_properties_get_double( properties, "_previous_mix" ) ); // Save the current mix level for the next iteration mlt_properties_set_double( properties, "_previous_mix", mlt_properties_get_double( b_props, "audio.mix" ) ); mlt_properties_set_double( b_props, "audio.reverse", mlt_properties_get_double( properties, "reverse" ) ); } else { double level = mlt_properties_get_double( properties, "start" ); double mix_start = level; double mix_end = mix_start; double mix_increment = 1.0 / length; if ( time - in < length ) { mix_start = mix_start * ( ( double )( time - in ) / length ); mix_end = mix_start + mix_increment; } else if ( time > out - length ) { mix_end = mix_start * ( ( double )( out - time - in ) / length ); mix_start = mix_end - mix_increment; } mix_start = mix_start < 0 ? 0 : mix_start > level ? level : mix_start; mix_end = mix_end < 0 ? 0 : mix_end > level ? level : mix_end; mlt_properties_set_double( b_props, "audio.previous_mix", mix_start ); mlt_properties_set_double( b_props, "audio.mix", mix_end ); } } // Override the get_audio method mlt_frame_push_audio( a_frame, this ); mlt_frame_push_audio( a_frame, b_frame ); mlt_frame_push_audio( a_frame, transition_get_audio ); return a_frame; } /** Constructor for the transition. */ mlt_transition transition_mix_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_transition this = calloc( 1, sizeof( struct mlt_transition_s ) ); if ( this != NULL && mlt_transition_init( this, NULL ) == 0 ) { this->process = transition_process; if ( arg != NULL ) mlt_properties_set_double( MLT_TRANSITION_PROPERTIES( this ), "start", atof( arg ) ); // Inform apps and framework that this is an audio only transition mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( this ), "_transition_type", 2 ); } return this; } mlt-0.9.0/src/modules/core/transition_mix.yml000066400000000000000000000016371215300731300212770ustar00rootroot00000000000000schema_version: 0.1 type: transition identifier: mix title: Mix version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Audio description: Mix two audio tracks. bugs: - Samples from the longer of the two frames are discarded. parameters: - identifier: start title: Start type: float mutable: yes description: > The mix level to apply to the second frame. Any negative value causes an automatic crossfade from 0 to 1. - identifier: end title: End type: float mutable: yes description: > The ending value of the mix level. Mix level will be interpolated from start to end over the in-out range. - identifier: reverse title: Reverse type: integer mutable: yes description: > Set to 1 to reverse the direction of the mix. default: 0 minimum: 0 maximum: 1 widget: checkbox mlt-0.9.0/src/modules/core/transition_region.c000066400000000000000000000332461215300731300214070ustar00rootroot00000000000000/* * transition_region.c -- region transition * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "transition_region.h" #include "transition_composite.h" #include #include #include #include static int create_instance( mlt_transition transition, char *name, char *value, int count ) { // Return from this function int error = 0; // Duplicate the value char *type = strdup( value ); // Pointer to filter argument char *arg = type == NULL ? NULL : strchr( type, ':' ); // New filter being created mlt_filter filter = NULL; // Cleanup type and arg if ( arg != NULL ) *arg ++ = '\0'; // Create the filter mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) ); if ( type ) filter = mlt_factory_filter( profile, type, arg ); // If we have a filter, then initialise and store it if ( filter != NULL ) { // Properties of transition mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); // String to hold the property name char id[ 256 ]; // String to hold the passdown key char key[ 256 ]; // Construct id sprintf( id, "_filter_%d", count ); // Counstruct key sprintf( key, "%s.", name ); // Just in case, let's assume that the filter here has a composite //mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "composite.geometry", "0%/0%:100%x100%" ); //mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "composite.fill", 1 ); // Pass all the key properties on the filter down mlt_properties_pass( MLT_FILTER_PROPERTIES( filter ), properties, key ); mlt_properties_pass_list( MLT_FILTER_PROPERTIES( filter ), properties, "in, out, length" ); // Ensure that filter is assigned mlt_properties_set_data( properties, id, filter, 0, ( mlt_destructor )mlt_filter_close, NULL ); } else { // Indicate that an error has occurred error = 1; } // Cleanup free( type ); // Return error condition return error; } static uint8_t *filter_get_alpha_mask( mlt_frame frame ) { uint8_t *alpha = NULL; // Obtain properties of frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Get the shape frame mlt_frame shape_frame = mlt_properties_get_data( properties, "shape_frame", NULL ); // Get the width and height of the image int region_width = mlt_properties_get_int( properties, "width" ); int region_height = mlt_properties_get_int( properties, "height" ); uint8_t *image = NULL; mlt_image_format format = mlt_image_yuv422; // Get the shape image to trigger alpha creation mlt_properties_set_int( MLT_FRAME_PROPERTIES( shape_frame ), "distort", 1 ); mlt_frame_get_image( shape_frame, &image, &format, ®ion_width, ®ion_height, 0 ); alpha = mlt_frame_get_alpha_mask( shape_frame ); int size = region_width * region_height; uint8_t *alpha_duplicate = mlt_pool_alloc( size ); // Generate from the Y component of the image if no alpha available if ( alpha == NULL ) { alpha = alpha_duplicate; while ( size -- ) { *alpha ++ = ( int )( ( ( *image ++ - 16 ) * 299 ) / 255 ); image ++; } } else { memcpy( alpha_duplicate, alpha, size ); } mlt_frame_set_alpha( frame, alpha_duplicate, region_width * region_height, mlt_pool_release ); return alpha_duplicate; } /** Do it :-). */ static int transition_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Error we will return int error = 0; // We will get the 'b frame' from the frame stack mlt_frame b_frame = mlt_frame_pop_frame( frame ); // Get the watermark transition object mlt_transition transition = mlt_frame_pop_service( frame ); // Get the properties of the transition mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); // Get the properties of the a frame mlt_properties a_props = MLT_FRAME_PROPERTIES( frame ); mlt_service_lock( MLT_TRANSITION_SERVICE( transition ) ); // Get the composite from the transition mlt_transition composite = mlt_properties_get_data( properties, "composite", NULL ); // Look for the first filter mlt_filter filter = mlt_properties_get_data( properties, "_filter_0", NULL ); // Get the position mlt_position position = mlt_transition_get_position( transition, frame ); // Create a composite if we don't have one if ( composite == NULL ) { // Create composite via the factory mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) ); composite = mlt_factory_transition( profile, "composite", NULL ); // If we have one if ( composite != NULL ) { // Get the properties mlt_properties composite_properties = MLT_TRANSITION_PROPERTIES( composite ); // We want to ensure that we don't get a wobble... //mlt_properties_set_int( composite_properties, "distort", 1 ); mlt_properties_set_int( composite_properties, "progressive", 1 ); // Pass all the composite. properties on the transition down mlt_properties_pass( composite_properties, properties, "composite." ); // Register the composite for reuse/destruction mlt_properties_set_data( properties, "composite", composite, 0, ( mlt_destructor )mlt_transition_close, NULL ); } } else { // Pass all current properties down mlt_properties composite_properties = MLT_TRANSITION_PROPERTIES( composite ); mlt_properties_pass( composite_properties, properties, "composite." ); } // Create filters if ( filter == NULL ) { // Loop Variable int i = 0; // Number of filters created int count = 0; // Loop for all properties for ( i = 0; i < mlt_properties_count( properties ); i ++ ) { // Get the name of this property char *name = mlt_properties_get_name( properties, i ); // If the name does not contain a . and matches filter if ( strchr( name, '.' ) == NULL && !strncmp( name, "filter", 6 ) ) { // Get the filter constructor char *value = mlt_properties_get_value( properties, i ); // Create an instance if ( create_instance( transition, name, value, count ) == 0 ) count ++; } } // Look for the first filter again filter = mlt_properties_get_data( properties, "_filter_0", NULL ); } else { // Pass all properties down mlt_filter temp = NULL; // Loop Variable int i = 0; // Number of filters found int count = 0; // Loop for all properties for ( i = 0; i < mlt_properties_count( properties ); i ++ ) { // Get the name of this property char *name = mlt_properties_get_name( properties, i ); // If the name does not contain a . and matches filter if ( strchr( name, '.' ) == NULL && !strncmp( name, "filter", 6 ) ) { // Strings to hold the id and pass down key char id[ 256 ]; char key[ 256 ]; // Construct id and key sprintf( id, "_filter_%d", count ); sprintf( key, "%s.", name ); // Get the filter temp = mlt_properties_get_data( properties, id, NULL ); if ( temp != NULL ) { mlt_properties_pass( MLT_FILTER_PROPERTIES( temp ), properties, key ); count ++; } } } } mlt_properties_set_int( a_props, "width", *width ); mlt_properties_set_int( a_props, "height", *height ); // Only continue if we have both filter and composite if ( composite != NULL ) { // Get the resource of this filter (could be a shape [rectangle/circle] or an alpha provider of choice const char *resource = mlt_properties_get( properties, "resource" ); // Get the old resource in case it's changed char *old_resource = mlt_properties_get( properties, "_old_resource" ); // String to hold the filter to query on char id[ 256 ]; // Index to hold the count int i = 0; // We will get the 'b frame' from the composite only if it's NULL (region filter) if ( b_frame == NULL ) { // Copy the region b_frame = composite_copy_region( composite, frame, position ); // Ensure a destructor char *name = mlt_properties_get( properties, "_unique_id" ); mlt_properties_set_data( a_props, name, b_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); } // Properties of the B frame mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); // filter_only prevents copying the alpha channel of the shape to the output frame // by compositing filtered frame over itself if ( mlt_properties_get_int( properties, "filter_only" ) ) { char *name = mlt_properties_get( properties, "_unique_id" ); frame = composite_copy_region( composite, b_frame, position ); mlt_properties_set_data( b_props, name, frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); } // Make sure the filter is in the correct position while ( filter != NULL ) { // Stack this filter if ( mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "off" ) == 0 ) mlt_filter_process( filter, b_frame ); // Generate the key for the next sprintf( id, "_filter_%d", ++ i ); // Get the next filter filter = mlt_properties_get_data( properties, id, NULL ); } // Allow filters to be attached to a region filter filter = mlt_properties_get_data( properties, "_region_filter", NULL ); if ( filter != NULL ) mlt_service_apply_filters( MLT_FILTER_SERVICE( filter ), b_frame, 0 ); // Hmm - this is probably going to go wrong.... mlt_frame_set_position( frame, position ); // Get the b frame and process with composite if successful mlt_transition_process( composite, frame, b_frame ); // If we have a shape producer copy the alpha mask from the shape frame to the b_frame if ( strcmp( resource, "rectangle" ) != 0 ) { // Get the producer from the transition mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL ); // If We have no producer then create one if ( producer == NULL || ( old_resource != NULL && strcmp( resource, old_resource ) ) ) { // Get the factory producer service char *factory = mlt_properties_get( properties, "factory" ); // Store the old resource mlt_properties_set( properties, "_old_resource", resource ); // Special case circle resource if ( strcmp( resource, "circle" ) == 0 ) resource = "pixbuf:"; // Create the producer mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) ); producer = mlt_factory_producer( profile, factory, resource ); // If we have one if ( producer != NULL ) { // Get the producer properties mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); // Ensure that we loop mlt_properties_set( producer_properties, "eof", "loop" ); // Now pass all producer. properties on the transition down mlt_properties_pass( producer_properties, properties, "producer." ); // Register the producer for reuse/destruction mlt_properties_set_data( properties, "producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); } } // Now use the shape producer if ( producer != NULL ) { // We will get the alpha frame from the producer mlt_frame shape_frame = NULL; // Make sure the producer is in the correct position mlt_producer_seek( producer, position ); // Get the shape frame if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &shape_frame, 0 ) == 0 ) { // Ensure that the shape frame will be closed mlt_properties_set_data( b_props, "shape_frame", shape_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); // Specify the callback for evaluation b_frame->get_alpha_mask = filter_get_alpha_mask; } } } // Get the image error = mlt_frame_get_image( frame, image, format, width, height, 0 ); } mlt_service_unlock( MLT_TRANSITION_SERVICE( transition ) ); return error; } /** Filter processing. */ static mlt_frame transition_process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ) { // Push the transition on to the frame mlt_frame_push_service( a_frame, transition ); // Push the b_frame on to the stack mlt_frame_push_frame( a_frame, b_frame ); // Push the transition method mlt_frame_push_get_image( a_frame, transition_get_image ); // Return the frame return a_frame; } /** Constructor for the transition. */ mlt_transition transition_region_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create a new transition mlt_transition transition = mlt_transition_new( ); // Further initialisation if ( transition != NULL ) { // Get the properties from the transition mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); // Assign the transition process method transition->process = transition_process; // Default factory mlt_properties_set( properties, "factory", mlt_environment( "MLT_PRODUCER" ) ); // Resource defines the shape of the region mlt_properties_set( properties, "resource", arg == NULL ? "rectangle" : arg ); // Inform apps and framework that this is a video only transition mlt_properties_set_int( properties, "_transition_type", 1 ); } // Return the transition return transition; } mlt-0.9.0/src/modules/core/transition_region.h000066400000000000000000000021461215300731300214070ustar00rootroot00000000000000/* * transition_region.h -- region transition * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _TRANSITION_REGION_H_ #define _TRANSITION_REGION_H_ #include extern mlt_transition transition_region_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); #endif mlt-0.9.0/src/modules/core/transition_region.yml000066400000000000000000000026011215300731300217550ustar00rootroot00000000000000schema_version: 0.1 type: transition identifier: region title: Regionalize version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video description: > Apply zero or more filters to B frame as it is composited onto a region of the A frame. The "shape" of the region can be defined by the alpha channel of a third producer. parameters: - identifier: argument title: Shape producer type: string description: > The default shape is a rectangle, "circle" is a pixbuf-generated SVG circle, anything else is loaded by the factory. - identifier: factory title: Factory type: string description: > The service that creates the shape producer. default: loader - identifier: filter[N] title: Filter type: string description: > One or more filters to apply. All filter properties are passed using the same filter "key". - identifier: composite.* title: Composite type: properties service-name: transition.composite description: > Properties may be set on the encapsulated composite transition. e.g.: composite.valign=c See "composite" transition for details. readonly: no - identifier: filter_only title: Use region for filtering only type: integer minimum: 0 maximum: 1 default: 0 widget: checkbox mlt-0.9.0/src/modules/decklink/000077500000000000000000000000001215300731300163325ustar00rootroot00000000000000mlt-0.9.0/src/modules/decklink/Makefile000077500000000000000000000021221215300731300177720ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lpthread include ../../../config.mak TARGET = ../libmltdecklink$(LIBSUF) OBJS = consumer_decklink.o \ producer_decklink.o \ common.o ifeq ($(targetos), MinGW) CFLAGS += -Iwin OBJS += win/DeckLinkAPI_i.o LDFLAGS += -lole32 else ifeq ($(targetos), Darwin) CFLAGS += -Idarwin OBJS += darwin/DeckLinkAPIDispatch.o else CFLAGS += -Ilinux OBJS += linux/DeckLinkAPIDispatch.o endif endif SRCS := $(OBJS:.o=.cpp) CXXFLAGS += $(CFLAGS) -Wno-deprecated -Wno-multichar -fno-rtti LDFLAGS += $(LIBDL) all: $(TARGET) $(TARGET): $(OBJS) $(CXX) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CXX) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/decklink" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/decklink" uninstall: rm "$(DESTDIR)$(moduledir)/libmltdecklink$(LIBSUF)" 2> /dev/null || true rm -rf "$(DESTDIR)$(mltdatadir)/decklink" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/decklink/common.cpp000066400000000000000000000040201215300731300203220ustar00rootroot00000000000000/* * common.cpp -- Blackmagic Design DeckLink common functions * Copyright (C) 2012 Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 consumer library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include #ifdef __DARWIN__ char* getCString( DLString aDLString ) { char* CString = (char*) malloc( 64 ); CFStringGetCString( aDLString, CString, 64, kCFStringEncodingMacRoman ); return CString; } void freeCString( char* aCString ) { if ( aCString ) free( aCString ); } void freeDLString( DLString aDLString ) { if ( aDLString ) CFRelease( aDLString ); } #elif defined(WIN32) char* getCString( DLString aDLString ) { char* CString = NULL; if ( aDLString ) { int size = WideCharToMultiByte( CP_UTF8, 0, aDLString, -1, NULL, 0, NULL, NULL ); if (size) { CString = new char[ size ]; size = WideCharToMultiByte( CP_UTF8, 0, aDLString, -1, CString, size, NULL, NULL ); if ( !size ) { delete[] CString; CString = NULL; } } } return CString; } void freeCString( char* aCString ) { delete[] aCString; } void freeDLString( DLString aDLString ) { if ( aDLString ) free( (void*) aDLString ); } #else char* getCString( DLString aDLString ) { return aDLString? (char*) aDLString : NULL; } void freeCString( char* aCString ) { } void freeDLString( DLString aDLString ) { if ( aDLString ) free( (void*) aDLString ); } #endif mlt-0.9.0/src/modules/decklink/common.h000066400000000000000000000025021215300731300177720ustar00rootroot00000000000000/* * common.h -- Blackmagic Design DeckLink common functions * Copyright (C) 2012 Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 consumer library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef DECKLINK_COMMON_H #define DECKLINK_COMMON_H #ifdef WIN32 # include # include "DeckLinkAPI_h.h" typedef BSTR DLString; #else # include "DeckLinkAPI.h" # ifdef __DARWIN__ typedef CFStringRef DLString; # else typedef const char* DLString; # endif #endif #define SAFE_RELEASE(V) if (V) { V->Release(); V = NULL; } char* getCString( DLString aDLString ); void freeCString( char* aCString ); void freeDLString( DLString aDLString ); #endif // DECKLINK_COMMON_H mlt-0.9.0/src/modules/decklink/consumer_decklink.cpp000066400000000000000000000524431215300731300225450ustar00rootroot00000000000000/* * consumer_decklink.c -- output through Blackmagic Design DeckLink * Copyright (C) 2010 Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 consumer library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define __STDC_FORMAT_MACROS /* see inttypes.h */ #include #include #include #include #include #include #include #include #include "common.h" static const unsigned PREROLL_MINIMUM = 3; class DeckLinkConsumer : public IDeckLinkVideoOutputCallback { private: mlt_consumer_s m_consumer; IDeckLink* m_deckLink; IDeckLinkOutput* m_deckLinkOutput; IDeckLinkDisplayMode* m_displayMode; int m_width; int m_height; BMDTimeValue m_duration; BMDTimeScale m_timescale; double m_fps; uint64_t m_count; int m_channels; unsigned m_dropped; IDeckLinkMutableVideoFrame* m_decklinkFrame; bool m_isAudio; int m_isKeyer; IDeckLinkKeyer* m_deckLinkKeyer; bool m_terminate_on_pause; uint32_t m_preroll; uint32_t m_acnt; bool m_reprio; pthread_t m_prerollThread; IDeckLinkDisplayMode* getDisplayMode() { mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( getConsumer() ) ); IDeckLinkDisplayModeIterator* iter = NULL; IDeckLinkDisplayMode* mode = NULL; IDeckLinkDisplayMode* result = 0; if ( m_deckLinkOutput->GetDisplayModeIterator( &iter ) == S_OK ) { while ( !result && iter->Next( &mode ) == S_OK ) { m_width = mode->GetWidth(); m_height = mode->GetHeight(); mode->GetFrameRate( &m_duration, &m_timescale ); m_fps = (double) m_timescale / m_duration; int p = mode->GetFieldDominance() == bmdProgressiveFrame; mlt_log_verbose( getConsumer(), "BMD mode %dx%d %.3f fps prog %d\n", m_width, m_height, m_fps, p ); if ( m_width == profile->width && p == profile->progressive && (int) m_fps == (int) mlt_profile_fps( profile ) && ( m_height == profile->height || ( m_height == 486 && profile->height == 480 ) ) ) result = mode; else SAFE_RELEASE( mode ); } SAFE_RELEASE( iter ); } return result; } public: mlt_consumer getConsumer() { return &m_consumer; } DeckLinkConsumer() { m_displayMode = NULL; m_deckLinkKeyer = NULL; m_deckLinkOutput = NULL; m_deckLink = NULL; m_decklinkFrame = NULL; } ~DeckLinkConsumer() { SAFE_RELEASE( m_displayMode ); SAFE_RELEASE( m_deckLinkKeyer ); SAFE_RELEASE( m_deckLinkOutput ); SAFE_RELEASE( m_deckLink ); } bool open( unsigned card = 0 ) { unsigned i = 0; #ifdef WIN32 IDeckLinkIterator* deckLinkIterator = NULL; HRESULT result = CoInitialize( NULL ); if ( FAILED( result ) ) { mlt_log_error( getConsumer(), "COM initialization failed\n" ); return false; } result = CoCreateInstance( CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**) &deckLinkIterator ); if ( FAILED( result ) ) { mlt_log_error( getConsumer(), "The DeckLink drivers not installed.\n" ); return false; } #else IDeckLinkIterator* deckLinkIterator = CreateDeckLinkIteratorInstance(); if ( !deckLinkIterator ) { mlt_log_error( getConsumer(), "The DeckLink drivers not installed.\n" ); return false; } #endif // Connect to the Nth DeckLink instance for ( i = 0; deckLinkIterator->Next( &m_deckLink ) == S_OK ; i++) { if( i == card ) break; else SAFE_RELEASE( m_deckLink ); } SAFE_RELEASE( deckLinkIterator ); if ( !m_deckLink ) { mlt_log_error( getConsumer(), "DeckLink card not found\n" ); return false; } // Obtain the audio/video output interface (IDeckLinkOutput) if ( m_deckLink->QueryInterface( IID_IDeckLinkOutput, (void**)&m_deckLinkOutput ) != S_OK ) { mlt_log_error( getConsumer(), "No DeckLink cards support output\n" ); SAFE_RELEASE( m_deckLink ); return false; } // Get the keyer interface IDeckLinkAttributes *deckLinkAttributes = 0; if ( m_deckLink->QueryInterface( IID_IDeckLinkAttributes, (void**) &deckLinkAttributes ) == S_OK ) { #ifdef WIN32 BOOL flag = FALSE; #else bool flag = false; #endif if ( deckLinkAttributes->GetFlag( BMDDeckLinkSupportsInternalKeying, &flag ) == S_OK && flag ) { if ( m_deckLink->QueryInterface( IID_IDeckLinkKeyer, (void**) &m_deckLinkKeyer ) != S_OK ) { mlt_log_error( getConsumer(), "Failed to get keyer\n" ); SAFE_RELEASE( m_deckLinkOutput ); SAFE_RELEASE( m_deckLink ); return false; } } SAFE_RELEASE( deckLinkAttributes ); } // Provide this class as a delegate to the audio and video output interfaces m_deckLinkOutput->SetScheduledFrameCompletionCallback( this ); return true; } void* preroll_thread() { mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() ); // preroll frames for ( unsigned i = 0; i < m_preroll && mlt_properties_get_int( properties, "running" ); i++ ) ScheduleNextFrame( true ); // start scheduled playback if ( mlt_properties_get_int( properties, "running" ) ) m_deckLinkOutput->StartScheduledPlayback( 0, m_timescale, 1.0 ); return 0; } static void* preroll_thread_proxy( void* arg ) { DeckLinkConsumer* self = static_cast< DeckLinkConsumer* >( arg ); return self->preroll_thread(); } bool start( unsigned preroll ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() ); // Initialize members m_count = 0; m_dropped = 0; m_decklinkFrame = NULL; preroll = preroll < PREROLL_MINIMUM ? PREROLL_MINIMUM : preroll; m_channels = mlt_properties_get_int( properties, "channels" ); m_isAudio = !mlt_properties_get_int( properties, "audio_off" ); m_terminate_on_pause = mlt_properties_get_int( properties, "terminate_on_pause" ); m_displayMode = getDisplayMode(); if ( !m_displayMode ) { mlt_log_error( getConsumer(), "Profile is not compatible with decklink.\n" ); return false; } // Set the keyer if ( m_deckLinkKeyer && ( m_isKeyer = mlt_properties_get_int( properties, "keyer" ) ) ) { bool external = ( m_isKeyer == 2 ); double level = mlt_properties_get_double( properties, "keyer_level" ); if ( m_deckLinkKeyer->Enable( external ) != S_OK ) mlt_log_error( getConsumer(), "Failed to enable %s keyer\n", external ? "external" : "internal" ); m_deckLinkKeyer->SetLevel( level <= 1 ? ( level > 0 ? 255 * level : 255 ) : 255 ); } else if ( m_deckLinkKeyer ) { m_deckLinkKeyer->Disable(); } // Set the video output mode if ( S_OK != m_deckLinkOutput->EnableVideoOutput( m_displayMode->GetDisplayMode(), bmdVideoOutputFlagDefault ) ) { mlt_log_error( getConsumer(), "Failed to enable video output\n" ); return false; } // Set the audio output mode if ( !m_isAudio ) { m_deckLinkOutput->DisableAudioOutput(); return true; } if ( S_OK != m_deckLinkOutput->EnableAudioOutput( bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, m_channels, bmdAudioOutputStreamTimestamped ) ) { mlt_log_error( getConsumer(), "Failed to enable audio output\n" ); stop(); return false; } m_preroll = preroll; m_reprio = false; // Set the running state mlt_properties_set_int( properties, "running", 1 ); // Do preroll in thread to ensure asynchronicity of mlt_consumer_start(). pthread_create( &m_prerollThread, NULL, preroll_thread_proxy, this ); return true; } bool stop() { mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() ); bool wasRunning = !!mlt_properties_get_int( properties, "running" ); // set running state is 0 mlt_properties_set_int( properties, "running", 0 ); if ( wasRunning ) pthread_join( m_prerollThread, NULL ); // Stop the audio and video output streams immediately if ( m_deckLinkOutput ) { m_deckLinkOutput->StopScheduledPlayback( 0, 0, 0 ); m_deckLinkOutput->DisableAudioOutput(); m_deckLinkOutput->DisableVideoOutput(); } // release decklink frame SAFE_RELEASE( m_decklinkFrame ); mlt_consumer_stopped( getConsumer() ); return true; } void renderAudio( mlt_frame frame ) { mlt_audio_format format = mlt_audio_s16; int frequency = bmdAudioSampleRate48kHz; int samples = mlt_sample_calculator( m_fps, frequency, m_count ); int16_t *pcm = 0; if ( !mlt_frame_get_audio( frame, (void**) &pcm, &format, &frequency, &m_channels, &samples ) ) { #ifdef WIN32 #define DECKLINK_UNSIGNED_FORMAT "%lu" unsigned long written = 0; #else #define DECKLINK_UNSIGNED_FORMAT "%u" uint32_t written = 0; #endif BMDTimeValue streamTime = m_count * frequency * m_duration / m_timescale; m_deckLinkOutput->GetBufferedAudioSampleFrameCount( &written ); if ( written > (m_preroll + 1) * samples ) { mlt_log_verbose( getConsumer(), "renderAudio: will flush " DECKLINK_UNSIGNED_FORMAT " audiosamples\n", written ); m_deckLinkOutput->FlushBufferedAudioSamples(); }; #ifdef WIN32 m_deckLinkOutput->ScheduleAudioSamples( pcm, samples, streamTime, frequency, (unsigned long*) &written ); #else m_deckLinkOutput->ScheduleAudioSamples( pcm, samples, streamTime, frequency, &written ); #endif if ( written != (uint32_t) samples ) mlt_log_verbose( getConsumer(), "renderAudio: samples=%d, written=" DECKLINK_UNSIGNED_FORMAT "\n", samples, written ); } } bool createFrame( IDeckLinkMutableVideoFrame** decklinkFrame ) { BMDPixelFormat format = m_isKeyer? bmdFormat8BitARGB : bmdFormat8BitYUV; IDeckLinkMutableVideoFrame* frame = 0; uint8_t *buffer = 0; int stride = m_width * ( m_isKeyer? 4 : 2 ); *decklinkFrame = NULL; // Generate a DeckLink video frame if ( S_OK != m_deckLinkOutput->CreateVideoFrame( m_width, m_height, stride, format, bmdFrameFlagDefault, &frame ) ) { mlt_log_verbose( getConsumer(), "Failed to create video frame\n" ); stop(); return false; } // Make the first line black for field order correction. if ( S_OK == frame->GetBytes( (void**) &buffer ) && buffer ) { if ( m_isKeyer ) { memset( buffer, 0, stride ); } else for ( int i = 0; i < m_width; i++ ) { *buffer++ = 128; *buffer++ = 16; } } *decklinkFrame = frame; return true; } void renderVideo( mlt_frame frame ) { mlt_image_format format = m_isKeyer? mlt_image_rgb24a : mlt_image_yuv422; uint8_t* image = 0; int rendered = mlt_properties_get_int( MLT_FRAME_PROPERTIES(frame), "rendered"); int height = m_height; if ( rendered && !mlt_frame_get_image( frame, &image, &format, &m_width, &height, 0 ) ) { uint8_t* buffer = 0; int stride = m_width * ( m_isKeyer? 4 : 2 ); SAFE_RELEASE( m_decklinkFrame ); if ( createFrame( &m_decklinkFrame ) ) m_decklinkFrame->GetBytes( (void**) &buffer ); if ( buffer ) { int progressive = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "progressive" ); // NTSC SDI is always 486 lines if ( m_height == 486 && height == 480 ) { // blank first 6 lines if ( m_isKeyer ) { memset( buffer, 0, stride * 6 ); buffer += stride * 6; } else for ( int i = 0; i < m_width * 6; i++ ) { *buffer++ = 128; *buffer++ = 16; } } if ( !m_isKeyer ) { // Normal non-keyer playout - needs byte swapping if ( !progressive && m_displayMode->GetFieldDominance() == bmdUpperFieldFirst ) // convert lower field first to top field first swab( (char*) image, (char*) buffer + stride, stride * ( height - 1 ) ); else swab( (char*) image, (char*) buffer, stride * height ); } else if ( !mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "test_image" ) ) { // Normal keyer output int y = height + 1; uint32_t* s = (uint32_t*) image; uint32_t* d = (uint32_t*) buffer; if ( !progressive && m_displayMode->GetFieldDominance() == bmdUpperFieldFirst ) { // Correct field order height--; y--; d += m_width; } // Need to relocate alpha channel RGBA => ARGB while ( --y ) { int x = m_width + 1; while ( --x ) { *d++ = ( *s << 8 ) | ( *s >> 24 ); s++; } } } else { // Keying blank frames - nullify alpha memset( buffer, 0, stride * height ); } } } if ( m_decklinkFrame ) m_deckLinkOutput->ScheduleVideoFrame( m_decklinkFrame, m_count * m_duration, m_duration, m_timescale ); if ( !rendered ) mlt_log_verbose( getConsumer(), "dropped video frame %u\n", ++m_dropped ); } HRESULT render( mlt_frame frame ) { HRESULT result = S_OK; // Get the audio double speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame), "_speed" ); if ( m_isAudio && speed == 1.0 ) renderAudio( frame ); // Get the video renderVideo( frame ); ++m_count; return result; } // *** DeckLink API implementation of IDeckLinkVideoOutputCallback IDeckLinkAudioOutputCallback *** // // IUnknown needs only a dummy implementation virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, LPVOID *ppv ) { return E_NOINTERFACE; } virtual ULONG STDMETHODCALLTYPE AddRef() { return 1; } virtual ULONG STDMETHODCALLTYPE Release() { return 1; } /************************* DeckLink API Delegate Methods *****************************/ virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted( IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult completed ) { if( !m_reprio ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() ); if ( mlt_properties_get( properties, "priority" ) ) { int r; pthread_t thread; pthread_attr_t tattr; struct sched_param param; pthread_attr_init(&tattr); pthread_attr_setschedpolicy(&tattr, SCHED_FIFO); if ( !strcmp( "max", mlt_properties_get( properties, "priority" ) ) ) param.sched_priority = sched_get_priority_max(SCHED_FIFO) - 1; else if ( !strcmp( "min", mlt_properties_get( properties, "priority" ) ) ) param.sched_priority = sched_get_priority_min(SCHED_FIFO) + 1; else param.sched_priority = mlt_properties_get_int( properties, "priority" ); pthread_attr_setschedparam(&tattr, ¶m); thread = pthread_self(); r = pthread_setschedparam(thread, SCHED_FIFO, ¶m); if( r ) mlt_log_verbose( getConsumer(), "ScheduledFrameCompleted: pthread_setschedparam returned %d\n", r); else mlt_log_verbose( getConsumer(), "ScheduledFrameCompleted: param.sched_priority=%d\n", param.sched_priority); }; m_reprio = true; }; #ifdef WIN32 unsigned long cnt; #else uint32_t cnt; #endif m_deckLinkOutput->GetBufferedAudioSampleFrameCount( &cnt ); if ( cnt != m_acnt ) { mlt_log_debug( getConsumer(), "ScheduledFrameCompleted: GetBufferedAudioSampleFrameCount %u -> " DECKLINK_UNSIGNED_FORMAT ", m_count=%"PRIu64"\n", m_acnt, cnt, m_count ); m_acnt = cnt; } // When a video frame has been released by the API, schedule another video frame to be output // ignore handler if frame was flushed if ( bmdOutputFrameFlushed == completed ) return S_OK; // schedule next frame ScheduleNextFrame( false ); // step forward frames counter if underrun if ( bmdOutputFrameDisplayedLate == completed ) { mlt_log_verbose( getConsumer(), "ScheduledFrameCompleted: bmdOutputFrameDisplayedLate == completed\n" ); m_count++; } if ( bmdOutputFrameDropped == completed ) { mlt_log_verbose( getConsumer(), "ScheduledFrameCompleted: bmdOutputFrameDropped == completed\n" ); m_count++; } return S_OK; } virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped() { return mlt_consumer_is_stopped( getConsumer() ) ? S_FALSE : S_OK; } void ScheduleNextFrame( bool preroll ) { // get the consumer mlt_consumer consumer = getConsumer(); // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Frame and size mlt_frame frame = NULL; if( mlt_properties_get_int( properties, "running" ) || preroll ) { frame = mlt_consumer_rt_frame( consumer ); if ( frame != NULL ) { render( frame ); mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); // terminate on pause if ( m_terminate_on_pause && mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0 ) stop(); mlt_frame_close( frame ); } } } }; /** Start the consumer. */ static int start( mlt_consumer consumer ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); DeckLinkConsumer* decklink = (DeckLinkConsumer*) consumer->child; return decklink->start( mlt_properties_get_int( properties, "preroll" ) ) ? 0 : 1; } /** Stop the consumer. */ static int stop( mlt_consumer consumer ) { // Get the properties DeckLinkConsumer* decklink = (DeckLinkConsumer*) consumer->child; return decklink->stop(); } /** Determine if the consumer is stopped. */ static int is_stopped( mlt_consumer consumer ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); return !mlt_properties_get_int( properties, "running" ); } /** Close the consumer. */ static void close( mlt_consumer consumer ) { // Stop the consumer mlt_consumer_stop( consumer ); // Close the parent consumer->close = NULL; mlt_consumer_close( consumer ); // Free the memory delete (DeckLinkConsumer*) consumer->child; } extern "C" { // Listen for the list_devices property to be set static void on_property_changed( void*, mlt_properties properties, const char *name ) { IDeckLinkIterator* decklinkIterator = NULL; IDeckLink* decklink = NULL; IDeckLinkInput* decklinkOutput = NULL; int i = 0; if ( name && !strcmp( name, "list_devices" ) ) mlt_event_block( (mlt_event) mlt_properties_get_data( properties, "list-devices-event", NULL ) ); else return; #ifdef WIN32 if ( FAILED( CoInitialize( NULL ) ) ) return; if ( FAILED( CoCreateInstance( CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**) &decklinkIterator ) ) ) return; #else if ( !( decklinkIterator = CreateDeckLinkIteratorInstance() ) ) return; #endif for ( ; decklinkIterator->Next( &decklink ) == S_OK; i++ ) { if ( decklink->QueryInterface( IID_IDeckLinkOutput, (void**) &decklinkOutput ) == S_OK ) { DLString name = NULL; if ( decklink->GetModelName( &name ) == S_OK ) { char *name_cstr = getCString( name ); const char *format = "device.%d"; char *key = (char*) calloc( 1, strlen( format ) + 1 ); sprintf( key, format, i ); mlt_properties_set( properties, key, name_cstr ); free( key ); freeDLString( name ); freeCString( name_cstr ); } SAFE_RELEASE( decklinkOutput ); } SAFE_RELEASE( decklink ); } SAFE_RELEASE( decklinkIterator ); mlt_properties_set_int( properties, "devices", i ); } /** Initialise the consumer. */ mlt_consumer consumer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Allocate the consumer DeckLinkConsumer* decklink = new DeckLinkConsumer(); mlt_consumer consumer = NULL; // If allocated if ( decklink && !mlt_consumer_init( decklink->getConsumer(), decklink, profile ) ) { // If initialises without error if ( decklink->open( arg? atoi(arg) : 0 ) ) { consumer = decklink->getConsumer(); mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Setup callbacks consumer->close = close; consumer->start = start; consumer->stop = stop; consumer->is_stopped = is_stopped; mlt_properties_set( properties, "deinterlace_method", "onefield" ); mlt_event event = mlt_events_listen( properties, properties, "property-changed", (mlt_listener) on_property_changed ); mlt_properties_set_data( properties, "list-devices-event", event, 0, NULL, NULL ); } } // Return consumer return consumer; } extern mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; const char *service_type = NULL; switch ( type ) { case consumer_type: service_type = "consumer"; break; case producer_type: service_type = "producer"; break; default: return NULL; } snprintf( file, PATH_MAX, "%s/decklink/%s_%s.yml", mlt_environment( "MLT_DATA" ), service_type, id ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( consumer_type, "decklink", consumer_decklink_init ); MLT_REGISTER( producer_type, "decklink", producer_decklink_init ); MLT_REGISTER_METADATA( consumer_type, "decklink", metadata, NULL ); MLT_REGISTER_METADATA( producer_type, "decklink", metadata, NULL ); } } // extern C mlt-0.9.0/src/modules/decklink/consumer_decklink.yml000066400000000000000000000051721215300731300225610ustar00rootroot00000000000000schema_version: 0.1 type: consumer identifier: decklink title: Blackmagic Design DeckLink Output version: 2 copyright: Copyright (C) 2011 Daniel R. Dennedy license: LGPL language: en creator: Dan Dennedy tags: - Audio - Video description: > Output audio and video using Blackmagic Design DeckLink SDI or Intensity HDMI cards. notes: > Please ensure that you use a MLT profile that is compatible with a broadcast standard which the card you are using supports. bugs: - Only internal keying is supported at this time. - Only 8-bit Y'CbCr or RGBA (key) is supported at this time. parameters: - identifier: argument title: Card type: integer readonly: no required: no mutable: no default: 0 minimum: 0 widget: spinner - identifier: preroll title: Pre-roll Count type: integer description: > This controls the amount of buffering in the DeckLink driver/library. Increase this if you get video tearing or choppy audio. However, as you increase the amount, you increase the risk of audio and video becoming out of synchronization. readonly: no required: no mutable: no default: 3 minimum: 2 unit: frames widget: spinner - identifier: keyer title: Enable Keyer type: integer description: > Keying is the process of compositing MLT output over a live SDI input. The alpha channel of the MLT video controls the transparent areas, and the keyer supports alpha-blending. You can not control the compositing rectangle. Rather, the entire MLT output overlays the entire video input. Therefore, you must use MLT's compositing services to control the size and position. The value 1 enables the internal keyer, the value 2 enables the external keyer, and the value 0 disables it. readonly: no required: no mutable: no default: 0 minimum: 0 maximum: 2 - identifier: keyer_level title: Key Opacity type: float description: > This controls the level of blending between the key and the input video. 1 is fully opaque and something near 0 is transparent. However, absolute 0 is considered as "not supplied" and also fully opaque. 0.5 is an evenly balanced blending of the key and input video. readonly: no required: no mutable: no minimum: 0 maximum: 1 default: 1 widget: slider - identifier: devices title: Number of devices type: integer readonly: yes minimum: 0 - identifier: device.* title: Device model description: The model name of each device that provides output. type: string readonly: yes mlt-0.9.0/src/modules/decklink/darwin/000077500000000000000000000000001215300731300176165ustar00rootroot00000000000000mlt-0.9.0/src/modules/decklink/darwin/DeckLinkAPI.h000077500000000000000000001462501215300731300220200ustar00rootroot00000000000000/* -LICENSE-START- ** Copyright (c) 2011 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by ** this license (the "Software") to use, reproduce, display, distribute, ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: ** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. ** ** 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT ** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE ** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ** DEALINGS IN THE SOFTWARE. ** -LICENSE-END- */ /* DeckLinkAPI.h */ #ifndef __DeckLink_API_h__ #define __DeckLink_API_h__ #include #include #include #define BLACKMAGIC_DECKLINK_API_MAGIC 1 // Type Declarations typedef int64_t BMDTimeValue; typedef int64_t BMDTimeScale; typedef uint32_t BMDTimecodeBCD; typedef uint32_t BMDTimecodeUserBits; // Interface ID Declarations #define IID_IDeckLinkVideoOutputCallback /* 20AA5225-1958-47CB-820B-80A8D521A6EE */ (REFIID){0x20,0xAA,0x52,0x25,0x19,0x58,0x47,0xCB,0x82,0x0B,0x80,0xA8,0xD5,0x21,0xA6,0xEE} #define IID_IDeckLinkInputCallback /* DD04E5EC-7415-42AB-AE4A-E80C4DFC044A */ (REFIID){0xDD,0x04,0xE5,0xEC,0x74,0x15,0x42,0xAB,0xAE,0x4A,0xE8,0x0C,0x4D,0xFC,0x04,0x4A} #define IID_IDeckLinkMemoryAllocator /* B36EB6E7-9D29-4AA8-92EF-843B87A289E8 */ (REFIID){0xB3,0x6E,0xB6,0xE7,0x9D,0x29,0x4A,0xA8,0x92,0xEF,0x84,0x3B,0x87,0xA2,0x89,0xE8} #define IID_IDeckLinkAudioOutputCallback /* 403C681B-7F46-4A12-B993-2BB127084EE6 */ (REFIID){0x40,0x3C,0x68,0x1B,0x7F,0x46,0x4A,0x12,0xB9,0x93,0x2B,0xB1,0x27,0x08,0x4E,0xE6} #define IID_IDeckLinkIterator /* 74E936FC-CC28-4A67-81A0-1E94E52D4E69 */ (REFIID){0x74,0xE9,0x36,0xFC,0xCC,0x28,0x4A,0x67,0x81,0xA0,0x1E,0x94,0xE5,0x2D,0x4E,0x69} #define IID_IDeckLinkAPIInformation /* 7BEA3C68-730D-4322-AF34-8A7152B532A4 */ (REFIID){0x7B,0xEA,0x3C,0x68,0x73,0x0D,0x43,0x22,0xAF,0x34,0x8A,0x71,0x52,0xB5,0x32,0xA4} #define IID_IDeckLinkDisplayModeIterator /* 9C88499F-F601-4021-B80B-032E4EB41C35 */ (REFIID){0x9C,0x88,0x49,0x9F,0xF6,0x01,0x40,0x21,0xB8,0x0B,0x03,0x2E,0x4E,0xB4,0x1C,0x35} #define IID_IDeckLinkDisplayMode /* 3EB2C1AB-0A3D-4523-A3AD-F40D7FB14E78 */ (REFIID){0x3E,0xB2,0xC1,0xAB,0x0A,0x3D,0x45,0x23,0xA3,0xAD,0xF4,0x0D,0x7F,0xB1,0x4E,0x78} #define IID_IDeckLink /* 62BFF75D-6569-4E55-8D4D-66AA03829ABC */ (REFIID){0x62,0xBF,0xF7,0x5D,0x65,0x69,0x4E,0x55,0x8D,0x4D,0x66,0xAA,0x03,0x82,0x9A,0xBC} #define IID_IDeckLinkOutput /* A3EF0963-0862-44ED-92A9-EE89ABF431C7 */ (REFIID){0xA3,0xEF,0x09,0x63,0x08,0x62,0x44,0xED,0x92,0xA9,0xEE,0x89,0xAB,0xF4,0x31,0xC7} #define IID_IDeckLinkInput /* 6D40EF78-28B9-4E21-990D-95BB7750A04F */ (REFIID){0x6D,0x40,0xEF,0x78,0x28,0xB9,0x4E,0x21,0x99,0x0D,0x95,0xBB,0x77,0x50,0xA0,0x4F} #define IID_IDeckLinkTimecode /* BC6CFBD3-8317-4325-AC1C-1216391E9340 */ (REFIID){0xBC,0x6C,0xFB,0xD3,0x83,0x17,0x43,0x25,0xAC,0x1C,0x12,0x16,0x39,0x1E,0x93,0x40} #define IID_IDeckLinkVideoFrame /* 3F716FE0-F023-4111-BE5D-EF4414C05B17 */ (REFIID){0x3F,0x71,0x6F,0xE0,0xF0,0x23,0x41,0x11,0xBE,0x5D,0xEF,0x44,0x14,0xC0,0x5B,0x17} #define IID_IDeckLinkMutableVideoFrame /* 69E2639F-40DA-4E19-B6F2-20ACE815C390 */ (REFIID){0x69,0xE2,0x63,0x9F,0x40,0xDA,0x4E,0x19,0xB6,0xF2,0x20,0xAC,0xE8,0x15,0xC3,0x90} #define IID_IDeckLinkVideoFrame3DExtensions /* DA0F7E4A-EDC7-48A8-9CDD-2DB51C729CD7 */ (REFIID){0xDA,0x0F,0x7E,0x4A,0xED,0xC7,0x48,0xA8,0x9C,0xDD,0x2D,0xB5,0x1C,0x72,0x9C,0xD7} #define IID_IDeckLinkVideoInputFrame /* 05CFE374-537C-4094-9A57-680525118F44 */ (REFIID){0x05,0xCF,0xE3,0x74,0x53,0x7C,0x40,0x94,0x9A,0x57,0x68,0x05,0x25,0x11,0x8F,0x44} #define IID_IDeckLinkVideoFrameAncillary /* 732E723C-D1A4-4E29-9E8E-4A88797A0004 */ (REFIID){0x73,0x2E,0x72,0x3C,0xD1,0xA4,0x4E,0x29,0x9E,0x8E,0x4A,0x88,0x79,0x7A,0x00,0x04} #define IID_IDeckLinkAudioInputPacket /* E43D5870-2894-11DE-8C30-0800200C9A66 */ (REFIID){0xE4,0x3D,0x58,0x70,0x28,0x94,0x11,0xDE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66} #define IID_IDeckLinkScreenPreviewCallback /* B1D3F49A-85FE-4C5D-95C8-0B5D5DCCD438 */ (REFIID){0xB1,0xD3,0xF4,0x9A,0x85,0xFE,0x4C,0x5D,0x95,0xC8,0x0B,0x5D,0x5D,0xCC,0xD4,0x38} #define IID_IDeckLinkCocoaScreenPreviewCallback /* D174152F-8F96-4C07-83A5-DD5F5AF0A2AA */ (REFIID){0xD1,0x74,0x15,0x2F,0x8F,0x96,0x4C,0x07,0x83,0xA5,0xDD,0x5F,0x5A,0xF0,0xA2,0xAA} #define IID_IDeckLinkGLScreenPreviewHelper /* 504E2209-CAC7-4C1A-9FB4-C5BB6274D22F */ (REFIID){0x50,0x4E,0x22,0x09,0xCA,0xC7,0x4C,0x1A,0x9F,0xB4,0xC5,0xBB,0x62,0x74,0xD2,0x2F} #define IID_IDeckLinkConfiguration /* C679A35B-610C-4D09-B748-1D0478100FC0 */ (REFIID){0xC6,0x79,0xA3,0x5B,0x61,0x0C,0x4D,0x09,0xB7,0x48,0x1D,0x04,0x78,0x10,0x0F,0xC0} #define IID_IDeckLinkAttributes /* ABC11843-D966-44CB-96E2-A1CB5D3135C4 */ (REFIID){0xAB,0xC1,0x18,0x43,0xD9,0x66,0x44,0xCB,0x96,0xE2,0xA1,0xCB,0x5D,0x31,0x35,0xC4} #define IID_IDeckLinkKeyer /* 89AFCAF5-65F8-421E-98F7-96FE5F5BFBA3 */ (REFIID){0x89,0xAF,0xCA,0xF5,0x65,0xF8,0x42,0x1E,0x98,0xF7,0x96,0xFE,0x5F,0x5B,0xFB,0xA3} #define IID_IDeckLinkVideoConversion /* 3BBCB8A2-DA2C-42D9-B5D8-88083644E99A */ (REFIID){0x3B,0xBC,0xB8,0xA2,0xDA,0x2C,0x42,0xD9,0xB5,0xD8,0x88,0x08,0x36,0x44,0xE9,0x9A} #define IID_IDeckLinkDeckControlStatusCallback /* E5F693C1-4283-4716-B18F-C1431521955B */ (REFIID){0xE5,0xF6,0x93,0xC1,0x42,0x83,0x47,0x16,0xB1,0x8F,0xC1,0x43,0x15,0x21,0x95,0x5B} #define IID_IDeckLinkDeckControl /* 522A9E39-0F3C-4742-94EE-D80DE335DA1D */ (REFIID){0x52,0x2A,0x9E,0x39,0x0F,0x3C,0x47,0x42,0x94,0xEE,0xD8,0x0D,0xE3,0x35,0xDA,0x1D} /* Enum BMDDisplayMode - Video display modes */ typedef uint32_t BMDDisplayMode; enum _BMDDisplayMode { /* SD Modes */ bmdModeNTSC = 'ntsc', bmdModeNTSC2398 = 'nt23', // 3:2 pulldown bmdModePAL = 'pal ', bmdModeNTSCp = 'ntsp', bmdModePALp = 'palp', /* HD 1080 Modes */ bmdModeHD1080p2398 = '23ps', bmdModeHD1080p24 = '24ps', bmdModeHD1080p25 = 'Hp25', bmdModeHD1080p2997 = 'Hp29', bmdModeHD1080p30 = 'Hp30', bmdModeHD1080i50 = 'Hi50', bmdModeHD1080i5994 = 'Hi59', bmdModeHD1080i6000 = 'Hi60', // N.B. This _really_ is 60.00 Hz. bmdModeHD1080p50 = 'Hp50', bmdModeHD1080p5994 = 'Hp59', bmdModeHD1080p6000 = 'Hp60', // N.B. This _really_ is 60.00 Hz. /* HD 720 Modes */ bmdModeHD720p50 = 'hp50', bmdModeHD720p5994 = 'hp59', bmdModeHD720p60 = 'hp60', /* 2k Modes */ bmdMode2k2398 = '2k23', bmdMode2k24 = '2k24', bmdMode2k25 = '2k25' }; /* Enum BMDFieldDominance - Video field dominance */ typedef uint32_t BMDFieldDominance; enum _BMDFieldDominance { bmdUnknownFieldDominance = 0, bmdLowerFieldFirst = 'lowr', bmdUpperFieldFirst = 'uppr', bmdProgressiveFrame = 'prog', bmdProgressiveSegmentedFrame = 'psf ' }; /* Enum BMDPixelFormat - Video pixel formats supported for output/input */ typedef uint32_t BMDPixelFormat; enum _BMDPixelFormat { bmdFormat8BitYUV = '2vuy', bmdFormat10BitYUV = 'v210', bmdFormat8BitARGB = 32, bmdFormat8BitBGRA = 'BGRA', bmdFormat10BitRGB = 'r210' // Big-endian RGB 10-bit per component with SMPTE video levels (64-960). Packed as 2:10:10:10 }; /* Enum BMDDisplayModeFlags - Flags to describe the characteristics of an IDeckLinkDisplayMode. */ typedef uint32_t BMDDisplayModeFlags; enum _BMDDisplayModeFlags { bmdDisplayModeSupports3D = 1 << 0, bmdDisplayModeColorspaceRec601 = 1 << 1, bmdDisplayModeColorspaceRec709 = 1 << 2 }; /* Enum BMDVideoOutputFlags - Flags to control the output of ancillary data along with video. */ typedef uint32_t BMDVideoOutputFlags; enum _BMDVideoOutputFlags { bmdVideoOutputFlagDefault = 0, bmdVideoOutputVANC = 1 << 0, bmdVideoOutputVITC = 1 << 1, bmdVideoOutputRP188 = 1 << 2, bmdVideoOutputDualStream3D = 1 << 4 }; /* Enum BMDFrameFlags - Frame flags */ typedef uint32_t BMDFrameFlags; enum _BMDFrameFlags { bmdFrameFlagDefault = 0, bmdFrameFlagFlipVertical = 1 << 0, /* Flags that are applicable only to instances of IDeckLinkVideoInputFrame */ bmdFrameHasNoInputSource = 1 << 31 }; /* Enum BMDVideoInputFlags - Flags applicable to video input */ typedef uint32_t BMDVideoInputFlags; enum _BMDVideoInputFlags { bmdVideoInputFlagDefault = 0, bmdVideoInputEnableFormatDetection = 1 << 0, bmdVideoInputDualStream3D = 1 << 1 }; /* Enum BMDVideoInputFormatChangedEvents - Bitmask passed to the VideoInputFormatChanged notification to identify the properties of the input signal that have changed */ typedef uint32_t BMDVideoInputFormatChangedEvents; enum _BMDVideoInputFormatChangedEvents { bmdVideoInputDisplayModeChanged = 1 << 0, bmdVideoInputFieldDominanceChanged = 1 << 1, bmdVideoInputColorspaceChanged = 1 << 2 }; /* Enum BMDDetectedVideoInputFormatFlags - Flags passed to the VideoInputFormatChanged notification to describe the detected video input signal */ typedef uint32_t BMDDetectedVideoInputFormatFlags; enum _BMDDetectedVideoInputFormatFlags { bmdDetectedVideoInputYCbCr422 = 1 << 0, bmdDetectedVideoInputRGB444 = 1 << 1 }; /* Enum BMDOutputFrameCompletionResult - Frame Completion Callback */ typedef uint32_t BMDOutputFrameCompletionResult; enum _BMDOutputFrameCompletionResult { bmdOutputFrameCompleted, bmdOutputFrameDisplayedLate, bmdOutputFrameDropped, bmdOutputFrameFlushed }; /* Enum BMDReferenceStatus - GenLock input status */ typedef uint32_t BMDReferenceStatus; enum _BMDReferenceStatus { bmdReferenceNotSupportedByHardware = 1 << 0, bmdReferenceLocked = 1 << 1 }; /* Enum BMDAudioSampleRate - Audio sample rates supported for output/input */ typedef uint32_t BMDAudioSampleRate; enum _BMDAudioSampleRate { bmdAudioSampleRate48kHz = 48000 }; /* Enum BMDAudioSampleType - Audio sample sizes supported for output/input */ typedef uint32_t BMDAudioSampleType; enum _BMDAudioSampleType { bmdAudioSampleType16bitInteger = 16, bmdAudioSampleType32bitInteger = 32 }; /* Enum BMDAudioOutputStreamType - Audio output stream type */ typedef uint32_t BMDAudioOutputStreamType; enum _BMDAudioOutputStreamType { bmdAudioOutputStreamContinuous, bmdAudioOutputStreamContinuousDontResample, bmdAudioOutputStreamTimestamped }; /* Enum BMDDisplayModeSupport - Output mode supported flags */ typedef uint32_t BMDDisplayModeSupport; enum _BMDDisplayModeSupport { bmdDisplayModeNotSupported = 0, bmdDisplayModeSupported, bmdDisplayModeSupportedWithConversion }; /* Enum BMDTimecodeFormat - Timecode formats for frame metadata */ typedef uint32_t BMDTimecodeFormat; enum _BMDTimecodeFormat { bmdTimecodeRP188 = 'rp18', bmdTimecodeRP188Field2 = 'rp12', bmdTimecodeVITC = 'vitc', bmdTimecodeVITCField2 = 'vit2', bmdTimecodeSerial = 'seri' }; /* Enum BMDTimecodeFlags - Timecode flags */ typedef uint32_t BMDTimecodeFlags; enum _BMDTimecodeFlags { bmdTimecodeFlagDefault = 0, bmdTimecodeIsDropFrame = 1 << 0 }; /* Enum BMDVideoConnection - Video connection types */ typedef uint32_t BMDVideoConnection; enum _BMDVideoConnection { bmdVideoConnectionSDI = 1 << 0, bmdVideoConnectionHDMI = 1 << 1, bmdVideoConnectionOpticalSDI = 1 << 2, bmdVideoConnectionComponent = 1 << 3, bmdVideoConnectionComposite = 1 << 4, bmdVideoConnectionSVideo = 1 << 5 }; /* Enum BMDAnalogVideoFlags - Analog video display flags */ typedef uint32_t BMDAnalogVideoFlags; enum _BMDAnalogVideoFlags { bmdAnalogVideoFlagCompositeSetup75 = 1 << 0, bmdAnalogVideoFlagComponentBetacamLevels = 1 << 1 }; /* Enum BMDAudioConnection - Audio connection types */ typedef uint32_t BMDAudioConnection; enum _BMDAudioConnection { bmdAudioConnectionEmbedded = 'embd', bmdAudioConnectionAESEBU = 'aes ', bmdAudioConnectionAnalog = 'anlg' }; /* Enum BMDAudioOutputAnalogAESSwitch - Audio output Analog/AESEBU switch */ typedef uint32_t BMDAudioOutputAnalogAESSwitch; enum _BMDAudioOutputAnalogAESSwitch { bmdAudioOutputSwitchAESEBU = 'aes ', bmdAudioOutputSwitchAnalog = 'anlg' }; /* Enum BMDVideoOutputConversionMode - Video/audio conversion mode */ typedef uint32_t BMDVideoOutputConversionMode; enum _BMDVideoOutputConversionMode { bmdNoVideoOutputConversion = 'none', bmdVideoOutputLetterboxDownconversion = 'ltbx', bmdVideoOutputAnamorphicDownconversion = 'amph', bmdVideoOutputHD720toHD1080Conversion = '720c', bmdVideoOutputHardwareLetterboxDownconversion = 'HWlb', bmdVideoOutputHardwareAnamorphicDownconversion = 'HWam', bmdVideoOutputHardwareCenterCutDownconversion = 'HWcc', bmdVideoOutputHardware720p1080pCrossconversion = 'xcap', bmdVideoOutputHardwareAnamorphic720pUpconversion = 'ua7p', bmdVideoOutputHardwareAnamorphic1080iUpconversion = 'ua1i', bmdVideoOutputHardwareAnamorphic149To720pUpconversion = 'u47p', bmdVideoOutputHardwareAnamorphic149To1080iUpconversion = 'u41i', bmdVideoOutputHardwarePillarbox720pUpconversion = 'up7p', bmdVideoOutputHardwarePillarbox1080iUpconversion = 'up1i' }; /* Enum BMDVideoInputConversionMode - Video input conversion mode */ typedef uint32_t BMDVideoInputConversionMode; enum _BMDVideoInputConversionMode { bmdNoVideoInputConversion = 'none', bmdVideoInputLetterboxDownconversionFromHD1080 = '10lb', bmdVideoInputAnamorphicDownconversionFromHD1080 = '10am', bmdVideoInputLetterboxDownconversionFromHD720 = '72lb', bmdVideoInputAnamorphicDownconversionFromHD720 = '72am', bmdVideoInputLetterboxUpconversion = 'lbup', bmdVideoInputAnamorphicUpconversion = 'amup' }; /* Enum BMDVideo3DPackingFormat - Video 3D packing format */ typedef uint32_t BMDVideo3DPackingFormat; enum _BMDVideo3DPackingFormat { bmdVideo3DPackingSidebySideHalf = 'sbsh', bmdVideo3DPackingLinebyLine = 'lbyl', bmdVideo3DPackingTopAndBottom = 'tabo', bmdVideo3DPackingFramePacking = 'frpk', bmdVideo3DPackingLeftOnly = 'left', bmdVideo3DPackingRightOnly = 'righ' }; /* Enum BMDIdleVideoOutputOperation - Video output operation when not playing video */ typedef uint32_t BMDIdleVideoOutputOperation; enum _BMDIdleVideoOutputOperation { bmdIdleVideoOutputBlack = 'blac', bmdIdleVideoOutputLastFrame = 'lafa' }; /* Enum BMDDeckLinkConfigurationID - DeckLink Configuration ID */ typedef uint32_t BMDDeckLinkConfigurationID; enum _BMDDeckLinkConfigurationID { /* Serial port Flags */ bmdDeckLinkConfigSwapSerialRxTx = 'ssrt', /* Video Input/Output Flags */ bmdDeckLinkConfigUse1080pNotPsF = 'fpro', /* Video Input/Output Integers */ bmdDeckLinkConfigHDMI3DPackingFormat = '3dpf', bmdDeckLinkConfigBypass = 'byps', /* Audio Input/Output Flags */ bmdDeckLinkConfigAnalogAudioConsumerLevels = 'aacl', /* Video output flags */ bmdDeckLinkConfigFieldFlickerRemoval = 'fdfr', bmdDeckLinkConfigHD1080p24ToHD1080i5994Conversion = 'to59', bmdDeckLinkConfig444SDIVideoOutput = '444o', bmdDeckLinkConfig3GBpsVideoOutput = '3gbs', bmdDeckLinkConfigBlackVideoOutputDuringCapture = 'bvoc', bmdDeckLinkConfigLowLatencyVideoOutput = 'llvo', /* Video Output Integers */ bmdDeckLinkConfigVideoOutputConnection = 'vocn', bmdDeckLinkConfigVideoOutputConversionMode = 'vocm', bmdDeckLinkConfigAnalogVideoOutputFlags = 'avof', bmdDeckLinkConfigReferenceInputTimingOffset = 'glot', bmdDeckLinkConfigVideoOutputIdleOperation = 'voio', /* Video Output Floats */ bmdDeckLinkConfigVideoOutputComponentLumaGain = 'oclg', bmdDeckLinkConfigVideoOutputComponentChromaBlueGain = 'occb', bmdDeckLinkConfigVideoOutputComponentChromaRedGain = 'occr', bmdDeckLinkConfigVideoOutputCompositeLumaGain = 'oilg', bmdDeckLinkConfigVideoOutputCompositeChromaGain = 'oicg', bmdDeckLinkConfigVideoOutputSVideoLumaGain = 'oslg', bmdDeckLinkConfigVideoOutputSVideoChromaGain = 'oscg', /* Video Input Integers */ bmdDeckLinkConfigVideoInputConnection = 'vicn', bmdDeckLinkConfigAnalogVideoInputFlags = 'avif', bmdDeckLinkConfigVideoInputConversionMode = 'vicm', bmdDeckLinkConfig32PulldownSequenceInitialTimecodeFrame = 'pdif', bmdDeckLinkConfigVANCSourceLine1Mapping = 'vsl1', bmdDeckLinkConfigVANCSourceLine2Mapping = 'vsl2', bmdDeckLinkConfigVANCSourceLine3Mapping = 'vsl3', /* Video Input Floats */ bmdDeckLinkConfigVideoInputComponentLumaGain = 'iclg', bmdDeckLinkConfigVideoInputComponentChromaBlueGain = 'iccb', bmdDeckLinkConfigVideoInputComponentChromaRedGain = 'iccr', bmdDeckLinkConfigVideoInputCompositeLumaGain = 'iilg', bmdDeckLinkConfigVideoInputCompositeChromaGain = 'iicg', bmdDeckLinkConfigVideoInputSVideoLumaGain = 'islg', bmdDeckLinkConfigVideoInputSVideoChromaGain = 'iscg', /* Audio Input Integers */ bmdDeckLinkConfigAudioInputConnection = 'aicn', /* Audio Input Floats */ bmdDeckLinkConfigAnalogAudioInputScaleChannel1 = 'ais1', bmdDeckLinkConfigAnalogAudioInputScaleChannel2 = 'ais2', bmdDeckLinkConfigAnalogAudioInputScaleChannel3 = 'ais3', bmdDeckLinkConfigAnalogAudioInputScaleChannel4 = 'ais4', bmdDeckLinkConfigDigitalAudioInputScale = 'dais', /* Audio Output Integers */ bmdDeckLinkConfigAudioOutputAESAnalogSwitch = 'aoaa', /* Audio Output Floats */ bmdDeckLinkConfigAnalogAudioOutputScaleChannel1 = 'aos1', bmdDeckLinkConfigAnalogAudioOutputScaleChannel2 = 'aos2', bmdDeckLinkConfigAnalogAudioOutputScaleChannel3 = 'aos3', bmdDeckLinkConfigAnalogAudioOutputScaleChannel4 = 'aos4', bmdDeckLinkConfigDigitalAudioOutputScale = 'daos' }; /* Enum BMDDeckLinkAttributeID - DeckLink Attribute ID */ typedef uint32_t BMDDeckLinkAttributeID; enum _BMDDeckLinkAttributeID { /* Flags */ BMDDeckLinkSupportsInternalKeying = 'keyi', BMDDeckLinkSupportsExternalKeying = 'keye', BMDDeckLinkSupportsHDKeying = 'keyh', BMDDeckLinkSupportsInputFormatDetection = 'infd', BMDDeckLinkHasReferenceInput = 'hrin', BMDDeckLinkHasSerialPort = 'hspt', BMDDeckLinkHasAnalogVideoOutputGain = 'avog', BMDDeckLinkCanOnlyAdjustOverallVideoOutputGain = 'ovog', BMDDeckLinkHasVideoInputAntiAliasingFilter = 'aafl', BMDDeckLinkHasBypass = 'byps', /* Integers */ BMDDeckLinkMaximumAudioChannels = 'mach', BMDDeckLinkNumberOfSubDevices = 'nsbd', BMDDeckLinkSubDeviceIndex = 'subi', BMDDeckLinkVideoOutputConnections = 'vocn', BMDDeckLinkVideoInputConnections = 'vicn', /* Floats */ BMDDeckLinkVideoInputGainMinimum = 'vigm', BMDDeckLinkVideoInputGainMaximum = 'vigx', BMDDeckLinkVideoOutputGainMinimum = 'vogm', BMDDeckLinkVideoOutputGainMaximum = 'vogx', /* Strings */ BMDDeckLinkSerialPortDeviceName = 'slpn' }; /* Enum BMDDeckLinkAPIInformationID - DeckLinkAPI information ID */ typedef uint32_t BMDDeckLinkAPIInformationID; enum _BMDDeckLinkAPIInformationID { BMDDeckLinkAPIVersion = 'vers' }; /* Enum BMDDeckControlMode - DeckControl mode */ typedef uint32_t BMDDeckControlMode; enum _BMDDeckControlMode { bmdDeckControlNotOpened = 'ntop', bmdDeckControlVTRControlMode = 'vtrc', bmdDeckControlExportMode = 'expm', bmdDeckControlCaptureMode = 'capm' }; /* Enum BMDDeckControlEvent - DeckControl event */ typedef uint32_t BMDDeckControlEvent; enum _BMDDeckControlEvent { bmdDeckControlAbortedEvent = 'abte', // This event is triggered when a capture or edit-to-tape operation is aborted. /* Export-To-Tape events */ bmdDeckControlPrepareForExportEvent = 'pfee', // This event is triggered a few frames before reaching the in-point. IDeckLinkInput::StartScheduledPlayback() should be called at this point. bmdDeckControlExportCompleteEvent = 'exce', // This event is triggered a few frames after reaching the out-point. At this point, it is safe to stop playback. /* Capture events */ bmdDeckControlPrepareForCaptureEvent = 'pfce', // This event is triggered a few frames before reaching the in-point. The serial timecode attached to IDeckLinkVideoInputFrames is now valid. bmdDeckControlCaptureCompleteEvent = 'ccev' // This event is triggered a few frames after reaching the out-point. }; /* Enum BMDDeckControlVTRControlState - VTR Control state */ typedef uint32_t BMDDeckControlVTRControlState; enum _BMDDeckControlVTRControlState { bmdDeckControlNotInVTRControlMode = 'nvcm', bmdDeckControlVTRControlPlaying = 'vtrp', bmdDeckControlVTRControlRecording = 'vtrr', bmdDeckControlVTRControlStill = 'vtra', bmdDeckControlVTRControlSeeking = 'vtrs', bmdDeckControlVTRControlStopped = 'vtro' }; /* Enum BMDDeckControlStatusFlags - Deck Control status flags */ typedef uint32_t BMDDeckControlStatusFlags; enum _BMDDeckControlStatusFlags { bmdDeckControlStatusDeckConnected = 1 << 0, bmdDeckControlStatusRemoteMode = 1 << 1, bmdDeckControlStatusRecordInhibited = 1 << 2, bmdDeckControlStatusCassetteOut = 1 << 3 }; /* Enum BMDDeckControlExportModeOpsFlags - Export mode flags */ typedef uint32_t BMDDeckControlExportModeOpsFlags; enum _BMDDeckControlExportModeOpsFlags { bmdDeckControlExportModeInsertVideo = 1 << 0, bmdDeckControlExportModeInsertAudio1 = 1 << 1, bmdDeckControlExportModeInsertAudio2 = 1 << 2, bmdDeckControlExportModeInsertAudio3 = 1 << 3, bmdDeckControlExportModeInsertAudio4 = 1 << 4, bmdDeckControlExportModeInsertAudio5 = 1 << 5, bmdDeckControlExportModeInsertAudio6 = 1 << 6, bmdDeckControlExportModeInsertAudio7 = 1 << 7, bmdDeckControlExportModeInsertAudio8 = 1 << 8, bmdDeckControlExportModeInsertAudio9 = 1 << 9, bmdDeckControlExportModeInsertAudio10 = 1 << 10, bmdDeckControlExportModeInsertAudio11 = 1 << 11, bmdDeckControlExportModeInsertAudio12 = 1 << 12, bmdDeckControlExportModeInsertTimeCode = 1 << 13, bmdDeckControlExportModeInsertAssemble = 1 << 14, bmdDeckControlExportModeInsertPreview = 1 << 15, bmdDeckControlUseManualExport = 1 << 16 }; /* Enum BMDDeckControlError - Deck Control error */ typedef uint32_t BMDDeckControlError; enum _BMDDeckControlError { bmdDeckControlNoError = 'noer', bmdDeckControlModeError = 'moer', bmdDeckControlMissedInPointError = 'mier', bmdDeckControlDeckTimeoutError = 'dter', bmdDeckControlCommandFailedError = 'cfer', bmdDeckControlDeviceAlreadyOpenedError = 'dalo', bmdDeckControlFailedToOpenDeviceError = 'fder', bmdDeckControlInLocalModeError = 'lmer', bmdDeckControlEndOfTapeError = 'eter', bmdDeckControlUserAbortError = 'uaer', bmdDeckControlNoTapeInDeckError = 'nter', bmdDeckControlNoVideoFromCardError = 'nvfc', bmdDeckControlNoCommunicationError = 'ncom', bmdDeckControlBufferTooSmallError = 'btsm', bmdDeckControlBadChecksumError = 'chks', bmdDeckControlUnknownError = 'uner' }; /* Enum BMD3DPreviewFormat - Linked Frame preview format */ typedef uint32_t BMD3DPreviewFormat; enum _BMD3DPreviewFormat { bmd3DPreviewFormatDefault = 'defa', bmd3DPreviewFormatLeftOnly = 'left', bmd3DPreviewFormatRightOnly = 'righ', bmd3DPreviewFormatSideBySide = 'side', bmd3DPreviewFormatTopBottom = 'topb' }; #if defined(__cplusplus) // Forward Declarations class IDeckLinkVideoOutputCallback; class IDeckLinkInputCallback; class IDeckLinkMemoryAllocator; class IDeckLinkAudioOutputCallback; class IDeckLinkIterator; class IDeckLinkAPIInformation; class IDeckLinkDisplayModeIterator; class IDeckLinkDisplayMode; class IDeckLink; class IDeckLinkOutput; class IDeckLinkInput; class IDeckLinkTimecode; class IDeckLinkVideoFrame; class IDeckLinkMutableVideoFrame; class IDeckLinkVideoFrame3DExtensions; class IDeckLinkVideoInputFrame; class IDeckLinkVideoFrameAncillary; class IDeckLinkAudioInputPacket; class IDeckLinkScreenPreviewCallback; class IDeckLinkCocoaScreenPreviewCallback; class IDeckLinkGLScreenPreviewHelper; class IDeckLinkConfiguration; class IDeckLinkAttributes; class IDeckLinkKeyer; class IDeckLinkVideoConversion; class IDeckLinkDeckControlStatusCallback; class IDeckLinkDeckControl; /* Interface IDeckLinkVideoOutputCallback - Frame completion callback. */ class IDeckLinkVideoOutputCallback : public IUnknown { public: virtual HRESULT ScheduledFrameCompleted (/* in */ IDeckLinkVideoFrame *completedFrame, /* in */ BMDOutputFrameCompletionResult result) = 0; virtual HRESULT ScheduledPlaybackHasStopped (void) = 0; protected: virtual ~IDeckLinkVideoOutputCallback () {}; // call Release method to drop reference count }; /* Interface IDeckLinkInputCallback - Frame arrival callback. */ class IDeckLinkInputCallback : public IUnknown { public: virtual HRESULT VideoInputFormatChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode *newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; virtual HRESULT VideoInputFrameArrived (/* in */ IDeckLinkVideoInputFrame* videoFrame, /* in */ IDeckLinkAudioInputPacket* audioPacket) = 0; protected: virtual ~IDeckLinkInputCallback () {}; // call Release method to drop reference count }; /* Interface IDeckLinkMemoryAllocator - Memory allocator for video frames. */ class IDeckLinkMemoryAllocator : public IUnknown { public: virtual HRESULT AllocateBuffer (/* in */ uint32_t bufferSize, /* out */ void **allocatedBuffer) = 0; virtual HRESULT ReleaseBuffer (/* in */ void *buffer) = 0; virtual HRESULT Commit (void) = 0; virtual HRESULT Decommit (void) = 0; }; /* Interface IDeckLinkAudioOutputCallback - Optional callback to allow audio samples to be pulled as required. */ class IDeckLinkAudioOutputCallback : public IUnknown { public: virtual HRESULT RenderAudioSamples (/* in */ bool preroll) = 0; }; /* Interface IDeckLinkIterator - enumerates installed DeckLink hardware */ class IDeckLinkIterator : public IUnknown { public: virtual HRESULT Next (/* out */ IDeckLink **deckLinkInstance) = 0; }; /* Interface IDeckLinkAPIInformation - DeckLinkAPI attribute interface */ class IDeckLinkAPIInformation : public IUnknown { public: virtual HRESULT GetFlag (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ bool *value) = 0; virtual HRESULT GetInt (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ int64_t *value) = 0; virtual HRESULT GetFloat (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ double *value) = 0; virtual HRESULT GetString (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ CFStringRef *value) = 0; protected: virtual ~IDeckLinkAPIInformation () {}; // call Release method to drop reference count }; /* Interface IDeckLinkDisplayModeIterator - enumerates over supported input/output display modes. */ class IDeckLinkDisplayModeIterator : public IUnknown { public: virtual HRESULT Next (/* out */ IDeckLinkDisplayMode **deckLinkDisplayMode) = 0; protected: virtual ~IDeckLinkDisplayModeIterator () {}; // call Release method to drop reference count }; /* Interface IDeckLinkDisplayMode - represents a display mode */ class IDeckLinkDisplayMode : public IUnknown { public: virtual HRESULT GetName (/* out */ CFStringRef *name) = 0; virtual BMDDisplayMode GetDisplayMode (void) = 0; virtual long GetWidth (void) = 0; virtual long GetHeight (void) = 0; virtual HRESULT GetFrameRate (/* out */ BMDTimeValue *frameDuration, /* out */ BMDTimeScale *timeScale) = 0; virtual BMDFieldDominance GetFieldDominance (void) = 0; virtual BMDDisplayModeFlags GetFlags (void) = 0; protected: virtual ~IDeckLinkDisplayMode () {}; // call Release method to drop reference count }; /* Interface IDeckLink - represents a DeckLink device */ class IDeckLink : public IUnknown { public: virtual HRESULT GetModelName (/* out */ CFStringRef *modelName) = 0; }; /* Interface IDeckLinkOutput - Created by QueryInterface from IDeckLink. */ class IDeckLinkOutput : public IUnknown { public: virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoOutputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; /* Video Output */ virtual HRESULT EnableVideoOutput (/* in */ BMDDisplayMode displayMode, /* in */ BMDVideoOutputFlags flags) = 0; virtual HRESULT DisableVideoOutput (void) = 0; virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame **outFrame) = 0; virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame *theFrame) = 0; virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame *theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0; virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback *theCallback) = 0; virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t *bufferedFrameCount) = 0; /* Audio Output */ virtual HRESULT EnableAudioOutput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount, /* in */ BMDAudioOutputStreamType streamType) = 0; virtual HRESULT DisableAudioOutput (void) = 0; virtual HRESULT WriteAudioSamplesSync (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t *sampleFramesWritten) = 0; virtual HRESULT BeginAudioPreroll (void) = 0; virtual HRESULT EndAudioPreroll (void) = 0; virtual HRESULT ScheduleAudioSamples (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t *sampleFramesWritten) = 0; virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t *bufferedSampleFrameCount) = 0; virtual HRESULT FlushBufferedAudioSamples (void) = 0; virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback *theCallback) = 0; /* Output Control */ virtual HRESULT StartScheduledPlayback (/* in */ BMDTimeValue playbackStartTime, /* in */ BMDTimeScale timeScale, /* in */ double playbackSpeed) = 0; virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue *actualStopTime, /* in */ BMDTimeScale timeScale) = 0; virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool *active) = 0; virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *streamTime, /* out */ double *playbackSpeed) = 0; virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus *referenceStatus) = 0; /* Hardware Timing */ virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; protected: virtual ~IDeckLinkOutput () {}; // call Release method to drop reference count }; /* Interface IDeckLinkInput - Created by QueryInterface from IDeckLink. */ class IDeckLinkInput : public IUnknown { public: virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; /* Video Input */ virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0; virtual HRESULT DisableVideoInput (void) = 0; virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t *availableFrameCount) = 0; /* Audio Input */ virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0; virtual HRESULT DisableAudioInput (void) = 0; virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t *availableSampleFrameCount) = 0; /* Input Control */ virtual HRESULT StartStreams (void) = 0; virtual HRESULT StopStreams (void) = 0; virtual HRESULT PauseStreams (void) = 0; virtual HRESULT FlushStreams (void) = 0; virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback *theCallback) = 0; /* Hardware Timing */ virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; protected: virtual ~IDeckLinkInput () {}; // call Release method to drop reference count }; /* Interface IDeckLinkTimecode - Used for video frame timecode representation. */ class IDeckLinkTimecode : public IUnknown { public: virtual BMDTimecodeBCD GetBCD (void) = 0; virtual HRESULT GetComponents (/* out */ uint8_t *hours, /* out */ uint8_t *minutes, /* out */ uint8_t *seconds, /* out */ uint8_t *frames) = 0; virtual HRESULT GetString (/* out */ CFStringRef *timecode) = 0; virtual BMDTimecodeFlags GetFlags (void) = 0; virtual HRESULT GetTimecodeUserBits (/* out */ BMDTimecodeUserBits *userBits) = 0; protected: virtual ~IDeckLinkTimecode () {}; // call Release method to drop reference count }; /* Interface IDeckLinkVideoFrame - Interface to encapsulate a video frame; can be caller-implemented. */ class IDeckLinkVideoFrame : public IUnknown { public: virtual long GetWidth (void) = 0; virtual long GetHeight (void) = 0; virtual long GetRowBytes (void) = 0; virtual BMDPixelFormat GetPixelFormat (void) = 0; virtual BMDFrameFlags GetFlags (void) = 0; virtual HRESULT GetBytes (/* out */ void **buffer) = 0; virtual HRESULT GetTimecode (/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode **timecode) = 0; virtual HRESULT GetAncillaryData (/* out */ IDeckLinkVideoFrameAncillary **ancillary) = 0; protected: virtual ~IDeckLinkVideoFrame () {}; // call Release method to drop reference count }; /* Interface IDeckLinkMutableVideoFrame - Created by IDeckLinkOutput::CreateVideoFrame. */ class IDeckLinkMutableVideoFrame : public IDeckLinkVideoFrame { public: virtual HRESULT SetFlags (/* in */ BMDFrameFlags newFlags) = 0; virtual HRESULT SetTimecode (/* in */ BMDTimecodeFormat format, /* in */ IDeckLinkTimecode *timecode) = 0; virtual HRESULT SetTimecodeFromComponents (/* in */ BMDTimecodeFormat format, /* in */ uint8_t hours, /* in */ uint8_t minutes, /* in */ uint8_t seconds, /* in */ uint8_t frames, /* in */ BMDTimecodeFlags flags) = 0; virtual HRESULT SetAncillaryData (/* in */ IDeckLinkVideoFrameAncillary *ancillary) = 0; virtual HRESULT SetTimecodeUserBits (/* in */ BMDTimecodeFormat format, /* in */ BMDTimecodeUserBits userBits) = 0; protected: virtual ~IDeckLinkMutableVideoFrame () {}; // call Release method to drop reference count }; /* Interface IDeckLinkVideoFrame3DExtensions - Optional interface implemented on IDeckLinkVideoFrame to support 3D frames */ class IDeckLinkVideoFrame3DExtensions : public IUnknown { public: virtual BMDVideo3DPackingFormat Get3DPackingFormat (void) = 0; virtual HRESULT GetFrameForRightEye (/* out */ IDeckLinkVideoFrame* *rightEyeFrame) = 0; protected: virtual ~IDeckLinkVideoFrame3DExtensions () {}; // call Release method to drop reference count }; /* Interface IDeckLinkVideoInputFrame - Provided by the IDeckLinkVideoInput frame arrival callback. */ class IDeckLinkVideoInputFrame : public IDeckLinkVideoFrame { public: virtual HRESULT GetStreamTime (/* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration, /* in */ BMDTimeScale timeScale) = 0; virtual HRESULT GetHardwareReferenceTimestamp (/* in */ BMDTimeScale timeScale, /* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration) = 0; protected: virtual ~IDeckLinkVideoInputFrame () {}; // call Release method to drop reference count }; /* Interface IDeckLinkVideoFrameAncillary - Obtained through QueryInterface() on an IDeckLinkVideoFrame object. */ class IDeckLinkVideoFrameAncillary : public IUnknown { public: virtual HRESULT GetBufferForVerticalBlankingLine (/* in */ uint32_t lineNumber, /* out */ void **buffer) = 0; virtual BMDPixelFormat GetPixelFormat (void) = 0; virtual BMDDisplayMode GetDisplayMode (void) = 0; protected: virtual ~IDeckLinkVideoFrameAncillary () {}; // call Release method to drop reference count }; /* Interface IDeckLinkAudioInputPacket - Provided by the IDeckLinkInput callback. */ class IDeckLinkAudioInputPacket : public IUnknown { public: virtual long GetSampleFrameCount (void) = 0; virtual HRESULT GetBytes (/* out */ void **buffer) = 0; virtual HRESULT GetPacketTime (/* out */ BMDTimeValue *packetTime, /* in */ BMDTimeScale timeScale) = 0; protected: virtual ~IDeckLinkAudioInputPacket () {}; // call Release method to drop reference count }; /* Interface IDeckLinkScreenPreviewCallback - Screen preview callback */ class IDeckLinkScreenPreviewCallback : public IUnknown { public: virtual HRESULT DrawFrame (/* in */ IDeckLinkVideoFrame *theFrame) = 0; protected: virtual ~IDeckLinkScreenPreviewCallback () {}; // call Release method to drop reference count }; /* Interface IDeckLinkCocoaScreenPreviewCallback - Screen preview callback for Cocoa-based applications */ class IDeckLinkCocoaScreenPreviewCallback : public IDeckLinkScreenPreviewCallback { public: protected: virtual ~IDeckLinkCocoaScreenPreviewCallback () {}; // call Release method to drop reference count }; /* Interface IDeckLinkGLScreenPreviewHelper - Created with CoCreateInstance(). */ class IDeckLinkGLScreenPreviewHelper : public IUnknown { public: /* Methods must be called with OpenGL context set */ virtual HRESULT InitializeGL (void) = 0; virtual HRESULT PaintGL (void) = 0; virtual HRESULT SetFrame (/* in */ IDeckLinkVideoFrame *theFrame) = 0; virtual HRESULT Set3DPreviewFormat (/* in */ BMD3DPreviewFormat previewFormat) = 0; protected: virtual ~IDeckLinkGLScreenPreviewHelper () {}; // call Release method to drop reference count }; /* Interface IDeckLinkConfiguration - DeckLink Configuration interface */ class IDeckLinkConfiguration : public IUnknown { public: virtual HRESULT SetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ bool value) = 0; virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool *value) = 0; virtual HRESULT SetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ int64_t value) = 0; virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t *value) = 0; virtual HRESULT SetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ double value) = 0; virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double *value) = 0; virtual HRESULT SetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ CFStringRef value) = 0; virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ CFStringRef *value) = 0; virtual HRESULT WriteConfigurationToPreferences (void) = 0; protected: virtual ~IDeckLinkConfiguration () {}; // call Release method to drop reference count }; /* Interface IDeckLinkAttributes - DeckLink Attribute interface */ class IDeckLinkAttributes : public IUnknown { public: virtual HRESULT GetFlag (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ bool *value) = 0; virtual HRESULT GetInt (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ int64_t *value) = 0; virtual HRESULT GetFloat (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ double *value) = 0; virtual HRESULT GetString (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ CFStringRef *value) = 0; protected: virtual ~IDeckLinkAttributes () {}; // call Release method to drop reference count }; /* Interface IDeckLinkKeyer - DeckLink Keyer interface */ class IDeckLinkKeyer : public IUnknown { public: virtual HRESULT Enable (/* in */ bool isExternal) = 0; virtual HRESULT SetLevel (/* in */ uint8_t level) = 0; virtual HRESULT RampUp (/* in */ uint32_t numberOfFrames) = 0; virtual HRESULT RampDown (/* in */ uint32_t numberOfFrames) = 0; virtual HRESULT Disable (void) = 0; protected: virtual ~IDeckLinkKeyer () {}; // call Release method to drop reference count }; /* Interface IDeckLinkVideoConversion - Created with CoCreateInstance(). */ class IDeckLinkVideoConversion : public IUnknown { public: virtual HRESULT ConvertFrame (/* in */ IDeckLinkVideoFrame* srcFrame, /* in */ IDeckLinkVideoFrame* dstFrame) = 0; protected: virtual ~IDeckLinkVideoConversion () {}; // call Release method to drop reference count }; /* Interface IDeckLinkDeckControlStatusCallback - Deck control state change callback. */ class IDeckLinkDeckControlStatusCallback : public IUnknown { public: virtual HRESULT TimecodeUpdate (/* in */ BMDTimecodeBCD currentTimecode) = 0; virtual HRESULT VTRControlStateChanged (/* in */ BMDDeckControlVTRControlState newState, /* in */ BMDDeckControlError error) = 0; virtual HRESULT DeckControlEventReceived (/* in */ BMDDeckControlEvent event, /* in */ BMDDeckControlError error) = 0; virtual HRESULT DeckControlStatusChanged (/* in */ BMDDeckControlStatusFlags flags, /* in */ uint32_t mask) = 0; protected: virtual ~IDeckLinkDeckControlStatusCallback () {}; // call Release method to drop reference count }; /* Interface IDeckLinkDeckControl - Deck Control main interface */ class IDeckLinkDeckControl : public IUnknown { public: virtual HRESULT Open (/* in */ BMDTimeScale timeScale, /* in */ BMDTimeValue timeValue, /* in */ bool timecodeIsDropFrame, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT Close (/* in */ bool standbyOn) = 0; virtual HRESULT GetCurrentState (/* out */ BMDDeckControlMode *mode, /* out */ BMDDeckControlVTRControlState *vtrControlState, /* out */ BMDDeckControlStatusFlags *flags) = 0; virtual HRESULT SetStandby (/* in */ bool standbyOn) = 0; virtual HRESULT SendCommand (/* in */ uint8_t *inBuffer, /* in */ uint32_t inBufferSize, /* out */ uint8_t *outBuffer, /* out */ uint32_t *outDataSize, /* in */ uint32_t outBufferSize, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT Play (/* out */ BMDDeckControlError *error) = 0; virtual HRESULT Stop (/* out */ BMDDeckControlError *error) = 0; virtual HRESULT TogglePlayStop (/* out */ BMDDeckControlError *error) = 0; virtual HRESULT Eject (/* out */ BMDDeckControlError *error) = 0; virtual HRESULT GoToTimecode (/* in */ BMDTimecodeBCD timecode, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT FastForward (/* in */ bool viewTape, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT Rewind (/* in */ bool viewTape, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT StepForward (/* out */ BMDDeckControlError *error) = 0; virtual HRESULT StepBack (/* out */ BMDDeckControlError *error) = 0; virtual HRESULT Jog (/* in */ double rate, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT Shuttle (/* in */ double rate, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT GetTimecodeString (/* out */ CFStringRef *currentTimeCode, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT GetTimecode (/* out */ IDeckLinkTimecode **currentTimecode, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT GetTimecodeBCD (/* out */ BMDTimecodeBCD *currentTimecode, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT SetPreroll (/* in */ uint32_t prerollSeconds) = 0; virtual HRESULT GetPreroll (/* out */ uint32_t *prerollSeconds) = 0; virtual HRESULT SetExportOffset (/* in */ int32_t exportOffsetFields) = 0; virtual HRESULT GetExportOffset (/* out */ int32_t *exportOffsetFields) = 0; virtual HRESULT GetManualExportOffset (/* out */ int32_t *deckManualExportOffsetFields) = 0; virtual HRESULT SetCaptureOffset (/* in */ int32_t captureOffsetFields) = 0; virtual HRESULT GetCaptureOffset (/* out */ int32_t *captureOffsetFields) = 0; virtual HRESULT StartExport (/* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* in */ BMDDeckControlExportModeOpsFlags exportModeOps, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT StartCapture (/* in */ bool useVITC, /* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT GetDeviceID (/* out */ uint16_t *deviceId, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT Abort (void) = 0; virtual HRESULT CrashRecordStart (/* out */ BMDDeckControlError *error) = 0; virtual HRESULT CrashRecordStop (/* out */ BMDDeckControlError *error) = 0; virtual HRESULT SetCallback (/* in */ IDeckLinkDeckControlStatusCallback *callback) = 0; protected: virtual ~IDeckLinkDeckControl () {}; // call Release method to drop reference count }; /* Functions */ extern "C" { IDeckLinkIterator* CreateDeckLinkIteratorInstance (void); IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance (void); IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper (void); IDeckLinkCocoaScreenPreviewCallback* CreateCocoaScreenPreview (void* /* (NSView*) */ parentView); IDeckLinkVideoConversion* CreateVideoConversionInstance (void); }; #endif // defined(__cplusplus) #endif // __DeckLink_API_h__ mlt-0.9.0/src/modules/decklink/darwin/DeckLinkAPIDispatch.cpp000077500000000000000000000116271215300731300240320ustar00rootroot00000000000000/* -LICENSE-START- ** Copyright (c) 2009 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by ** this license (the "Software") to use, reproduce, display, distribute, ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: ** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. ** ** 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT ** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE ** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ** DEALINGS IN THE SOFTWARE. ** -LICENSE-END- */ /* DeckLinkAPIDispatch.cpp */ #include "DeckLinkAPI.h" #include #if BLACKMAGIC_DECKLINK_API_MAGIC != 1 #error The DeckLink API version of DeckLinkAPIDispatch.cpp is not the same version as DeckLinkAPI.h #endif #define kDeckLinkAPI_BundlePath "/Library/Application Support/Blackmagic Design/Blackmagic DeckLink/DeckLinkAPI.bundle" typedef IDeckLinkIterator* (*CreateIteratorFunc)(void); typedef IDeckLinkAPIInformation* (*CreateAPIInformationFunc)(void); typedef IDeckLinkGLScreenPreviewHelper* (*CreateOpenGLScreenPreviewHelperFunc)(void); typedef IDeckLinkCocoaScreenPreviewCallback* (*CreateCocoaScreenPreviewFunc)(void*); typedef IDeckLinkVideoConversion* (*CreateVideoConversionInstanceFunc)(void); static pthread_once_t gDeckLinkOnceControl = PTHREAD_ONCE_INIT; static CFBundleRef gBundleRef = NULL; static CreateIteratorFunc gCreateIteratorFunc = NULL; static CreateAPIInformationFunc gCreateAPIInformationFunc = NULL; static CreateOpenGLScreenPreviewHelperFunc gCreateOpenGLPreviewFunc = NULL; static CreateCocoaScreenPreviewFunc gCreateCocoaPreviewFunc = NULL; static CreateVideoConversionInstanceFunc gCreateVideoConversionFunc = NULL; void InitDeckLinkAPI (void) { CFURLRef bundleURL; bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR(kDeckLinkAPI_BundlePath), kCFURLPOSIXPathStyle, true); if (bundleURL != NULL) { gBundleRef = CFBundleCreate(kCFAllocatorDefault, bundleURL); if (gBundleRef != NULL) { gCreateIteratorFunc = (CreateIteratorFunc)CFBundleGetFunctionPointerForName(gBundleRef, CFSTR("CreateDeckLinkIteratorInstance_0001")); gCreateAPIInformationFunc = (CreateAPIInformationFunc)CFBundleGetFunctionPointerForName(gBundleRef, CFSTR("CreateDeckLinkAPIInformationInstance_0001")); gCreateOpenGLPreviewFunc = (CreateOpenGLScreenPreviewHelperFunc)CFBundleGetFunctionPointerForName(gBundleRef, CFSTR("CreateOpenGLScreenPreviewHelper_0001")); gCreateCocoaPreviewFunc = (CreateCocoaScreenPreviewFunc)CFBundleGetFunctionPointerForName(gBundleRef, CFSTR("CreateCocoaScreenPreview_0001")); gCreateVideoConversionFunc = (CreateVideoConversionInstanceFunc)CFBundleGetFunctionPointerForName(gBundleRef, CFSTR("CreateVideoConversionInstance_0001")); } CFRelease(bundleURL); } } bool IsDeckLinkAPIPresent (void) { // If the DeckLink API bundle was successfully loaded, return this knowledge to the caller if (gBundleRef != NULL) return true; return false; } IDeckLinkIterator* CreateDeckLinkIteratorInstance (void) { pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); if (gCreateIteratorFunc == NULL) return NULL; return gCreateIteratorFunc(); } IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance (void) { pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); if (gCreateAPIInformationFunc == NULL) return NULL; return gCreateAPIInformationFunc(); } IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper (void) { pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); if (gCreateOpenGLPreviewFunc == NULL) return NULL; return gCreateOpenGLPreviewFunc(); } IDeckLinkCocoaScreenPreviewCallback* CreateCocoaScreenPreview (void* parentView) { pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); if (gCreateCocoaPreviewFunc == NULL) return NULL; return gCreateCocoaPreviewFunc(parentView); } IDeckLinkVideoConversion* CreateVideoConversionInstance (void) { pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); if (gCreateVideoConversionFunc == NULL) return NULL; return gCreateVideoConversionFunc(); } mlt-0.9.0/src/modules/decklink/linux/000077500000000000000000000000001215300731300174715ustar00rootroot00000000000000mlt-0.9.0/src/modules/decklink/linux/DeckLinkAPI.h000066400000000000000000001441111215300731300216620ustar00rootroot00000000000000/* -LICENSE-START- ** Copyright (c) 2009 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by ** this license (the "Software") to use, reproduce, display, distribute, ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: ** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. ** ** 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT ** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE ** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ** DEALINGS IN THE SOFTWARE. ** -LICENSE-END- */ /* DeckLinkAPI.h */ #ifndef __DeckLink_API_h__ #define __DeckLink_API_h__ #include #include "LinuxCOM.h" #define BLACKMAGIC_DECKLINK_API_MAGIC 1 // Type Declarations typedef int64_t BMDTimeValue; typedef int64_t BMDTimeScale; typedef uint32_t BMDTimecodeBCD; typedef uint32_t BMDTimecodeUserBits; // Interface ID Declarations #define IID_IDeckLinkVideoOutputCallback /* 20AA5225-1958-47CB-820B-80A8D521A6EE */ (REFIID){0x20,0xAA,0x52,0x25,0x19,0x58,0x47,0xCB,0x82,0x0B,0x80,0xA8,0xD5,0x21,0xA6,0xEE} #define IID_IDeckLinkInputCallback /* DD04E5EC-7415-42AB-AE4A-E80C4DFC044A */ (REFIID){0xDD,0x04,0xE5,0xEC,0x74,0x15,0x42,0xAB,0xAE,0x4A,0xE8,0x0C,0x4D,0xFC,0x04,0x4A} #define IID_IDeckLinkMemoryAllocator /* B36EB6E7-9D29-4AA8-92EF-843B87A289E8 */ (REFIID){0xB3,0x6E,0xB6,0xE7,0x9D,0x29,0x4A,0xA8,0x92,0xEF,0x84,0x3B,0x87,0xA2,0x89,0xE8} #define IID_IDeckLinkAudioOutputCallback /* 403C681B-7F46-4A12-B993-2BB127084EE6 */ (REFIID){0x40,0x3C,0x68,0x1B,0x7F,0x46,0x4A,0x12,0xB9,0x93,0x2B,0xB1,0x27,0x08,0x4E,0xE6} #define IID_IDeckLinkIterator /* 74E936FC-CC28-4A67-81A0-1E94E52D4E69 */ (REFIID){0x74,0xE9,0x36,0xFC,0xCC,0x28,0x4A,0x67,0x81,0xA0,0x1E,0x94,0xE5,0x2D,0x4E,0x69} #define IID_IDeckLinkAPIInformation /* 7BEA3C68-730D-4322-AF34-8A7152B532A4 */ (REFIID){0x7B,0xEA,0x3C,0x68,0x73,0x0D,0x43,0x22,0xAF,0x34,0x8A,0x71,0x52,0xB5,0x32,0xA4} #define IID_IDeckLinkDisplayModeIterator /* 9C88499F-F601-4021-B80B-032E4EB41C35 */ (REFIID){0x9C,0x88,0x49,0x9F,0xF6,0x01,0x40,0x21,0xB8,0x0B,0x03,0x2E,0x4E,0xB4,0x1C,0x35} #define IID_IDeckLinkDisplayMode /* 3EB2C1AB-0A3D-4523-A3AD-F40D7FB14E78 */ (REFIID){0x3E,0xB2,0xC1,0xAB,0x0A,0x3D,0x45,0x23,0xA3,0xAD,0xF4,0x0D,0x7F,0xB1,0x4E,0x78} #define IID_IDeckLink /* 62BFF75D-6569-4E55-8D4D-66AA03829ABC */ (REFIID){0x62,0xBF,0xF7,0x5D,0x65,0x69,0x4E,0x55,0x8D,0x4D,0x66,0xAA,0x03,0x82,0x9A,0xBC} #define IID_IDeckLinkOutput /* A3EF0963-0862-44ED-92A9-EE89ABF431C7 */ (REFIID){0xA3,0xEF,0x09,0x63,0x08,0x62,0x44,0xED,0x92,0xA9,0xEE,0x89,0xAB,0xF4,0x31,0xC7} #define IID_IDeckLinkInput /* 6D40EF78-28B9-4E21-990D-95BB7750A04F */ (REFIID){0x6D,0x40,0xEF,0x78,0x28,0xB9,0x4E,0x21,0x99,0x0D,0x95,0xBB,0x77,0x50,0xA0,0x4F} #define IID_IDeckLinkTimecode /* BC6CFBD3-8317-4325-AC1C-1216391E9340 */ (REFIID){0xBC,0x6C,0xFB,0xD3,0x83,0x17,0x43,0x25,0xAC,0x1C,0x12,0x16,0x39,0x1E,0x93,0x40} #define IID_IDeckLinkVideoFrame /* 3F716FE0-F023-4111-BE5D-EF4414C05B17 */ (REFIID){0x3F,0x71,0x6F,0xE0,0xF0,0x23,0x41,0x11,0xBE,0x5D,0xEF,0x44,0x14,0xC0,0x5B,0x17} #define IID_IDeckLinkMutableVideoFrame /* 69E2639F-40DA-4E19-B6F2-20ACE815C390 */ (REFIID){0x69,0xE2,0x63,0x9F,0x40,0xDA,0x4E,0x19,0xB6,0xF2,0x20,0xAC,0xE8,0x15,0xC3,0x90} #define IID_IDeckLinkVideoFrame3DExtensions /* DA0F7E4A-EDC7-48A8-9CDD-2DB51C729CD7 */ (REFIID){0xDA,0x0F,0x7E,0x4A,0xED,0xC7,0x48,0xA8,0x9C,0xDD,0x2D,0xB5,0x1C,0x72,0x9C,0xD7} #define IID_IDeckLinkVideoInputFrame /* 05CFE374-537C-4094-9A57-680525118F44 */ (REFIID){0x05,0xCF,0xE3,0x74,0x53,0x7C,0x40,0x94,0x9A,0x57,0x68,0x05,0x25,0x11,0x8F,0x44} #define IID_IDeckLinkVideoFrameAncillary /* 732E723C-D1A4-4E29-9E8E-4A88797A0004 */ (REFIID){0x73,0x2E,0x72,0x3C,0xD1,0xA4,0x4E,0x29,0x9E,0x8E,0x4A,0x88,0x79,0x7A,0x00,0x04} #define IID_IDeckLinkAudioInputPacket /* E43D5870-2894-11DE-8C30-0800200C9A66 */ (REFIID){0xE4,0x3D,0x58,0x70,0x28,0x94,0x11,0xDE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66} #define IID_IDeckLinkScreenPreviewCallback /* B1D3F49A-85FE-4C5D-95C8-0B5D5DCCD438 */ (REFIID){0xB1,0xD3,0xF4,0x9A,0x85,0xFE,0x4C,0x5D,0x95,0xC8,0x0B,0x5D,0x5D,0xCC,0xD4,0x38} #define IID_IDeckLinkGLScreenPreviewHelper /* 504E2209-CAC7-4C1A-9FB4-C5BB6274D22F */ (REFIID){0x50,0x4E,0x22,0x09,0xCA,0xC7,0x4C,0x1A,0x9F,0xB4,0xC5,0xBB,0x62,0x74,0xD2,0x2F} #define IID_IDeckLinkConfiguration /* C679A35B-610C-4D09-B748-1D0478100FC0 */ (REFIID){0xC6,0x79,0xA3,0x5B,0x61,0x0C,0x4D,0x09,0xB7,0x48,0x1D,0x04,0x78,0x10,0x0F,0xC0} #define IID_IDeckLinkAttributes /* ABC11843-D966-44CB-96E2-A1CB5D3135C4 */ (REFIID){0xAB,0xC1,0x18,0x43,0xD9,0x66,0x44,0xCB,0x96,0xE2,0xA1,0xCB,0x5D,0x31,0x35,0xC4} #define IID_IDeckLinkKeyer /* 89AFCAF5-65F8-421E-98F7-96FE5F5BFBA3 */ (REFIID){0x89,0xAF,0xCA,0xF5,0x65,0xF8,0x42,0x1E,0x98,0xF7,0x96,0xFE,0x5F,0x5B,0xFB,0xA3} #define IID_IDeckLinkVideoConversion /* 3BBCB8A2-DA2C-42D9-B5D8-88083644E99A */ (REFIID){0x3B,0xBC,0xB8,0xA2,0xDA,0x2C,0x42,0xD9,0xB5,0xD8,0x88,0x08,0x36,0x44,0xE9,0x9A} #define IID_IDeckLinkDeckControlStatusCallback /* E5F693C1-4283-4716-B18F-C1431521955B */ (REFIID){0xE5,0xF6,0x93,0xC1,0x42,0x83,0x47,0x16,0xB1,0x8F,0xC1,0x43,0x15,0x21,0x95,0x5B} #define IID_IDeckLinkDeckControl /* A4D81043-0619-42B7-8ED6-602D29041DF7 */ (REFIID){0xA4,0xD8,0x10,0x43,0x06,0x19,0x42,0xB7,0x8E,0xD6,0x60,0x2D,0x29,0x04,0x1D,0xF7} /* Enum BMDDisplayMode - Video display modes */ typedef uint32_t BMDDisplayMode; enum _BMDDisplayMode { /* SD Modes */ bmdModeNTSC = /* 'ntsc' */ 0x6E747363, bmdModeNTSC2398 = /* 'nt23' */ 0x6E743233, // 3:2 pulldown bmdModePAL = /* 'pal ' */ 0x70616C20, /* HD 1080 Modes */ bmdModeHD1080p2398 = /* '23ps' */ 0x32337073, bmdModeHD1080p24 = /* '24ps' */ 0x32347073, bmdModeHD1080p25 = /* 'Hp25' */ 0x48703235, bmdModeHD1080p2997 = /* 'Hp29' */ 0x48703239, bmdModeHD1080p30 = /* 'Hp30' */ 0x48703330, bmdModeHD1080i50 = /* 'Hi50' */ 0x48693530, bmdModeHD1080i5994 = /* 'Hi59' */ 0x48693539, bmdModeHD1080i6000 = /* 'Hi60' */ 0x48693630, // N.B. This _really_ is 60.00 Hz. bmdModeHD1080p50 = /* 'Hp50' */ 0x48703530, bmdModeHD1080p5994 = /* 'Hp59' */ 0x48703539, bmdModeHD1080p6000 = /* 'Hp60' */ 0x48703630, // N.B. This _really_ is 60.00 Hz. /* HD 720 Modes */ bmdModeHD720p50 = /* 'hp50' */ 0x68703530, bmdModeHD720p5994 = /* 'hp59' */ 0x68703539, bmdModeHD720p60 = /* 'hp60' */ 0x68703630, /* 2k Modes */ bmdMode2k2398 = /* '2k23' */ 0x326B3233, bmdMode2k24 = /* '2k24' */ 0x326B3234, bmdMode2k25 = /* '2k25' */ 0x326B3235 }; /* Enum BMDFieldDominance - Video field dominance */ typedef uint32_t BMDFieldDominance; enum _BMDFieldDominance { bmdUnknownFieldDominance = 0, bmdLowerFieldFirst = /* 'lowr' */ 0x6C6F7772, bmdUpperFieldFirst = /* 'uppr' */ 0x75707072, bmdProgressiveFrame = /* 'prog' */ 0x70726F67, bmdProgressiveSegmentedFrame = /* 'psf ' */ 0x70736620 }; /* Enum BMDPixelFormat - Video pixel formats supported for output/input */ typedef uint32_t BMDPixelFormat; enum _BMDPixelFormat { bmdFormat8BitYUV = /* '2vuy' */ 0x32767579, bmdFormat10BitYUV = /* 'v210' */ 0x76323130, bmdFormat8BitARGB = 32, bmdFormat8BitBGRA = /* 'BGRA' */ 0x42475241, bmdFormat10BitRGB = /* 'r210' */ 0x72323130 // Big-endian RGB 10-bit per component with SMPTE video levels (64-960). Packed as 2:10:10:10 }; /* Enum BMDDisplayModeFlags - Flags to describe the characteristics of an IDeckLinkDisplayMode. */ typedef uint32_t BMDDisplayModeFlags; enum _BMDDisplayModeFlags { bmdDisplayModeSupports3D = 1 << 0, bmdDisplayModeColorspaceRec601 = 1 << 1, bmdDisplayModeColorspaceRec709 = 1 << 2 }; /* Enum BMDVideoOutputFlags - Flags to control the output of ancillary data along with video. */ typedef uint32_t BMDVideoOutputFlags; enum _BMDVideoOutputFlags { bmdVideoOutputFlagDefault = 0, bmdVideoOutputVANC = 1 << 0, bmdVideoOutputVITC = 1 << 1, bmdVideoOutputRP188 = 1 << 2, bmdVideoOutputDualStream3D = 1 << 4 }; /* Enum BMDFrameFlags - Frame flags */ typedef uint32_t BMDFrameFlags; enum _BMDFrameFlags { bmdFrameFlagDefault = 0, bmdFrameFlagFlipVertical = 1 << 0, /* Flags that are applicable only to instances of IDeckLinkVideoInputFrame */ bmdFrameHasNoInputSource = 1 << 31 }; /* Enum BMDVideoInputFlags - Flags applicable to video input */ typedef uint32_t BMDVideoInputFlags; enum _BMDVideoInputFlags { bmdVideoInputFlagDefault = 0, bmdVideoInputEnableFormatDetection = 1 << 0, bmdVideoInputDualStream3D = 1 << 1 }; /* Enum BMDVideoInputFormatChangedEvents - Bitmask passed to the VideoInputFormatChanged notification to identify the properties of the input signal that have changed */ typedef uint32_t BMDVideoInputFormatChangedEvents; enum _BMDVideoInputFormatChangedEvents { bmdVideoInputDisplayModeChanged = 1 << 0, bmdVideoInputFieldDominanceChanged = 1 << 1, bmdVideoInputColorspaceChanged = 1 << 2 }; /* Enum BMDDetectedVideoInputFormatFlags - Flags passed to the VideoInputFormatChanged notification to describe the detected video input signal */ typedef uint32_t BMDDetectedVideoInputFormatFlags; enum _BMDDetectedVideoInputFormatFlags { bmdDetectedVideoInputYCbCr422 = 1 << 0, bmdDetectedVideoInputRGB444 = 1 << 1 }; /* Enum BMDOutputFrameCompletionResult - Frame Completion Callback */ typedef uint32_t BMDOutputFrameCompletionResult; enum _BMDOutputFrameCompletionResult { bmdOutputFrameCompleted, bmdOutputFrameDisplayedLate, bmdOutputFrameDropped, bmdOutputFrameFlushed }; /* Enum BMDReferenceStatus - GenLock input status */ typedef uint32_t BMDReferenceStatus; enum _BMDReferenceStatus { bmdReferenceNotSupportedByHardware = 1 << 0, bmdReferenceLocked = 1 << 1 }; /* Enum BMDAudioSampleRate - Audio sample rates supported for output/input */ typedef uint32_t BMDAudioSampleRate; enum _BMDAudioSampleRate { bmdAudioSampleRate48kHz = 48000 }; /* Enum BMDAudioSampleType - Audio sample sizes supported for output/input */ typedef uint32_t BMDAudioSampleType; enum _BMDAudioSampleType { bmdAudioSampleType16bitInteger = 16, bmdAudioSampleType32bitInteger = 32 }; /* Enum BMDAudioOutputStreamType - Audio output stream type */ typedef uint32_t BMDAudioOutputStreamType; enum _BMDAudioOutputStreamType { bmdAudioOutputStreamContinuous, bmdAudioOutputStreamContinuousDontResample, bmdAudioOutputStreamTimestamped }; /* Enum BMDDisplayModeSupport - Output mode supported flags */ typedef uint32_t BMDDisplayModeSupport; enum _BMDDisplayModeSupport { bmdDisplayModeNotSupported = 0, bmdDisplayModeSupported, bmdDisplayModeSupportedWithConversion }; /* Enum BMDTimecodeFormat - Timecode formats for frame metadata */ typedef uint32_t BMDTimecodeFormat; enum _BMDTimecodeFormat { bmdTimecodeRP188 = /* 'rp18' */ 0x72703138, bmdTimecodeVITC = /* 'vitc' */ 0x76697463, bmdTimecodeSerial = /* 'seri' */ 0x73657269 }; /* Enum BMDTimecodeFlags - Timecode flags */ typedef uint32_t BMDTimecodeFlags; enum _BMDTimecodeFlags { bmdTimecodeFlagDefault = 0, bmdTimecodeIsDropFrame = 1 << 0 }; /* Enum BMDVideoConnection - Video connection types */ typedef uint32_t BMDVideoConnection; enum _BMDVideoConnection { bmdVideoConnectionSDI = 1 << 0, bmdVideoConnectionHDMI = 1 << 1, bmdVideoConnectionOpticalSDI = 1 << 2, bmdVideoConnectionComponent = 1 << 3, bmdVideoConnectionComposite = 1 << 4, bmdVideoConnectionSVideo = 1 << 5 }; /* Enum BMDAnalogVideoFlags - Analog video display flags */ typedef uint32_t BMDAnalogVideoFlags; enum _BMDAnalogVideoFlags { bmdAnalogVideoFlagCompositeSetup75 = 1 << 0, bmdAnalogVideoFlagComponentBetacamLevels = 1 << 1 }; /* Enum BMDAudioConnection - Audio connection types */ typedef uint32_t BMDAudioConnection; enum _BMDAudioConnection { bmdAudioConnectionEmbedded = /* 'embd' */ 0x656D6264, bmdAudioConnectionAESEBU = /* 'aes ' */ 0x61657320, bmdAudioConnectionAnalog = /* 'anlg' */ 0x616E6C67 }; /* Enum BMDAudioOutputAnalogAESSwitch - Audio output Analog/AESEBU switch */ typedef uint32_t BMDAudioOutputAnalogAESSwitch; enum _BMDAudioOutputAnalogAESSwitch { bmdAudioOutputSwitchAESEBU = /* 'aes ' */ 0x61657320, bmdAudioOutputSwitchAnalog = /* 'anlg' */ 0x616E6C67 }; /* Enum BMDVideoOutputConversionMode - Video/audio conversion mode */ typedef uint32_t BMDVideoOutputConversionMode; enum _BMDVideoOutputConversionMode { bmdNoVideoOutputConversion = /* 'none' */ 0x6E6F6E65, bmdVideoOutputLetterboxDownconversion = /* 'ltbx' */ 0x6C746278, bmdVideoOutputAnamorphicDownconversion = /* 'amph' */ 0x616D7068, bmdVideoOutputHD720toHD1080Conversion = /* '720c' */ 0x37323063, bmdVideoOutputHardwareLetterboxDownconversion = /* 'HWlb' */ 0x48576C62, bmdVideoOutputHardwareAnamorphicDownconversion = /* 'HWam' */ 0x4857616D, bmdVideoOutputHardwareCenterCutDownconversion = /* 'HWcc' */ 0x48576363, bmdVideoOutputHardware720p1080pCrossconversion = /* 'xcap' */ 0x78636170, bmdVideoOutputHardwareAnamorphic720pUpconversion = /* 'ua7p' */ 0x75613770, bmdVideoOutputHardwareAnamorphic1080iUpconversion = /* 'ua1i' */ 0x75613169, bmdVideoOutputHardwareAnamorphic149To720pUpconversion = /* 'u47p' */ 0x75343770, bmdVideoOutputHardwareAnamorphic149To1080iUpconversion = /* 'u41i' */ 0x75343169, bmdVideoOutputHardwarePillarbox720pUpconversion = /* 'up7p' */ 0x75703770, bmdVideoOutputHardwarePillarbox1080iUpconversion = /* 'up1i' */ 0x75703169 }; /* Enum BMDVideoInputConversionMode - Video input conversion mode */ typedef uint32_t BMDVideoInputConversionMode; enum _BMDVideoInputConversionMode { bmdNoVideoInputConversion = /* 'none' */ 0x6E6F6E65, bmdVideoInputLetterboxDownconversionFromHD1080 = /* '10lb' */ 0x31306C62, bmdVideoInputAnamorphicDownconversionFromHD1080 = /* '10am' */ 0x3130616D, bmdVideoInputLetterboxDownconversionFromHD720 = /* '72lb' */ 0x37326C62, bmdVideoInputAnamorphicDownconversionFromHD720 = /* '72am' */ 0x3732616D, bmdVideoInputLetterboxUpconversion = /* 'lbup' */ 0x6C627570, bmdVideoInputAnamorphicUpconversion = /* 'amup' */ 0x616D7570 }; /* Enum BMDVideo3DPackingFormat - Video 3D packing format */ typedef uint32_t BMDVideo3DPackingFormat; enum _BMDVideo3DPackingFormat { bmdVideo3DPackingSidebySideHalf = /* 'sbsh' */ 0x73627368, bmdVideo3DPackingLinebyLine = /* 'lbyl' */ 0x6C62796C, bmdVideo3DPackingTopAndBottom = /* 'tabo' */ 0x7461626F, bmdVideo3DPackingLeftOnly = /* 'left' */ 0x6C656674, bmdVideo3DPackingRightOnly = /* 'righ' */ 0x72696768 }; /* Enum BMDDeckLinkConfigurationID - DeckLink Configuration ID */ typedef uint32_t BMDDeckLinkConfigurationID; enum _BMDDeckLinkConfigurationID { /* Video Input/Output Flags */ bmdDeckLinkConfigUse1080pNotPsF = /* 'fpro' */ 0x6670726F, /* Video Input/Output Integers */ bmdDeckLinkConfigHDMI3DPackingFormat = /* '3dpf' */ 0x33647066, /* Audio Input/Output Flags */ bmdDeckLinkConfigAnalogAudioConsumerLevels = /* 'aacl' */ 0x6161636C, /* Video output flags */ bmdDeckLinkConfigFieldFlickerRemoval = /* 'fdfr' */ 0x66646672, bmdDeckLinkConfigHD1080p24ToHD1080i5994Conversion = /* 'to59' */ 0x746F3539, bmdDeckLinkConfig444SDIVideoOutput = /* '444o' */ 0x3434346F, bmdDeckLinkConfig3GBpsVideoOutput = /* '3gbs' */ 0x33676273, bmdDeckLinkConfigBlackVideoOutputDuringCapture = /* 'bvoc' */ 0x62766F63, bmdDeckLinkConfigLowLatencyVideoOutput = /* 'llvo' */ 0x6C6C766F, /* Video Output Integers */ bmdDeckLinkConfigVideoOutputConnection = /* 'vocn' */ 0x766F636E, bmdDeckLinkConfigVideoOutputConversionMode = /* 'vocm' */ 0x766F636D, bmdDeckLinkConfigAnalogVideoOutputFlags = /* 'avof' */ 0x61766F66, bmdDeckLinkConfigReferenceInputTimingOffset = /* 'glot' */ 0x676C6F74, /* Video Input Integers */ bmdDeckLinkConfigVideoInputConnection = /* 'vicn' */ 0x7669636E, bmdDeckLinkConfigAnalogVideoInputFlags = /* 'avif' */ 0x61766966, bmdDeckLinkConfigVideoInputConversionMode = /* 'vicm' */ 0x7669636D, bmdDeckLinkConfig32PulldownSequenceInitialTimecodeFrame = /* 'pdif' */ 0x70646966, bmdDeckLinkConfigVANCSourceLine1Mapping = /* 'vsl1' */ 0x76736C31, bmdDeckLinkConfigVANCSourceLine2Mapping = /* 'vsl2' */ 0x76736C32, bmdDeckLinkConfigVANCSourceLine3Mapping = /* 'vsl3' */ 0x76736C33, /* Audio Input Integers */ bmdDeckLinkConfigAudioInputConnection = /* 'aicn' */ 0x6169636E, /* Audio Input Floats */ bmdDeckLinkConfigAnalogAudioInputScaleChannel1 = /* 'ais1' */ 0x61697331, bmdDeckLinkConfigAnalogAudioInputScaleChannel2 = /* 'ais2' */ 0x61697332, bmdDeckLinkConfigAnalogAudioInputScaleChannel3 = /* 'ais3' */ 0x61697333, bmdDeckLinkConfigAnalogAudioInputScaleChannel4 = /* 'ais4' */ 0x61697334, bmdDeckLinkConfigDigitalAudioInputScale = /* 'dais' */ 0x64616973, /* Audio Output Integers */ bmdDeckLinkConfigAudioOutputAESAnalogSwitch = /* 'aoaa' */ 0x616F6161, /* Audio Output Floats */ bmdDeckLinkConfigAnalogAudioOutputScaleChannel1 = /* 'aos1' */ 0x616F7331, bmdDeckLinkConfigAnalogAudioOutputScaleChannel2 = /* 'aos2' */ 0x616F7332, bmdDeckLinkConfigAnalogAudioOutputScaleChannel3 = /* 'aos3' */ 0x616F7333, bmdDeckLinkConfigAnalogAudioOutputScaleChannel4 = /* 'aos4' */ 0x616F7334, bmdDeckLinkConfigDigitalAudioOutputScale = /* 'daos' */ 0x64616F73 }; /* Enum BMDDeckLinkAttributeID - DeckLink Attribute ID */ typedef uint32_t BMDDeckLinkAttributeID; enum _BMDDeckLinkAttributeID { /* Flags */ BMDDeckLinkSupportsInternalKeying = /* 'keyi' */ 0x6B657969, BMDDeckLinkSupportsExternalKeying = /* 'keye' */ 0x6B657965, BMDDeckLinkSupportsHDKeying = /* 'keyh' */ 0x6B657968, BMDDeckLinkSupportsInputFormatDetection = /* 'infd' */ 0x696E6664, BMDDeckLinkHasReferenceInput = /* 'hrin' */ 0x6872696E, BMDDeckLinkHasSerialPort = /* 'hspt' */ 0x68737074, /* Integers */ BMDDeckLinkMaximumAudioChannels = /* 'mach' */ 0x6D616368, BMDDeckLinkNumberOfSubDevices = /* 'nsbd' */ 0x6E736264, BMDDeckLinkSubDeviceIndex = /* 'subi' */ 0x73756269, BMDDeckLinkVideoOutputConnections = /* 'vocn' */ 0x766F636E, BMDDeckLinkVideoInputConnections = /* 'vicn' */ 0x7669636E, /* Strings */ BMDDeckLinkSerialPortDeviceName = /* 'slpn' */ 0x736C706E }; /* Enum BMDDeckLinkAPIInformationID - DeckLinkAPI information ID */ typedef uint32_t BMDDeckLinkAPIInformationID; enum _BMDDeckLinkAPIInformationID { BMDDeckLinkAPIVersion = /* 'vers' */ 0x76657273 }; /* Enum BMDDeckControlMode - DeckControl mode */ typedef uint32_t BMDDeckControlMode; enum _BMDDeckControlMode { bmdDeckControlNotOpened = /* 'ntop' */ 0x6E746F70, bmdDeckControlVTRControlMode = /* 'vtrc' */ 0x76747263, bmdDeckControlExportMode = /* 'expm' */ 0x6578706D, bmdDeckControlCaptureMode = /* 'capm' */ 0x6361706D }; /* Enum BMDDeckControlEvent - DeckControl event */ typedef uint32_t BMDDeckControlEvent; enum _BMDDeckControlEvent { bmdDeckControlAbortedEvent = /* 'abte' */ 0x61627465, // This event is triggered when a capture or edit-to-tape operation is aborted. /* Export-To-Tape events */ bmdDeckControlPrepareForExportEvent = /* 'pfee' */ 0x70666565, // This event is triggered a few frames before reaching the in-point. IDeckLinkInput::StartScheduledPlayback() should be called at this point. bmdDeckControlExportCompleteEvent = /* 'exce' */ 0x65786365, // This event is triggered a few frames after reaching the out-point. At this point, it is safe to stop playback. /* Capture events */ bmdDeckControlPrepareForCaptureEvent = /* 'pfce' */ 0x70666365, // This event is triggered a few frames before reaching the in-point. The serial timecode attached to IDeckLinkVideoInputFrames is now valid. bmdDeckControlCaptureCompleteEvent = /* 'ccev' */ 0x63636576 // This event is triggered a few frames after reaching the out-point. }; /* Enum BMDDeckControlVTRControlState - VTR Control state */ typedef uint32_t BMDDeckControlVTRControlState; enum _BMDDeckControlVTRControlState { bmdDeckControlNotInVTRControlMode = /* 'nvcm' */ 0x6E76636D, bmdDeckControlVTRControlPlaying = /* 'vtrp' */ 0x76747270, bmdDeckControlVTRControlRecording = /* 'vtrr' */ 0x76747272, bmdDeckControlVTRControlStill = /* 'vtra' */ 0x76747261, bmdDeckControlVTRControlSeeking = /* 'vtrs' */ 0x76747273, bmdDeckControlVTRControlStopped = /* 'vtro' */ 0x7674726F }; /* Enum BMDDeckControlStatusFlags - Deck Control status flags */ typedef uint32_t BMDDeckControlStatusFlags; enum _BMDDeckControlStatusFlags { bmdDeckControlStatusDeckConnected = 1 << 0, bmdDeckControlStatusRemoteMode = 1 << 1, bmdDeckControlStatusRecordInhibited = 1 << 2, bmdDeckControlStatusCassetteOut = 1 << 3 }; /* Enum BMDDeckControlExportModeOpsFlags - Export mode flags */ typedef uint32_t BMDDeckControlExportModeOpsFlags; enum _BMDDeckControlExportModeOpsFlags { bmdDeckControlExportModeInsertVideo = 1 << 0, bmdDeckControlExportModeInsertAudio1 = 1 << 1, bmdDeckControlExportModeInsertAudio2 = 1 << 2, bmdDeckControlExportModeInsertAudio3 = 1 << 3, bmdDeckControlExportModeInsertAudio4 = 1 << 4, bmdDeckControlExportModeInsertAudio5 = 1 << 5, bmdDeckControlExportModeInsertAudio6 = 1 << 6, bmdDeckControlExportModeInsertAudio7 = 1 << 7, bmdDeckControlExportModeInsertAudio8 = 1 << 8, bmdDeckControlExportModeInsertAudio9 = 1 << 9, bmdDeckControlExportModeInsertAudio10 = 1 << 10, bmdDeckControlExportModeInsertAudio11 = 1 << 11, bmdDeckControlExportModeInsertAudio12 = 1 << 12, bmdDeckControlExportModeInsertTimeCode = 1 << 13, bmdDeckControlExportModeInsertAssemble = 1 << 14, bmdDeckControlExportModeInsertPreview = 1 << 15, bmdDeckControlUseManualExport = 1 << 16 }; /* Enum BMDDeckControlError - Deck Control error */ typedef uint32_t BMDDeckControlError; enum _BMDDeckControlError { bmdDeckControlNoError = /* 'noer' */ 0x6E6F6572, bmdDeckControlModeError = /* 'moer' */ 0x6D6F6572, bmdDeckControlMissedInPointError = /* 'mier' */ 0x6D696572, bmdDeckControlDeckTimeoutError = /* 'dter' */ 0x64746572, bmdDeckControlCommandFailedError = /* 'cfer' */ 0x63666572, bmdDeckControlDeviceAlreadyOpenedError = /* 'dalo' */ 0x64616C6F, bmdDeckControlFailedToOpenDeviceError = /* 'fder' */ 0x66646572, bmdDeckControlInLocalModeError = /* 'lmer' */ 0x6C6D6572, bmdDeckControlEndOfTapeError = /* 'eter' */ 0x65746572, bmdDeckControlUserAbortError = /* 'uaer' */ 0x75616572, bmdDeckControlNoTapeInDeckError = /* 'nter' */ 0x6E746572, bmdDeckControlNoVideoFromCardError = /* 'nvfc' */ 0x6E766663, bmdDeckControlNoCommunicationError = /* 'ncom' */ 0x6E636F6D, bmdDeckControlUnknownError = /* 'uner' */ 0x756E6572 }; /* Enum BMD3DPreviewFormat - Linked Frame preview format */ typedef uint32_t BMD3DPreviewFormat; enum _BMD3DPreviewFormat { bmd3DPreviewFormatDefault = /* 'defa' */ 0x64656661, bmd3DPreviewFormatLeftOnly = /* 'left' */ 0x6C656674, bmd3DPreviewFormatRightOnly = /* 'righ' */ 0x72696768, bmd3DPreviewFormatSideBySide = /* 'side' */ 0x73696465, bmd3DPreviewFormatTopBottom = /* 'topb' */ 0x746F7062 }; #if defined(__cplusplus) // Forward Declarations class IDeckLinkVideoOutputCallback; class IDeckLinkInputCallback; class IDeckLinkMemoryAllocator; class IDeckLinkAudioOutputCallback; class IDeckLinkIterator; class IDeckLinkAPIInformation; class IDeckLinkDisplayModeIterator; class IDeckLinkDisplayMode; class IDeckLink; class IDeckLinkOutput; class IDeckLinkInput; class IDeckLinkTimecode; class IDeckLinkVideoFrame; class IDeckLinkMutableVideoFrame; class IDeckLinkVideoFrame3DExtensions; class IDeckLinkVideoInputFrame; class IDeckLinkVideoFrameAncillary; class IDeckLinkAudioInputPacket; class IDeckLinkScreenPreviewCallback; class IDeckLinkGLScreenPreviewHelper; class IDeckLinkConfiguration; class IDeckLinkAttributes; class IDeckLinkKeyer; class IDeckLinkVideoConversion; class IDeckLinkDeckControlStatusCallback; class IDeckLinkDeckControl; /* Interface IDeckLinkVideoOutputCallback - Frame completion callback. */ class IDeckLinkVideoOutputCallback : public IUnknown { public: virtual HRESULT ScheduledFrameCompleted (/* in */ IDeckLinkVideoFrame *completedFrame, /* in */ BMDOutputFrameCompletionResult result) = 0; virtual HRESULT ScheduledPlaybackHasStopped (void) = 0; protected: virtual ~IDeckLinkVideoOutputCallback () {}; // call Release method to drop reference count }; /* Interface IDeckLinkInputCallback - Frame arrival callback. */ class IDeckLinkInputCallback : public IUnknown { public: virtual HRESULT VideoInputFormatChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode *newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; virtual HRESULT VideoInputFrameArrived (/* in */ IDeckLinkVideoInputFrame* videoFrame, /* in */ IDeckLinkAudioInputPacket* audioPacket) = 0; protected: virtual ~IDeckLinkInputCallback () {}; // call Release method to drop reference count }; /* Interface IDeckLinkMemoryAllocator - Memory allocator for video frames. */ class IDeckLinkMemoryAllocator : public IUnknown { public: virtual HRESULT AllocateBuffer (/* in */ uint32_t bufferSize, /* out */ void **allocatedBuffer) = 0; virtual HRESULT ReleaseBuffer (/* in */ void *buffer) = 0; virtual HRESULT Commit (void) = 0; virtual HRESULT Decommit (void) = 0; }; /* Interface IDeckLinkAudioOutputCallback - Optional callback to allow audio samples to be pulled as required. */ class IDeckLinkAudioOutputCallback : public IUnknown { public: virtual HRESULT RenderAudioSamples (/* in */ bool preroll) = 0; }; /* Interface IDeckLinkIterator - enumerates installed DeckLink hardware */ class IDeckLinkIterator : public IUnknown { public: virtual HRESULT Next (/* out */ IDeckLink **deckLinkInstance) = 0; }; /* Interface IDeckLinkAPIInformation - DeckLinkAPI attribute interface */ class IDeckLinkAPIInformation : public IUnknown { public: virtual HRESULT GetFlag (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ bool *value) = 0; virtual HRESULT GetInt (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ int64_t *value) = 0; virtual HRESULT GetFloat (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ double *value) = 0; virtual HRESULT GetString (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ const char **value) = 0; protected: virtual ~IDeckLinkAPIInformation () {}; // call Release method to drop reference count }; /* Interface IDeckLinkDisplayModeIterator - enumerates over supported input/output display modes. */ class IDeckLinkDisplayModeIterator : public IUnknown { public: virtual HRESULT Next (/* out */ IDeckLinkDisplayMode **deckLinkDisplayMode) = 0; protected: virtual ~IDeckLinkDisplayModeIterator () {}; // call Release method to drop reference count }; /* Interface IDeckLinkDisplayMode - represents a display mode */ class IDeckLinkDisplayMode : public IUnknown { public: virtual HRESULT GetName (/* out */ const char **name) = 0; virtual BMDDisplayMode GetDisplayMode (void) = 0; virtual long GetWidth (void) = 0; virtual long GetHeight (void) = 0; virtual HRESULT GetFrameRate (/* out */ BMDTimeValue *frameDuration, /* out */ BMDTimeScale *timeScale) = 0; virtual BMDFieldDominance GetFieldDominance (void) = 0; virtual BMDDisplayModeFlags GetFlags (void) = 0; protected: virtual ~IDeckLinkDisplayMode () {}; // call Release method to drop reference count }; /* Interface IDeckLink - represents a DeckLink device */ class IDeckLink : public IUnknown { public: virtual HRESULT GetModelName (/* out */ const char **modelName) = 0; }; /* Interface IDeckLinkOutput - Created by QueryInterface from IDeckLink. */ class IDeckLinkOutput : public IUnknown { public: virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoOutputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; /* Video Output */ virtual HRESULT EnableVideoOutput (/* in */ BMDDisplayMode displayMode, /* in */ BMDVideoOutputFlags flags) = 0; virtual HRESULT DisableVideoOutput (void) = 0; virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame **outFrame) = 0; virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame *theFrame) = 0; virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame *theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0; virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback *theCallback) = 0; virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t *bufferedFrameCount) = 0; /* Audio Output */ virtual HRESULT EnableAudioOutput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount, /* in */ BMDAudioOutputStreamType streamType) = 0; virtual HRESULT DisableAudioOutput (void) = 0; virtual HRESULT WriteAudioSamplesSync (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t *sampleFramesWritten) = 0; virtual HRESULT BeginAudioPreroll (void) = 0; virtual HRESULT EndAudioPreroll (void) = 0; virtual HRESULT ScheduleAudioSamples (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t *sampleFramesWritten) = 0; virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t *bufferedSampleFrameCount) = 0; virtual HRESULT FlushBufferedAudioSamples (void) = 0; virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback *theCallback) = 0; /* Output Control */ virtual HRESULT StartScheduledPlayback (/* in */ BMDTimeValue playbackStartTime, /* in */ BMDTimeScale timeScale, /* in */ double playbackSpeed) = 0; virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue *actualStopTime, /* in */ BMDTimeScale timeScale) = 0; virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool *active) = 0; virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *streamTime, /* out */ double *playbackSpeed) = 0; virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus *referenceStatus) = 0; /* Hardware Timing */ virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; protected: virtual ~IDeckLinkOutput () {}; // call Release method to drop reference count }; /* Interface IDeckLinkInput - Created by QueryInterface from IDeckLink. */ class IDeckLinkInput : public IUnknown { public: virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; /* Video Input */ virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0; virtual HRESULT DisableVideoInput (void) = 0; virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t *availableFrameCount) = 0; /* Audio Input */ virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0; virtual HRESULT DisableAudioInput (void) = 0; virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t *availableSampleFrameCount) = 0; /* Input Control */ virtual HRESULT StartStreams (void) = 0; virtual HRESULT StopStreams (void) = 0; virtual HRESULT PauseStreams (void) = 0; virtual HRESULT FlushStreams (void) = 0; virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback *theCallback) = 0; /* Hardware Timing */ virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; protected: virtual ~IDeckLinkInput () {}; // call Release method to drop reference count }; /* Interface IDeckLinkTimecode - Used for video frame timecode representation. */ class IDeckLinkTimecode : public IUnknown { public: virtual BMDTimecodeBCD GetBCD (void) = 0; virtual HRESULT GetComponents (/* out */ uint8_t *hours, /* out */ uint8_t *minutes, /* out */ uint8_t *seconds, /* out */ uint8_t *frames) = 0; virtual HRESULT GetString (/* out */ const char **timecode) = 0; virtual BMDTimecodeFlags GetFlags (void) = 0; virtual HRESULT GetTimecodeUserBits (/* out */ BMDTimecodeUserBits *userBits) = 0; protected: virtual ~IDeckLinkTimecode () {}; // call Release method to drop reference count }; /* Interface IDeckLinkVideoFrame - Interface to encapsulate a video frame; can be caller-implemented. */ class IDeckLinkVideoFrame : public IUnknown { public: virtual long GetWidth (void) = 0; virtual long GetHeight (void) = 0; virtual long GetRowBytes (void) = 0; virtual BMDPixelFormat GetPixelFormat (void) = 0; virtual BMDFrameFlags GetFlags (void) = 0; virtual HRESULT GetBytes (/* out */ void **buffer) = 0; virtual HRESULT GetTimecode (/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode **timecode) = 0; virtual HRESULT GetAncillaryData (/* out */ IDeckLinkVideoFrameAncillary **ancillary) = 0; protected: virtual ~IDeckLinkVideoFrame () {}; // call Release method to drop reference count }; /* Interface IDeckLinkMutableVideoFrame - Created by IDeckLinkOutput::CreateVideoFrame. */ class IDeckLinkMutableVideoFrame : public IDeckLinkVideoFrame { public: virtual HRESULT SetFlags (/* in */ BMDFrameFlags newFlags) = 0; virtual HRESULT SetTimecode (/* in */ BMDTimecodeFormat format, /* in */ IDeckLinkTimecode *timecode) = 0; virtual HRESULT SetTimecodeFromComponents (/* in */ BMDTimecodeFormat format, /* in */ uint8_t hours, /* in */ uint8_t minutes, /* in */ uint8_t seconds, /* in */ uint8_t frames, /* in */ BMDTimecodeFlags flags) = 0; virtual HRESULT SetAncillaryData (/* in */ IDeckLinkVideoFrameAncillary *ancillary) = 0; virtual HRESULT SetTimecodeUserBits (/* in */ BMDTimecodeFormat format, /* in */ BMDTimecodeUserBits userBits) = 0; protected: virtual ~IDeckLinkMutableVideoFrame () {}; // call Release method to drop reference count }; /* Interface IDeckLinkVideoFrame3DExtensions - Optional interface implemented on IDeckLinkVideoFrame to support 3D frames */ class IDeckLinkVideoFrame3DExtensions : public IUnknown { public: virtual BMDVideo3DPackingFormat Get3DPackingFormat (void) = 0; virtual HRESULT GetFrameForRightEye (/* in */ IDeckLinkVideoFrame* *rightEyeFrame) = 0; protected: virtual ~IDeckLinkVideoFrame3DExtensions () {}; // call Release method to drop reference count }; /* Interface IDeckLinkVideoInputFrame - Provided by the IDeckLinkVideoInput frame arrival callback. */ class IDeckLinkVideoInputFrame : public IDeckLinkVideoFrame { public: virtual HRESULT GetStreamTime (/* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration, /* in */ BMDTimeScale timeScale) = 0; virtual HRESULT GetHardwareReferenceTimestamp (/* in */ BMDTimeScale timeScale, /* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration) = 0; protected: virtual ~IDeckLinkVideoInputFrame () {}; // call Release method to drop reference count }; /* Interface IDeckLinkVideoFrameAncillary - Obtained through QueryInterface() on an IDeckLinkVideoFrame object. */ class IDeckLinkVideoFrameAncillary : public IUnknown { public: virtual HRESULT GetBufferForVerticalBlankingLine (/* in */ uint32_t lineNumber, /* out */ void **buffer) = 0; virtual BMDPixelFormat GetPixelFormat (void) = 0; virtual BMDDisplayMode GetDisplayMode (void) = 0; protected: virtual ~IDeckLinkVideoFrameAncillary () {}; // call Release method to drop reference count }; /* Interface IDeckLinkAudioInputPacket - Provided by the IDeckLinkInput callback. */ class IDeckLinkAudioInputPacket : public IUnknown { public: virtual long GetSampleFrameCount (void) = 0; virtual HRESULT GetBytes (/* out */ void **buffer) = 0; virtual HRESULT GetPacketTime (/* out */ BMDTimeValue *packetTime, /* in */ BMDTimeScale timeScale) = 0; protected: virtual ~IDeckLinkAudioInputPacket () {}; // call Release method to drop reference count }; /* Interface IDeckLinkScreenPreviewCallback - Screen preview callback */ class IDeckLinkScreenPreviewCallback : public IUnknown { public: virtual HRESULT DrawFrame (/* in */ IDeckLinkVideoFrame *theFrame) = 0; protected: virtual ~IDeckLinkScreenPreviewCallback () {}; // call Release method to drop reference count }; /* Interface IDeckLinkGLScreenPreviewHelper - Created with CoCreateInstance(). */ class IDeckLinkGLScreenPreviewHelper : public IUnknown { public: /* Methods must be called with OpenGL context set */ virtual HRESULT InitializeGL (void) = 0; virtual HRESULT PaintGL (void) = 0; virtual HRESULT SetFrame (/* in */ IDeckLinkVideoFrame *theFrame) = 0; virtual HRESULT Set3DPreviewFormat (/* in */ BMD3DPreviewFormat previewFormat) = 0; protected: virtual ~IDeckLinkGLScreenPreviewHelper () {}; // call Release method to drop reference count }; /* Interface IDeckLinkConfiguration - DeckLink Configuration interface */ class IDeckLinkConfiguration : public IUnknown { public: virtual HRESULT SetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ bool value) = 0; virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool *value) = 0; virtual HRESULT SetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ int64_t value) = 0; virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t *value) = 0; virtual HRESULT SetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ double value) = 0; virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double *value) = 0; virtual HRESULT SetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ const char *value) = 0; virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ const char **value) = 0; virtual HRESULT WriteConfigurationToPreferences (void) = 0; protected: virtual ~IDeckLinkConfiguration () {}; // call Release method to drop reference count }; /* Interface IDeckLinkAttributes - DeckLink Attribute interface */ class IDeckLinkAttributes : public IUnknown { public: virtual HRESULT GetFlag (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ bool *value) = 0; virtual HRESULT GetInt (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ int64_t *value) = 0; virtual HRESULT GetFloat (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ double *value) = 0; virtual HRESULT GetString (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ const char **value) = 0; protected: virtual ~IDeckLinkAttributes () {}; // call Release method to drop reference count }; /* Interface IDeckLinkKeyer - DeckLink Keyer interface */ class IDeckLinkKeyer : public IUnknown { public: virtual HRESULT Enable (/* in */ bool isExternal) = 0; virtual HRESULT SetLevel (/* in */ uint8_t level) = 0; virtual HRESULT RampUp (/* in */ uint32_t numberOfFrames) = 0; virtual HRESULT RampDown (/* in */ uint32_t numberOfFrames) = 0; virtual HRESULT Disable (void) = 0; protected: virtual ~IDeckLinkKeyer () {}; // call Release method to drop reference count }; /* Interface IDeckLinkVideoConversion - Created with CoCreateInstance(). */ class IDeckLinkVideoConversion : public IUnknown { public: virtual HRESULT ConvertFrame (/* in */ IDeckLinkVideoFrame* srcFrame, /* in */ IDeckLinkVideoFrame* dstFrame) = 0; protected: virtual ~IDeckLinkVideoConversion () {}; // call Release method to drop reference count }; /* Interface IDeckLinkDeckControlStatusCallback - Deck control state change callback. */ class IDeckLinkDeckControlStatusCallback : public IUnknown { public: virtual HRESULT TimecodeUpdate (/* in */ BMDTimecodeBCD currentTimecode) = 0; virtual HRESULT VTRControlStateChanged (/* in */ BMDDeckControlVTRControlState newState, /* in */ BMDDeckControlError error) = 0; virtual HRESULT DeckControlEventReceived (/* in */ BMDDeckControlEvent event, /* in */ BMDDeckControlError error) = 0; virtual HRESULT DeckControlStatusChanged (/* in */ BMDDeckControlStatusFlags flags, /* in */ uint32_t mask) = 0; protected: virtual ~IDeckLinkDeckControlStatusCallback () {}; // call Release method to drop reference count }; /* Interface IDeckLinkDeckControl - Deck Control main interface */ class IDeckLinkDeckControl : public IUnknown { public: virtual HRESULT Open (/* in */ BMDTimeScale timeScale, /* in */ BMDTimeValue timeValue, /* in */ bool timecodeIsDropFrame, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT Close (/* in */ bool standbyOn) = 0; virtual HRESULT GetCurrentState (/* out */ BMDDeckControlMode *mode, /* out */ BMDDeckControlVTRControlState *vtrControlState, /* out */ BMDDeckControlStatusFlags *flags) = 0; virtual HRESULT SetStandby (/* in */ bool standbyOn) = 0; virtual HRESULT Play (/* out */ BMDDeckControlError *error) = 0; virtual HRESULT Stop (/* out */ BMDDeckControlError *error) = 0; virtual HRESULT TogglePlayStop (/* out */ BMDDeckControlError *error) = 0; virtual HRESULT Eject (/* out */ BMDDeckControlError *error) = 0; virtual HRESULT GoToTimecode (/* in */ BMDTimecodeBCD timecode, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT FastForward (/* in */ bool viewTape, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT Rewind (/* in */ bool viewTape, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT StepForward (/* out */ BMDDeckControlError *error) = 0; virtual HRESULT StepBack (/* out */ BMDDeckControlError *error) = 0; virtual HRESULT Jog (/* in */ double rate, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT Shuttle (/* in */ double rate, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT GetTimecodeString (/* out */ const char **currentTimeCode, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT GetTimecode (/* out */ IDeckLinkTimecode **currentTimecode, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT GetTimecodeBCD (/* out */ BMDTimecodeBCD *currentTimecode, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT SetPreroll (/* in */ uint32_t prerollSeconds) = 0; virtual HRESULT GetPreroll (/* out */ uint32_t *prerollSeconds) = 0; virtual HRESULT SetExportOffset (/* in */ int32_t exportOffsetFields) = 0; virtual HRESULT GetExportOffset (/* out */ int32_t *exportOffsetFields) = 0; virtual HRESULT GetManualExportOffset (/* out */ int32_t *deckManualExportOffsetFields) = 0; virtual HRESULT SetCaptureOffset (/* in */ int32_t captureOffsetFields) = 0; virtual HRESULT GetCaptureOffset (/* out */ int32_t *captureOffsetFields) = 0; virtual HRESULT StartExport (/* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* in */ BMDDeckControlExportModeOpsFlags exportModeOps, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT StartCapture (/* in */ bool useVITC, /* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT GetDeviceID (/* out */ uint16_t *deviceId, /* out */ BMDDeckControlError *error) = 0; virtual HRESULT Abort (void) = 0; virtual HRESULT CrashRecordStart (/* out */ BMDDeckControlError *error) = 0; virtual HRESULT CrashRecordStop (/* out */ BMDDeckControlError *error) = 0; virtual HRESULT SetCallback (/* in */ IDeckLinkDeckControlStatusCallback *callback) = 0; protected: virtual ~IDeckLinkDeckControl () {}; // call Release method to drop reference count }; /* Functions */ extern "C" { IDeckLinkIterator* CreateDeckLinkIteratorInstance (void); IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper (void); IDeckLinkVideoConversion* CreateVideoConversionInstance (void); }; #endif // defined(__cplusplus) #endif // __DeckLink_API_h__ mlt-0.9.0/src/modules/decklink/linux/DeckLinkAPIDispatch.cpp000066400000000000000000000074311215300731300237000ustar00rootroot00000000000000/* -LICENSE-START- ** Copyright (c) 2009 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by ** this license (the "Software") to use, reproduce, display, distribute, ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: ** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. ** ** 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT ** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE ** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ** DEALINGS IN THE SOFTWARE. ** -LICENSE-END- **/ #include #include #include #include "DeckLinkAPI.h" #define kDeckLinkAPI_Name "libDeckLinkAPI.so" #define KDeckLinkPreviewAPI_Name "libDeckLinkPreviewAPI.so" typedef IDeckLinkIterator* (*CreateIteratorFunc)(void); typedef IDeckLinkGLScreenPreviewHelper* (*CreateOpenGLScreenPreviewHelperFunc)(void); typedef IDeckLinkVideoConversion* (*CreateVideoConversionInstanceFunc)(void); static pthread_once_t gDeckLinkOnceControl = PTHREAD_ONCE_INIT; static pthread_once_t gPreviewOnceControl = PTHREAD_ONCE_INIT; static CreateIteratorFunc gCreateIteratorFunc = NULL; static CreateOpenGLScreenPreviewHelperFunc gCreateOpenGLPreviewFunc = NULL; static CreateVideoConversionInstanceFunc gCreateVideoConversionFunc = NULL; void InitDeckLinkAPI (void) { void *libraryHandle; libraryHandle = dlopen(kDeckLinkAPI_Name, RTLD_NOW|RTLD_GLOBAL); if (!libraryHandle) { fprintf(stderr, "%s\n", dlerror()); return; } gCreateIteratorFunc = (CreateIteratorFunc)dlsym(libraryHandle, "CreateDeckLinkIteratorInstance_0001"); if (!gCreateIteratorFunc) fprintf(stderr, "%s\n", dlerror()); gCreateVideoConversionFunc = (CreateVideoConversionInstanceFunc)dlsym(libraryHandle, "CreateVideoConversionInstance_0001"); if (!gCreateVideoConversionFunc) fprintf(stderr, "%s\n", dlerror()); } void InitDeckLinkPreviewAPI (void) { void *libraryHandle; libraryHandle = dlopen(KDeckLinkPreviewAPI_Name, RTLD_NOW|RTLD_GLOBAL); if (!libraryHandle) { fprintf(stderr, "%s\n", dlerror()); return; } gCreateOpenGLPreviewFunc = (CreateOpenGLScreenPreviewHelperFunc)dlsym(libraryHandle, "CreateOpenGLScreenPreviewHelper_0001"); if (!gCreateOpenGLPreviewFunc) fprintf(stderr, "%s\n", dlerror()); } IDeckLinkIterator* CreateDeckLinkIteratorInstance (void) { pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); if (gCreateIteratorFunc == NULL) return NULL; return gCreateIteratorFunc(); } IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper (void) { pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); pthread_once(&gPreviewOnceControl, InitDeckLinkPreviewAPI); if (gCreateOpenGLPreviewFunc == NULL) return NULL; return gCreateOpenGLPreviewFunc(); } IDeckLinkVideoConversion* CreateVideoConversionInstance (void) { pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); if (gCreateVideoConversionFunc == NULL) return NULL; return gCreateVideoConversionFunc(); } mlt-0.9.0/src/modules/decklink/linux/LinuxCOM.h000066400000000000000000000065411215300731300213060ustar00rootroot00000000000000/* -LICENSE-START- ** Copyright (c) 2009 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation covered by ** this license (the "Software") to use, reproduce, display, distribute, ** execute, and transmit the Software, and to prepare derivative works of the ** Software, and to permit third-parties to whom the Software is furnished to ** do so, all subject to the following: ** ** The copyright notices in the Software and this entire statement, including ** the above license grant, this restriction and the following disclaimer, ** must be included in all copies of the Software, in whole or in part, and ** all derivative works of the Software, unless such copies or derivative ** works are solely in the form of machine-executable object code generated by ** a source language processor. ** ** 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT ** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE ** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ** DEALINGS IN THE SOFTWARE. ** -LICENSE-END- */ #ifndef __LINUX_COM_H_ #define __LINUX_COM_H_ struct REFIID { unsigned char byte0; unsigned char byte1; unsigned char byte2; unsigned char byte3; unsigned char byte4; unsigned char byte5; unsigned char byte6; unsigned char byte7; unsigned char byte8; unsigned char byte9; unsigned char byte10; unsigned char byte11; unsigned char byte12; unsigned char byte13; unsigned char byte14; unsigned char byte15; }; typedef REFIID CFUUIDBytes; #define CFUUIDGetUUIDBytes(x) x typedef int HRESULT; typedef unsigned long ULONG; typedef void *LPVOID; #define SUCCEEDED(Status) ((HRESULT)(Status) >= 0) #define FAILED(Status) ((HRESULT)(Status)<0) #define IS_ERROR(Status) ((unsigned long)(Status) >> 31 == SEVERITY_ERROR) #define HRESULT_CODE(hr) ((hr) & 0xFFFF) #define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff) #define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1) #define SEVERITY_SUCCESS 0 #define SEVERITY_ERROR 1 #define MAKE_HRESULT(sev,fac,code) ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) ) #define S_OK ((HRESULT)0x00000000L) #define S_FALSE ((HRESULT)0x00000001L) #define E_UNEXPECTED ((HRESULT)0x8000FFFFL) #define E_NOTIMPL ((HRESULT)0x80000001L) #define E_OUTOFMEMORY ((HRESULT)0x80000002L) #define E_INVALIDARG ((HRESULT)0x80000003L) #define E_NOINTERFACE ((HRESULT)0x80000004L) #define E_POINTER ((HRESULT)0x80000005L) #define E_HANDLE ((HRESULT)0x80000006L) #define E_ABORT ((HRESULT)0x80000007L) #define E_FAIL ((HRESULT)0x80000008L) #define E_ACCESSDENIED ((HRESULT)0x80000009L) #define STDMETHODCALLTYPE #define IID_IUnknown (REFIID){0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} #define IUnknownUUID IID_IUnknown #ifdef __cplusplus class IUnknown { public: virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) = 0; virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0; virtual ULONG STDMETHODCALLTYPE Release(void) = 0; }; #endif #endif mlt-0.9.0/src/modules/decklink/producer_decklink.cpp000066400000000000000000000541751215300731300225410ustar00rootroot00000000000000/* * producer_decklink.c -- input from Blackmagic Design DeckLink * Copyright (C) 2011 Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 consumer library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include "common.h" class DeckLinkProducer : public IDeckLinkInputCallback { private: mlt_producer m_producer; IDeckLink* m_decklink; IDeckLinkInput* m_decklinkInput; mlt_deque m_queue; pthread_mutex_t m_mutex; pthread_cond_t m_condition; bool m_started; int m_dropped; bool m_isBuffering; int m_topFieldFirst; int m_colorspace; int m_vancLines; mlt_cache m_cache; BMDDisplayMode getDisplayMode( mlt_profile profile, int vancLines ) { IDeckLinkDisplayModeIterator* iter = NULL; IDeckLinkDisplayMode* mode = NULL; BMDDisplayMode result = (BMDDisplayMode) bmdDisplayModeNotSupported; if ( m_decklinkInput->GetDisplayModeIterator( &iter ) == S_OK ) { while ( !result && iter->Next( &mode ) == S_OK ) { int width = mode->GetWidth(); int height = mode->GetHeight(); BMDTimeValue duration; BMDTimeScale timescale; mode->GetFrameRate( &duration, ×cale ); double fps = (double) timescale / duration; int p = mode->GetFieldDominance() == bmdProgressiveFrame; m_topFieldFirst = mode->GetFieldDominance() == bmdUpperFieldFirst; m_colorspace = ( mode->GetFlags() & bmdDisplayModeColorspaceRec709 ) ? 709 : 601; mlt_log_verbose( getProducer(), "BMD mode %dx%d %.3f fps prog %d tff %d\n", width, height, fps, p, m_topFieldFirst ); if ( width == profile->width && p == profile->progressive && ( height + vancLines == profile->height || ( height == 486 && profile->height == 480 + vancLines ) ) && (int) fps == (int) mlt_profile_fps( profile ) ) result = mode->GetDisplayMode(); SAFE_RELEASE( mode ); } SAFE_RELEASE( iter ); } return result; } public: void setProducer( mlt_producer producer ) { m_producer = producer; } mlt_producer getProducer() const { return m_producer; } DeckLinkProducer() { m_producer = NULL; m_decklink = NULL; m_decklinkInput = NULL; } ~DeckLinkProducer() { if ( m_queue ) { stop(); mlt_deque_close( m_queue ); pthread_mutex_destroy( &m_mutex ); pthread_cond_destroy( &m_condition ); mlt_cache_close( m_cache ); } SAFE_RELEASE( m_decklinkInput ); SAFE_RELEASE( m_decklink ); } bool open( unsigned card = 0 ) { IDeckLinkIterator* decklinkIterator = NULL; try { #ifdef WIN32 HRESULT result = CoInitialize( NULL ); if ( FAILED( result ) ) throw "COM initialization failed"; result = CoCreateInstance( CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**) &decklinkIterator ); if ( FAILED( result ) ) throw "The DeckLink drivers are not installed."; #else decklinkIterator = CreateDeckLinkIteratorInstance(); if ( !decklinkIterator ) throw "The DeckLink drivers are not installed."; #endif // Connect to the Nth DeckLink instance for ( unsigned i = 0; decklinkIterator->Next( &m_decklink ) == S_OK ; i++) { if ( i == card ) break; else SAFE_RELEASE( m_decklink ); } SAFE_RELEASE( decklinkIterator ); if ( !m_decklink ) throw "DeckLink card not found."; // Get the input interface if ( m_decklink->QueryInterface( IID_IDeckLinkInput, (void**) &m_decklinkInput ) != S_OK ) throw "No DeckLink cards support input."; // Provide this class as a delegate to the input callback m_decklinkInput->SetCallback( this ); // Initialize other members pthread_mutex_init( &m_mutex, NULL ); pthread_cond_init( &m_condition, NULL ); m_queue = mlt_deque_init(); m_started = false; m_dropped = 0; m_isBuffering = true; m_cache = mlt_cache_init(); // 3 covers YADIF and increasing framerate use cases mlt_cache_set_size( m_cache, 3 ); } catch ( const char *error ) { SAFE_RELEASE( m_decklinkInput ); SAFE_RELEASE( m_decklink ); mlt_log_error( getProducer(), "%s\n", error ); return false; } return true; } bool start( mlt_profile profile = 0 ) { if ( m_started ) return false; try { // Initialize some members m_vancLines = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "vanc" ); if ( m_vancLines == -1 ) m_vancLines = profile->height <= 512 ? 26 : 32; if ( !profile ) profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) ); // Get the display mode BMDDisplayMode displayMode = getDisplayMode( profile, m_vancLines ); if ( displayMode == (BMDDisplayMode) bmdDisplayModeNotSupported ) { mlt_log_info( getProducer(), "profile = %dx%d %f fps %s\n", profile->width, profile->height, mlt_profile_fps( profile ), profile->progressive? "progressive" : "interlace" ); throw "Profile is not compatible with decklink."; } // Determine if supports input format detection #ifdef WIN32 BOOL doesDetectFormat = FALSE; #else bool doesDetectFormat = false; #endif IDeckLinkAttributes *decklinkAttributes = 0; if ( m_decklink->QueryInterface( IID_IDeckLinkAttributes, (void**) &decklinkAttributes ) == S_OK ) { if ( decklinkAttributes->GetFlag( BMDDeckLinkSupportsInputFormatDetection, &doesDetectFormat ) != S_OK ) doesDetectFormat = false; SAFE_RELEASE( decklinkAttributes ); } mlt_log_verbose( getProducer(), "%s format detection\n", doesDetectFormat ? "supports" : "does not support" ); // Enable video capture BMDPixelFormat pixelFormat = bmdFormat8BitYUV; BMDVideoInputFlags flags = doesDetectFormat ? bmdVideoInputEnableFormatDetection : bmdVideoInputFlagDefault; if ( S_OK != m_decklinkInput->EnableVideoInput( displayMode, pixelFormat, flags ) ) throw "Failed to enable video capture."; // Enable audio capture BMDAudioSampleRate sampleRate = bmdAudioSampleRate48kHz; BMDAudioSampleType sampleType = bmdAudioSampleType16bitInteger; int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ); if ( S_OK != m_decklinkInput->EnableAudioInput( sampleRate, sampleType, channels ) ) throw "Failed to enable audio capture."; // Start capture m_dropped = 0; mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", m_dropped ); m_started = m_decklinkInput->StartStreams() == S_OK; if ( !m_started ) throw "Failed to start capture."; } catch ( const char *error ) { m_decklinkInput->DisableVideoInput(); mlt_log_error( getProducer(), "%s\n", error ); return false; } return true; } void stop() { if ( !m_started ) return; m_started = false; // Release the wait in getFrame pthread_mutex_lock( &m_mutex ); pthread_cond_broadcast( &m_condition ); pthread_mutex_unlock( &m_mutex ); m_decklinkInput->StopStreams(); m_decklinkInput->DisableVideoInput(); m_decklinkInput->DisableAudioInput(); // Cleanup queue pthread_mutex_lock( &m_mutex ); while ( mlt_frame frame = (mlt_frame) mlt_deque_pop_back( m_queue ) ) mlt_frame_close( frame ); pthread_mutex_unlock( &m_mutex ); } mlt_frame getFrame() { struct timeval now; struct timespec tm; double fps = mlt_producer_get_fps( getProducer() ); mlt_position position = mlt_producer_position( getProducer() ); mlt_frame frame = mlt_cache_get_frame( m_cache, position ); // Allow the buffer to fill to the requested initial buffer level. if ( m_isBuffering ) { int prefill = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "prefill" ); int buffer = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" ); m_isBuffering = false; prefill = prefill > buffer ? buffer : prefill; pthread_mutex_lock( &m_mutex ); while ( mlt_deque_count( m_queue ) < prefill ) { // Wait up to buffer/fps seconds gettimeofday( &now, NULL ); long usec = now.tv_sec * 1000000 + now.tv_usec; usec += 1000000 * buffer / fps; tm.tv_sec = usec / 1000000; tm.tv_nsec = (usec % 1000000) * 1000; if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) ) break; } pthread_mutex_unlock( &m_mutex ); } if ( !frame ) { // Wait if queue is empty pthread_mutex_lock( &m_mutex ); while ( mlt_deque_count( m_queue ) < 1 ) { // Wait up to twice frame duration gettimeofday( &now, NULL ); long usec = now.tv_sec * 1000000 + now.tv_usec; usec += 2000000 / fps; tm.tv_sec = usec / 1000000; tm.tv_nsec = (usec % 1000000) * 1000; if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) ) // Stop waiting if error (timed out) break; } frame = ( mlt_frame ) mlt_deque_pop_front( m_queue ); pthread_mutex_unlock( &m_mutex ); // add to cache if ( frame ) { mlt_frame_set_position( frame, position ); mlt_cache_put_frame( m_cache, frame ); } } // Set frame timestamp and properties if ( frame ) { mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) ); mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_properties_set_int( properties, "progressive", profile->progressive ); mlt_properties_set_int( properties, "meta.media.progressive", profile->progressive ); mlt_properties_set_int( properties, "top_field_first", m_topFieldFirst ); mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) ); mlt_properties_set_int( properties, "meta.media.sample_aspect_num", profile->sample_aspect_num ); mlt_properties_set_int( properties, "meta.media.sample_aspect_den", profile->sample_aspect_den ); mlt_properties_set_int( properties, "meta.media.frame_rate_num", profile->frame_rate_num ); mlt_properties_set_int( properties, "meta.media.frame_rate_den", profile->frame_rate_den ); mlt_properties_set_int( properties, "width", profile->width ); mlt_properties_set_int( properties, "meta.media.width", profile->width ); mlt_properties_set_int( properties, "height", profile->height ); mlt_properties_set_int( properties, "meta.media.height", profile->height ); mlt_properties_set_int( properties, "format", mlt_image_yuv422 ); mlt_properties_set_int( properties, "colorspace", m_colorspace ); mlt_properties_set_int( properties, "meta.media.colorspace", m_colorspace ); mlt_properties_set_int( properties, "audio_frequency", 48000 ); mlt_properties_set_int( properties, "audio_channels", mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ) ); } else mlt_log_warning( getProducer(), "buffer underrun\n" ); return frame; } // *** DeckLink API implementation of IDeckLinkInputCallback *** // // IUnknown needs only a dummy implementation virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, LPVOID *ppv ) { return E_NOINTERFACE; } virtual ULONG STDMETHODCALLTYPE AddRef() { return 1; } virtual ULONG STDMETHODCALLTYPE Release() { return 1; } /************************* DeckLink API Delegate Methods *****************************/ virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( IDeckLinkVideoInputFrame* video, IDeckLinkAudioInputPacket* audio ) { if ( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "preview" ) && mlt_producer_get_speed( getProducer() ) == 0.0 && !mlt_deque_count( m_queue )) { pthread_cond_broadcast( &m_condition ); return S_OK; } // Create mlt_frame mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( getProducer() ) ); // Copy video if ( video ) { if ( !( video->GetFlags() & bmdFrameHasNoInputSource ) ) { int size = video->GetRowBytes() * ( video->GetHeight() + m_vancLines ); void* image = mlt_pool_alloc( size ); void* buffer = 0; unsigned char* p = (unsigned char*) image; int n = size / 2; \ // Initialize VANC lines to nominal black while ( --n ) { *p ++ = 16; *p ++ = 128; } // Capture VANC if ( m_vancLines > 0 ) { IDeckLinkVideoFrameAncillary* vanc = 0; if ( video->GetAncillaryData( &vanc ) == S_OK && vanc ) { for ( int i = 1; i < m_vancLines + 1; i++ ) { if ( vanc->GetBufferForVerticalBlankingLine( i, &buffer ) == S_OK ) swab( (char*) buffer, (char*) image + ( i - 1 ) * video->GetRowBytes(), video->GetRowBytes() ); else mlt_log_debug( getProducer(), "failed capture vanc line %d\n", i ); } SAFE_RELEASE(vanc); } } // Capture image video->GetBytes( &buffer ); if ( image && buffer ) { size = video->GetRowBytes() * video->GetHeight(); swab( (char*) buffer, (char*) image + m_vancLines * video->GetRowBytes(), size ); mlt_frame_set_image( frame, (uint8_t*) image, size, mlt_pool_release ); } else if ( image ) { mlt_log_verbose( getProducer(), "no video\n" ); mlt_pool_release( image ); } } else { mlt_log_verbose( getProducer(), "no signal\n" ); mlt_frame_close( frame ); frame = 0; } // Get timecode IDeckLinkTimecode* timecode = 0; if ( video->GetTimecode( bmdTimecodeVITC, &timecode ) == S_OK && timecode ) { DLString timecodeString = 0; if ( timecode->GetString( &timecodeString ) == S_OK ) { char* s = getCString( timecodeString ); mlt_properties_set( MLT_FRAME_PROPERTIES( frame ), "meta.attr.vitc.markup", s ); mlt_log_debug( getProducer(), "timecode %s\n", s ); freeCString( s ); } freeDLString( timecodeString ); SAFE_RELEASE( timecode ); } } else { mlt_log_verbose( getProducer(), "no video\n" ); mlt_frame_close( frame ); frame = 0; } // Copy audio if ( frame && audio ) { int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ); int size = audio->GetSampleFrameCount() * channels * sizeof(int16_t); mlt_audio_format format = mlt_audio_s16; void* pcm = mlt_pool_alloc( size ); void* buffer = 0; audio->GetBytes( &buffer ); if ( buffer ) { memcpy( pcm, buffer, size ); mlt_frame_set_audio( frame, pcm, format, size, mlt_pool_release ); mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "audio_samples", audio->GetSampleFrameCount() ); } else { mlt_log_verbose( getProducer(), "no audio\n" ); mlt_pool_release( pcm ); } } else { mlt_log_verbose( getProducer(), "no audio\n" ); } // Put frame in queue if ( frame ) { int queueMax = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" ); pthread_mutex_lock( &m_mutex ); if ( mlt_deque_count( m_queue ) < queueMax ) { mlt_deque_push_back( m_queue, frame ); pthread_cond_broadcast( &m_condition ); } else { mlt_frame_close( frame ); mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", ++m_dropped ); mlt_log_warning( getProducer(), "frame dropped %d\n", m_dropped ); } pthread_mutex_unlock( &m_mutex ); } return S_OK; } virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged( BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode* mode, BMDDetectedVideoInputFormatFlags flags ) { mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) ); if ( events & bmdVideoInputDisplayModeChanged ) { BMDTimeValue duration; BMDTimeScale timescale; mode->GetFrameRate( &duration, ×cale ); profile->width = mode->GetWidth(); profile->height = mode->GetHeight() + m_vancLines; profile->frame_rate_num = timescale; profile->frame_rate_den = duration; if ( profile->width == 720 ) { if ( profile->height == 576 ) { profile->sample_aspect_num = 16; profile->sample_aspect_den = 15; } else { profile->sample_aspect_num = 8; profile->sample_aspect_den = 9; } profile->display_aspect_num = 4; profile->display_aspect_den = 3; } else { profile->sample_aspect_num = 1; profile->sample_aspect_den = 1; profile->display_aspect_num = 16; profile->display_aspect_den = 9; } free( profile->description ); profile->description = strdup( "decklink" ); mlt_log_verbose( getProducer(), "format changed %dx%d %.3f fps\n", profile->width, profile->height, (double) profile->frame_rate_num / profile->frame_rate_den ); } if ( events & bmdVideoInputFieldDominanceChanged ) { profile->progressive = mode->GetFieldDominance() == bmdProgressiveFrame; m_topFieldFirst = mode->GetFieldDominance() == bmdUpperFieldFirst; mlt_log_verbose( getProducer(), "field dominance changed prog %d tff %d\n", profile->progressive, m_topFieldFirst ); } if ( events & bmdVideoInputColorspaceChanged ) { profile->colorspace = m_colorspace = ( mode->GetFlags() & bmdDisplayModeColorspaceRec709 ) ? 709 : 601; mlt_log_verbose( getProducer(), "colorspace changed %d\n", profile->colorspace ); } return S_OK; } }; static int get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { return mlt_frame_get_audio( frame, (void**) buffer, format, frequency, channels, samples ); } static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { return mlt_frame_get_image( frame, buffer, format, width, height, writable ); } static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { DeckLinkProducer* decklink = (DeckLinkProducer*) producer->child; mlt_position pos = mlt_producer_position( producer ); mlt_position end = mlt_producer_get_playtime( producer ); end = ( mlt_producer_get_length( producer ) < end ? mlt_producer_get_length( producer ) : end ) - 1; // Re-open if needed if ( !decklink && pos < end ) { producer->child = decklink = new DeckLinkProducer(); decklink->setProducer( producer ); decklink->open( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES(producer), "resource" ) ); } // Start if needed if ( decklink ) { decklink->start( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) ); // Get the next frame from the decklink object if ( ( *frame = decklink->getFrame() )) { // Add audio and video getters mlt_frame_push_audio( *frame, (void*) get_audio ); mlt_frame_push_get_image( *frame, get_image ); } } if ( !*frame ) *frame = mlt_frame_init( MLT_PRODUCER_SERVICE(producer) ); // Calculate the next timecode mlt_producer_prepare_next( producer ); // Close DeckLink if at end if ( pos >= end && decklink ) { decklink->stop(); delete decklink; producer->child = NULL; } return 0; } static void producer_close( mlt_producer producer ) { delete (DeckLinkProducer*) producer->child; producer->close = NULL; mlt_producer_close( producer ); } extern "C" { // Listen for the list_devices property to be set static void on_property_changed( void*, mlt_properties properties, const char *name ) { IDeckLinkIterator* decklinkIterator = NULL; IDeckLink* decklink = NULL; IDeckLinkInput* decklinkInput = NULL; int i = 0; if ( name && !strcmp( name, "list_devices" ) ) mlt_event_block( (mlt_event) mlt_properties_get_data( properties, "list-devices-event", NULL ) ); else return; #ifdef WIN32 if ( FAILED( CoInitialize( NULL ) ) ) return; if ( FAILED( CoCreateInstance( CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**) &decklinkIterator ) ) ) return; #else if ( !( decklinkIterator = CreateDeckLinkIteratorInstance() ) ) return; #endif for ( ; decklinkIterator->Next( &decklink ) == S_OK; i++ ) { if ( decklink->QueryInterface( IID_IDeckLinkInput, (void**) &decklinkInput ) == S_OK ) { DLString name = NULL; if ( decklink->GetModelName( &name ) == S_OK ) { char *name_cstr = getCString( name ); const char *format = "device.%d"; char *key = (char*) calloc( 1, strlen( format ) + 1 ); sprintf( key, format, i ); mlt_properties_set( properties, key, name_cstr ); free( key ); freeDLString( name ); freeCString( name_cstr ); } SAFE_RELEASE( decklinkInput ); } SAFE_RELEASE( decklink ); } SAFE_RELEASE( decklinkIterator ); mlt_properties_set_int( properties, "devices", i ); } /** Initialise the producer. */ mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Allocate the producer DeckLinkProducer* decklink = new DeckLinkProducer(); mlt_producer producer = (mlt_producer) calloc( 1, sizeof( *producer ) ); // If allocated and initializes if ( decklink && !mlt_producer_init( producer, decklink ) ) { if ( decklink->open( arg? atoi( arg ) : 0 ) ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); // Close DeckLink and defer re-open to get_frame delete decklink; producer->child = NULL; // Set callbacks producer->close = (mlt_destructor) producer_close; producer->get_frame = get_frame; // Set properties mlt_properties_set( properties, "resource", (arg && strcmp( arg, ""))? arg : "0" ); mlt_properties_set_int( properties, "channels", 2 ); mlt_properties_set_int( properties, "buffer", 25 ); mlt_properties_set_int( properties, "prefill", 25 ); // These properties effectively make it infinite. mlt_properties_set_int( properties, "length", INT_MAX ); mlt_properties_set_int( properties, "out", INT_MAX - 1 ); mlt_properties_set( properties, "eof", "loop" ); mlt_event event = mlt_events_listen( properties, properties, "property-changed", (mlt_listener) on_property_changed ); mlt_properties_set_data( properties, "list-devices-event", event, 0, NULL, NULL ); } } return producer; } } mlt-0.9.0/src/modules/decklink/producer_decklink.yml000066400000000000000000000051651215300731300225530ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: decklink title: Blackmagic Design DeckLink Capture version: 1 copyright: Copytight (C) 2011 Daniel R. Dennedy license: LGPL language: en creator: Dan Dennedy tags: - Audio - Video description: > Capture video and audio using Blackmagic Design DeckLink SDI or Intensity HDMI cards. notes: > Please ensure that you use a MLT profile that is compatible with a broadcast standard which the card you are using supports. If you must use an interlaced profile but wish to deinterlace or scale the input, then you must use the consumer producer, e.g.: melt -profile square_pal consumer:decklink: profile=dv_pal bugs: - It is incompatible with the yadif deinterlacer. - Transport controls such as seeking has no affect. - External deck control is not implemented. - Only 8-bit Y'CbCr is supported at this time. parameters: - identifier: argument title: Card type: integer default: 0 minimum: 0 widget: spinner - identifier: channels title: Audio channels type: integer default: 2 minimum: 2 maximum: 16 widget: spinner - identifier: buffer title: Maximum buffer description: > There is a queue of frames between this plugin and its consumer. If the consumer has a little, intermittent delay then it reduces the risk of dropping a frame. However, this provides a maximum number of frames that can be buffered to prevent consuming memory unbounded in the case of frequent or sustained delays. type: integer default: 25 minimum: 0 unit: frames widget: spinner - identifier: prefill title: Initial buffer description: Initially fill the buffer with a number of frames. type: integer default: 25 minimum: 0 unit: frames widget: spinner - identifier: vanc title: Vertical ancillary capture description: > Captures vertical ancillary data as image data and places it at the top of the visible/active image. You can either set the number of lines to capture or use -1 for automatic (32 lines) mode. type: integer minimum: -1 default: 0 unit: lines widget: spinner - identifier: preview title: Enable preview description: Support preview monitoring when paused (speed = 0). type: integer minimum: 0 maximum: 1 default: 0 widget: checkbox - identifier: devices title: Number of devices type: integer readonly: yes minimum: 0 - identifier: device.* title: Device model description: The model name of each device that accepts input. type: string readonly: yes mlt-0.9.0/src/modules/decklink/win/000077500000000000000000000000001215300731300171275ustar00rootroot00000000000000mlt-0.9.0/src/modules/decklink/win/DeckLinkAPI_h.h000066400000000000000000011033441215300731300216330ustar00rootroot00000000000000 /* this ALWAYS GENERATED file contains the definitions for the interfaces */ /* File created by MIDL compiler version 7.00.0555 */ /* at Tue Sep 07 12:31:45 2010 */ /* Compiler settings for video\DeckLinkAPI.idl: Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 protocol : dce , ms_ext, c_ext, robust error checks: allocation ref bounds_check enum stub_data VC __declspec() decoration level: __declspec(uuid()), __declspec(selectany), __declspec(novtable) DECLSPEC_UUID(), MIDL_INTERFACE() */ /* @@MIDL_FILE_HEADING( ) */ //#pragma warning( disable: 4049 ) /* more than 64k source lines */ /* verify that the version is high enough to compile this file*/ #ifndef __REQUIRED_RPCNDR_H_VERSION__ #define __REQUIRED_RPCNDR_H_VERSION__ 475 #endif #include "rpc.h" #include "rpcndr.h" #ifndef __RPCNDR_H_VERSION__ #error this stub requires an updated version of #endif // __RPCNDR_H_VERSION__ #ifndef __DeckLinkAPI_h_h__ #define __DeckLinkAPI_h_h__ #if defined(_MSC_VER) && (_MSC_VER >= 1020) #pragma once #endif /* Forward Declarations */ #ifndef __IDeckLinkVideoOutputCallback_FWD_DEFINED__ #define __IDeckLinkVideoOutputCallback_FWD_DEFINED__ typedef interface IDeckLinkVideoOutputCallback IDeckLinkVideoOutputCallback; #endif /* __IDeckLinkVideoOutputCallback_FWD_DEFINED__ */ #ifndef __IDeckLinkInputCallback_FWD_DEFINED__ #define __IDeckLinkInputCallback_FWD_DEFINED__ typedef interface IDeckLinkInputCallback IDeckLinkInputCallback; #endif /* __IDeckLinkInputCallback_FWD_DEFINED__ */ #ifndef __IDeckLinkMemoryAllocator_FWD_DEFINED__ #define __IDeckLinkMemoryAllocator_FWD_DEFINED__ typedef interface IDeckLinkMemoryAllocator IDeckLinkMemoryAllocator; #endif /* __IDeckLinkMemoryAllocator_FWD_DEFINED__ */ #ifndef __IDeckLinkAudioOutputCallback_FWD_DEFINED__ #define __IDeckLinkAudioOutputCallback_FWD_DEFINED__ typedef interface IDeckLinkAudioOutputCallback IDeckLinkAudioOutputCallback; #endif /* __IDeckLinkAudioOutputCallback_FWD_DEFINED__ */ #ifndef __IDeckLinkIterator_FWD_DEFINED__ #define __IDeckLinkIterator_FWD_DEFINED__ typedef interface IDeckLinkIterator IDeckLinkIterator; #endif /* __IDeckLinkIterator_FWD_DEFINED__ */ #ifndef __IDeckLinkAPIInformation_FWD_DEFINED__ #define __IDeckLinkAPIInformation_FWD_DEFINED__ typedef interface IDeckLinkAPIInformation IDeckLinkAPIInformation; #endif /* __IDeckLinkAPIInformation_FWD_DEFINED__ */ #ifndef __IDeckLinkDisplayModeIterator_FWD_DEFINED__ #define __IDeckLinkDisplayModeIterator_FWD_DEFINED__ typedef interface IDeckLinkDisplayModeIterator IDeckLinkDisplayModeIterator; #endif /* __IDeckLinkDisplayModeIterator_FWD_DEFINED__ */ #ifndef __IDeckLinkDisplayMode_FWD_DEFINED__ #define __IDeckLinkDisplayMode_FWD_DEFINED__ typedef interface IDeckLinkDisplayMode IDeckLinkDisplayMode; #endif /* __IDeckLinkDisplayMode_FWD_DEFINED__ */ #ifndef __IDeckLink_FWD_DEFINED__ #define __IDeckLink_FWD_DEFINED__ typedef interface IDeckLink IDeckLink; #endif /* __IDeckLink_FWD_DEFINED__ */ #ifndef __IDeckLinkOutput_FWD_DEFINED__ #define __IDeckLinkOutput_FWD_DEFINED__ typedef interface IDeckLinkOutput IDeckLinkOutput; #endif /* __IDeckLinkOutput_FWD_DEFINED__ */ #ifndef __IDeckLinkInput_FWD_DEFINED__ #define __IDeckLinkInput_FWD_DEFINED__ typedef interface IDeckLinkInput IDeckLinkInput; #endif /* __IDeckLinkInput_FWD_DEFINED__ */ #ifndef __IDeckLinkTimecode_FWD_DEFINED__ #define __IDeckLinkTimecode_FWD_DEFINED__ typedef interface IDeckLinkTimecode IDeckLinkTimecode; #endif /* __IDeckLinkTimecode_FWD_DEFINED__ */ #ifndef __IDeckLinkVideoFrame_FWD_DEFINED__ #define __IDeckLinkVideoFrame_FWD_DEFINED__ typedef interface IDeckLinkVideoFrame IDeckLinkVideoFrame; #endif /* __IDeckLinkVideoFrame_FWD_DEFINED__ */ #ifndef __IDeckLinkMutableVideoFrame_FWD_DEFINED__ #define __IDeckLinkMutableVideoFrame_FWD_DEFINED__ typedef interface IDeckLinkMutableVideoFrame IDeckLinkMutableVideoFrame; #endif /* __IDeckLinkMutableVideoFrame_FWD_DEFINED__ */ #ifndef __IDeckLinkVideoFrame3DExtensions_FWD_DEFINED__ #define __IDeckLinkVideoFrame3DExtensions_FWD_DEFINED__ typedef interface IDeckLinkVideoFrame3DExtensions IDeckLinkVideoFrame3DExtensions; #endif /* __IDeckLinkVideoFrame3DExtensions_FWD_DEFINED__ */ #ifndef __IDeckLinkVideoInputFrame_FWD_DEFINED__ #define __IDeckLinkVideoInputFrame_FWD_DEFINED__ typedef interface IDeckLinkVideoInputFrame IDeckLinkVideoInputFrame; #endif /* __IDeckLinkVideoInputFrame_FWD_DEFINED__ */ #ifndef __IDeckLinkVideoFrameAncillary_FWD_DEFINED__ #define __IDeckLinkVideoFrameAncillary_FWD_DEFINED__ typedef interface IDeckLinkVideoFrameAncillary IDeckLinkVideoFrameAncillary; #endif /* __IDeckLinkVideoFrameAncillary_FWD_DEFINED__ */ #ifndef __IDeckLinkAudioInputPacket_FWD_DEFINED__ #define __IDeckLinkAudioInputPacket_FWD_DEFINED__ typedef interface IDeckLinkAudioInputPacket IDeckLinkAudioInputPacket; #endif /* __IDeckLinkAudioInputPacket_FWD_DEFINED__ */ #ifndef __IDeckLinkScreenPreviewCallback_FWD_DEFINED__ #define __IDeckLinkScreenPreviewCallback_FWD_DEFINED__ typedef interface IDeckLinkScreenPreviewCallback IDeckLinkScreenPreviewCallback; #endif /* __IDeckLinkScreenPreviewCallback_FWD_DEFINED__ */ #ifndef __IDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ #define __IDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ typedef interface IDeckLinkGLScreenPreviewHelper IDeckLinkGLScreenPreviewHelper; #endif /* __IDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ */ #ifndef __IDeckLinkConfiguration_FWD_DEFINED__ #define __IDeckLinkConfiguration_FWD_DEFINED__ typedef interface IDeckLinkConfiguration IDeckLinkConfiguration; #endif /* __IDeckLinkConfiguration_FWD_DEFINED__ */ #ifndef __IDeckLinkAttributes_FWD_DEFINED__ #define __IDeckLinkAttributes_FWD_DEFINED__ typedef interface IDeckLinkAttributes IDeckLinkAttributes; #endif /* __IDeckLinkAttributes_FWD_DEFINED__ */ #ifndef __IDeckLinkKeyer_FWD_DEFINED__ #define __IDeckLinkKeyer_FWD_DEFINED__ typedef interface IDeckLinkKeyer IDeckLinkKeyer; #endif /* __IDeckLinkKeyer_FWD_DEFINED__ */ #ifndef __IDeckLinkVideoConversion_FWD_DEFINED__ #define __IDeckLinkVideoConversion_FWD_DEFINED__ typedef interface IDeckLinkVideoConversion IDeckLinkVideoConversion; #endif /* __IDeckLinkVideoConversion_FWD_DEFINED__ */ #ifndef __IDeckLinkDeckControlStatusCallback_FWD_DEFINED__ #define __IDeckLinkDeckControlStatusCallback_FWD_DEFINED__ typedef interface IDeckLinkDeckControlStatusCallback IDeckLinkDeckControlStatusCallback; #endif /* __IDeckLinkDeckControlStatusCallback_FWD_DEFINED__ */ #ifndef __IDeckLinkDeckControl_FWD_DEFINED__ #define __IDeckLinkDeckControl_FWD_DEFINED__ typedef interface IDeckLinkDeckControl IDeckLinkDeckControl; #endif /* __IDeckLinkDeckControl_FWD_DEFINED__ */ #ifndef __CDeckLinkIterator_FWD_DEFINED__ #define __CDeckLinkIterator_FWD_DEFINED__ #ifdef __cplusplus typedef class CDeckLinkIterator CDeckLinkIterator; #else typedef struct CDeckLinkIterator CDeckLinkIterator; #endif /* __cplusplus */ #endif /* __CDeckLinkIterator_FWD_DEFINED__ */ #ifndef __CDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ #define __CDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ #ifdef __cplusplus typedef class CDeckLinkGLScreenPreviewHelper CDeckLinkGLScreenPreviewHelper; #else typedef struct CDeckLinkGLScreenPreviewHelper CDeckLinkGLScreenPreviewHelper; #endif /* __cplusplus */ #endif /* __CDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ */ #ifndef __CDeckLinkVideoConversion_FWD_DEFINED__ #define __CDeckLinkVideoConversion_FWD_DEFINED__ #ifdef __cplusplus typedef class CDeckLinkVideoConversion CDeckLinkVideoConversion; #else typedef struct CDeckLinkVideoConversion CDeckLinkVideoConversion; #endif /* __cplusplus */ #endif /* __CDeckLinkVideoConversion_FWD_DEFINED__ */ #ifndef __IDeckLinkDisplayModeIterator_v7_6_FWD_DEFINED__ #define __IDeckLinkDisplayModeIterator_v7_6_FWD_DEFINED__ typedef interface IDeckLinkDisplayModeIterator_v7_6 IDeckLinkDisplayModeIterator_v7_6; #endif /* __IDeckLinkDisplayModeIterator_v7_6_FWD_DEFINED__ */ #ifndef __IDeckLinkDisplayMode_v7_6_FWD_DEFINED__ #define __IDeckLinkDisplayMode_v7_6_FWD_DEFINED__ typedef interface IDeckLinkDisplayMode_v7_6 IDeckLinkDisplayMode_v7_6; #endif /* __IDeckLinkDisplayMode_v7_6_FWD_DEFINED__ */ #ifndef __IDeckLinkOutput_v7_6_FWD_DEFINED__ #define __IDeckLinkOutput_v7_6_FWD_DEFINED__ typedef interface IDeckLinkOutput_v7_6 IDeckLinkOutput_v7_6; #endif /* __IDeckLinkOutput_v7_6_FWD_DEFINED__ */ #ifndef __IDeckLinkInput_v7_6_FWD_DEFINED__ #define __IDeckLinkInput_v7_6_FWD_DEFINED__ typedef interface IDeckLinkInput_v7_6 IDeckLinkInput_v7_6; #endif /* __IDeckLinkInput_v7_6_FWD_DEFINED__ */ #ifndef __IDeckLinkTimecode_v7_6_FWD_DEFINED__ #define __IDeckLinkTimecode_v7_6_FWD_DEFINED__ typedef interface IDeckLinkTimecode_v7_6 IDeckLinkTimecode_v7_6; #endif /* __IDeckLinkTimecode_v7_6_FWD_DEFINED__ */ #ifndef __IDeckLinkVideoFrame_v7_6_FWD_DEFINED__ #define __IDeckLinkVideoFrame_v7_6_FWD_DEFINED__ typedef interface IDeckLinkVideoFrame_v7_6 IDeckLinkVideoFrame_v7_6; #endif /* __IDeckLinkVideoFrame_v7_6_FWD_DEFINED__ */ #ifndef __IDeckLinkMutableVideoFrame_v7_6_FWD_DEFINED__ #define __IDeckLinkMutableVideoFrame_v7_6_FWD_DEFINED__ typedef interface IDeckLinkMutableVideoFrame_v7_6 IDeckLinkMutableVideoFrame_v7_6; #endif /* __IDeckLinkMutableVideoFrame_v7_6_FWD_DEFINED__ */ #ifndef __IDeckLinkVideoInputFrame_v7_6_FWD_DEFINED__ #define __IDeckLinkVideoInputFrame_v7_6_FWD_DEFINED__ typedef interface IDeckLinkVideoInputFrame_v7_6 IDeckLinkVideoInputFrame_v7_6; #endif /* __IDeckLinkVideoInputFrame_v7_6_FWD_DEFINED__ */ #ifndef __IDeckLinkScreenPreviewCallback_v7_6_FWD_DEFINED__ #define __IDeckLinkScreenPreviewCallback_v7_6_FWD_DEFINED__ typedef interface IDeckLinkScreenPreviewCallback_v7_6 IDeckLinkScreenPreviewCallback_v7_6; #endif /* __IDeckLinkScreenPreviewCallback_v7_6_FWD_DEFINED__ */ #ifndef __IDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ #define __IDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ typedef interface IDeckLinkGLScreenPreviewHelper_v7_6 IDeckLinkGLScreenPreviewHelper_v7_6; #endif /* __IDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ */ #ifndef __IDeckLinkVideoConversion_v7_6_FWD_DEFINED__ #define __IDeckLinkVideoConversion_v7_6_FWD_DEFINED__ typedef interface IDeckLinkVideoConversion_v7_6 IDeckLinkVideoConversion_v7_6; #endif /* __IDeckLinkVideoConversion_v7_6_FWD_DEFINED__ */ #ifndef __IDeckLinkConfiguration_v7_6_FWD_DEFINED__ #define __IDeckLinkConfiguration_v7_6_FWD_DEFINED__ typedef interface IDeckLinkConfiguration_v7_6 IDeckLinkConfiguration_v7_6; #endif /* __IDeckLinkConfiguration_v7_6_FWD_DEFINED__ */ #ifndef __IDeckLinkVideoOutputCallback_v7_6_FWD_DEFINED__ #define __IDeckLinkVideoOutputCallback_v7_6_FWD_DEFINED__ typedef interface IDeckLinkVideoOutputCallback_v7_6 IDeckLinkVideoOutputCallback_v7_6; #endif /* __IDeckLinkVideoOutputCallback_v7_6_FWD_DEFINED__ */ #ifndef __IDeckLinkInputCallback_v7_6_FWD_DEFINED__ #define __IDeckLinkInputCallback_v7_6_FWD_DEFINED__ typedef interface IDeckLinkInputCallback_v7_6 IDeckLinkInputCallback_v7_6; #endif /* __IDeckLinkInputCallback_v7_6_FWD_DEFINED__ */ #ifndef __CDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ #define __CDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ #ifdef __cplusplus typedef class CDeckLinkGLScreenPreviewHelper_v7_6 CDeckLinkGLScreenPreviewHelper_v7_6; #else typedef struct CDeckLinkGLScreenPreviewHelper_v7_6 CDeckLinkGLScreenPreviewHelper_v7_6; #endif /* __cplusplus */ #endif /* __CDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ */ #ifndef __CDeckLinkVideoConversion_v7_6_FWD_DEFINED__ #define __CDeckLinkVideoConversion_v7_6_FWD_DEFINED__ #ifdef __cplusplus typedef class CDeckLinkVideoConversion_v7_6 CDeckLinkVideoConversion_v7_6; #else typedef struct CDeckLinkVideoConversion_v7_6 CDeckLinkVideoConversion_v7_6; #endif /* __cplusplus */ #endif /* __CDeckLinkVideoConversion_v7_6_FWD_DEFINED__ */ #ifndef __IDeckLinkInputCallback_v7_3_FWD_DEFINED__ #define __IDeckLinkInputCallback_v7_3_FWD_DEFINED__ typedef interface IDeckLinkInputCallback_v7_3 IDeckLinkInputCallback_v7_3; #endif /* __IDeckLinkInputCallback_v7_3_FWD_DEFINED__ */ #ifndef __IDeckLinkOutput_v7_3_FWD_DEFINED__ #define __IDeckLinkOutput_v7_3_FWD_DEFINED__ typedef interface IDeckLinkOutput_v7_3 IDeckLinkOutput_v7_3; #endif /* __IDeckLinkOutput_v7_3_FWD_DEFINED__ */ #ifndef __IDeckLinkInput_v7_3_FWD_DEFINED__ #define __IDeckLinkInput_v7_3_FWD_DEFINED__ typedef interface IDeckLinkInput_v7_3 IDeckLinkInput_v7_3; #endif /* __IDeckLinkInput_v7_3_FWD_DEFINED__ */ #ifndef __IDeckLinkVideoInputFrame_v7_3_FWD_DEFINED__ #define __IDeckLinkVideoInputFrame_v7_3_FWD_DEFINED__ typedef interface IDeckLinkVideoInputFrame_v7_3 IDeckLinkVideoInputFrame_v7_3; #endif /* __IDeckLinkVideoInputFrame_v7_3_FWD_DEFINED__ */ #ifndef __IDeckLinkDisplayModeIterator_v7_1_FWD_DEFINED__ #define __IDeckLinkDisplayModeIterator_v7_1_FWD_DEFINED__ typedef interface IDeckLinkDisplayModeIterator_v7_1 IDeckLinkDisplayModeIterator_v7_1; #endif /* __IDeckLinkDisplayModeIterator_v7_1_FWD_DEFINED__ */ #ifndef __IDeckLinkDisplayMode_v7_1_FWD_DEFINED__ #define __IDeckLinkDisplayMode_v7_1_FWD_DEFINED__ typedef interface IDeckLinkDisplayMode_v7_1 IDeckLinkDisplayMode_v7_1; #endif /* __IDeckLinkDisplayMode_v7_1_FWD_DEFINED__ */ #ifndef __IDeckLinkVideoFrame_v7_1_FWD_DEFINED__ #define __IDeckLinkVideoFrame_v7_1_FWD_DEFINED__ typedef interface IDeckLinkVideoFrame_v7_1 IDeckLinkVideoFrame_v7_1; #endif /* __IDeckLinkVideoFrame_v7_1_FWD_DEFINED__ */ #ifndef __IDeckLinkVideoInputFrame_v7_1_FWD_DEFINED__ #define __IDeckLinkVideoInputFrame_v7_1_FWD_DEFINED__ typedef interface IDeckLinkVideoInputFrame_v7_1 IDeckLinkVideoInputFrame_v7_1; #endif /* __IDeckLinkVideoInputFrame_v7_1_FWD_DEFINED__ */ #ifndef __IDeckLinkAudioInputPacket_v7_1_FWD_DEFINED__ #define __IDeckLinkAudioInputPacket_v7_1_FWD_DEFINED__ typedef interface IDeckLinkAudioInputPacket_v7_1 IDeckLinkAudioInputPacket_v7_1; #endif /* __IDeckLinkAudioInputPacket_v7_1_FWD_DEFINED__ */ #ifndef __IDeckLinkVideoOutputCallback_v7_1_FWD_DEFINED__ #define __IDeckLinkVideoOutputCallback_v7_1_FWD_DEFINED__ typedef interface IDeckLinkVideoOutputCallback_v7_1 IDeckLinkVideoOutputCallback_v7_1; #endif /* __IDeckLinkVideoOutputCallback_v7_1_FWD_DEFINED__ */ #ifndef __IDeckLinkInputCallback_v7_1_FWD_DEFINED__ #define __IDeckLinkInputCallback_v7_1_FWD_DEFINED__ typedef interface IDeckLinkInputCallback_v7_1 IDeckLinkInputCallback_v7_1; #endif /* __IDeckLinkInputCallback_v7_1_FWD_DEFINED__ */ #ifndef __IDeckLinkOutput_v7_1_FWD_DEFINED__ #define __IDeckLinkOutput_v7_1_FWD_DEFINED__ typedef interface IDeckLinkOutput_v7_1 IDeckLinkOutput_v7_1; #endif /* __IDeckLinkOutput_v7_1_FWD_DEFINED__ */ #ifndef __IDeckLinkInput_v7_1_FWD_DEFINED__ #define __IDeckLinkInput_v7_1_FWD_DEFINED__ typedef interface IDeckLinkInput_v7_1 IDeckLinkInput_v7_1; #endif /* __IDeckLinkInput_v7_1_FWD_DEFINED__ */ /* header files for imported files */ #include "unknwn.h" #ifdef __cplusplus extern "C"{ #endif #ifndef __DeckLinkAPI_LIBRARY_DEFINED__ #define __DeckLinkAPI_LIBRARY_DEFINED__ /* library DeckLinkAPI */ /* [helpstring][version][uuid] */ typedef LONGLONG BMDTimeValue; typedef LONGLONG BMDTimeScale; typedef unsigned long BMDTimecodeBCD; typedef unsigned long BMDTimecodeUserBits; typedef unsigned long BMDDisplayModeFlags; typedef unsigned long BMDFrameFlags; typedef unsigned long BMDVideoInputFlags; typedef unsigned long BMDVideoInputFormatChangedEvents; typedef unsigned long BMDDetectedVideoInputFormatFlags; typedef unsigned long BMDTimecodeFlags; typedef unsigned long BMDAnalogVideoFlags; typedef unsigned long BMDDeckControlStatusFlags; typedef unsigned long BMDDeckControlExportModeOpsFlags; #if 0 typedef enum _BMDDisplayModeFlags BMDDisplayModeFlags; typedef enum _BMDFrameFlags BMDFrameFlags; typedef enum _BMDVideoInputFlags BMDVideoInputFlags; typedef enum _BMDVideoInputFormatChangedEvents BMDVideoInputFormatChangedEvents; typedef enum _BMDDetectedVideoInputFormatFlags BMDDetectedVideoInputFormatFlags; typedef enum _BMDTimecodeFlags BMDTimecodeFlags; typedef enum _BMDAnalogVideoFlags BMDAnalogVideoFlags; typedef enum _BMDDeckControlStatusFlags BMDDeckControlStatusFlags; typedef enum _BMDDeckControlExportModeOpsFlags BMDDeckControlExportModeOpsFlags; #endif typedef /* [v1_enum] */ enum _BMDDisplayMode { bmdModeNTSC = 0x6e747363, bmdModeNTSC2398 = 0x6e743233, bmdModePAL = 0x70616c20, bmdModeHD1080p2398 = 0x32337073, bmdModeHD1080p24 = 0x32347073, bmdModeHD1080p25 = 0x48703235, bmdModeHD1080p2997 = 0x48703239, bmdModeHD1080p30 = 0x48703330, bmdModeHD1080i50 = 0x48693530, bmdModeHD1080i5994 = 0x48693539, bmdModeHD1080i6000 = 0x48693630, bmdModeHD1080p50 = 0x48703530, bmdModeHD1080p5994 = 0x48703539, bmdModeHD1080p6000 = 0x48703630, bmdModeHD720p50 = 0x68703530, bmdModeHD720p5994 = 0x68703539, bmdModeHD720p60 = 0x68703630, bmdMode2k2398 = 0x326b3233, bmdMode2k24 = 0x326b3234, bmdMode2k25 = 0x326b3235 } BMDDisplayMode; typedef /* [v1_enum] */ enum _BMDFieldDominance { bmdUnknownFieldDominance = 0, bmdLowerFieldFirst = 0x6c6f7772, bmdUpperFieldFirst = 0x75707072, bmdProgressiveFrame = 0x70726f67, bmdProgressiveSegmentedFrame = 0x70736620 } BMDFieldDominance; typedef /* [v1_enum] */ enum _BMDPixelFormat { bmdFormat8BitYUV = 0x32767579, bmdFormat10BitYUV = 0x76323130, bmdFormat8BitARGB = 32, bmdFormat8BitBGRA = 0x42475241, bmdFormat10BitRGB = 0x72323130 } BMDPixelFormat; /* [v1_enum] */ enum _BMDDisplayModeFlags { bmdDisplayModeSupports3D = ( 1 << 0 ) , bmdDisplayModeColorspaceRec601 = ( 1 << 1 ) , bmdDisplayModeColorspaceRec709 = ( 1 << 2 ) } ; typedef /* [v1_enum] */ enum _BMDVideoOutputFlags { bmdVideoOutputFlagDefault = 0, bmdVideoOutputVANC = ( 1 << 0 ) , bmdVideoOutputVITC = ( 1 << 1 ) , bmdVideoOutputRP188 = ( 1 << 2 ) , bmdVideoOutputDualStream3D = ( 1 << 4 ) } BMDVideoOutputFlags; /* [v1_enum] */ enum _BMDFrameFlags { bmdFrameFlagDefault = 0, bmdFrameFlagFlipVertical = ( 1 << 0 ) , bmdFrameHasNoInputSource = ( 1 << 31 ) } ; /* [v1_enum] */ enum _BMDVideoInputFlags { bmdVideoInputFlagDefault = 0, bmdVideoInputEnableFormatDetection = ( 1 << 0 ) , bmdVideoInputDualStream3D = ( 1 << 1 ) } ; /* [v1_enum] */ enum _BMDVideoInputFormatChangedEvents { bmdVideoInputDisplayModeChanged = ( 1 << 0 ) , bmdVideoInputFieldDominanceChanged = ( 1 << 1 ) , bmdVideoInputColorspaceChanged = ( 1 << 2 ) } ; /* [v1_enum] */ enum _BMDDetectedVideoInputFormatFlags { bmdDetectedVideoInputYCbCr422 = ( 1 << 0 ) , bmdDetectedVideoInputRGB444 = ( 1 << 1 ) } ; typedef /* [v1_enum] */ enum _BMDOutputFrameCompletionResult { bmdOutputFrameCompleted = 0, bmdOutputFrameDisplayedLate = ( bmdOutputFrameCompleted + 1 ) , bmdOutputFrameDropped = ( bmdOutputFrameDisplayedLate + 1 ) , bmdOutputFrameFlushed = ( bmdOutputFrameDropped + 1 ) } BMDOutputFrameCompletionResult; typedef /* [v1_enum] */ enum _BMDReferenceStatus { bmdReferenceNotSupportedByHardware = ( 1 << 0 ) , bmdReferenceLocked = ( 1 << 1 ) } BMDReferenceStatus; typedef /* [v1_enum] */ enum _BMDAudioSampleRate { bmdAudioSampleRate48kHz = 48000 } BMDAudioSampleRate; typedef /* [v1_enum] */ enum _BMDAudioSampleType { bmdAudioSampleType16bitInteger = 16, bmdAudioSampleType32bitInteger = 32 } BMDAudioSampleType; typedef /* [v1_enum] */ enum _BMDAudioOutputStreamType { bmdAudioOutputStreamContinuous = 0, bmdAudioOutputStreamContinuousDontResample = ( bmdAudioOutputStreamContinuous + 1 ) , bmdAudioOutputStreamTimestamped = ( bmdAudioOutputStreamContinuousDontResample + 1 ) } BMDAudioOutputStreamType; typedef /* [v1_enum] */ enum _BMDDisplayModeSupport { bmdDisplayModeNotSupported = 0, bmdDisplayModeSupported = ( bmdDisplayModeNotSupported + 1 ) , bmdDisplayModeSupportedWithConversion = ( bmdDisplayModeSupported + 1 ) } BMDDisplayModeSupport; typedef /* [v1_enum] */ enum _BMDTimecodeFormat { bmdTimecodeRP188 = 0x72703138, bmdTimecodeVITC = 0x76697463, bmdTimecodeSerial = 0x73657269 } BMDTimecodeFormat; /* [v1_enum] */ enum _BMDTimecodeFlags { bmdTimecodeFlagDefault = 0, bmdTimecodeIsDropFrame = ( 1 << 0 ) } ; typedef /* [v1_enum] */ enum _BMDVideoConnection { bmdVideoConnectionSDI = ( 1 << 0 ) , bmdVideoConnectionHDMI = ( 1 << 1 ) , bmdVideoConnectionOpticalSDI = ( 1 << 2 ) , bmdVideoConnectionComponent = ( 1 << 3 ) , bmdVideoConnectionComposite = ( 1 << 4 ) , bmdVideoConnectionSVideo = ( 1 << 5 ) } BMDVideoConnection; /* [v1_enum] */ enum _BMDAnalogVideoFlags { bmdAnalogVideoFlagCompositeSetup75 = ( 1 << 0 ) , bmdAnalogVideoFlagComponentBetacamLevels = ( 1 << 1 ) } ; typedef /* [v1_enum] */ enum _BMDAudioConnection { bmdAudioConnectionEmbedded = 0x656d6264, bmdAudioConnectionAESEBU = 0x61657320, bmdAudioConnectionAnalog = 0x616e6c67 } BMDAudioConnection; typedef /* [v1_enum] */ enum _BMDAudioOutputAnalogAESSwitch { bmdAudioOutputSwitchAESEBU = 0x61657320, bmdAudioOutputSwitchAnalog = 0x616e6c67 } BMDAudioOutputAnalogAESSwitch; typedef /* [v1_enum] */ enum _BMDVideoOutputConversionMode { bmdNoVideoOutputConversion = 0x6e6f6e65, bmdVideoOutputLetterboxDownconversion = 0x6c746278, bmdVideoOutputAnamorphicDownconversion = 0x616d7068, bmdVideoOutputHD720toHD1080Conversion = 0x37323063, bmdVideoOutputHardwareLetterboxDownconversion = 0x48576c62, bmdVideoOutputHardwareAnamorphicDownconversion = 0x4857616d, bmdVideoOutputHardwareCenterCutDownconversion = 0x48576363, bmdVideoOutputHardware720p1080pCrossconversion = 0x78636170, bmdVideoOutputHardwareAnamorphic720pUpconversion = 0x75613770, bmdVideoOutputHardwareAnamorphic1080iUpconversion = 0x75613169, bmdVideoOutputHardwareAnamorphic149To720pUpconversion = 0x75343770, bmdVideoOutputHardwareAnamorphic149To1080iUpconversion = 0x75343169, bmdVideoOutputHardwarePillarbox720pUpconversion = 0x75703770, bmdVideoOutputHardwarePillarbox1080iUpconversion = 0x75703169 } BMDVideoOutputConversionMode; typedef /* [v1_enum] */ enum _BMDVideoInputConversionMode { bmdNoVideoInputConversion = 0x6e6f6e65, bmdVideoInputLetterboxDownconversionFromHD1080 = 0x31306c62, bmdVideoInputAnamorphicDownconversionFromHD1080 = 0x3130616d, bmdVideoInputLetterboxDownconversionFromHD720 = 0x37326c62, bmdVideoInputAnamorphicDownconversionFromHD720 = 0x3732616d, bmdVideoInputLetterboxUpconversion = 0x6c627570, bmdVideoInputAnamorphicUpconversion = 0x616d7570 } BMDVideoInputConversionMode; typedef /* [v1_enum] */ enum _BMDVideo3DPackingFormat { bmdVideo3DPackingSidebySideHalf = 0x73627368, bmdVideo3DPackingLinebyLine = 0x6c62796c, bmdVideo3DPackingTopAndBottom = 0x7461626f, bmdVideo3DPackingLeftOnly = 0x6c656674, bmdVideo3DPackingRightOnly = 0x72696768 } BMDVideo3DPackingFormat; typedef /* [v1_enum] */ enum _BMDDeckLinkConfigurationID { bmdDeckLinkConfigUse1080pNotPsF = 0x6670726f, bmdDeckLinkConfigHDMI3DPackingFormat = 0x33647066, bmdDeckLinkConfigAnalogAudioConsumerLevels = 0x6161636c, bmdDeckLinkConfigFieldFlickerRemoval = 0x66646672, bmdDeckLinkConfigHD1080p24ToHD1080i5994Conversion = 0x746f3539, bmdDeckLinkConfig444SDIVideoOutput = 0x3434346f, bmdDeckLinkConfig3GBpsVideoOutput = 0x33676273, bmdDeckLinkConfigBlackVideoOutputDuringCapture = 0x62766f63, bmdDeckLinkConfigLowLatencyVideoOutput = 0x6c6c766f, bmdDeckLinkConfigVideoOutputConnection = 0x766f636e, bmdDeckLinkConfigVideoOutputConversionMode = 0x766f636d, bmdDeckLinkConfigAnalogVideoOutputFlags = 0x61766f66, bmdDeckLinkConfigReferenceInputTimingOffset = 0x676c6f74, bmdDeckLinkConfigVideoInputConnection = 0x7669636e, bmdDeckLinkConfigAnalogVideoInputFlags = 0x61766966, bmdDeckLinkConfigVideoInputConversionMode = 0x7669636d, bmdDeckLinkConfig32PulldownSequenceInitialTimecodeFrame = 0x70646966, bmdDeckLinkConfigVANCSourceLine1Mapping = 0x76736c31, bmdDeckLinkConfigVANCSourceLine2Mapping = 0x76736c32, bmdDeckLinkConfigVANCSourceLine3Mapping = 0x76736c33, bmdDeckLinkConfigAudioInputConnection = 0x6169636e, bmdDeckLinkConfigAnalogAudioInputScaleChannel1 = 0x61697331, bmdDeckLinkConfigAnalogAudioInputScaleChannel2 = 0x61697332, bmdDeckLinkConfigAnalogAudioInputScaleChannel3 = 0x61697333, bmdDeckLinkConfigAnalogAudioInputScaleChannel4 = 0x61697334, bmdDeckLinkConfigDigitalAudioInputScale = 0x64616973, bmdDeckLinkConfigAudioOutputAESAnalogSwitch = 0x616f6161, bmdDeckLinkConfigAnalogAudioOutputScaleChannel1 = 0x616f7331, bmdDeckLinkConfigAnalogAudioOutputScaleChannel2 = 0x616f7332, bmdDeckLinkConfigAnalogAudioOutputScaleChannel3 = 0x616f7333, bmdDeckLinkConfigAnalogAudioOutputScaleChannel4 = 0x616f7334, bmdDeckLinkConfigDigitalAudioOutputScale = 0x64616f73 } BMDDeckLinkConfigurationID; typedef /* [v1_enum] */ enum _BMDDeckLinkAttributeID { BMDDeckLinkSupportsInternalKeying = 0x6b657969, BMDDeckLinkSupportsExternalKeying = 0x6b657965, BMDDeckLinkSupportsHDKeying = 0x6b657968, BMDDeckLinkSupportsInputFormatDetection = 0x696e6664, BMDDeckLinkHasReferenceInput = 0x6872696e, BMDDeckLinkHasSerialPort = 0x68737074, BMDDeckLinkMaximumAudioChannels = 0x6d616368, BMDDeckLinkNumberOfSubDevices = 0x6e736264, BMDDeckLinkSubDeviceIndex = 0x73756269, BMDDeckLinkVideoOutputConnections = 0x766f636e, BMDDeckLinkVideoInputConnections = 0x7669636e, BMDDeckLinkSerialPortDeviceName = 0x736c706e } BMDDeckLinkAttributeID; typedef /* [v1_enum] */ enum _BMDDeckLinkAPIInformationID { BMDDeckLinkAPIVersion = 0x76657273 } BMDDeckLinkAPIInformationID; typedef /* [v1_enum] */ enum _BMDDeckControlMode { bmdDeckControlNotOpened = 0x6e746f70, bmdDeckControlVTRControlMode = 0x76747263, bmdDeckControlExportMode = 0x6578706d, bmdDeckControlCaptureMode = 0x6361706d } BMDDeckControlMode; typedef /* [v1_enum] */ enum _BMDDeckControlEvent { bmdDeckControlAbortedEvent = 0x61627465, bmdDeckControlPrepareForExportEvent = 0x70666565, bmdDeckControlExportCompleteEvent = 0x65786365, bmdDeckControlPrepareForCaptureEvent = 0x70666365, bmdDeckControlCaptureCompleteEvent = 0x63636576 } BMDDeckControlEvent; typedef /* [v1_enum] */ enum _BMDDeckControlVTRControlState { bmdDeckControlNotInVTRControlMode = 0x6e76636d, bmdDeckControlVTRControlPlaying = 0x76747270, bmdDeckControlVTRControlRecording = 0x76747272, bmdDeckControlVTRControlStill = 0x76747261, bmdDeckControlVTRControlSeeking = 0x76747273, bmdDeckControlVTRControlStopped = 0x7674726f } BMDDeckControlVTRControlState; /* [v1_enum] */ enum _BMDDeckControlStatusFlags { bmdDeckControlStatusDeckConnected = ( 1 << 0 ) , bmdDeckControlStatusRemoteMode = ( 1 << 1 ) , bmdDeckControlStatusRecordInhibited = ( 1 << 2 ) , bmdDeckControlStatusCassetteOut = ( 1 << 3 ) } ; /* [v1_enum] */ enum _BMDDeckControlExportModeOpsFlags { bmdDeckControlExportModeInsertVideo = ( 1 << 0 ) , bmdDeckControlExportModeInsertAudio1 = ( 1 << 1 ) , bmdDeckControlExportModeInsertAudio2 = ( 1 << 2 ) , bmdDeckControlExportModeInsertAudio3 = ( 1 << 3 ) , bmdDeckControlExportModeInsertAudio4 = ( 1 << 4 ) , bmdDeckControlExportModeInsertAudio5 = ( 1 << 5 ) , bmdDeckControlExportModeInsertAudio6 = ( 1 << 6 ) , bmdDeckControlExportModeInsertAudio7 = ( 1 << 7 ) , bmdDeckControlExportModeInsertAudio8 = ( 1 << 8 ) , bmdDeckControlExportModeInsertAudio9 = ( 1 << 9 ) , bmdDeckControlExportModeInsertAudio10 = ( 1 << 10 ) , bmdDeckControlExportModeInsertAudio11 = ( 1 << 11 ) , bmdDeckControlExportModeInsertAudio12 = ( 1 << 12 ) , bmdDeckControlExportModeInsertTimeCode = ( 1 << 13 ) , bmdDeckControlExportModeInsertAssemble = ( 1 << 14 ) , bmdDeckControlExportModeInsertPreview = ( 1 << 15 ) , bmdDeckControlUseManualExport = ( 1 << 16 ) } ; typedef /* [v1_enum] */ enum _BMDDeckControlError { bmdDeckControlNoError = 0x6e6f6572, bmdDeckControlModeError = 0x6d6f6572, bmdDeckControlMissedInPointError = 0x6d696572, bmdDeckControlDeckTimeoutError = 0x64746572, bmdDeckControlCommandFailedError = 0x63666572, bmdDeckControlDeviceAlreadyOpenedError = 0x64616c6f, bmdDeckControlFailedToOpenDeviceError = 0x66646572, bmdDeckControlInLocalModeError = 0x6c6d6572, bmdDeckControlEndOfTapeError = 0x65746572, bmdDeckControlUserAbortError = 0x75616572, bmdDeckControlNoTapeInDeckError = 0x6e746572, bmdDeckControlNoVideoFromCardError = 0x6e766663, bmdDeckControlNoCommunicationError = 0x6e636f6d, bmdDeckControlUnknownError = 0x756e6572 } BMDDeckControlError; typedef /* [v1_enum] */ enum _BMD3DPreviewFormat { bmd3DPreviewFormatDefault = 0x64656661, bmd3DPreviewFormatLeftOnly = 0x6c656674, bmd3DPreviewFormatRightOnly = 0x72696768, bmd3DPreviewFormatSideBySide = 0x73696465, bmd3DPreviewFormatTopBottom = 0x746f7062 } BMD3DPreviewFormat; typedef /* [v1_enum] */ enum _BMDVideoConnection_v7_6 { bmdVideoConnectionSDI_v7_6 = 0x73646920, bmdVideoConnectionHDMI_v7_6 = 0x68646d69, bmdVideoConnectionOpticalSDI_v7_6 = 0x6f707469, bmdVideoConnectionComponent_v7_6 = 0x63706e74, bmdVideoConnectionComposite_v7_6 = 0x636d7374, bmdVideoConnectionSVideo_v7_6 = 0x73766964 } BMDVideoConnection_v7_6; EXTERN_C const IID LIBID_DeckLinkAPI; #ifndef __IDeckLinkVideoOutputCallback_INTERFACE_DEFINED__ #define __IDeckLinkVideoOutputCallback_INTERFACE_DEFINED__ /* interface IDeckLinkVideoOutputCallback */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkVideoOutputCallback; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("20AA5225-1958-47CB-820B-80A8D521A6EE") IDeckLinkVideoOutputCallback : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted( /* [in] */ IDeckLinkVideoFrame *completedFrame, /* [in] */ BMDOutputFrameCompletionResult result) = 0; virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped( void) = 0; }; #else /* C style interface */ typedef struct IDeckLinkVideoOutputCallbackVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkVideoOutputCallback * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkVideoOutputCallback * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkVideoOutputCallback * This); HRESULT ( STDMETHODCALLTYPE *ScheduledFrameCompleted )( IDeckLinkVideoOutputCallback * This, /* [in] */ IDeckLinkVideoFrame *completedFrame, /* [in] */ BMDOutputFrameCompletionResult result); HRESULT ( STDMETHODCALLTYPE *ScheduledPlaybackHasStopped )( IDeckLinkVideoOutputCallback * This); END_INTERFACE } IDeckLinkVideoOutputCallbackVtbl; interface IDeckLinkVideoOutputCallback { CONST_VTBL struct IDeckLinkVideoOutputCallbackVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkVideoOutputCallback_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkVideoOutputCallback_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkVideoOutputCallback_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkVideoOutputCallback_ScheduledFrameCompleted(This,completedFrame,result) \ ( (This)->lpVtbl -> ScheduledFrameCompleted(This,completedFrame,result) ) #define IDeckLinkVideoOutputCallback_ScheduledPlaybackHasStopped(This) \ ( (This)->lpVtbl -> ScheduledPlaybackHasStopped(This) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkVideoOutputCallback_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkInputCallback_INTERFACE_DEFINED__ #define __IDeckLinkInputCallback_INTERFACE_DEFINED__ /* interface IDeckLinkInputCallback */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkInputCallback; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("DD04E5EC-7415-42AB-AE4A-E80C4DFC044A") IDeckLinkInputCallback : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged( /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, /* [in] */ IDeckLinkDisplayMode *newDisplayMode, /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( /* [in] */ IDeckLinkVideoInputFrame *videoFrame, /* [in] */ IDeckLinkAudioInputPacket *audioPacket) = 0; }; #else /* C style interface */ typedef struct IDeckLinkInputCallbackVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkInputCallback * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkInputCallback * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkInputCallback * This); HRESULT ( STDMETHODCALLTYPE *VideoInputFormatChanged )( IDeckLinkInputCallback * This, /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, /* [in] */ IDeckLinkDisplayMode *newDisplayMode, /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags); HRESULT ( STDMETHODCALLTYPE *VideoInputFrameArrived )( IDeckLinkInputCallback * This, /* [in] */ IDeckLinkVideoInputFrame *videoFrame, /* [in] */ IDeckLinkAudioInputPacket *audioPacket); END_INTERFACE } IDeckLinkInputCallbackVtbl; interface IDeckLinkInputCallback { CONST_VTBL struct IDeckLinkInputCallbackVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkInputCallback_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkInputCallback_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkInputCallback_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkInputCallback_VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) \ ( (This)->lpVtbl -> VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) ) #define IDeckLinkInputCallback_VideoInputFrameArrived(This,videoFrame,audioPacket) \ ( (This)->lpVtbl -> VideoInputFrameArrived(This,videoFrame,audioPacket) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkInputCallback_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkMemoryAllocator_INTERFACE_DEFINED__ #define __IDeckLinkMemoryAllocator_INTERFACE_DEFINED__ /* interface IDeckLinkMemoryAllocator */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkMemoryAllocator; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("B36EB6E7-9D29-4AA8-92EF-843B87A289E8") IDeckLinkMemoryAllocator : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE AllocateBuffer( /* [in] */ unsigned long bufferSize, /* [out] */ void **allocatedBuffer) = 0; virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer( /* [in] */ void *buffer) = 0; virtual HRESULT STDMETHODCALLTYPE Commit( void) = 0; virtual HRESULT STDMETHODCALLTYPE Decommit( void) = 0; }; #else /* C style interface */ typedef struct IDeckLinkMemoryAllocatorVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkMemoryAllocator * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkMemoryAllocator * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkMemoryAllocator * This); HRESULT ( STDMETHODCALLTYPE *AllocateBuffer )( IDeckLinkMemoryAllocator * This, /* [in] */ unsigned long bufferSize, /* [out] */ void **allocatedBuffer); HRESULT ( STDMETHODCALLTYPE *ReleaseBuffer )( IDeckLinkMemoryAllocator * This, /* [in] */ void *buffer); HRESULT ( STDMETHODCALLTYPE *Commit )( IDeckLinkMemoryAllocator * This); HRESULT ( STDMETHODCALLTYPE *Decommit )( IDeckLinkMemoryAllocator * This); END_INTERFACE } IDeckLinkMemoryAllocatorVtbl; interface IDeckLinkMemoryAllocator { CONST_VTBL struct IDeckLinkMemoryAllocatorVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkMemoryAllocator_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkMemoryAllocator_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkMemoryAllocator_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkMemoryAllocator_AllocateBuffer(This,bufferSize,allocatedBuffer) \ ( (This)->lpVtbl -> AllocateBuffer(This,bufferSize,allocatedBuffer) ) #define IDeckLinkMemoryAllocator_ReleaseBuffer(This,buffer) \ ( (This)->lpVtbl -> ReleaseBuffer(This,buffer) ) #define IDeckLinkMemoryAllocator_Commit(This) \ ( (This)->lpVtbl -> Commit(This) ) #define IDeckLinkMemoryAllocator_Decommit(This) \ ( (This)->lpVtbl -> Decommit(This) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkMemoryAllocator_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkAudioOutputCallback_INTERFACE_DEFINED__ #define __IDeckLinkAudioOutputCallback_INTERFACE_DEFINED__ /* interface IDeckLinkAudioOutputCallback */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkAudioOutputCallback; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("403C681B-7F46-4A12-B993-2BB127084EE6") IDeckLinkAudioOutputCallback : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE RenderAudioSamples( /* [in] */ BOOL preroll) = 0; }; #else /* C style interface */ typedef struct IDeckLinkAudioOutputCallbackVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkAudioOutputCallback * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkAudioOutputCallback * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkAudioOutputCallback * This); HRESULT ( STDMETHODCALLTYPE *RenderAudioSamples )( IDeckLinkAudioOutputCallback * This, /* [in] */ BOOL preroll); END_INTERFACE } IDeckLinkAudioOutputCallbackVtbl; interface IDeckLinkAudioOutputCallback { CONST_VTBL struct IDeckLinkAudioOutputCallbackVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkAudioOutputCallback_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkAudioOutputCallback_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkAudioOutputCallback_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkAudioOutputCallback_RenderAudioSamples(This,preroll) \ ( (This)->lpVtbl -> RenderAudioSamples(This,preroll) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkAudioOutputCallback_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkIterator_INTERFACE_DEFINED__ #define __IDeckLinkIterator_INTERFACE_DEFINED__ /* interface IDeckLinkIterator */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkIterator; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("74E936FC-CC28-4A67-81A0-1E94E52D4E69") IDeckLinkIterator : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE Next( /* [out] */ IDeckLink **deckLinkInstance) = 0; }; #else /* C style interface */ typedef struct IDeckLinkIteratorVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkIterator * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkIterator * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkIterator * This); HRESULT ( STDMETHODCALLTYPE *Next )( IDeckLinkIterator * This, /* [out] */ IDeckLink **deckLinkInstance); END_INTERFACE } IDeckLinkIteratorVtbl; interface IDeckLinkIterator { CONST_VTBL struct IDeckLinkIteratorVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkIterator_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkIterator_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkIterator_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkIterator_Next(This,deckLinkInstance) \ ( (This)->lpVtbl -> Next(This,deckLinkInstance) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkIterator_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkAPIInformation_INTERFACE_DEFINED__ #define __IDeckLinkAPIInformation_INTERFACE_DEFINED__ /* interface IDeckLinkAPIInformation */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkAPIInformation; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("7BEA3C68-730D-4322-AF34-8A7152B532A4") IDeckLinkAPIInformation : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE GetFlag( /* [in] */ BMDDeckLinkAPIInformationID cfgID, /* [out] */ BOOL *value) = 0; virtual HRESULT STDMETHODCALLTYPE GetInt( /* [in] */ BMDDeckLinkAPIInformationID cfgID, /* [out] */ LONGLONG *value) = 0; virtual HRESULT STDMETHODCALLTYPE GetFloat( /* [in] */ BMDDeckLinkAPIInformationID cfgID, /* [out] */ double *value) = 0; virtual HRESULT STDMETHODCALLTYPE GetString( /* [in] */ BMDDeckLinkAPIInformationID cfgID, /* [out] */ BSTR *value) = 0; }; #else /* C style interface */ typedef struct IDeckLinkAPIInformationVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkAPIInformation * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkAPIInformation * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkAPIInformation * This); HRESULT ( STDMETHODCALLTYPE *GetFlag )( IDeckLinkAPIInformation * This, /* [in] */ BMDDeckLinkAPIInformationID cfgID, /* [out] */ BOOL *value); HRESULT ( STDMETHODCALLTYPE *GetInt )( IDeckLinkAPIInformation * This, /* [in] */ BMDDeckLinkAPIInformationID cfgID, /* [out] */ LONGLONG *value); HRESULT ( STDMETHODCALLTYPE *GetFloat )( IDeckLinkAPIInformation * This, /* [in] */ BMDDeckLinkAPIInformationID cfgID, /* [out] */ double *value); HRESULT ( STDMETHODCALLTYPE *GetString )( IDeckLinkAPIInformation * This, /* [in] */ BMDDeckLinkAPIInformationID cfgID, /* [out] */ BSTR *value); END_INTERFACE } IDeckLinkAPIInformationVtbl; interface IDeckLinkAPIInformation { CONST_VTBL struct IDeckLinkAPIInformationVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkAPIInformation_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkAPIInformation_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkAPIInformation_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkAPIInformation_GetFlag(This,cfgID,value) \ ( (This)->lpVtbl -> GetFlag(This,cfgID,value) ) #define IDeckLinkAPIInformation_GetInt(This,cfgID,value) \ ( (This)->lpVtbl -> GetInt(This,cfgID,value) ) #define IDeckLinkAPIInformation_GetFloat(This,cfgID,value) \ ( (This)->lpVtbl -> GetFloat(This,cfgID,value) ) #define IDeckLinkAPIInformation_GetString(This,cfgID,value) \ ( (This)->lpVtbl -> GetString(This,cfgID,value) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkAPIInformation_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkDisplayModeIterator_INTERFACE_DEFINED__ #define __IDeckLinkDisplayModeIterator_INTERFACE_DEFINED__ /* interface IDeckLinkDisplayModeIterator */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkDisplayModeIterator; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("9C88499F-F601-4021-B80B-032E4EB41C35") IDeckLinkDisplayModeIterator : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE Next( /* [out] */ IDeckLinkDisplayMode **deckLinkDisplayMode) = 0; }; #else /* C style interface */ typedef struct IDeckLinkDisplayModeIteratorVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkDisplayModeIterator * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkDisplayModeIterator * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkDisplayModeIterator * This); HRESULT ( STDMETHODCALLTYPE *Next )( IDeckLinkDisplayModeIterator * This, /* [out] */ IDeckLinkDisplayMode **deckLinkDisplayMode); END_INTERFACE } IDeckLinkDisplayModeIteratorVtbl; interface IDeckLinkDisplayModeIterator { CONST_VTBL struct IDeckLinkDisplayModeIteratorVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkDisplayModeIterator_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkDisplayModeIterator_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkDisplayModeIterator_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkDisplayModeIterator_Next(This,deckLinkDisplayMode) \ ( (This)->lpVtbl -> Next(This,deckLinkDisplayMode) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkDisplayModeIterator_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkDisplayMode_INTERFACE_DEFINED__ #define __IDeckLinkDisplayMode_INTERFACE_DEFINED__ /* interface IDeckLinkDisplayMode */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkDisplayMode; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("3EB2C1AB-0A3D-4523-A3AD-F40D7FB14E78") IDeckLinkDisplayMode : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE GetName( /* [out] */ BSTR *name) = 0; virtual BMDDisplayMode STDMETHODCALLTYPE GetDisplayMode( void) = 0; virtual long STDMETHODCALLTYPE GetWidth( void) = 0; virtual long STDMETHODCALLTYPE GetHeight( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetFrameRate( /* [out] */ BMDTimeValue *frameDuration, /* [out] */ BMDTimeScale *timeScale) = 0; virtual BMDFieldDominance STDMETHODCALLTYPE GetFieldDominance( void) = 0; virtual BMDDisplayModeFlags STDMETHODCALLTYPE GetFlags( void) = 0; }; #else /* C style interface */ typedef struct IDeckLinkDisplayModeVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkDisplayMode * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkDisplayMode * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkDisplayMode * This); HRESULT ( STDMETHODCALLTYPE *GetName )( IDeckLinkDisplayMode * This, /* [out] */ BSTR *name); BMDDisplayMode ( STDMETHODCALLTYPE *GetDisplayMode )( IDeckLinkDisplayMode * This); long ( STDMETHODCALLTYPE *GetWidth )( IDeckLinkDisplayMode * This); long ( STDMETHODCALLTYPE *GetHeight )( IDeckLinkDisplayMode * This); HRESULT ( STDMETHODCALLTYPE *GetFrameRate )( IDeckLinkDisplayMode * This, /* [out] */ BMDTimeValue *frameDuration, /* [out] */ BMDTimeScale *timeScale); BMDFieldDominance ( STDMETHODCALLTYPE *GetFieldDominance )( IDeckLinkDisplayMode * This); BMDDisplayModeFlags ( STDMETHODCALLTYPE *GetFlags )( IDeckLinkDisplayMode * This); END_INTERFACE } IDeckLinkDisplayModeVtbl; interface IDeckLinkDisplayMode { CONST_VTBL struct IDeckLinkDisplayModeVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkDisplayMode_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkDisplayMode_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkDisplayMode_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkDisplayMode_GetName(This,name) \ ( (This)->lpVtbl -> GetName(This,name) ) #define IDeckLinkDisplayMode_GetDisplayMode(This) \ ( (This)->lpVtbl -> GetDisplayMode(This) ) #define IDeckLinkDisplayMode_GetWidth(This) \ ( (This)->lpVtbl -> GetWidth(This) ) #define IDeckLinkDisplayMode_GetHeight(This) \ ( (This)->lpVtbl -> GetHeight(This) ) #define IDeckLinkDisplayMode_GetFrameRate(This,frameDuration,timeScale) \ ( (This)->lpVtbl -> GetFrameRate(This,frameDuration,timeScale) ) #define IDeckLinkDisplayMode_GetFieldDominance(This) \ ( (This)->lpVtbl -> GetFieldDominance(This) ) #define IDeckLinkDisplayMode_GetFlags(This) \ ( (This)->lpVtbl -> GetFlags(This) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkDisplayMode_INTERFACE_DEFINED__ */ #ifndef __IDeckLink_INTERFACE_DEFINED__ #define __IDeckLink_INTERFACE_DEFINED__ /* interface IDeckLink */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLink; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("62BFF75D-6569-4E55-8D4D-66AA03829ABC") IDeckLink : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE GetModelName( /* [out] */ BSTR *modelName) = 0; }; #else /* C style interface */ typedef struct IDeckLinkVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLink * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLink * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLink * This); HRESULT ( STDMETHODCALLTYPE *GetModelName )( IDeckLink * This, /* [out] */ BSTR *modelName); END_INTERFACE } IDeckLinkVtbl; interface IDeckLink { CONST_VTBL struct IDeckLinkVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLink_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLink_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLink_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLink_GetModelName(This,modelName) \ ( (This)->lpVtbl -> GetModelName(This,modelName) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLink_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkOutput_INTERFACE_DEFINED__ #define __IDeckLinkOutput_INTERFACE_DEFINED__ /* interface IDeckLinkOutput */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkOutput; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("A3EF0963-0862-44ED-92A9-EE89ABF431C7") IDeckLinkOutput : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( /* [in] */ BMDDisplayMode displayMode, /* [in] */ BMDPixelFormat pixelFormat, /* [in] */ BMDVideoOutputFlags flags, /* [out] */ BMDDisplayModeSupport *result, /* [out] */ IDeckLinkDisplayMode **resultDisplayMode) = 0; virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0; virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput( /* [in] */ BMDDisplayMode displayMode, /* [in] */ BMDVideoOutputFlags flags) = 0; virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator( /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0; virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame( /* [in] */ long width, /* [in] */ long height, /* [in] */ long rowBytes, /* [in] */ BMDPixelFormat pixelFormat, /* [in] */ BMDFrameFlags flags, /* [out] */ IDeckLinkMutableVideoFrame **outFrame) = 0; virtual HRESULT STDMETHODCALLTYPE CreateAncillaryData( /* [in] */ BMDPixelFormat pixelFormat, /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync( /* [in] */ IDeckLinkVideoFrame *theFrame) = 0; virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame( /* [in] */ IDeckLinkVideoFrame *theFrame, /* [in] */ BMDTimeValue displayTime, /* [in] */ BMDTimeValue displayDuration, /* [in] */ BMDTimeScale timeScale) = 0; virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback( /* [in] */ IDeckLinkVideoOutputCallback *theCallback) = 0; virtual HRESULT STDMETHODCALLTYPE GetBufferedVideoFrameCount( /* [out] */ unsigned long *bufferedFrameCount) = 0; virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput( /* [in] */ BMDAudioSampleRate sampleRate, /* [in] */ BMDAudioSampleType sampleType, /* [in] */ unsigned long channelCount, /* [in] */ BMDAudioOutputStreamType streamType) = 0; virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0; virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync( /* [in] */ void *buffer, /* [in] */ unsigned long sampleFrameCount, /* [out] */ unsigned long *sampleFramesWritten) = 0; virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0; virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0; virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples( /* [in] */ void *buffer, /* [in] */ unsigned long sampleFrameCount, /* [in] */ BMDTimeValue streamTime, /* [in] */ BMDTimeScale timeScale, /* [out] */ unsigned long *sampleFramesWritten) = 0; virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( /* [out] */ unsigned long *bufferedSampleFrameCount) = 0; virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetAudioCallback( /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0; virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback( /* [in] */ BMDTimeValue playbackStartTime, /* [in] */ BMDTimeScale timeScale, /* [in] */ double playbackSpeed) = 0; virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback( /* [in] */ BMDTimeValue stopPlaybackAtTime, /* [out] */ BMDTimeValue *actualStopTime, /* [in] */ BMDTimeScale timeScale) = 0; virtual HRESULT STDMETHODCALLTYPE IsScheduledPlaybackRunning( /* [out] */ BOOL *active) = 0; virtual HRESULT STDMETHODCALLTYPE GetScheduledStreamTime( /* [in] */ BMDTimeScale desiredTimeScale, /* [out] */ BMDTimeValue *streamTime, /* [out] */ double *playbackSpeed) = 0; virtual HRESULT STDMETHODCALLTYPE GetReferenceStatus( /* [out] */ BMDReferenceStatus *referenceStatus) = 0; virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( /* [in] */ BMDTimeScale desiredTimeScale, /* [out] */ BMDTimeValue *hardwareTime, /* [out] */ BMDTimeValue *timeInFrame, /* [out] */ BMDTimeValue *ticksPerFrame) = 0; }; #else /* C style interface */ typedef struct IDeckLinkOutputVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkOutput * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkOutput * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkOutput * This); HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( IDeckLinkOutput * This, /* [in] */ BMDDisplayMode displayMode, /* [in] */ BMDPixelFormat pixelFormat, /* [in] */ BMDVideoOutputFlags flags, /* [out] */ BMDDisplayModeSupport *result, /* [out] */ IDeckLinkDisplayMode **resultDisplayMode); HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( IDeckLinkOutput * This, /* [out] */ IDeckLinkDisplayModeIterator **iterator); HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( IDeckLinkOutput * This, /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback); HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )( IDeckLinkOutput * This, /* [in] */ BMDDisplayMode displayMode, /* [in] */ BMDVideoOutputFlags flags); HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )( IDeckLinkOutput * This); HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )( IDeckLinkOutput * This, /* [in] */ IDeckLinkMemoryAllocator *theAllocator); HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )( IDeckLinkOutput * This, /* [in] */ long width, /* [in] */ long height, /* [in] */ long rowBytes, /* [in] */ BMDPixelFormat pixelFormat, /* [in] */ BMDFrameFlags flags, /* [out] */ IDeckLinkMutableVideoFrame **outFrame); HRESULT ( STDMETHODCALLTYPE *CreateAncillaryData )( IDeckLinkOutput * This, /* [in] */ BMDPixelFormat pixelFormat, /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer); HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )( IDeckLinkOutput * This, /* [in] */ IDeckLinkVideoFrame *theFrame); HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )( IDeckLinkOutput * This, /* [in] */ IDeckLinkVideoFrame *theFrame, /* [in] */ BMDTimeValue displayTime, /* [in] */ BMDTimeValue displayDuration, /* [in] */ BMDTimeScale timeScale); HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )( IDeckLinkOutput * This, /* [in] */ IDeckLinkVideoOutputCallback *theCallback); HRESULT ( STDMETHODCALLTYPE *GetBufferedVideoFrameCount )( IDeckLinkOutput * This, /* [out] */ unsigned long *bufferedFrameCount); HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )( IDeckLinkOutput * This, /* [in] */ BMDAudioSampleRate sampleRate, /* [in] */ BMDAudioSampleType sampleType, /* [in] */ unsigned long channelCount, /* [in] */ BMDAudioOutputStreamType streamType); HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )( IDeckLinkOutput * This); HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )( IDeckLinkOutput * This, /* [in] */ void *buffer, /* [in] */ unsigned long sampleFrameCount, /* [out] */ unsigned long *sampleFramesWritten); HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )( IDeckLinkOutput * This); HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )( IDeckLinkOutput * This); HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )( IDeckLinkOutput * This, /* [in] */ void *buffer, /* [in] */ unsigned long sampleFrameCount, /* [in] */ BMDTimeValue streamTime, /* [in] */ BMDTimeScale timeScale, /* [out] */ unsigned long *sampleFramesWritten); HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( IDeckLinkOutput * This, /* [out] */ unsigned long *bufferedSampleFrameCount); HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )( IDeckLinkOutput * This); HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )( IDeckLinkOutput * This, /* [in] */ IDeckLinkAudioOutputCallback *theCallback); HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )( IDeckLinkOutput * This, /* [in] */ BMDTimeValue playbackStartTime, /* [in] */ BMDTimeScale timeScale, /* [in] */ double playbackSpeed); HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )( IDeckLinkOutput * This, /* [in] */ BMDTimeValue stopPlaybackAtTime, /* [out] */ BMDTimeValue *actualStopTime, /* [in] */ BMDTimeScale timeScale); HRESULT ( STDMETHODCALLTYPE *IsScheduledPlaybackRunning )( IDeckLinkOutput * This, /* [out] */ BOOL *active); HRESULT ( STDMETHODCALLTYPE *GetScheduledStreamTime )( IDeckLinkOutput * This, /* [in] */ BMDTimeScale desiredTimeScale, /* [out] */ BMDTimeValue *streamTime, /* [out] */ double *playbackSpeed); HRESULT ( STDMETHODCALLTYPE *GetReferenceStatus )( IDeckLinkOutput * This, /* [out] */ BMDReferenceStatus *referenceStatus); HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( IDeckLinkOutput * This, /* [in] */ BMDTimeScale desiredTimeScale, /* [out] */ BMDTimeValue *hardwareTime, /* [out] */ BMDTimeValue *timeInFrame, /* [out] */ BMDTimeValue *ticksPerFrame); END_INTERFACE } IDeckLinkOutputVtbl; interface IDeckLinkOutput { CONST_VTBL struct IDeckLinkOutputVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkOutput_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkOutput_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkOutput_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkOutput_DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) \ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) ) #define IDeckLinkOutput_GetDisplayModeIterator(This,iterator) \ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) #define IDeckLinkOutput_SetScreenPreviewCallback(This,previewCallback) \ ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) #define IDeckLinkOutput_EnableVideoOutput(This,displayMode,flags) \ ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode,flags) ) #define IDeckLinkOutput_DisableVideoOutput(This) \ ( (This)->lpVtbl -> DisableVideoOutput(This) ) #define IDeckLinkOutput_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \ ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) ) #define IDeckLinkOutput_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \ ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) ) #define IDeckLinkOutput_CreateAncillaryData(This,pixelFormat,outBuffer) \ ( (This)->lpVtbl -> CreateAncillaryData(This,pixelFormat,outBuffer) ) #define IDeckLinkOutput_DisplayVideoFrameSync(This,theFrame) \ ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) ) #define IDeckLinkOutput_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \ ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) ) #define IDeckLinkOutput_SetScheduledFrameCompletionCallback(This,theCallback) \ ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) ) #define IDeckLinkOutput_GetBufferedVideoFrameCount(This,bufferedFrameCount) \ ( (This)->lpVtbl -> GetBufferedVideoFrameCount(This,bufferedFrameCount) ) #define IDeckLinkOutput_EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) \ ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) ) #define IDeckLinkOutput_DisableAudioOutput(This) \ ( (This)->lpVtbl -> DisableAudioOutput(This) ) #define IDeckLinkOutput_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \ ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) ) #define IDeckLinkOutput_BeginAudioPreroll(This) \ ( (This)->lpVtbl -> BeginAudioPreroll(This) ) #define IDeckLinkOutput_EndAudioPreroll(This) \ ( (This)->lpVtbl -> EndAudioPreroll(This) ) #define IDeckLinkOutput_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \ ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) ) #define IDeckLinkOutput_GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) \ ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) ) #define IDeckLinkOutput_FlushBufferedAudioSamples(This) \ ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) ) #define IDeckLinkOutput_SetAudioCallback(This,theCallback) \ ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) ) #define IDeckLinkOutput_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \ ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) ) #define IDeckLinkOutput_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \ ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) ) #define IDeckLinkOutput_IsScheduledPlaybackRunning(This,active) \ ( (This)->lpVtbl -> IsScheduledPlaybackRunning(This,active) ) #define IDeckLinkOutput_GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) \ ( (This)->lpVtbl -> GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) ) #define IDeckLinkOutput_GetReferenceStatus(This,referenceStatus) \ ( (This)->lpVtbl -> GetReferenceStatus(This,referenceStatus) ) #define IDeckLinkOutput_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \ ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkOutput_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkInput_INTERFACE_DEFINED__ #define __IDeckLinkInput_INTERFACE_DEFINED__ /* interface IDeckLinkInput */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkInput; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("6D40EF78-28B9-4E21-990D-95BB7750A04F") IDeckLinkInput : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( /* [in] */ BMDDisplayMode displayMode, /* [in] */ BMDPixelFormat pixelFormat, /* [in] */ BMDVideoInputFlags flags, /* [out] */ BMDDisplayModeSupport *result, /* [out] */ IDeckLinkDisplayMode **resultDisplayMode) = 0; virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0; virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; virtual HRESULT STDMETHODCALLTYPE EnableVideoInput( /* [in] */ BMDDisplayMode displayMode, /* [in] */ BMDPixelFormat pixelFormat, /* [in] */ BMDVideoInputFlags flags) = 0; virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoFrameCount( /* [out] */ unsigned long *availableFrameCount) = 0; virtual HRESULT STDMETHODCALLTYPE EnableAudioInput( /* [in] */ BMDAudioSampleRate sampleRate, /* [in] */ BMDAudioSampleType sampleType, /* [in] */ unsigned long channelCount) = 0; virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetAvailableAudioSampleFrameCount( /* [out] */ unsigned long *availableSampleFrameCount) = 0; virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0; virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0; virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0; virtual HRESULT STDMETHODCALLTYPE FlushStreams( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetCallback( /* [in] */ IDeckLinkInputCallback *theCallback) = 0; virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( /* [in] */ BMDTimeScale desiredTimeScale, /* [out] */ BMDTimeValue *hardwareTime, /* [out] */ BMDTimeValue *timeInFrame, /* [out] */ BMDTimeValue *ticksPerFrame) = 0; }; #else /* C style interface */ typedef struct IDeckLinkInputVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkInput * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkInput * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkInput * This); HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( IDeckLinkInput * This, /* [in] */ BMDDisplayMode displayMode, /* [in] */ BMDPixelFormat pixelFormat, /* [in] */ BMDVideoInputFlags flags, /* [out] */ BMDDisplayModeSupport *result, /* [out] */ IDeckLinkDisplayMode **resultDisplayMode); HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( IDeckLinkInput * This, /* [out] */ IDeckLinkDisplayModeIterator **iterator); HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( IDeckLinkInput * This, /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback); HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )( IDeckLinkInput * This, /* [in] */ BMDDisplayMode displayMode, /* [in] */ BMDPixelFormat pixelFormat, /* [in] */ BMDVideoInputFlags flags); HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )( IDeckLinkInput * This); HRESULT ( STDMETHODCALLTYPE *GetAvailableVideoFrameCount )( IDeckLinkInput * This, /* [out] */ unsigned long *availableFrameCount); HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )( IDeckLinkInput * This, /* [in] */ BMDAudioSampleRate sampleRate, /* [in] */ BMDAudioSampleType sampleType, /* [in] */ unsigned long channelCount); HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )( IDeckLinkInput * This); HRESULT ( STDMETHODCALLTYPE *GetAvailableAudioSampleFrameCount )( IDeckLinkInput * This, /* [out] */ unsigned long *availableSampleFrameCount); HRESULT ( STDMETHODCALLTYPE *StartStreams )( IDeckLinkInput * This); HRESULT ( STDMETHODCALLTYPE *StopStreams )( IDeckLinkInput * This); HRESULT ( STDMETHODCALLTYPE *PauseStreams )( IDeckLinkInput * This); HRESULT ( STDMETHODCALLTYPE *FlushStreams )( IDeckLinkInput * This); HRESULT ( STDMETHODCALLTYPE *SetCallback )( IDeckLinkInput * This, /* [in] */ IDeckLinkInputCallback *theCallback); HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( IDeckLinkInput * This, /* [in] */ BMDTimeScale desiredTimeScale, /* [out] */ BMDTimeValue *hardwareTime, /* [out] */ BMDTimeValue *timeInFrame, /* [out] */ BMDTimeValue *ticksPerFrame); END_INTERFACE } IDeckLinkInputVtbl; interface IDeckLinkInput { CONST_VTBL struct IDeckLinkInputVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkInput_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkInput_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkInput_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkInput_DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) \ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) ) #define IDeckLinkInput_GetDisplayModeIterator(This,iterator) \ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) #define IDeckLinkInput_SetScreenPreviewCallback(This,previewCallback) \ ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) #define IDeckLinkInput_EnableVideoInput(This,displayMode,pixelFormat,flags) \ ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) ) #define IDeckLinkInput_DisableVideoInput(This) \ ( (This)->lpVtbl -> DisableVideoInput(This) ) #define IDeckLinkInput_GetAvailableVideoFrameCount(This,availableFrameCount) \ ( (This)->lpVtbl -> GetAvailableVideoFrameCount(This,availableFrameCount) ) #define IDeckLinkInput_EnableAudioInput(This,sampleRate,sampleType,channelCount) \ ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) ) #define IDeckLinkInput_DisableAudioInput(This) \ ( (This)->lpVtbl -> DisableAudioInput(This) ) #define IDeckLinkInput_GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) \ ( (This)->lpVtbl -> GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) ) #define IDeckLinkInput_StartStreams(This) \ ( (This)->lpVtbl -> StartStreams(This) ) #define IDeckLinkInput_StopStreams(This) \ ( (This)->lpVtbl -> StopStreams(This) ) #define IDeckLinkInput_PauseStreams(This) \ ( (This)->lpVtbl -> PauseStreams(This) ) #define IDeckLinkInput_FlushStreams(This) \ ( (This)->lpVtbl -> FlushStreams(This) ) #define IDeckLinkInput_SetCallback(This,theCallback) \ ( (This)->lpVtbl -> SetCallback(This,theCallback) ) #define IDeckLinkInput_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \ ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkInput_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkTimecode_INTERFACE_DEFINED__ #define __IDeckLinkTimecode_INTERFACE_DEFINED__ /* interface IDeckLinkTimecode */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkTimecode; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("BC6CFBD3-8317-4325-AC1C-1216391E9340") IDeckLinkTimecode : public IUnknown { public: virtual BMDTimecodeBCD STDMETHODCALLTYPE GetBCD( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetComponents( /* [out] */ unsigned char *hours, /* [out] */ unsigned char *minutes, /* [out] */ unsigned char *seconds, /* [out] */ unsigned char *frames) = 0; virtual HRESULT STDMETHODCALLTYPE GetString( /* [out] */ BSTR *timecode) = 0; virtual BMDTimecodeFlags STDMETHODCALLTYPE GetFlags( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetTimecodeUserBits( /* [out] */ BMDTimecodeUserBits *userBits) = 0; }; #else /* C style interface */ typedef struct IDeckLinkTimecodeVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkTimecode * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkTimecode * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkTimecode * This); BMDTimecodeBCD ( STDMETHODCALLTYPE *GetBCD )( IDeckLinkTimecode * This); HRESULT ( STDMETHODCALLTYPE *GetComponents )( IDeckLinkTimecode * This, /* [out] */ unsigned char *hours, /* [out] */ unsigned char *minutes, /* [out] */ unsigned char *seconds, /* [out] */ unsigned char *frames); HRESULT ( STDMETHODCALLTYPE *GetString )( IDeckLinkTimecode * This, /* [out] */ BSTR *timecode); BMDTimecodeFlags ( STDMETHODCALLTYPE *GetFlags )( IDeckLinkTimecode * This); HRESULT ( STDMETHODCALLTYPE *GetTimecodeUserBits )( IDeckLinkTimecode * This, /* [out] */ BMDTimecodeUserBits *userBits); END_INTERFACE } IDeckLinkTimecodeVtbl; interface IDeckLinkTimecode { CONST_VTBL struct IDeckLinkTimecodeVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkTimecode_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkTimecode_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkTimecode_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkTimecode_GetBCD(This) \ ( (This)->lpVtbl -> GetBCD(This) ) #define IDeckLinkTimecode_GetComponents(This,hours,minutes,seconds,frames) \ ( (This)->lpVtbl -> GetComponents(This,hours,minutes,seconds,frames) ) #define IDeckLinkTimecode_GetString(This,timecode) \ ( (This)->lpVtbl -> GetString(This,timecode) ) #define IDeckLinkTimecode_GetFlags(This) \ ( (This)->lpVtbl -> GetFlags(This) ) #define IDeckLinkTimecode_GetTimecodeUserBits(This,userBits) \ ( (This)->lpVtbl -> GetTimecodeUserBits(This,userBits) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkTimecode_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkVideoFrame_INTERFACE_DEFINED__ #define __IDeckLinkVideoFrame_INTERFACE_DEFINED__ /* interface IDeckLinkVideoFrame */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkVideoFrame; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("3F716FE0-F023-4111-BE5D-EF4414C05B17") IDeckLinkVideoFrame : public IUnknown { public: virtual long STDMETHODCALLTYPE GetWidth( void) = 0; virtual long STDMETHODCALLTYPE GetHeight( void) = 0; virtual long STDMETHODCALLTYPE GetRowBytes( void) = 0; virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat( void) = 0; virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetBytes( /* [out] */ void **buffer) = 0; virtual HRESULT STDMETHODCALLTYPE GetTimecode( /* [in] */ BMDTimecodeFormat format, /* [out] */ IDeckLinkTimecode **timecode) = 0; virtual HRESULT STDMETHODCALLTYPE GetAncillaryData( /* [out] */ IDeckLinkVideoFrameAncillary **ancillary) = 0; }; #else /* C style interface */ typedef struct IDeckLinkVideoFrameVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkVideoFrame * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkVideoFrame * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkVideoFrame * This); long ( STDMETHODCALLTYPE *GetWidth )( IDeckLinkVideoFrame * This); long ( STDMETHODCALLTYPE *GetHeight )( IDeckLinkVideoFrame * This); long ( STDMETHODCALLTYPE *GetRowBytes )( IDeckLinkVideoFrame * This); BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( IDeckLinkVideoFrame * This); BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( IDeckLinkVideoFrame * This); HRESULT ( STDMETHODCALLTYPE *GetBytes )( IDeckLinkVideoFrame * This, /* [out] */ void **buffer); HRESULT ( STDMETHODCALLTYPE *GetTimecode )( IDeckLinkVideoFrame * This, /* [in] */ BMDTimecodeFormat format, /* [out] */ IDeckLinkTimecode **timecode); HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( IDeckLinkVideoFrame * This, /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); END_INTERFACE } IDeckLinkVideoFrameVtbl; interface IDeckLinkVideoFrame { CONST_VTBL struct IDeckLinkVideoFrameVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkVideoFrame_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkVideoFrame_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkVideoFrame_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkVideoFrame_GetWidth(This) \ ( (This)->lpVtbl -> GetWidth(This) ) #define IDeckLinkVideoFrame_GetHeight(This) \ ( (This)->lpVtbl -> GetHeight(This) ) #define IDeckLinkVideoFrame_GetRowBytes(This) \ ( (This)->lpVtbl -> GetRowBytes(This) ) #define IDeckLinkVideoFrame_GetPixelFormat(This) \ ( (This)->lpVtbl -> GetPixelFormat(This) ) #define IDeckLinkVideoFrame_GetFlags(This) \ ( (This)->lpVtbl -> GetFlags(This) ) #define IDeckLinkVideoFrame_GetBytes(This,buffer) \ ( (This)->lpVtbl -> GetBytes(This,buffer) ) #define IDeckLinkVideoFrame_GetTimecode(This,format,timecode) \ ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) #define IDeckLinkVideoFrame_GetAncillaryData(This,ancillary) \ ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkVideoFrame_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkMutableVideoFrame_INTERFACE_DEFINED__ #define __IDeckLinkMutableVideoFrame_INTERFACE_DEFINED__ /* interface IDeckLinkMutableVideoFrame */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkMutableVideoFrame; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("69E2639F-40DA-4E19-B6F2-20ACE815C390") IDeckLinkMutableVideoFrame : public IDeckLinkVideoFrame { public: virtual HRESULT STDMETHODCALLTYPE SetFlags( /* [in] */ BMDFrameFlags newFlags) = 0; virtual HRESULT STDMETHODCALLTYPE SetTimecode( /* [in] */ BMDTimecodeFormat format, /* [in] */ IDeckLinkTimecode *timecode) = 0; virtual HRESULT STDMETHODCALLTYPE SetTimecodeFromComponents( /* [in] */ BMDTimecodeFormat format, /* [in] */ unsigned char hours, /* [in] */ unsigned char minutes, /* [in] */ unsigned char seconds, /* [in] */ unsigned char frames, /* [in] */ BMDTimecodeFlags flags) = 0; virtual HRESULT STDMETHODCALLTYPE SetAncillaryData( /* [in] */ IDeckLinkVideoFrameAncillary *ancillary) = 0; virtual HRESULT STDMETHODCALLTYPE SetTimecodeUserBits( /* [in] */ BMDTimecodeFormat format, /* [in] */ BMDTimecodeUserBits userBits) = 0; }; #else /* C style interface */ typedef struct IDeckLinkMutableVideoFrameVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkMutableVideoFrame * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkMutableVideoFrame * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkMutableVideoFrame * This); long ( STDMETHODCALLTYPE *GetWidth )( IDeckLinkMutableVideoFrame * This); long ( STDMETHODCALLTYPE *GetHeight )( IDeckLinkMutableVideoFrame * This); long ( STDMETHODCALLTYPE *GetRowBytes )( IDeckLinkMutableVideoFrame * This); BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( IDeckLinkMutableVideoFrame * This); BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( IDeckLinkMutableVideoFrame * This); HRESULT ( STDMETHODCALLTYPE *GetBytes )( IDeckLinkMutableVideoFrame * This, /* [out] */ void **buffer); HRESULT ( STDMETHODCALLTYPE *GetTimecode )( IDeckLinkMutableVideoFrame * This, /* [in] */ BMDTimecodeFormat format, /* [out] */ IDeckLinkTimecode **timecode); HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( IDeckLinkMutableVideoFrame * This, /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); HRESULT ( STDMETHODCALLTYPE *SetFlags )( IDeckLinkMutableVideoFrame * This, /* [in] */ BMDFrameFlags newFlags); HRESULT ( STDMETHODCALLTYPE *SetTimecode )( IDeckLinkMutableVideoFrame * This, /* [in] */ BMDTimecodeFormat format, /* [in] */ IDeckLinkTimecode *timecode); HRESULT ( STDMETHODCALLTYPE *SetTimecodeFromComponents )( IDeckLinkMutableVideoFrame * This, /* [in] */ BMDTimecodeFormat format, /* [in] */ unsigned char hours, /* [in] */ unsigned char minutes, /* [in] */ unsigned char seconds, /* [in] */ unsigned char frames, /* [in] */ BMDTimecodeFlags flags); HRESULT ( STDMETHODCALLTYPE *SetAncillaryData )( IDeckLinkMutableVideoFrame * This, /* [in] */ IDeckLinkVideoFrameAncillary *ancillary); HRESULT ( STDMETHODCALLTYPE *SetTimecodeUserBits )( IDeckLinkMutableVideoFrame * This, /* [in] */ BMDTimecodeFormat format, /* [in] */ BMDTimecodeUserBits userBits); END_INTERFACE } IDeckLinkMutableVideoFrameVtbl; interface IDeckLinkMutableVideoFrame { CONST_VTBL struct IDeckLinkMutableVideoFrameVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkMutableVideoFrame_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkMutableVideoFrame_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkMutableVideoFrame_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkMutableVideoFrame_GetWidth(This) \ ( (This)->lpVtbl -> GetWidth(This) ) #define IDeckLinkMutableVideoFrame_GetHeight(This) \ ( (This)->lpVtbl -> GetHeight(This) ) #define IDeckLinkMutableVideoFrame_GetRowBytes(This) \ ( (This)->lpVtbl -> GetRowBytes(This) ) #define IDeckLinkMutableVideoFrame_GetPixelFormat(This) \ ( (This)->lpVtbl -> GetPixelFormat(This) ) #define IDeckLinkMutableVideoFrame_GetFlags(This) \ ( (This)->lpVtbl -> GetFlags(This) ) #define IDeckLinkMutableVideoFrame_GetBytes(This,buffer) \ ( (This)->lpVtbl -> GetBytes(This,buffer) ) #define IDeckLinkMutableVideoFrame_GetTimecode(This,format,timecode) \ ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) #define IDeckLinkMutableVideoFrame_GetAncillaryData(This,ancillary) \ ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) #define IDeckLinkMutableVideoFrame_SetFlags(This,newFlags) \ ( (This)->lpVtbl -> SetFlags(This,newFlags) ) #define IDeckLinkMutableVideoFrame_SetTimecode(This,format,timecode) \ ( (This)->lpVtbl -> SetTimecode(This,format,timecode) ) #define IDeckLinkMutableVideoFrame_SetTimecodeFromComponents(This,format,hours,minutes,seconds,frames,flags) \ ( (This)->lpVtbl -> SetTimecodeFromComponents(This,format,hours,minutes,seconds,frames,flags) ) #define IDeckLinkMutableVideoFrame_SetAncillaryData(This,ancillary) \ ( (This)->lpVtbl -> SetAncillaryData(This,ancillary) ) #define IDeckLinkMutableVideoFrame_SetTimecodeUserBits(This,format,userBits) \ ( (This)->lpVtbl -> SetTimecodeUserBits(This,format,userBits) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkMutableVideoFrame_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkVideoFrame3DExtensions_INTERFACE_DEFINED__ #define __IDeckLinkVideoFrame3DExtensions_INTERFACE_DEFINED__ /* interface IDeckLinkVideoFrame3DExtensions */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkVideoFrame3DExtensions; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("DA0F7E4A-EDC7-48A8-9CDD-2DB51C729CD7") IDeckLinkVideoFrame3DExtensions : public IUnknown { public: virtual BMDVideo3DPackingFormat STDMETHODCALLTYPE Get3DPackingFormat( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetFrameForRightEye( /* [in] */ IDeckLinkVideoFrame **rightEyeFrame) = 0; }; #else /* C style interface */ typedef struct IDeckLinkVideoFrame3DExtensionsVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkVideoFrame3DExtensions * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkVideoFrame3DExtensions * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkVideoFrame3DExtensions * This); BMDVideo3DPackingFormat ( STDMETHODCALLTYPE *Get3DPackingFormat )( IDeckLinkVideoFrame3DExtensions * This); HRESULT ( STDMETHODCALLTYPE *GetFrameForRightEye )( IDeckLinkVideoFrame3DExtensions * This, /* [in] */ IDeckLinkVideoFrame **rightEyeFrame); END_INTERFACE } IDeckLinkVideoFrame3DExtensionsVtbl; interface IDeckLinkVideoFrame3DExtensions { CONST_VTBL struct IDeckLinkVideoFrame3DExtensionsVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkVideoFrame3DExtensions_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkVideoFrame3DExtensions_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkVideoFrame3DExtensions_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkVideoFrame3DExtensions_Get3DPackingFormat(This) \ ( (This)->lpVtbl -> Get3DPackingFormat(This) ) #define IDeckLinkVideoFrame3DExtensions_GetFrameForRightEye(This,rightEyeFrame) \ ( (This)->lpVtbl -> GetFrameForRightEye(This,rightEyeFrame) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkVideoFrame3DExtensions_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkVideoInputFrame_INTERFACE_DEFINED__ #define __IDeckLinkVideoInputFrame_INTERFACE_DEFINED__ /* interface IDeckLinkVideoInputFrame */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkVideoInputFrame; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("05CFE374-537C-4094-9A57-680525118F44") IDeckLinkVideoInputFrame : public IDeckLinkVideoFrame { public: virtual HRESULT STDMETHODCALLTYPE GetStreamTime( /* [out] */ BMDTimeValue *frameTime, /* [out] */ BMDTimeValue *frameDuration, /* [in] */ BMDTimeScale timeScale) = 0; virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceTimestamp( /* [in] */ BMDTimeScale timeScale, /* [out] */ BMDTimeValue *frameTime, /* [out] */ BMDTimeValue *frameDuration) = 0; }; #else /* C style interface */ typedef struct IDeckLinkVideoInputFrameVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkVideoInputFrame * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkVideoInputFrame * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkVideoInputFrame * This); long ( STDMETHODCALLTYPE *GetWidth )( IDeckLinkVideoInputFrame * This); long ( STDMETHODCALLTYPE *GetHeight )( IDeckLinkVideoInputFrame * This); long ( STDMETHODCALLTYPE *GetRowBytes )( IDeckLinkVideoInputFrame * This); BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( IDeckLinkVideoInputFrame * This); BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( IDeckLinkVideoInputFrame * This); HRESULT ( STDMETHODCALLTYPE *GetBytes )( IDeckLinkVideoInputFrame * This, /* [out] */ void **buffer); HRESULT ( STDMETHODCALLTYPE *GetTimecode )( IDeckLinkVideoInputFrame * This, /* [in] */ BMDTimecodeFormat format, /* [out] */ IDeckLinkTimecode **timecode); HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( IDeckLinkVideoInputFrame * This, /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); HRESULT ( STDMETHODCALLTYPE *GetStreamTime )( IDeckLinkVideoInputFrame * This, /* [out] */ BMDTimeValue *frameTime, /* [out] */ BMDTimeValue *frameDuration, /* [in] */ BMDTimeScale timeScale); HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceTimestamp )( IDeckLinkVideoInputFrame * This, /* [in] */ BMDTimeScale timeScale, /* [out] */ BMDTimeValue *frameTime, /* [out] */ BMDTimeValue *frameDuration); END_INTERFACE } IDeckLinkVideoInputFrameVtbl; interface IDeckLinkVideoInputFrame { CONST_VTBL struct IDeckLinkVideoInputFrameVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkVideoInputFrame_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkVideoInputFrame_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkVideoInputFrame_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkVideoInputFrame_GetWidth(This) \ ( (This)->lpVtbl -> GetWidth(This) ) #define IDeckLinkVideoInputFrame_GetHeight(This) \ ( (This)->lpVtbl -> GetHeight(This) ) #define IDeckLinkVideoInputFrame_GetRowBytes(This) \ ( (This)->lpVtbl -> GetRowBytes(This) ) #define IDeckLinkVideoInputFrame_GetPixelFormat(This) \ ( (This)->lpVtbl -> GetPixelFormat(This) ) #define IDeckLinkVideoInputFrame_GetFlags(This) \ ( (This)->lpVtbl -> GetFlags(This) ) #define IDeckLinkVideoInputFrame_GetBytes(This,buffer) \ ( (This)->lpVtbl -> GetBytes(This,buffer) ) #define IDeckLinkVideoInputFrame_GetTimecode(This,format,timecode) \ ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) #define IDeckLinkVideoInputFrame_GetAncillaryData(This,ancillary) \ ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) #define IDeckLinkVideoInputFrame_GetStreamTime(This,frameTime,frameDuration,timeScale) \ ( (This)->lpVtbl -> GetStreamTime(This,frameTime,frameDuration,timeScale) ) #define IDeckLinkVideoInputFrame_GetHardwareReferenceTimestamp(This,timeScale,frameTime,frameDuration) \ ( (This)->lpVtbl -> GetHardwareReferenceTimestamp(This,timeScale,frameTime,frameDuration) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkVideoInputFrame_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkVideoFrameAncillary_INTERFACE_DEFINED__ #define __IDeckLinkVideoFrameAncillary_INTERFACE_DEFINED__ /* interface IDeckLinkVideoFrameAncillary */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkVideoFrameAncillary; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("732E723C-D1A4-4E29-9E8E-4A88797A0004") IDeckLinkVideoFrameAncillary : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE GetBufferForVerticalBlankingLine( /* [in] */ unsigned long lineNumber, /* [out] */ void **buffer) = 0; virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat( void) = 0; virtual BMDDisplayMode STDMETHODCALLTYPE GetDisplayMode( void) = 0; }; #else /* C style interface */ typedef struct IDeckLinkVideoFrameAncillaryVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkVideoFrameAncillary * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkVideoFrameAncillary * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkVideoFrameAncillary * This); HRESULT ( STDMETHODCALLTYPE *GetBufferForVerticalBlankingLine )( IDeckLinkVideoFrameAncillary * This, /* [in] */ unsigned long lineNumber, /* [out] */ void **buffer); BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( IDeckLinkVideoFrameAncillary * This); BMDDisplayMode ( STDMETHODCALLTYPE *GetDisplayMode )( IDeckLinkVideoFrameAncillary * This); END_INTERFACE } IDeckLinkVideoFrameAncillaryVtbl; interface IDeckLinkVideoFrameAncillary { CONST_VTBL struct IDeckLinkVideoFrameAncillaryVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkVideoFrameAncillary_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkVideoFrameAncillary_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkVideoFrameAncillary_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkVideoFrameAncillary_GetBufferForVerticalBlankingLine(This,lineNumber,buffer) \ ( (This)->lpVtbl -> GetBufferForVerticalBlankingLine(This,lineNumber,buffer) ) #define IDeckLinkVideoFrameAncillary_GetPixelFormat(This) \ ( (This)->lpVtbl -> GetPixelFormat(This) ) #define IDeckLinkVideoFrameAncillary_GetDisplayMode(This) \ ( (This)->lpVtbl -> GetDisplayMode(This) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkVideoFrameAncillary_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkAudioInputPacket_INTERFACE_DEFINED__ #define __IDeckLinkAudioInputPacket_INTERFACE_DEFINED__ /* interface IDeckLinkAudioInputPacket */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkAudioInputPacket; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("E43D5870-2894-11DE-8C30-0800200C9A66") IDeckLinkAudioInputPacket : public IUnknown { public: virtual long STDMETHODCALLTYPE GetSampleFrameCount( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetBytes( /* [out] */ void **buffer) = 0; virtual HRESULT STDMETHODCALLTYPE GetPacketTime( /* [out] */ BMDTimeValue *packetTime, /* [in] */ BMDTimeScale timeScale) = 0; }; #else /* C style interface */ typedef struct IDeckLinkAudioInputPacketVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkAudioInputPacket * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkAudioInputPacket * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkAudioInputPacket * This); long ( STDMETHODCALLTYPE *GetSampleFrameCount )( IDeckLinkAudioInputPacket * This); HRESULT ( STDMETHODCALLTYPE *GetBytes )( IDeckLinkAudioInputPacket * This, /* [out] */ void **buffer); HRESULT ( STDMETHODCALLTYPE *GetPacketTime )( IDeckLinkAudioInputPacket * This, /* [out] */ BMDTimeValue *packetTime, /* [in] */ BMDTimeScale timeScale); END_INTERFACE } IDeckLinkAudioInputPacketVtbl; interface IDeckLinkAudioInputPacket { CONST_VTBL struct IDeckLinkAudioInputPacketVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkAudioInputPacket_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkAudioInputPacket_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkAudioInputPacket_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkAudioInputPacket_GetSampleFrameCount(This) \ ( (This)->lpVtbl -> GetSampleFrameCount(This) ) #define IDeckLinkAudioInputPacket_GetBytes(This,buffer) \ ( (This)->lpVtbl -> GetBytes(This,buffer) ) #define IDeckLinkAudioInputPacket_GetPacketTime(This,packetTime,timeScale) \ ( (This)->lpVtbl -> GetPacketTime(This,packetTime,timeScale) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkAudioInputPacket_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkScreenPreviewCallback_INTERFACE_DEFINED__ #define __IDeckLinkScreenPreviewCallback_INTERFACE_DEFINED__ /* interface IDeckLinkScreenPreviewCallback */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkScreenPreviewCallback; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("B1D3F49A-85FE-4C5D-95C8-0B5D5DCCD438") IDeckLinkScreenPreviewCallback : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE DrawFrame( /* [in] */ IDeckLinkVideoFrame *theFrame) = 0; }; #else /* C style interface */ typedef struct IDeckLinkScreenPreviewCallbackVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkScreenPreviewCallback * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkScreenPreviewCallback * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkScreenPreviewCallback * This); HRESULT ( STDMETHODCALLTYPE *DrawFrame )( IDeckLinkScreenPreviewCallback * This, /* [in] */ IDeckLinkVideoFrame *theFrame); END_INTERFACE } IDeckLinkScreenPreviewCallbackVtbl; interface IDeckLinkScreenPreviewCallback { CONST_VTBL struct IDeckLinkScreenPreviewCallbackVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkScreenPreviewCallback_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkScreenPreviewCallback_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkScreenPreviewCallback_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkScreenPreviewCallback_DrawFrame(This,theFrame) \ ( (This)->lpVtbl -> DrawFrame(This,theFrame) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkScreenPreviewCallback_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkGLScreenPreviewHelper_INTERFACE_DEFINED__ #define __IDeckLinkGLScreenPreviewHelper_INTERFACE_DEFINED__ /* interface IDeckLinkGLScreenPreviewHelper */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkGLScreenPreviewHelper; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("504E2209-CAC7-4C1A-9FB4-C5BB6274D22F") IDeckLinkGLScreenPreviewHelper : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE InitializeGL( void) = 0; virtual HRESULT STDMETHODCALLTYPE PaintGL( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetFrame( /* [in] */ IDeckLinkVideoFrame *theFrame) = 0; virtual HRESULT STDMETHODCALLTYPE Set3DPreviewFormat( /* [in] */ BMD3DPreviewFormat previewFormat) = 0; }; #else /* C style interface */ typedef struct IDeckLinkGLScreenPreviewHelperVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkGLScreenPreviewHelper * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkGLScreenPreviewHelper * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkGLScreenPreviewHelper * This); HRESULT ( STDMETHODCALLTYPE *InitializeGL )( IDeckLinkGLScreenPreviewHelper * This); HRESULT ( STDMETHODCALLTYPE *PaintGL )( IDeckLinkGLScreenPreviewHelper * This); HRESULT ( STDMETHODCALLTYPE *SetFrame )( IDeckLinkGLScreenPreviewHelper * This, /* [in] */ IDeckLinkVideoFrame *theFrame); HRESULT ( STDMETHODCALLTYPE *Set3DPreviewFormat )( IDeckLinkGLScreenPreviewHelper * This, /* [in] */ BMD3DPreviewFormat previewFormat); END_INTERFACE } IDeckLinkGLScreenPreviewHelperVtbl; interface IDeckLinkGLScreenPreviewHelper { CONST_VTBL struct IDeckLinkGLScreenPreviewHelperVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkGLScreenPreviewHelper_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkGLScreenPreviewHelper_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkGLScreenPreviewHelper_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkGLScreenPreviewHelper_InitializeGL(This) \ ( (This)->lpVtbl -> InitializeGL(This) ) #define IDeckLinkGLScreenPreviewHelper_PaintGL(This) \ ( (This)->lpVtbl -> PaintGL(This) ) #define IDeckLinkGLScreenPreviewHelper_SetFrame(This,theFrame) \ ( (This)->lpVtbl -> SetFrame(This,theFrame) ) #define IDeckLinkGLScreenPreviewHelper_Set3DPreviewFormat(This,previewFormat) \ ( (This)->lpVtbl -> Set3DPreviewFormat(This,previewFormat) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkGLScreenPreviewHelper_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkConfiguration_INTERFACE_DEFINED__ #define __IDeckLinkConfiguration_INTERFACE_DEFINED__ /* interface IDeckLinkConfiguration */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkConfiguration; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("C679A35B-610C-4D09-B748-1D0478100FC0") IDeckLinkConfiguration : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE SetFlag( /* [in] */ BMDDeckLinkConfigurationID cfgID, /* [in] */ BOOL value) = 0; virtual HRESULT STDMETHODCALLTYPE GetFlag( /* [in] */ BMDDeckLinkConfigurationID cfgID, /* [out] */ BOOL *value) = 0; virtual HRESULT STDMETHODCALLTYPE SetInt( /* [in] */ BMDDeckLinkConfigurationID cfgID, /* [in] */ LONGLONG value) = 0; virtual HRESULT STDMETHODCALLTYPE GetInt( /* [in] */ BMDDeckLinkConfigurationID cfgID, /* [out] */ LONGLONG *value) = 0; virtual HRESULT STDMETHODCALLTYPE SetFloat( /* [in] */ BMDDeckLinkConfigurationID cfgID, /* [in] */ double value) = 0; virtual HRESULT STDMETHODCALLTYPE GetFloat( /* [in] */ BMDDeckLinkConfigurationID cfgID, /* [out] */ double *value) = 0; virtual HRESULT STDMETHODCALLTYPE SetString( /* [in] */ BMDDeckLinkConfigurationID cfgID, /* [in] */ BSTR value) = 0; virtual HRESULT STDMETHODCALLTYPE GetString( /* [in] */ BMDDeckLinkConfigurationID cfgID, /* [out] */ BSTR *value) = 0; virtual HRESULT STDMETHODCALLTYPE WriteConfigurationToPreferences( void) = 0; }; #else /* C style interface */ typedef struct IDeckLinkConfigurationVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkConfiguration * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkConfiguration * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkConfiguration * This); HRESULT ( STDMETHODCALLTYPE *SetFlag )( IDeckLinkConfiguration * This, /* [in] */ BMDDeckLinkConfigurationID cfgID, /* [in] */ BOOL value); HRESULT ( STDMETHODCALLTYPE *GetFlag )( IDeckLinkConfiguration * This, /* [in] */ BMDDeckLinkConfigurationID cfgID, /* [out] */ BOOL *value); HRESULT ( STDMETHODCALLTYPE *SetInt )( IDeckLinkConfiguration * This, /* [in] */ BMDDeckLinkConfigurationID cfgID, /* [in] */ LONGLONG value); HRESULT ( STDMETHODCALLTYPE *GetInt )( IDeckLinkConfiguration * This, /* [in] */ BMDDeckLinkConfigurationID cfgID, /* [out] */ LONGLONG *value); HRESULT ( STDMETHODCALLTYPE *SetFloat )( IDeckLinkConfiguration * This, /* [in] */ BMDDeckLinkConfigurationID cfgID, /* [in] */ double value); HRESULT ( STDMETHODCALLTYPE *GetFloat )( IDeckLinkConfiguration * This, /* [in] */ BMDDeckLinkConfigurationID cfgID, /* [out] */ double *value); HRESULT ( STDMETHODCALLTYPE *SetString )( IDeckLinkConfiguration * This, /* [in] */ BMDDeckLinkConfigurationID cfgID, /* [in] */ BSTR value); HRESULT ( STDMETHODCALLTYPE *GetString )( IDeckLinkConfiguration * This, /* [in] */ BMDDeckLinkConfigurationID cfgID, /* [out] */ BSTR *value); HRESULT ( STDMETHODCALLTYPE *WriteConfigurationToPreferences )( IDeckLinkConfiguration * This); END_INTERFACE } IDeckLinkConfigurationVtbl; interface IDeckLinkConfiguration { CONST_VTBL struct IDeckLinkConfigurationVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkConfiguration_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkConfiguration_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkConfiguration_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkConfiguration_SetFlag(This,cfgID,value) \ ( (This)->lpVtbl -> SetFlag(This,cfgID,value) ) #define IDeckLinkConfiguration_GetFlag(This,cfgID,value) \ ( (This)->lpVtbl -> GetFlag(This,cfgID,value) ) #define IDeckLinkConfiguration_SetInt(This,cfgID,value) \ ( (This)->lpVtbl -> SetInt(This,cfgID,value) ) #define IDeckLinkConfiguration_GetInt(This,cfgID,value) \ ( (This)->lpVtbl -> GetInt(This,cfgID,value) ) #define IDeckLinkConfiguration_SetFloat(This,cfgID,value) \ ( (This)->lpVtbl -> SetFloat(This,cfgID,value) ) #define IDeckLinkConfiguration_GetFloat(This,cfgID,value) \ ( (This)->lpVtbl -> GetFloat(This,cfgID,value) ) #define IDeckLinkConfiguration_SetString(This,cfgID,value) \ ( (This)->lpVtbl -> SetString(This,cfgID,value) ) #define IDeckLinkConfiguration_GetString(This,cfgID,value) \ ( (This)->lpVtbl -> GetString(This,cfgID,value) ) #define IDeckLinkConfiguration_WriteConfigurationToPreferences(This) \ ( (This)->lpVtbl -> WriteConfigurationToPreferences(This) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkConfiguration_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkAttributes_INTERFACE_DEFINED__ #define __IDeckLinkAttributes_INTERFACE_DEFINED__ /* interface IDeckLinkAttributes */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkAttributes; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("ABC11843-D966-44CB-96E2-A1CB5D3135C4") IDeckLinkAttributes : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE GetFlag( /* [in] */ BMDDeckLinkAttributeID cfgID, /* [out] */ BOOL *value) = 0; virtual HRESULT STDMETHODCALLTYPE GetInt( /* [in] */ BMDDeckLinkAttributeID cfgID, /* [out] */ LONGLONG *value) = 0; virtual HRESULT STDMETHODCALLTYPE GetFloat( /* [in] */ BMDDeckLinkAttributeID cfgID, /* [out] */ double *value) = 0; virtual HRESULT STDMETHODCALLTYPE GetString( /* [in] */ BMDDeckLinkAttributeID cfgID, /* [out] */ BSTR *value) = 0; }; #else /* C style interface */ typedef struct IDeckLinkAttributesVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkAttributes * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkAttributes * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkAttributes * This); HRESULT ( STDMETHODCALLTYPE *GetFlag )( IDeckLinkAttributes * This, /* [in] */ BMDDeckLinkAttributeID cfgID, /* [out] */ BOOL *value); HRESULT ( STDMETHODCALLTYPE *GetInt )( IDeckLinkAttributes * This, /* [in] */ BMDDeckLinkAttributeID cfgID, /* [out] */ LONGLONG *value); HRESULT ( STDMETHODCALLTYPE *GetFloat )( IDeckLinkAttributes * This, /* [in] */ BMDDeckLinkAttributeID cfgID, /* [out] */ double *value); HRESULT ( STDMETHODCALLTYPE *GetString )( IDeckLinkAttributes * This, /* [in] */ BMDDeckLinkAttributeID cfgID, /* [out] */ BSTR *value); END_INTERFACE } IDeckLinkAttributesVtbl; interface IDeckLinkAttributes { CONST_VTBL struct IDeckLinkAttributesVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkAttributes_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkAttributes_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkAttributes_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkAttributes_GetFlag(This,cfgID,value) \ ( (This)->lpVtbl -> GetFlag(This,cfgID,value) ) #define IDeckLinkAttributes_GetInt(This,cfgID,value) \ ( (This)->lpVtbl -> GetInt(This,cfgID,value) ) #define IDeckLinkAttributes_GetFloat(This,cfgID,value) \ ( (This)->lpVtbl -> GetFloat(This,cfgID,value) ) #define IDeckLinkAttributes_GetString(This,cfgID,value) \ ( (This)->lpVtbl -> GetString(This,cfgID,value) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkAttributes_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkKeyer_INTERFACE_DEFINED__ #define __IDeckLinkKeyer_INTERFACE_DEFINED__ /* interface IDeckLinkKeyer */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkKeyer; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("89AFCAF5-65F8-421E-98F7-96FE5F5BFBA3") IDeckLinkKeyer : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE Enable( /* [in] */ BOOL isExternal) = 0; virtual HRESULT STDMETHODCALLTYPE SetLevel( /* [in] */ unsigned char level) = 0; virtual HRESULT STDMETHODCALLTYPE RampUp( /* [in] */ unsigned long numberOfFrames) = 0; virtual HRESULT STDMETHODCALLTYPE RampDown( /* [in] */ unsigned long numberOfFrames) = 0; virtual HRESULT STDMETHODCALLTYPE Disable( void) = 0; }; #else /* C style interface */ typedef struct IDeckLinkKeyerVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkKeyer * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkKeyer * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkKeyer * This); HRESULT ( STDMETHODCALLTYPE *Enable )( IDeckLinkKeyer * This, /* [in] */ BOOL isExternal); HRESULT ( STDMETHODCALLTYPE *SetLevel )( IDeckLinkKeyer * This, /* [in] */ unsigned char level); HRESULT ( STDMETHODCALLTYPE *RampUp )( IDeckLinkKeyer * This, /* [in] */ unsigned long numberOfFrames); HRESULT ( STDMETHODCALLTYPE *RampDown )( IDeckLinkKeyer * This, /* [in] */ unsigned long numberOfFrames); HRESULT ( STDMETHODCALLTYPE *Disable )( IDeckLinkKeyer * This); END_INTERFACE } IDeckLinkKeyerVtbl; interface IDeckLinkKeyer { CONST_VTBL struct IDeckLinkKeyerVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkKeyer_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkKeyer_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkKeyer_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkKeyer_Enable(This,isExternal) \ ( (This)->lpVtbl -> Enable(This,isExternal) ) #define IDeckLinkKeyer_SetLevel(This,level) \ ( (This)->lpVtbl -> SetLevel(This,level) ) #define IDeckLinkKeyer_RampUp(This,numberOfFrames) \ ( (This)->lpVtbl -> RampUp(This,numberOfFrames) ) #define IDeckLinkKeyer_RampDown(This,numberOfFrames) \ ( (This)->lpVtbl -> RampDown(This,numberOfFrames) ) #define IDeckLinkKeyer_Disable(This) \ ( (This)->lpVtbl -> Disable(This) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkKeyer_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkVideoConversion_INTERFACE_DEFINED__ #define __IDeckLinkVideoConversion_INTERFACE_DEFINED__ /* interface IDeckLinkVideoConversion */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkVideoConversion; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("3BBCB8A2-DA2C-42D9-B5D8-88083644E99A") IDeckLinkVideoConversion : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE ConvertFrame( /* [in] */ IDeckLinkVideoFrame *srcFrame, /* [in] */ IDeckLinkVideoFrame *dstFrame) = 0; }; #else /* C style interface */ typedef struct IDeckLinkVideoConversionVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkVideoConversion * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkVideoConversion * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkVideoConversion * This); HRESULT ( STDMETHODCALLTYPE *ConvertFrame )( IDeckLinkVideoConversion * This, /* [in] */ IDeckLinkVideoFrame *srcFrame, /* [in] */ IDeckLinkVideoFrame *dstFrame); END_INTERFACE } IDeckLinkVideoConversionVtbl; interface IDeckLinkVideoConversion { CONST_VTBL struct IDeckLinkVideoConversionVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkVideoConversion_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkVideoConversion_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkVideoConversion_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkVideoConversion_ConvertFrame(This,srcFrame,dstFrame) \ ( (This)->lpVtbl -> ConvertFrame(This,srcFrame,dstFrame) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkVideoConversion_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkDeckControlStatusCallback_INTERFACE_DEFINED__ #define __IDeckLinkDeckControlStatusCallback_INTERFACE_DEFINED__ /* interface IDeckLinkDeckControlStatusCallback */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkDeckControlStatusCallback; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("E5F693C1-4283-4716-B18F-C1431521955B") IDeckLinkDeckControlStatusCallback : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE TimecodeUpdate( /* [in] */ BMDTimecodeBCD currentTimecode) = 0; virtual HRESULT STDMETHODCALLTYPE VTRControlStateChanged( /* [in] */ BMDDeckControlVTRControlState newState, /* [in] */ BMDDeckControlError error) = 0; virtual HRESULT STDMETHODCALLTYPE DeckControlEventReceived( /* [in] */ BMDDeckControlEvent event, /* [in] */ BMDDeckControlError error) = 0; virtual HRESULT STDMETHODCALLTYPE DeckControlStatusChanged( /* [in] */ BMDDeckControlStatusFlags flags, /* [in] */ unsigned long mask) = 0; }; #else /* C style interface */ typedef struct IDeckLinkDeckControlStatusCallbackVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkDeckControlStatusCallback * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkDeckControlStatusCallback * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkDeckControlStatusCallback * This); HRESULT ( STDMETHODCALLTYPE *TimecodeUpdate )( IDeckLinkDeckControlStatusCallback * This, /* [in] */ BMDTimecodeBCD currentTimecode); HRESULT ( STDMETHODCALLTYPE *VTRControlStateChanged )( IDeckLinkDeckControlStatusCallback * This, /* [in] */ BMDDeckControlVTRControlState newState, /* [in] */ BMDDeckControlError error); HRESULT ( STDMETHODCALLTYPE *DeckControlEventReceived )( IDeckLinkDeckControlStatusCallback * This, /* [in] */ BMDDeckControlEvent event, /* [in] */ BMDDeckControlError error); HRESULT ( STDMETHODCALLTYPE *DeckControlStatusChanged )( IDeckLinkDeckControlStatusCallback * This, /* [in] */ BMDDeckControlStatusFlags flags, /* [in] */ unsigned long mask); END_INTERFACE } IDeckLinkDeckControlStatusCallbackVtbl; interface IDeckLinkDeckControlStatusCallback { CONST_VTBL struct IDeckLinkDeckControlStatusCallbackVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkDeckControlStatusCallback_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkDeckControlStatusCallback_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkDeckControlStatusCallback_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkDeckControlStatusCallback_TimecodeUpdate(This,currentTimecode) \ ( (This)->lpVtbl -> TimecodeUpdate(This,currentTimecode) ) #define IDeckLinkDeckControlStatusCallback_VTRControlStateChanged(This,newState,error) \ ( (This)->lpVtbl -> VTRControlStateChanged(This,newState,error) ) #define IDeckLinkDeckControlStatusCallback_DeckControlEventReceived(This,event,error) \ ( (This)->lpVtbl -> DeckControlEventReceived(This,event,error) ) #define IDeckLinkDeckControlStatusCallback_DeckControlStatusChanged(This,flags,mask) \ ( (This)->lpVtbl -> DeckControlStatusChanged(This,flags,mask) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkDeckControlStatusCallback_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkDeckControl_INTERFACE_DEFINED__ #define __IDeckLinkDeckControl_INTERFACE_DEFINED__ /* interface IDeckLinkDeckControl */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkDeckControl; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("A4D81043-0619-42B7-8ED6-602D29041DF7") IDeckLinkDeckControl : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE Open( /* [in] */ BMDTimeScale timeScale, /* [in] */ BMDTimeValue timeValue, /* [in] */ BOOL timecodeIsDropFrame, /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE Close( /* [in] */ BOOL standbyOn) = 0; virtual HRESULT STDMETHODCALLTYPE GetCurrentState( /* [out] */ BMDDeckControlMode *mode, /* [out] */ BMDDeckControlVTRControlState *vtrControlState, /* [out] */ BMDDeckControlStatusFlags *flags) = 0; virtual HRESULT STDMETHODCALLTYPE SetStandby( /* [in] */ BOOL standbyOn) = 0; virtual HRESULT STDMETHODCALLTYPE Play( /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE Stop( /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE TogglePlayStop( /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE Eject( /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE GoToTimecode( /* [in] */ BMDTimecodeBCD timecode, /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE FastForward( /* [in] */ BOOL viewTape, /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE Rewind( /* [in] */ BOOL viewTape, /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE StepForward( /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE StepBack( /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE Jog( /* [in] */ double rate, /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE Shuttle( /* [in] */ double rate, /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE GetTimecodeString( /* [out] */ BSTR *currentTimeCode, /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE GetTimecode( /* [out] */ IDeckLinkTimecode **currentTimecode, /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE GetTimecodeBCD( /* [out] */ BMDTimecodeBCD *currentTimecode, /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE SetPreroll( /* [in] */ unsigned long prerollSeconds) = 0; virtual HRESULT STDMETHODCALLTYPE GetPreroll( /* [out] */ unsigned long *prerollSeconds) = 0; virtual HRESULT STDMETHODCALLTYPE SetExportOffset( /* [in] */ long exportOffsetFields) = 0; virtual HRESULT STDMETHODCALLTYPE GetExportOffset( /* [out] */ long *exportOffsetFields) = 0; virtual HRESULT STDMETHODCALLTYPE GetManualExportOffset( /* [out] */ long *deckManualExportOffsetFields) = 0; virtual HRESULT STDMETHODCALLTYPE SetCaptureOffset( /* [in] */ long captureOffsetFields) = 0; virtual HRESULT STDMETHODCALLTYPE GetCaptureOffset( /* [out] */ long *captureOffsetFields) = 0; virtual HRESULT STDMETHODCALLTYPE StartExport( /* [in] */ BMDTimecodeBCD inTimecode, /* [in] */ BMDTimecodeBCD outTimecode, /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps, /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE StartCapture( /* [in] */ BOOL useVITC, /* [in] */ BMDTimecodeBCD inTimecode, /* [in] */ BMDTimecodeBCD outTimecode, /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE GetDeviceID( /* [out] */ unsigned short *deviceId, /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE Abort( void) = 0; virtual HRESULT STDMETHODCALLTYPE CrashRecordStart( /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE CrashRecordStop( /* [out] */ BMDDeckControlError *error) = 0; virtual HRESULT STDMETHODCALLTYPE SetCallback( /* [in] */ IDeckLinkDeckControlStatusCallback *callback) = 0; }; #else /* C style interface */ typedef struct IDeckLinkDeckControlVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkDeckControl * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkDeckControl * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkDeckControl * This); HRESULT ( STDMETHODCALLTYPE *Open )( IDeckLinkDeckControl * This, /* [in] */ BMDTimeScale timeScale, /* [in] */ BMDTimeValue timeValue, /* [in] */ BOOL timecodeIsDropFrame, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *Close )( IDeckLinkDeckControl * This, /* [in] */ BOOL standbyOn); HRESULT ( STDMETHODCALLTYPE *GetCurrentState )( IDeckLinkDeckControl * This, /* [out] */ BMDDeckControlMode *mode, /* [out] */ BMDDeckControlVTRControlState *vtrControlState, /* [out] */ BMDDeckControlStatusFlags *flags); HRESULT ( STDMETHODCALLTYPE *SetStandby )( IDeckLinkDeckControl * This, /* [in] */ BOOL standbyOn); HRESULT ( STDMETHODCALLTYPE *Play )( IDeckLinkDeckControl * This, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *Stop )( IDeckLinkDeckControl * This, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *TogglePlayStop )( IDeckLinkDeckControl * This, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *Eject )( IDeckLinkDeckControl * This, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *GoToTimecode )( IDeckLinkDeckControl * This, /* [in] */ BMDTimecodeBCD timecode, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *FastForward )( IDeckLinkDeckControl * This, /* [in] */ BOOL viewTape, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *Rewind )( IDeckLinkDeckControl * This, /* [in] */ BOOL viewTape, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *StepForward )( IDeckLinkDeckControl * This, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *StepBack )( IDeckLinkDeckControl * This, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *Jog )( IDeckLinkDeckControl * This, /* [in] */ double rate, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *Shuttle )( IDeckLinkDeckControl * This, /* [in] */ double rate, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *GetTimecodeString )( IDeckLinkDeckControl * This, /* [out] */ BSTR *currentTimeCode, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *GetTimecode )( IDeckLinkDeckControl * This, /* [out] */ IDeckLinkTimecode **currentTimecode, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *GetTimecodeBCD )( IDeckLinkDeckControl * This, /* [out] */ BMDTimecodeBCD *currentTimecode, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *SetPreroll )( IDeckLinkDeckControl * This, /* [in] */ unsigned long prerollSeconds); HRESULT ( STDMETHODCALLTYPE *GetPreroll )( IDeckLinkDeckControl * This, /* [out] */ unsigned long *prerollSeconds); HRESULT ( STDMETHODCALLTYPE *SetExportOffset )( IDeckLinkDeckControl * This, /* [in] */ long exportOffsetFields); HRESULT ( STDMETHODCALLTYPE *GetExportOffset )( IDeckLinkDeckControl * This, /* [out] */ long *exportOffsetFields); HRESULT ( STDMETHODCALLTYPE *GetManualExportOffset )( IDeckLinkDeckControl * This, /* [out] */ long *deckManualExportOffsetFields); HRESULT ( STDMETHODCALLTYPE *SetCaptureOffset )( IDeckLinkDeckControl * This, /* [in] */ long captureOffsetFields); HRESULT ( STDMETHODCALLTYPE *GetCaptureOffset )( IDeckLinkDeckControl * This, /* [out] */ long *captureOffsetFields); HRESULT ( STDMETHODCALLTYPE *StartExport )( IDeckLinkDeckControl * This, /* [in] */ BMDTimecodeBCD inTimecode, /* [in] */ BMDTimecodeBCD outTimecode, /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *StartCapture )( IDeckLinkDeckControl * This, /* [in] */ BOOL useVITC, /* [in] */ BMDTimecodeBCD inTimecode, /* [in] */ BMDTimecodeBCD outTimecode, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *GetDeviceID )( IDeckLinkDeckControl * This, /* [out] */ unsigned short *deviceId, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *Abort )( IDeckLinkDeckControl * This); HRESULT ( STDMETHODCALLTYPE *CrashRecordStart )( IDeckLinkDeckControl * This, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *CrashRecordStop )( IDeckLinkDeckControl * This, /* [out] */ BMDDeckControlError *error); HRESULT ( STDMETHODCALLTYPE *SetCallback )( IDeckLinkDeckControl * This, /* [in] */ IDeckLinkDeckControlStatusCallback *callback); END_INTERFACE } IDeckLinkDeckControlVtbl; interface IDeckLinkDeckControl { CONST_VTBL struct IDeckLinkDeckControlVtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkDeckControl_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkDeckControl_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkDeckControl_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkDeckControl_Open(This,timeScale,timeValue,timecodeIsDropFrame,error) \ ( (This)->lpVtbl -> Open(This,timeScale,timeValue,timecodeIsDropFrame,error) ) #define IDeckLinkDeckControl_Close(This,standbyOn) \ ( (This)->lpVtbl -> Close(This,standbyOn) ) #define IDeckLinkDeckControl_GetCurrentState(This,mode,vtrControlState,flags) \ ( (This)->lpVtbl -> GetCurrentState(This,mode,vtrControlState,flags) ) #define IDeckLinkDeckControl_SetStandby(This,standbyOn) \ ( (This)->lpVtbl -> SetStandby(This,standbyOn) ) #define IDeckLinkDeckControl_Play(This,error) \ ( (This)->lpVtbl -> Play(This,error) ) #define IDeckLinkDeckControl_Stop(This,error) \ ( (This)->lpVtbl -> Stop(This,error) ) #define IDeckLinkDeckControl_TogglePlayStop(This,error) \ ( (This)->lpVtbl -> TogglePlayStop(This,error) ) #define IDeckLinkDeckControl_Eject(This,error) \ ( (This)->lpVtbl -> Eject(This,error) ) #define IDeckLinkDeckControl_GoToTimecode(This,timecode,error) \ ( (This)->lpVtbl -> GoToTimecode(This,timecode,error) ) #define IDeckLinkDeckControl_FastForward(This,viewTape,error) \ ( (This)->lpVtbl -> FastForward(This,viewTape,error) ) #define IDeckLinkDeckControl_Rewind(This,viewTape,error) \ ( (This)->lpVtbl -> Rewind(This,viewTape,error) ) #define IDeckLinkDeckControl_StepForward(This,error) \ ( (This)->lpVtbl -> StepForward(This,error) ) #define IDeckLinkDeckControl_StepBack(This,error) \ ( (This)->lpVtbl -> StepBack(This,error) ) #define IDeckLinkDeckControl_Jog(This,rate,error) \ ( (This)->lpVtbl -> Jog(This,rate,error) ) #define IDeckLinkDeckControl_Shuttle(This,rate,error) \ ( (This)->lpVtbl -> Shuttle(This,rate,error) ) #define IDeckLinkDeckControl_GetTimecodeString(This,currentTimeCode,error) \ ( (This)->lpVtbl -> GetTimecodeString(This,currentTimeCode,error) ) #define IDeckLinkDeckControl_GetTimecode(This,currentTimecode,error) \ ( (This)->lpVtbl -> GetTimecode(This,currentTimecode,error) ) #define IDeckLinkDeckControl_GetTimecodeBCD(This,currentTimecode,error) \ ( (This)->lpVtbl -> GetTimecodeBCD(This,currentTimecode,error) ) #define IDeckLinkDeckControl_SetPreroll(This,prerollSeconds) \ ( (This)->lpVtbl -> SetPreroll(This,prerollSeconds) ) #define IDeckLinkDeckControl_GetPreroll(This,prerollSeconds) \ ( (This)->lpVtbl -> GetPreroll(This,prerollSeconds) ) #define IDeckLinkDeckControl_SetExportOffset(This,exportOffsetFields) \ ( (This)->lpVtbl -> SetExportOffset(This,exportOffsetFields) ) #define IDeckLinkDeckControl_GetExportOffset(This,exportOffsetFields) \ ( (This)->lpVtbl -> GetExportOffset(This,exportOffsetFields) ) #define IDeckLinkDeckControl_GetManualExportOffset(This,deckManualExportOffsetFields) \ ( (This)->lpVtbl -> GetManualExportOffset(This,deckManualExportOffsetFields) ) #define IDeckLinkDeckControl_SetCaptureOffset(This,captureOffsetFields) \ ( (This)->lpVtbl -> SetCaptureOffset(This,captureOffsetFields) ) #define IDeckLinkDeckControl_GetCaptureOffset(This,captureOffsetFields) \ ( (This)->lpVtbl -> GetCaptureOffset(This,captureOffsetFields) ) #define IDeckLinkDeckControl_StartExport(This,inTimecode,outTimecode,exportModeOps,error) \ ( (This)->lpVtbl -> StartExport(This,inTimecode,outTimecode,exportModeOps,error) ) #define IDeckLinkDeckControl_StartCapture(This,useVITC,inTimecode,outTimecode,error) \ ( (This)->lpVtbl -> StartCapture(This,useVITC,inTimecode,outTimecode,error) ) #define IDeckLinkDeckControl_GetDeviceID(This,deviceId,error) \ ( (This)->lpVtbl -> GetDeviceID(This,deviceId,error) ) #define IDeckLinkDeckControl_Abort(This) \ ( (This)->lpVtbl -> Abort(This) ) #define IDeckLinkDeckControl_CrashRecordStart(This,error) \ ( (This)->lpVtbl -> CrashRecordStart(This,error) ) #define IDeckLinkDeckControl_CrashRecordStop(This,error) \ ( (This)->lpVtbl -> CrashRecordStop(This,error) ) #define IDeckLinkDeckControl_SetCallback(This,callback) \ ( (This)->lpVtbl -> SetCallback(This,callback) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkDeckControl_INTERFACE_DEFINED__ */ EXTERN_C const CLSID CLSID_CDeckLinkIterator; #ifdef __cplusplus class DECLSPEC_UUID("D9EDA3B3-2887-41FA-B724-017CF1EB1D37") CDeckLinkIterator; #endif EXTERN_C const CLSID CLSID_CDeckLinkGLScreenPreviewHelper; #ifdef __cplusplus class DECLSPEC_UUID("F63E77C7-B655-4A4A-9AD0-3CA85D394343") CDeckLinkGLScreenPreviewHelper; #endif EXTERN_C const CLSID CLSID_CDeckLinkVideoConversion; #ifdef __cplusplus class DECLSPEC_UUID("7DBBBB11-5B7B-467D-AEA4-CEA468FD368C") CDeckLinkVideoConversion; #endif #ifndef __IDeckLinkDisplayModeIterator_v7_6_INTERFACE_DEFINED__ #define __IDeckLinkDisplayModeIterator_v7_6_INTERFACE_DEFINED__ /* interface IDeckLinkDisplayModeIterator_v7_6 */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkDisplayModeIterator_v7_6; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("455D741F-1779-4800-86F5-0B5D13D79751") IDeckLinkDisplayModeIterator_v7_6 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE Next( /* [out] */ IDeckLinkDisplayMode_v7_6 **deckLinkDisplayMode) = 0; }; #else /* C style interface */ typedef struct IDeckLinkDisplayModeIterator_v7_6Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkDisplayModeIterator_v7_6 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkDisplayModeIterator_v7_6 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkDisplayModeIterator_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *Next )( IDeckLinkDisplayModeIterator_v7_6 * This, /* [out] */ IDeckLinkDisplayMode_v7_6 **deckLinkDisplayMode); END_INTERFACE } IDeckLinkDisplayModeIterator_v7_6Vtbl; interface IDeckLinkDisplayModeIterator_v7_6 { CONST_VTBL struct IDeckLinkDisplayModeIterator_v7_6Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkDisplayModeIterator_v7_6_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkDisplayModeIterator_v7_6_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkDisplayModeIterator_v7_6_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkDisplayModeIterator_v7_6_Next(This,deckLinkDisplayMode) \ ( (This)->lpVtbl -> Next(This,deckLinkDisplayMode) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkDisplayModeIterator_v7_6_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkDisplayMode_v7_6_INTERFACE_DEFINED__ #define __IDeckLinkDisplayMode_v7_6_INTERFACE_DEFINED__ /* interface IDeckLinkDisplayMode_v7_6 */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkDisplayMode_v7_6; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("87451E84-2B7E-439E-A629-4393EA4A8550") IDeckLinkDisplayMode_v7_6 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE GetName( /* [out] */ BSTR *name) = 0; virtual BMDDisplayMode STDMETHODCALLTYPE GetDisplayMode( void) = 0; virtual long STDMETHODCALLTYPE GetWidth( void) = 0; virtual long STDMETHODCALLTYPE GetHeight( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetFrameRate( /* [out] */ BMDTimeValue *frameDuration, /* [out] */ BMDTimeScale *timeScale) = 0; virtual BMDFieldDominance STDMETHODCALLTYPE GetFieldDominance( void) = 0; }; #else /* C style interface */ typedef struct IDeckLinkDisplayMode_v7_6Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkDisplayMode_v7_6 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkDisplayMode_v7_6 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkDisplayMode_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *GetName )( IDeckLinkDisplayMode_v7_6 * This, /* [out] */ BSTR *name); BMDDisplayMode ( STDMETHODCALLTYPE *GetDisplayMode )( IDeckLinkDisplayMode_v7_6 * This); long ( STDMETHODCALLTYPE *GetWidth )( IDeckLinkDisplayMode_v7_6 * This); long ( STDMETHODCALLTYPE *GetHeight )( IDeckLinkDisplayMode_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *GetFrameRate )( IDeckLinkDisplayMode_v7_6 * This, /* [out] */ BMDTimeValue *frameDuration, /* [out] */ BMDTimeScale *timeScale); BMDFieldDominance ( STDMETHODCALLTYPE *GetFieldDominance )( IDeckLinkDisplayMode_v7_6 * This); END_INTERFACE } IDeckLinkDisplayMode_v7_6Vtbl; interface IDeckLinkDisplayMode_v7_6 { CONST_VTBL struct IDeckLinkDisplayMode_v7_6Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkDisplayMode_v7_6_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkDisplayMode_v7_6_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkDisplayMode_v7_6_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkDisplayMode_v7_6_GetName(This,name) \ ( (This)->lpVtbl -> GetName(This,name) ) #define IDeckLinkDisplayMode_v7_6_GetDisplayMode(This) \ ( (This)->lpVtbl -> GetDisplayMode(This) ) #define IDeckLinkDisplayMode_v7_6_GetWidth(This) \ ( (This)->lpVtbl -> GetWidth(This) ) #define IDeckLinkDisplayMode_v7_6_GetHeight(This) \ ( (This)->lpVtbl -> GetHeight(This) ) #define IDeckLinkDisplayMode_v7_6_GetFrameRate(This,frameDuration,timeScale) \ ( (This)->lpVtbl -> GetFrameRate(This,frameDuration,timeScale) ) #define IDeckLinkDisplayMode_v7_6_GetFieldDominance(This) \ ( (This)->lpVtbl -> GetFieldDominance(This) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkDisplayMode_v7_6_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkOutput_v7_6_INTERFACE_DEFINED__ #define __IDeckLinkOutput_v7_6_INTERFACE_DEFINED__ /* interface IDeckLinkOutput_v7_6 */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkOutput_v7_6; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("29228142-EB8C-4141-A621-F74026450955") IDeckLinkOutput_v7_6 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* [out] */ BMDDisplayModeSupport *result) = 0; virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( /* [in] */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback) = 0; virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput( BMDDisplayMode displayMode, BMDVideoOutputFlags flags) = 0; virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator( /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0; virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame( long width, long height, long rowBytes, BMDPixelFormat pixelFormat, BMDFrameFlags flags, /* [out] */ IDeckLinkMutableVideoFrame_v7_6 **outFrame) = 0; virtual HRESULT STDMETHODCALLTYPE CreateAncillaryData( BMDPixelFormat pixelFormat, /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync( /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame) = 0; virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame( /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame, BMDTimeValue displayTime, BMDTimeValue displayDuration, BMDTimeScale timeScale) = 0; virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback( /* [in] */ IDeckLinkVideoOutputCallback_v7_6 *theCallback) = 0; virtual HRESULT STDMETHODCALLTYPE GetBufferedVideoFrameCount( /* [out] */ unsigned long *bufferedFrameCount) = 0; virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput( BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType, unsigned long channelCount, BMDAudioOutputStreamType streamType) = 0; virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0; virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync( /* [in] */ void *buffer, unsigned long sampleFrameCount, /* [out] */ unsigned long *sampleFramesWritten) = 0; virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0; virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0; virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples( /* [in] */ void *buffer, unsigned long sampleFrameCount, BMDTimeValue streamTime, BMDTimeScale timeScale, /* [out] */ unsigned long *sampleFramesWritten) = 0; virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( /* [out] */ unsigned long *bufferedSampleFrameCount) = 0; virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetAudioCallback( /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0; virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback( BMDTimeValue playbackStartTime, BMDTimeScale timeScale, double playbackSpeed) = 0; virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback( BMDTimeValue stopPlaybackAtTime, /* [out] */ BMDTimeValue *actualStopTime, BMDTimeScale timeScale) = 0; virtual HRESULT STDMETHODCALLTYPE IsScheduledPlaybackRunning( /* [out] */ BOOL *active) = 0; virtual HRESULT STDMETHODCALLTYPE GetScheduledStreamTime( BMDTimeScale desiredTimeScale, /* [out] */ BMDTimeValue *streamTime, /* [out] */ double *playbackSpeed) = 0; virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( BMDTimeScale desiredTimeScale, /* [out] */ BMDTimeValue *hardwareTime, /* [out] */ BMDTimeValue *timeInFrame, /* [out] */ BMDTimeValue *ticksPerFrame) = 0; }; #else /* C style interface */ typedef struct IDeckLinkOutput_v7_6Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkOutput_v7_6 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkOutput_v7_6 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkOutput_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( IDeckLinkOutput_v7_6 * This, BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* [out] */ BMDDisplayModeSupport *result); HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( IDeckLinkOutput_v7_6 * This, /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator); HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( IDeckLinkOutput_v7_6 * This, /* [in] */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback); HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )( IDeckLinkOutput_v7_6 * This, BMDDisplayMode displayMode, BMDVideoOutputFlags flags); HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )( IDeckLinkOutput_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )( IDeckLinkOutput_v7_6 * This, /* [in] */ IDeckLinkMemoryAllocator *theAllocator); HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )( IDeckLinkOutput_v7_6 * This, long width, long height, long rowBytes, BMDPixelFormat pixelFormat, BMDFrameFlags flags, /* [out] */ IDeckLinkMutableVideoFrame_v7_6 **outFrame); HRESULT ( STDMETHODCALLTYPE *CreateAncillaryData )( IDeckLinkOutput_v7_6 * This, BMDPixelFormat pixelFormat, /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer); HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )( IDeckLinkOutput_v7_6 * This, /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame); HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )( IDeckLinkOutput_v7_6 * This, /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame, BMDTimeValue displayTime, BMDTimeValue displayDuration, BMDTimeScale timeScale); HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )( IDeckLinkOutput_v7_6 * This, /* [in] */ IDeckLinkVideoOutputCallback_v7_6 *theCallback); HRESULT ( STDMETHODCALLTYPE *GetBufferedVideoFrameCount )( IDeckLinkOutput_v7_6 * This, /* [out] */ unsigned long *bufferedFrameCount); HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )( IDeckLinkOutput_v7_6 * This, BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType, unsigned long channelCount, BMDAudioOutputStreamType streamType); HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )( IDeckLinkOutput_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )( IDeckLinkOutput_v7_6 * This, /* [in] */ void *buffer, unsigned long sampleFrameCount, /* [out] */ unsigned long *sampleFramesWritten); HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )( IDeckLinkOutput_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )( IDeckLinkOutput_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )( IDeckLinkOutput_v7_6 * This, /* [in] */ void *buffer, unsigned long sampleFrameCount, BMDTimeValue streamTime, BMDTimeScale timeScale, /* [out] */ unsigned long *sampleFramesWritten); HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( IDeckLinkOutput_v7_6 * This, /* [out] */ unsigned long *bufferedSampleFrameCount); HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )( IDeckLinkOutput_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )( IDeckLinkOutput_v7_6 * This, /* [in] */ IDeckLinkAudioOutputCallback *theCallback); HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )( IDeckLinkOutput_v7_6 * This, BMDTimeValue playbackStartTime, BMDTimeScale timeScale, double playbackSpeed); HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )( IDeckLinkOutput_v7_6 * This, BMDTimeValue stopPlaybackAtTime, /* [out] */ BMDTimeValue *actualStopTime, BMDTimeScale timeScale); HRESULT ( STDMETHODCALLTYPE *IsScheduledPlaybackRunning )( IDeckLinkOutput_v7_6 * This, /* [out] */ BOOL *active); HRESULT ( STDMETHODCALLTYPE *GetScheduledStreamTime )( IDeckLinkOutput_v7_6 * This, BMDTimeScale desiredTimeScale, /* [out] */ BMDTimeValue *streamTime, /* [out] */ double *playbackSpeed); HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( IDeckLinkOutput_v7_6 * This, BMDTimeScale desiredTimeScale, /* [out] */ BMDTimeValue *hardwareTime, /* [out] */ BMDTimeValue *timeInFrame, /* [out] */ BMDTimeValue *ticksPerFrame); END_INTERFACE } IDeckLinkOutput_v7_6Vtbl; interface IDeckLinkOutput_v7_6 { CONST_VTBL struct IDeckLinkOutput_v7_6Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkOutput_v7_6_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkOutput_v7_6_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkOutput_v7_6_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkOutput_v7_6_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) #define IDeckLinkOutput_v7_6_GetDisplayModeIterator(This,iterator) \ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) #define IDeckLinkOutput_v7_6_SetScreenPreviewCallback(This,previewCallback) \ ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) #define IDeckLinkOutput_v7_6_EnableVideoOutput(This,displayMode,flags) \ ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode,flags) ) #define IDeckLinkOutput_v7_6_DisableVideoOutput(This) \ ( (This)->lpVtbl -> DisableVideoOutput(This) ) #define IDeckLinkOutput_v7_6_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \ ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) ) #define IDeckLinkOutput_v7_6_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \ ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) ) #define IDeckLinkOutput_v7_6_CreateAncillaryData(This,pixelFormat,outBuffer) \ ( (This)->lpVtbl -> CreateAncillaryData(This,pixelFormat,outBuffer) ) #define IDeckLinkOutput_v7_6_DisplayVideoFrameSync(This,theFrame) \ ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) ) #define IDeckLinkOutput_v7_6_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \ ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) ) #define IDeckLinkOutput_v7_6_SetScheduledFrameCompletionCallback(This,theCallback) \ ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) ) #define IDeckLinkOutput_v7_6_GetBufferedVideoFrameCount(This,bufferedFrameCount) \ ( (This)->lpVtbl -> GetBufferedVideoFrameCount(This,bufferedFrameCount) ) #define IDeckLinkOutput_v7_6_EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) \ ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) ) #define IDeckLinkOutput_v7_6_DisableAudioOutput(This) \ ( (This)->lpVtbl -> DisableAudioOutput(This) ) #define IDeckLinkOutput_v7_6_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \ ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) ) #define IDeckLinkOutput_v7_6_BeginAudioPreroll(This) \ ( (This)->lpVtbl -> BeginAudioPreroll(This) ) #define IDeckLinkOutput_v7_6_EndAudioPreroll(This) \ ( (This)->lpVtbl -> EndAudioPreroll(This) ) #define IDeckLinkOutput_v7_6_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \ ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) ) #define IDeckLinkOutput_v7_6_GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) \ ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) ) #define IDeckLinkOutput_v7_6_FlushBufferedAudioSamples(This) \ ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) ) #define IDeckLinkOutput_v7_6_SetAudioCallback(This,theCallback) \ ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) ) #define IDeckLinkOutput_v7_6_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \ ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) ) #define IDeckLinkOutput_v7_6_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \ ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) ) #define IDeckLinkOutput_v7_6_IsScheduledPlaybackRunning(This,active) \ ( (This)->lpVtbl -> IsScheduledPlaybackRunning(This,active) ) #define IDeckLinkOutput_v7_6_GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) \ ( (This)->lpVtbl -> GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) ) #define IDeckLinkOutput_v7_6_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \ ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkOutput_v7_6_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkInput_v7_6_INTERFACE_DEFINED__ #define __IDeckLinkInput_v7_6_INTERFACE_DEFINED__ /* interface IDeckLinkInput_v7_6 */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkInput_v7_6; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("300C135A-9F43-48E2-9906-6D7911D93CF1") IDeckLinkInput_v7_6 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* [out] */ BMDDisplayModeSupport *result) = 0; virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( /* [in] */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback) = 0; virtual HRESULT STDMETHODCALLTYPE EnableVideoInput( BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDVideoInputFlags flags) = 0; virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoFrameCount( /* [out] */ unsigned long *availableFrameCount) = 0; virtual HRESULT STDMETHODCALLTYPE EnableAudioInput( BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType, unsigned long channelCount) = 0; virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetAvailableAudioSampleFrameCount( /* [out] */ unsigned long *availableSampleFrameCount) = 0; virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0; virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0; virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0; virtual HRESULT STDMETHODCALLTYPE FlushStreams( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetCallback( /* [in] */ IDeckLinkInputCallback_v7_6 *theCallback) = 0; virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( BMDTimeScale desiredTimeScale, /* [out] */ BMDTimeValue *hardwareTime, /* [out] */ BMDTimeValue *timeInFrame, /* [out] */ BMDTimeValue *ticksPerFrame) = 0; }; #else /* C style interface */ typedef struct IDeckLinkInput_v7_6Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkInput_v7_6 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkInput_v7_6 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkInput_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( IDeckLinkInput_v7_6 * This, BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* [out] */ BMDDisplayModeSupport *result); HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( IDeckLinkInput_v7_6 * This, /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator); HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( IDeckLinkInput_v7_6 * This, /* [in] */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback); HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )( IDeckLinkInput_v7_6 * This, BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDVideoInputFlags flags); HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )( IDeckLinkInput_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *GetAvailableVideoFrameCount )( IDeckLinkInput_v7_6 * This, /* [out] */ unsigned long *availableFrameCount); HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )( IDeckLinkInput_v7_6 * This, BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType, unsigned long channelCount); HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )( IDeckLinkInput_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *GetAvailableAudioSampleFrameCount )( IDeckLinkInput_v7_6 * This, /* [out] */ unsigned long *availableSampleFrameCount); HRESULT ( STDMETHODCALLTYPE *StartStreams )( IDeckLinkInput_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *StopStreams )( IDeckLinkInput_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *PauseStreams )( IDeckLinkInput_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *FlushStreams )( IDeckLinkInput_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *SetCallback )( IDeckLinkInput_v7_6 * This, /* [in] */ IDeckLinkInputCallback_v7_6 *theCallback); HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( IDeckLinkInput_v7_6 * This, BMDTimeScale desiredTimeScale, /* [out] */ BMDTimeValue *hardwareTime, /* [out] */ BMDTimeValue *timeInFrame, /* [out] */ BMDTimeValue *ticksPerFrame); END_INTERFACE } IDeckLinkInput_v7_6Vtbl; interface IDeckLinkInput_v7_6 { CONST_VTBL struct IDeckLinkInput_v7_6Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkInput_v7_6_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkInput_v7_6_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkInput_v7_6_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkInput_v7_6_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) #define IDeckLinkInput_v7_6_GetDisplayModeIterator(This,iterator) \ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) #define IDeckLinkInput_v7_6_SetScreenPreviewCallback(This,previewCallback) \ ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) #define IDeckLinkInput_v7_6_EnableVideoInput(This,displayMode,pixelFormat,flags) \ ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) ) #define IDeckLinkInput_v7_6_DisableVideoInput(This) \ ( (This)->lpVtbl -> DisableVideoInput(This) ) #define IDeckLinkInput_v7_6_GetAvailableVideoFrameCount(This,availableFrameCount) \ ( (This)->lpVtbl -> GetAvailableVideoFrameCount(This,availableFrameCount) ) #define IDeckLinkInput_v7_6_EnableAudioInput(This,sampleRate,sampleType,channelCount) \ ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) ) #define IDeckLinkInput_v7_6_DisableAudioInput(This) \ ( (This)->lpVtbl -> DisableAudioInput(This) ) #define IDeckLinkInput_v7_6_GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) \ ( (This)->lpVtbl -> GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) ) #define IDeckLinkInput_v7_6_StartStreams(This) \ ( (This)->lpVtbl -> StartStreams(This) ) #define IDeckLinkInput_v7_6_StopStreams(This) \ ( (This)->lpVtbl -> StopStreams(This) ) #define IDeckLinkInput_v7_6_PauseStreams(This) \ ( (This)->lpVtbl -> PauseStreams(This) ) #define IDeckLinkInput_v7_6_FlushStreams(This) \ ( (This)->lpVtbl -> FlushStreams(This) ) #define IDeckLinkInput_v7_6_SetCallback(This,theCallback) \ ( (This)->lpVtbl -> SetCallback(This,theCallback) ) #define IDeckLinkInput_v7_6_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \ ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkInput_v7_6_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkTimecode_v7_6_INTERFACE_DEFINED__ #define __IDeckLinkTimecode_v7_6_INTERFACE_DEFINED__ /* interface IDeckLinkTimecode_v7_6 */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkTimecode_v7_6; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("EFB9BCA6-A521-44F7-BD69-2332F24D9EE6") IDeckLinkTimecode_v7_6 : public IUnknown { public: virtual BMDTimecodeBCD STDMETHODCALLTYPE GetBCD( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetComponents( /* [out] */ unsigned char *hours, /* [out] */ unsigned char *minutes, /* [out] */ unsigned char *seconds, /* [out] */ unsigned char *frames) = 0; virtual HRESULT STDMETHODCALLTYPE GetString( /* [out] */ BSTR *timecode) = 0; virtual BMDTimecodeFlags STDMETHODCALLTYPE GetFlags( void) = 0; }; #else /* C style interface */ typedef struct IDeckLinkTimecode_v7_6Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkTimecode_v7_6 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkTimecode_v7_6 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkTimecode_v7_6 * This); BMDTimecodeBCD ( STDMETHODCALLTYPE *GetBCD )( IDeckLinkTimecode_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *GetComponents )( IDeckLinkTimecode_v7_6 * This, /* [out] */ unsigned char *hours, /* [out] */ unsigned char *minutes, /* [out] */ unsigned char *seconds, /* [out] */ unsigned char *frames); HRESULT ( STDMETHODCALLTYPE *GetString )( IDeckLinkTimecode_v7_6 * This, /* [out] */ BSTR *timecode); BMDTimecodeFlags ( STDMETHODCALLTYPE *GetFlags )( IDeckLinkTimecode_v7_6 * This); END_INTERFACE } IDeckLinkTimecode_v7_6Vtbl; interface IDeckLinkTimecode_v7_6 { CONST_VTBL struct IDeckLinkTimecode_v7_6Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkTimecode_v7_6_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkTimecode_v7_6_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkTimecode_v7_6_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkTimecode_v7_6_GetBCD(This) \ ( (This)->lpVtbl -> GetBCD(This) ) #define IDeckLinkTimecode_v7_6_GetComponents(This,hours,minutes,seconds,frames) \ ( (This)->lpVtbl -> GetComponents(This,hours,minutes,seconds,frames) ) #define IDeckLinkTimecode_v7_6_GetString(This,timecode) \ ( (This)->lpVtbl -> GetString(This,timecode) ) #define IDeckLinkTimecode_v7_6_GetFlags(This) \ ( (This)->lpVtbl -> GetFlags(This) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkTimecode_v7_6_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkVideoFrame_v7_6_INTERFACE_DEFINED__ #define __IDeckLinkVideoFrame_v7_6_INTERFACE_DEFINED__ /* interface IDeckLinkVideoFrame_v7_6 */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkVideoFrame_v7_6; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("A8D8238E-6B18-4196-99E1-5AF717B83D32") IDeckLinkVideoFrame_v7_6 : public IUnknown { public: virtual long STDMETHODCALLTYPE GetWidth( void) = 0; virtual long STDMETHODCALLTYPE GetHeight( void) = 0; virtual long STDMETHODCALLTYPE GetRowBytes( void) = 0; virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat( void) = 0; virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetBytes( /* [out] */ void **buffer) = 0; virtual HRESULT STDMETHODCALLTYPE GetTimecode( BMDTimecodeFormat format, /* [out] */ IDeckLinkTimecode_v7_6 **timecode) = 0; virtual HRESULT STDMETHODCALLTYPE GetAncillaryData( /* [out] */ IDeckLinkVideoFrameAncillary **ancillary) = 0; }; #else /* C style interface */ typedef struct IDeckLinkVideoFrame_v7_6Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkVideoFrame_v7_6 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkVideoFrame_v7_6 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkVideoFrame_v7_6 * This); long ( STDMETHODCALLTYPE *GetWidth )( IDeckLinkVideoFrame_v7_6 * This); long ( STDMETHODCALLTYPE *GetHeight )( IDeckLinkVideoFrame_v7_6 * This); long ( STDMETHODCALLTYPE *GetRowBytes )( IDeckLinkVideoFrame_v7_6 * This); BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( IDeckLinkVideoFrame_v7_6 * This); BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( IDeckLinkVideoFrame_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *GetBytes )( IDeckLinkVideoFrame_v7_6 * This, /* [out] */ void **buffer); HRESULT ( STDMETHODCALLTYPE *GetTimecode )( IDeckLinkVideoFrame_v7_6 * This, BMDTimecodeFormat format, /* [out] */ IDeckLinkTimecode_v7_6 **timecode); HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( IDeckLinkVideoFrame_v7_6 * This, /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); END_INTERFACE } IDeckLinkVideoFrame_v7_6Vtbl; interface IDeckLinkVideoFrame_v7_6 { CONST_VTBL struct IDeckLinkVideoFrame_v7_6Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkVideoFrame_v7_6_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkVideoFrame_v7_6_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkVideoFrame_v7_6_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkVideoFrame_v7_6_GetWidth(This) \ ( (This)->lpVtbl -> GetWidth(This) ) #define IDeckLinkVideoFrame_v7_6_GetHeight(This) \ ( (This)->lpVtbl -> GetHeight(This) ) #define IDeckLinkVideoFrame_v7_6_GetRowBytes(This) \ ( (This)->lpVtbl -> GetRowBytes(This) ) #define IDeckLinkVideoFrame_v7_6_GetPixelFormat(This) \ ( (This)->lpVtbl -> GetPixelFormat(This) ) #define IDeckLinkVideoFrame_v7_6_GetFlags(This) \ ( (This)->lpVtbl -> GetFlags(This) ) #define IDeckLinkVideoFrame_v7_6_GetBytes(This,buffer) \ ( (This)->lpVtbl -> GetBytes(This,buffer) ) #define IDeckLinkVideoFrame_v7_6_GetTimecode(This,format,timecode) \ ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) #define IDeckLinkVideoFrame_v7_6_GetAncillaryData(This,ancillary) \ ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkVideoFrame_v7_6_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkMutableVideoFrame_v7_6_INTERFACE_DEFINED__ #define __IDeckLinkMutableVideoFrame_v7_6_INTERFACE_DEFINED__ /* interface IDeckLinkMutableVideoFrame_v7_6 */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkMutableVideoFrame_v7_6; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("46FCEE00-B4E6-43D0-91C0-023A7FCEB34F") IDeckLinkMutableVideoFrame_v7_6 : public IDeckLinkVideoFrame_v7_6 { public: virtual HRESULT STDMETHODCALLTYPE SetFlags( BMDFrameFlags newFlags) = 0; virtual HRESULT STDMETHODCALLTYPE SetTimecode( BMDTimecodeFormat format, /* [in] */ IDeckLinkTimecode_v7_6 *timecode) = 0; virtual HRESULT STDMETHODCALLTYPE SetTimecodeFromComponents( BMDTimecodeFormat format, unsigned char hours, unsigned char minutes, unsigned char seconds, unsigned char frames, BMDTimecodeFlags flags) = 0; virtual HRESULT STDMETHODCALLTYPE SetAncillaryData( /* [in] */ IDeckLinkVideoFrameAncillary *ancillary) = 0; }; #else /* C style interface */ typedef struct IDeckLinkMutableVideoFrame_v7_6Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkMutableVideoFrame_v7_6 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkMutableVideoFrame_v7_6 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkMutableVideoFrame_v7_6 * This); long ( STDMETHODCALLTYPE *GetWidth )( IDeckLinkMutableVideoFrame_v7_6 * This); long ( STDMETHODCALLTYPE *GetHeight )( IDeckLinkMutableVideoFrame_v7_6 * This); long ( STDMETHODCALLTYPE *GetRowBytes )( IDeckLinkMutableVideoFrame_v7_6 * This); BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( IDeckLinkMutableVideoFrame_v7_6 * This); BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( IDeckLinkMutableVideoFrame_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *GetBytes )( IDeckLinkMutableVideoFrame_v7_6 * This, /* [out] */ void **buffer); HRESULT ( STDMETHODCALLTYPE *GetTimecode )( IDeckLinkMutableVideoFrame_v7_6 * This, BMDTimecodeFormat format, /* [out] */ IDeckLinkTimecode_v7_6 **timecode); HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( IDeckLinkMutableVideoFrame_v7_6 * This, /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); HRESULT ( STDMETHODCALLTYPE *SetFlags )( IDeckLinkMutableVideoFrame_v7_6 * This, BMDFrameFlags newFlags); HRESULT ( STDMETHODCALLTYPE *SetTimecode )( IDeckLinkMutableVideoFrame_v7_6 * This, BMDTimecodeFormat format, /* [in] */ IDeckLinkTimecode_v7_6 *timecode); HRESULT ( STDMETHODCALLTYPE *SetTimecodeFromComponents )( IDeckLinkMutableVideoFrame_v7_6 * This, BMDTimecodeFormat format, unsigned char hours, unsigned char minutes, unsigned char seconds, unsigned char frames, BMDTimecodeFlags flags); HRESULT ( STDMETHODCALLTYPE *SetAncillaryData )( IDeckLinkMutableVideoFrame_v7_6 * This, /* [in] */ IDeckLinkVideoFrameAncillary *ancillary); END_INTERFACE } IDeckLinkMutableVideoFrame_v7_6Vtbl; interface IDeckLinkMutableVideoFrame_v7_6 { CONST_VTBL struct IDeckLinkMutableVideoFrame_v7_6Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkMutableVideoFrame_v7_6_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkMutableVideoFrame_v7_6_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkMutableVideoFrame_v7_6_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkMutableVideoFrame_v7_6_GetWidth(This) \ ( (This)->lpVtbl -> GetWidth(This) ) #define IDeckLinkMutableVideoFrame_v7_6_GetHeight(This) \ ( (This)->lpVtbl -> GetHeight(This) ) #define IDeckLinkMutableVideoFrame_v7_6_GetRowBytes(This) \ ( (This)->lpVtbl -> GetRowBytes(This) ) #define IDeckLinkMutableVideoFrame_v7_6_GetPixelFormat(This) \ ( (This)->lpVtbl -> GetPixelFormat(This) ) #define IDeckLinkMutableVideoFrame_v7_6_GetFlags(This) \ ( (This)->lpVtbl -> GetFlags(This) ) #define IDeckLinkMutableVideoFrame_v7_6_GetBytes(This,buffer) \ ( (This)->lpVtbl -> GetBytes(This,buffer) ) #define IDeckLinkMutableVideoFrame_v7_6_GetTimecode(This,format,timecode) \ ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) #define IDeckLinkMutableVideoFrame_v7_6_GetAncillaryData(This,ancillary) \ ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) #define IDeckLinkMutableVideoFrame_v7_6_SetFlags(This,newFlags) \ ( (This)->lpVtbl -> SetFlags(This,newFlags) ) #define IDeckLinkMutableVideoFrame_v7_6_SetTimecode(This,format,timecode) \ ( (This)->lpVtbl -> SetTimecode(This,format,timecode) ) #define IDeckLinkMutableVideoFrame_v7_6_SetTimecodeFromComponents(This,format,hours,minutes,seconds,frames,flags) \ ( (This)->lpVtbl -> SetTimecodeFromComponents(This,format,hours,minutes,seconds,frames,flags) ) #define IDeckLinkMutableVideoFrame_v7_6_SetAncillaryData(This,ancillary) \ ( (This)->lpVtbl -> SetAncillaryData(This,ancillary) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkMutableVideoFrame_v7_6_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkVideoInputFrame_v7_6_INTERFACE_DEFINED__ #define __IDeckLinkVideoInputFrame_v7_6_INTERFACE_DEFINED__ /* interface IDeckLinkVideoInputFrame_v7_6 */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkVideoInputFrame_v7_6; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("9A74FA41-AE9F-47AC-8CF4-01F42DD59965") IDeckLinkVideoInputFrame_v7_6 : public IDeckLinkVideoFrame_v7_6 { public: virtual HRESULT STDMETHODCALLTYPE GetStreamTime( /* [out] */ BMDTimeValue *frameTime, /* [out] */ BMDTimeValue *frameDuration, BMDTimeScale timeScale) = 0; virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceTimestamp( BMDTimeScale timeScale, /* [out] */ BMDTimeValue *frameTime, /* [out] */ BMDTimeValue *frameDuration) = 0; }; #else /* C style interface */ typedef struct IDeckLinkVideoInputFrame_v7_6Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkVideoInputFrame_v7_6 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkVideoInputFrame_v7_6 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkVideoInputFrame_v7_6 * This); long ( STDMETHODCALLTYPE *GetWidth )( IDeckLinkVideoInputFrame_v7_6 * This); long ( STDMETHODCALLTYPE *GetHeight )( IDeckLinkVideoInputFrame_v7_6 * This); long ( STDMETHODCALLTYPE *GetRowBytes )( IDeckLinkVideoInputFrame_v7_6 * This); BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( IDeckLinkVideoInputFrame_v7_6 * This); BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( IDeckLinkVideoInputFrame_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *GetBytes )( IDeckLinkVideoInputFrame_v7_6 * This, /* [out] */ void **buffer); HRESULT ( STDMETHODCALLTYPE *GetTimecode )( IDeckLinkVideoInputFrame_v7_6 * This, BMDTimecodeFormat format, /* [out] */ IDeckLinkTimecode_v7_6 **timecode); HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( IDeckLinkVideoInputFrame_v7_6 * This, /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); HRESULT ( STDMETHODCALLTYPE *GetStreamTime )( IDeckLinkVideoInputFrame_v7_6 * This, /* [out] */ BMDTimeValue *frameTime, /* [out] */ BMDTimeValue *frameDuration, BMDTimeScale timeScale); HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceTimestamp )( IDeckLinkVideoInputFrame_v7_6 * This, BMDTimeScale timeScale, /* [out] */ BMDTimeValue *frameTime, /* [out] */ BMDTimeValue *frameDuration); END_INTERFACE } IDeckLinkVideoInputFrame_v7_6Vtbl; interface IDeckLinkVideoInputFrame_v7_6 { CONST_VTBL struct IDeckLinkVideoInputFrame_v7_6Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkVideoInputFrame_v7_6_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkVideoInputFrame_v7_6_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkVideoInputFrame_v7_6_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkVideoInputFrame_v7_6_GetWidth(This) \ ( (This)->lpVtbl -> GetWidth(This) ) #define IDeckLinkVideoInputFrame_v7_6_GetHeight(This) \ ( (This)->lpVtbl -> GetHeight(This) ) #define IDeckLinkVideoInputFrame_v7_6_GetRowBytes(This) \ ( (This)->lpVtbl -> GetRowBytes(This) ) #define IDeckLinkVideoInputFrame_v7_6_GetPixelFormat(This) \ ( (This)->lpVtbl -> GetPixelFormat(This) ) #define IDeckLinkVideoInputFrame_v7_6_GetFlags(This) \ ( (This)->lpVtbl -> GetFlags(This) ) #define IDeckLinkVideoInputFrame_v7_6_GetBytes(This,buffer) \ ( (This)->lpVtbl -> GetBytes(This,buffer) ) #define IDeckLinkVideoInputFrame_v7_6_GetTimecode(This,format,timecode) \ ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) #define IDeckLinkVideoInputFrame_v7_6_GetAncillaryData(This,ancillary) \ ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) #define IDeckLinkVideoInputFrame_v7_6_GetStreamTime(This,frameTime,frameDuration,timeScale) \ ( (This)->lpVtbl -> GetStreamTime(This,frameTime,frameDuration,timeScale) ) #define IDeckLinkVideoInputFrame_v7_6_GetHardwareReferenceTimestamp(This,timeScale,frameTime,frameDuration) \ ( (This)->lpVtbl -> GetHardwareReferenceTimestamp(This,timeScale,frameTime,frameDuration) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkVideoInputFrame_v7_6_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkScreenPreviewCallback_v7_6_INTERFACE_DEFINED__ #define __IDeckLinkScreenPreviewCallback_v7_6_INTERFACE_DEFINED__ /* interface IDeckLinkScreenPreviewCallback_v7_6 */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkScreenPreviewCallback_v7_6; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("373F499D-4B4D-4518-AD22-6354E5A5825E") IDeckLinkScreenPreviewCallback_v7_6 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE DrawFrame( /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame) = 0; }; #else /* C style interface */ typedef struct IDeckLinkScreenPreviewCallback_v7_6Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkScreenPreviewCallback_v7_6 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkScreenPreviewCallback_v7_6 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkScreenPreviewCallback_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *DrawFrame )( IDeckLinkScreenPreviewCallback_v7_6 * This, /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame); END_INTERFACE } IDeckLinkScreenPreviewCallback_v7_6Vtbl; interface IDeckLinkScreenPreviewCallback_v7_6 { CONST_VTBL struct IDeckLinkScreenPreviewCallback_v7_6Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkScreenPreviewCallback_v7_6_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkScreenPreviewCallback_v7_6_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkScreenPreviewCallback_v7_6_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkScreenPreviewCallback_v7_6_DrawFrame(This,theFrame) \ ( (This)->lpVtbl -> DrawFrame(This,theFrame) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkScreenPreviewCallback_v7_6_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkGLScreenPreviewHelper_v7_6_INTERFACE_DEFINED__ #define __IDeckLinkGLScreenPreviewHelper_v7_6_INTERFACE_DEFINED__ /* interface IDeckLinkGLScreenPreviewHelper_v7_6 */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkGLScreenPreviewHelper_v7_6; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("BA575CD9-A15E-497B-B2C2-F9AFE7BE4EBA") IDeckLinkGLScreenPreviewHelper_v7_6 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE InitializeGL( void) = 0; virtual HRESULT STDMETHODCALLTYPE PaintGL( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetFrame( /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame) = 0; }; #else /* C style interface */ typedef struct IDeckLinkGLScreenPreviewHelper_v7_6Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkGLScreenPreviewHelper_v7_6 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkGLScreenPreviewHelper_v7_6 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkGLScreenPreviewHelper_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *InitializeGL )( IDeckLinkGLScreenPreviewHelper_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *PaintGL )( IDeckLinkGLScreenPreviewHelper_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *SetFrame )( IDeckLinkGLScreenPreviewHelper_v7_6 * This, /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame); END_INTERFACE } IDeckLinkGLScreenPreviewHelper_v7_6Vtbl; interface IDeckLinkGLScreenPreviewHelper_v7_6 { CONST_VTBL struct IDeckLinkGLScreenPreviewHelper_v7_6Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkGLScreenPreviewHelper_v7_6_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkGLScreenPreviewHelper_v7_6_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkGLScreenPreviewHelper_v7_6_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkGLScreenPreviewHelper_v7_6_InitializeGL(This) \ ( (This)->lpVtbl -> InitializeGL(This) ) #define IDeckLinkGLScreenPreviewHelper_v7_6_PaintGL(This) \ ( (This)->lpVtbl -> PaintGL(This) ) #define IDeckLinkGLScreenPreviewHelper_v7_6_SetFrame(This,theFrame) \ ( (This)->lpVtbl -> SetFrame(This,theFrame) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkGLScreenPreviewHelper_v7_6_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkVideoConversion_v7_6_INTERFACE_DEFINED__ #define __IDeckLinkVideoConversion_v7_6_INTERFACE_DEFINED__ /* interface IDeckLinkVideoConversion_v7_6 */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkVideoConversion_v7_6; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("3EB504C9-F97D-40FE-A158-D407D48CB53B") IDeckLinkVideoConversion_v7_6 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE ConvertFrame( /* [in] */ IDeckLinkVideoFrame_v7_6 *srcFrame, /* [in] */ IDeckLinkVideoFrame_v7_6 *dstFrame) = 0; }; #else /* C style interface */ typedef struct IDeckLinkVideoConversion_v7_6Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkVideoConversion_v7_6 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkVideoConversion_v7_6 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkVideoConversion_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *ConvertFrame )( IDeckLinkVideoConversion_v7_6 * This, /* [in] */ IDeckLinkVideoFrame_v7_6 *srcFrame, /* [in] */ IDeckLinkVideoFrame_v7_6 *dstFrame); END_INTERFACE } IDeckLinkVideoConversion_v7_6Vtbl; interface IDeckLinkVideoConversion_v7_6 { CONST_VTBL struct IDeckLinkVideoConversion_v7_6Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkVideoConversion_v7_6_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkVideoConversion_v7_6_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkVideoConversion_v7_6_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkVideoConversion_v7_6_ConvertFrame(This,srcFrame,dstFrame) \ ( (This)->lpVtbl -> ConvertFrame(This,srcFrame,dstFrame) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkVideoConversion_v7_6_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkConfiguration_v7_6_INTERFACE_DEFINED__ #define __IDeckLinkConfiguration_v7_6_INTERFACE_DEFINED__ /* interface IDeckLinkConfiguration_v7_6 */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkConfiguration_v7_6; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("B8EAD569-B764-47F0-A73F-AE40DF6CBF10") IDeckLinkConfiguration_v7_6 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE GetConfigurationValidator( /* [out] */ IDeckLinkConfiguration_v7_6 **configObject) = 0; virtual HRESULT STDMETHODCALLTYPE WriteConfigurationToPreferences( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFormat( /* [in] */ BMDVideoConnection_v7_6 videoOutputConnection) = 0; virtual HRESULT STDMETHODCALLTYPE IsVideoOutputActive( /* [in] */ BMDVideoConnection_v7_6 videoOutputConnection, /* [out] */ BOOL *active) = 0; virtual HRESULT STDMETHODCALLTYPE SetAnalogVideoOutputFlags( /* [in] */ BMDAnalogVideoFlags analogVideoFlags) = 0; virtual HRESULT STDMETHODCALLTYPE GetAnalogVideoOutputFlags( /* [out] */ BMDAnalogVideoFlags *analogVideoFlags) = 0; virtual HRESULT STDMETHODCALLTYPE EnableFieldFlickerRemovalWhenPaused( /* [in] */ BOOL enable) = 0; virtual HRESULT STDMETHODCALLTYPE IsEnabledFieldFlickerRemovalWhenPaused( /* [out] */ BOOL *enabled) = 0; virtual HRESULT STDMETHODCALLTYPE Set444And3GBpsVideoOutput( /* [in] */ BOOL enable444VideoOutput, /* [in] */ BOOL enable3GbsOutput) = 0; virtual HRESULT STDMETHODCALLTYPE Get444And3GBpsVideoOutput( /* [out] */ BOOL *is444VideoOutputEnabled, /* [out] */ BOOL *threeGbsOutputEnabled) = 0; virtual HRESULT STDMETHODCALLTYPE SetVideoOutputConversionMode( /* [in] */ BMDVideoOutputConversionMode conversionMode) = 0; virtual HRESULT STDMETHODCALLTYPE GetVideoOutputConversionMode( /* [out] */ BMDVideoOutputConversionMode *conversionMode) = 0; virtual HRESULT STDMETHODCALLTYPE Set_HD1080p24_to_HD1080i5994_Conversion( /* [in] */ BOOL enable) = 0; virtual HRESULT STDMETHODCALLTYPE Get_HD1080p24_to_HD1080i5994_Conversion( /* [out] */ BOOL *enabled) = 0; virtual HRESULT STDMETHODCALLTYPE SetVideoInputFormat( /* [in] */ BMDVideoConnection_v7_6 videoInputFormat) = 0; virtual HRESULT STDMETHODCALLTYPE GetVideoInputFormat( /* [out] */ BMDVideoConnection_v7_6 *videoInputFormat) = 0; virtual HRESULT STDMETHODCALLTYPE SetAnalogVideoInputFlags( /* [in] */ BMDAnalogVideoFlags analogVideoFlags) = 0; virtual HRESULT STDMETHODCALLTYPE GetAnalogVideoInputFlags( /* [out] */ BMDAnalogVideoFlags *analogVideoFlags) = 0; virtual HRESULT STDMETHODCALLTYPE SetVideoInputConversionMode( /* [in] */ BMDVideoInputConversionMode conversionMode) = 0; virtual HRESULT STDMETHODCALLTYPE GetVideoInputConversionMode( /* [out] */ BMDVideoInputConversionMode *conversionMode) = 0; virtual HRESULT STDMETHODCALLTYPE SetBlackVideoOutputDuringCapture( /* [in] */ BOOL blackOutInCapture) = 0; virtual HRESULT STDMETHODCALLTYPE GetBlackVideoOutputDuringCapture( /* [out] */ BOOL *blackOutInCapture) = 0; virtual HRESULT STDMETHODCALLTYPE Set32PulldownSequenceInitialTimecodeFrame( /* [in] */ unsigned long aFrameTimecode) = 0; virtual HRESULT STDMETHODCALLTYPE Get32PulldownSequenceInitialTimecodeFrame( /* [out] */ unsigned long *aFrameTimecode) = 0; virtual HRESULT STDMETHODCALLTYPE SetVancSourceLineMapping( /* [in] */ unsigned long activeLine1VANCsource, /* [in] */ unsigned long activeLine2VANCsource, /* [in] */ unsigned long activeLine3VANCsource) = 0; virtual HRESULT STDMETHODCALLTYPE GetVancSourceLineMapping( /* [out] */ unsigned long *activeLine1VANCsource, /* [out] */ unsigned long *activeLine2VANCsource, /* [out] */ unsigned long *activeLine3VANCsource) = 0; virtual HRESULT STDMETHODCALLTYPE SetAudioInputFormat( /* [in] */ BMDAudioConnection audioInputFormat) = 0; virtual HRESULT STDMETHODCALLTYPE GetAudioInputFormat( /* [out] */ BMDAudioConnection *audioInputFormat) = 0; }; #else /* C style interface */ typedef struct IDeckLinkConfiguration_v7_6Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkConfiguration_v7_6 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkConfiguration_v7_6 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkConfiguration_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *GetConfigurationValidator )( IDeckLinkConfiguration_v7_6 * This, /* [out] */ IDeckLinkConfiguration_v7_6 **configObject); HRESULT ( STDMETHODCALLTYPE *WriteConfigurationToPreferences )( IDeckLinkConfiguration_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFormat )( IDeckLinkConfiguration_v7_6 * This, /* [in] */ BMDVideoConnection_v7_6 videoOutputConnection); HRESULT ( STDMETHODCALLTYPE *IsVideoOutputActive )( IDeckLinkConfiguration_v7_6 * This, /* [in] */ BMDVideoConnection_v7_6 videoOutputConnection, /* [out] */ BOOL *active); HRESULT ( STDMETHODCALLTYPE *SetAnalogVideoOutputFlags )( IDeckLinkConfiguration_v7_6 * This, /* [in] */ BMDAnalogVideoFlags analogVideoFlags); HRESULT ( STDMETHODCALLTYPE *GetAnalogVideoOutputFlags )( IDeckLinkConfiguration_v7_6 * This, /* [out] */ BMDAnalogVideoFlags *analogVideoFlags); HRESULT ( STDMETHODCALLTYPE *EnableFieldFlickerRemovalWhenPaused )( IDeckLinkConfiguration_v7_6 * This, /* [in] */ BOOL enable); HRESULT ( STDMETHODCALLTYPE *IsEnabledFieldFlickerRemovalWhenPaused )( IDeckLinkConfiguration_v7_6 * This, /* [out] */ BOOL *enabled); HRESULT ( STDMETHODCALLTYPE *Set444And3GBpsVideoOutput )( IDeckLinkConfiguration_v7_6 * This, /* [in] */ BOOL enable444VideoOutput, /* [in] */ BOOL enable3GbsOutput); HRESULT ( STDMETHODCALLTYPE *Get444And3GBpsVideoOutput )( IDeckLinkConfiguration_v7_6 * This, /* [out] */ BOOL *is444VideoOutputEnabled, /* [out] */ BOOL *threeGbsOutputEnabled); HRESULT ( STDMETHODCALLTYPE *SetVideoOutputConversionMode )( IDeckLinkConfiguration_v7_6 * This, /* [in] */ BMDVideoOutputConversionMode conversionMode); HRESULT ( STDMETHODCALLTYPE *GetVideoOutputConversionMode )( IDeckLinkConfiguration_v7_6 * This, /* [out] */ BMDVideoOutputConversionMode *conversionMode); HRESULT ( STDMETHODCALLTYPE *Set_HD1080p24_to_HD1080i5994_Conversion )( IDeckLinkConfiguration_v7_6 * This, /* [in] */ BOOL enable); HRESULT ( STDMETHODCALLTYPE *Get_HD1080p24_to_HD1080i5994_Conversion )( IDeckLinkConfiguration_v7_6 * This, /* [out] */ BOOL *enabled); HRESULT ( STDMETHODCALLTYPE *SetVideoInputFormat )( IDeckLinkConfiguration_v7_6 * This, /* [in] */ BMDVideoConnection_v7_6 videoInputFormat); HRESULT ( STDMETHODCALLTYPE *GetVideoInputFormat )( IDeckLinkConfiguration_v7_6 * This, /* [out] */ BMDVideoConnection_v7_6 *videoInputFormat); HRESULT ( STDMETHODCALLTYPE *SetAnalogVideoInputFlags )( IDeckLinkConfiguration_v7_6 * This, /* [in] */ BMDAnalogVideoFlags analogVideoFlags); HRESULT ( STDMETHODCALLTYPE *GetAnalogVideoInputFlags )( IDeckLinkConfiguration_v7_6 * This, /* [out] */ BMDAnalogVideoFlags *analogVideoFlags); HRESULT ( STDMETHODCALLTYPE *SetVideoInputConversionMode )( IDeckLinkConfiguration_v7_6 * This, /* [in] */ BMDVideoInputConversionMode conversionMode); HRESULT ( STDMETHODCALLTYPE *GetVideoInputConversionMode )( IDeckLinkConfiguration_v7_6 * This, /* [out] */ BMDVideoInputConversionMode *conversionMode); HRESULT ( STDMETHODCALLTYPE *SetBlackVideoOutputDuringCapture )( IDeckLinkConfiguration_v7_6 * This, /* [in] */ BOOL blackOutInCapture); HRESULT ( STDMETHODCALLTYPE *GetBlackVideoOutputDuringCapture )( IDeckLinkConfiguration_v7_6 * This, /* [out] */ BOOL *blackOutInCapture); HRESULT ( STDMETHODCALLTYPE *Set32PulldownSequenceInitialTimecodeFrame )( IDeckLinkConfiguration_v7_6 * This, /* [in] */ unsigned long aFrameTimecode); HRESULT ( STDMETHODCALLTYPE *Get32PulldownSequenceInitialTimecodeFrame )( IDeckLinkConfiguration_v7_6 * This, /* [out] */ unsigned long *aFrameTimecode); HRESULT ( STDMETHODCALLTYPE *SetVancSourceLineMapping )( IDeckLinkConfiguration_v7_6 * This, /* [in] */ unsigned long activeLine1VANCsource, /* [in] */ unsigned long activeLine2VANCsource, /* [in] */ unsigned long activeLine3VANCsource); HRESULT ( STDMETHODCALLTYPE *GetVancSourceLineMapping )( IDeckLinkConfiguration_v7_6 * This, /* [out] */ unsigned long *activeLine1VANCsource, /* [out] */ unsigned long *activeLine2VANCsource, /* [out] */ unsigned long *activeLine3VANCsource); HRESULT ( STDMETHODCALLTYPE *SetAudioInputFormat )( IDeckLinkConfiguration_v7_6 * This, /* [in] */ BMDAudioConnection audioInputFormat); HRESULT ( STDMETHODCALLTYPE *GetAudioInputFormat )( IDeckLinkConfiguration_v7_6 * This, /* [out] */ BMDAudioConnection *audioInputFormat); END_INTERFACE } IDeckLinkConfiguration_v7_6Vtbl; interface IDeckLinkConfiguration_v7_6 { CONST_VTBL struct IDeckLinkConfiguration_v7_6Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkConfiguration_v7_6_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkConfiguration_v7_6_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkConfiguration_v7_6_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkConfiguration_v7_6_GetConfigurationValidator(This,configObject) \ ( (This)->lpVtbl -> GetConfigurationValidator(This,configObject) ) #define IDeckLinkConfiguration_v7_6_WriteConfigurationToPreferences(This) \ ( (This)->lpVtbl -> WriteConfigurationToPreferences(This) ) #define IDeckLinkConfiguration_v7_6_SetVideoOutputFormat(This,videoOutputConnection) \ ( (This)->lpVtbl -> SetVideoOutputFormat(This,videoOutputConnection) ) #define IDeckLinkConfiguration_v7_6_IsVideoOutputActive(This,videoOutputConnection,active) \ ( (This)->lpVtbl -> IsVideoOutputActive(This,videoOutputConnection,active) ) #define IDeckLinkConfiguration_v7_6_SetAnalogVideoOutputFlags(This,analogVideoFlags) \ ( (This)->lpVtbl -> SetAnalogVideoOutputFlags(This,analogVideoFlags) ) #define IDeckLinkConfiguration_v7_6_GetAnalogVideoOutputFlags(This,analogVideoFlags) \ ( (This)->lpVtbl -> GetAnalogVideoOutputFlags(This,analogVideoFlags) ) #define IDeckLinkConfiguration_v7_6_EnableFieldFlickerRemovalWhenPaused(This,enable) \ ( (This)->lpVtbl -> EnableFieldFlickerRemovalWhenPaused(This,enable) ) #define IDeckLinkConfiguration_v7_6_IsEnabledFieldFlickerRemovalWhenPaused(This,enabled) \ ( (This)->lpVtbl -> IsEnabledFieldFlickerRemovalWhenPaused(This,enabled) ) #define IDeckLinkConfiguration_v7_6_Set444And3GBpsVideoOutput(This,enable444VideoOutput,enable3GbsOutput) \ ( (This)->lpVtbl -> Set444And3GBpsVideoOutput(This,enable444VideoOutput,enable3GbsOutput) ) #define IDeckLinkConfiguration_v7_6_Get444And3GBpsVideoOutput(This,is444VideoOutputEnabled,threeGbsOutputEnabled) \ ( (This)->lpVtbl -> Get444And3GBpsVideoOutput(This,is444VideoOutputEnabled,threeGbsOutputEnabled) ) #define IDeckLinkConfiguration_v7_6_SetVideoOutputConversionMode(This,conversionMode) \ ( (This)->lpVtbl -> SetVideoOutputConversionMode(This,conversionMode) ) #define IDeckLinkConfiguration_v7_6_GetVideoOutputConversionMode(This,conversionMode) \ ( (This)->lpVtbl -> GetVideoOutputConversionMode(This,conversionMode) ) #define IDeckLinkConfiguration_v7_6_Set_HD1080p24_to_HD1080i5994_Conversion(This,enable) \ ( (This)->lpVtbl -> Set_HD1080p24_to_HD1080i5994_Conversion(This,enable) ) #define IDeckLinkConfiguration_v7_6_Get_HD1080p24_to_HD1080i5994_Conversion(This,enabled) \ ( (This)->lpVtbl -> Get_HD1080p24_to_HD1080i5994_Conversion(This,enabled) ) #define IDeckLinkConfiguration_v7_6_SetVideoInputFormat(This,videoInputFormat) \ ( (This)->lpVtbl -> SetVideoInputFormat(This,videoInputFormat) ) #define IDeckLinkConfiguration_v7_6_GetVideoInputFormat(This,videoInputFormat) \ ( (This)->lpVtbl -> GetVideoInputFormat(This,videoInputFormat) ) #define IDeckLinkConfiguration_v7_6_SetAnalogVideoInputFlags(This,analogVideoFlags) \ ( (This)->lpVtbl -> SetAnalogVideoInputFlags(This,analogVideoFlags) ) #define IDeckLinkConfiguration_v7_6_GetAnalogVideoInputFlags(This,analogVideoFlags) \ ( (This)->lpVtbl -> GetAnalogVideoInputFlags(This,analogVideoFlags) ) #define IDeckLinkConfiguration_v7_6_SetVideoInputConversionMode(This,conversionMode) \ ( (This)->lpVtbl -> SetVideoInputConversionMode(This,conversionMode) ) #define IDeckLinkConfiguration_v7_6_GetVideoInputConversionMode(This,conversionMode) \ ( (This)->lpVtbl -> GetVideoInputConversionMode(This,conversionMode) ) #define IDeckLinkConfiguration_v7_6_SetBlackVideoOutputDuringCapture(This,blackOutInCapture) \ ( (This)->lpVtbl -> SetBlackVideoOutputDuringCapture(This,blackOutInCapture) ) #define IDeckLinkConfiguration_v7_6_GetBlackVideoOutputDuringCapture(This,blackOutInCapture) \ ( (This)->lpVtbl -> GetBlackVideoOutputDuringCapture(This,blackOutInCapture) ) #define IDeckLinkConfiguration_v7_6_Set32PulldownSequenceInitialTimecodeFrame(This,aFrameTimecode) \ ( (This)->lpVtbl -> Set32PulldownSequenceInitialTimecodeFrame(This,aFrameTimecode) ) #define IDeckLinkConfiguration_v7_6_Get32PulldownSequenceInitialTimecodeFrame(This,aFrameTimecode) \ ( (This)->lpVtbl -> Get32PulldownSequenceInitialTimecodeFrame(This,aFrameTimecode) ) #define IDeckLinkConfiguration_v7_6_SetVancSourceLineMapping(This,activeLine1VANCsource,activeLine2VANCsource,activeLine3VANCsource) \ ( (This)->lpVtbl -> SetVancSourceLineMapping(This,activeLine1VANCsource,activeLine2VANCsource,activeLine3VANCsource) ) #define IDeckLinkConfiguration_v7_6_GetVancSourceLineMapping(This,activeLine1VANCsource,activeLine2VANCsource,activeLine3VANCsource) \ ( (This)->lpVtbl -> GetVancSourceLineMapping(This,activeLine1VANCsource,activeLine2VANCsource,activeLine3VANCsource) ) #define IDeckLinkConfiguration_v7_6_SetAudioInputFormat(This,audioInputFormat) \ ( (This)->lpVtbl -> SetAudioInputFormat(This,audioInputFormat) ) #define IDeckLinkConfiguration_v7_6_GetAudioInputFormat(This,audioInputFormat) \ ( (This)->lpVtbl -> GetAudioInputFormat(This,audioInputFormat) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkConfiguration_v7_6_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkVideoOutputCallback_v7_6_INTERFACE_DEFINED__ #define __IDeckLinkVideoOutputCallback_v7_6_INTERFACE_DEFINED__ /* interface IDeckLinkVideoOutputCallback_v7_6 */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkVideoOutputCallback_v7_6; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("E763A626-4A3C-49D1-BF13-E7AD3692AE52") IDeckLinkVideoOutputCallback_v7_6 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted( /* [in] */ IDeckLinkVideoFrame_v7_6 *completedFrame, /* [in] */ BMDOutputFrameCompletionResult result) = 0; virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped( void) = 0; }; #else /* C style interface */ typedef struct IDeckLinkVideoOutputCallback_v7_6Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkVideoOutputCallback_v7_6 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkVideoOutputCallback_v7_6 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkVideoOutputCallback_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *ScheduledFrameCompleted )( IDeckLinkVideoOutputCallback_v7_6 * This, /* [in] */ IDeckLinkVideoFrame_v7_6 *completedFrame, /* [in] */ BMDOutputFrameCompletionResult result); HRESULT ( STDMETHODCALLTYPE *ScheduledPlaybackHasStopped )( IDeckLinkVideoOutputCallback_v7_6 * This); END_INTERFACE } IDeckLinkVideoOutputCallback_v7_6Vtbl; interface IDeckLinkVideoOutputCallback_v7_6 { CONST_VTBL struct IDeckLinkVideoOutputCallback_v7_6Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkVideoOutputCallback_v7_6_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkVideoOutputCallback_v7_6_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkVideoOutputCallback_v7_6_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkVideoOutputCallback_v7_6_ScheduledFrameCompleted(This,completedFrame,result) \ ( (This)->lpVtbl -> ScheduledFrameCompleted(This,completedFrame,result) ) #define IDeckLinkVideoOutputCallback_v7_6_ScheduledPlaybackHasStopped(This) \ ( (This)->lpVtbl -> ScheduledPlaybackHasStopped(This) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkVideoOutputCallback_v7_6_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkInputCallback_v7_6_INTERFACE_DEFINED__ #define __IDeckLinkInputCallback_v7_6_INTERFACE_DEFINED__ /* interface IDeckLinkInputCallback_v7_6 */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkInputCallback_v7_6; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("31D28EE7-88B6-4CB1-897A-CDBF79A26414") IDeckLinkInputCallback_v7_6 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged( /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, /* [in] */ IDeckLinkDisplayMode_v7_6 *newDisplayMode, /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( /* [in] */ IDeckLinkVideoInputFrame_v7_6 *videoFrame, /* [in] */ IDeckLinkAudioInputPacket *audioPacket) = 0; }; #else /* C style interface */ typedef struct IDeckLinkInputCallback_v7_6Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkInputCallback_v7_6 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkInputCallback_v7_6 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkInputCallback_v7_6 * This); HRESULT ( STDMETHODCALLTYPE *VideoInputFormatChanged )( IDeckLinkInputCallback_v7_6 * This, /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, /* [in] */ IDeckLinkDisplayMode_v7_6 *newDisplayMode, /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags); HRESULT ( STDMETHODCALLTYPE *VideoInputFrameArrived )( IDeckLinkInputCallback_v7_6 * This, /* [in] */ IDeckLinkVideoInputFrame_v7_6 *videoFrame, /* [in] */ IDeckLinkAudioInputPacket *audioPacket); END_INTERFACE } IDeckLinkInputCallback_v7_6Vtbl; interface IDeckLinkInputCallback_v7_6 { CONST_VTBL struct IDeckLinkInputCallback_v7_6Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkInputCallback_v7_6_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkInputCallback_v7_6_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkInputCallback_v7_6_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkInputCallback_v7_6_VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) \ ( (This)->lpVtbl -> VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) ) #define IDeckLinkInputCallback_v7_6_VideoInputFrameArrived(This,videoFrame,audioPacket) \ ( (This)->lpVtbl -> VideoInputFrameArrived(This,videoFrame,audioPacket) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkInputCallback_v7_6_INTERFACE_DEFINED__ */ EXTERN_C const CLSID CLSID_CDeckLinkGLScreenPreviewHelper_v7_6; #ifdef __cplusplus class DECLSPEC_UUID("D398CEE7-4434-4CA3-9BA6-5AE34556B905") CDeckLinkGLScreenPreviewHelper_v7_6; #endif EXTERN_C const CLSID CLSID_CDeckLinkVideoConversion_v7_6; #ifdef __cplusplus class DECLSPEC_UUID("FFA84F77-73BE-4FB7-B03E-B5E44B9F759B") CDeckLinkVideoConversion_v7_6; #endif #ifndef __IDeckLinkInputCallback_v7_3_INTERFACE_DEFINED__ #define __IDeckLinkInputCallback_v7_3_INTERFACE_DEFINED__ /* interface IDeckLinkInputCallback_v7_3 */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkInputCallback_v7_3; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("FD6F311D-4D00-444B-9ED4-1F25B5730AD0") IDeckLinkInputCallback_v7_3 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged( /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, /* [in] */ IDeckLinkDisplayMode_v7_6 *newDisplayMode, /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( /* [in] */ IDeckLinkVideoInputFrame_v7_3 *videoFrame, /* [in] */ IDeckLinkAudioInputPacket *audioPacket) = 0; }; #else /* C style interface */ typedef struct IDeckLinkInputCallback_v7_3Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkInputCallback_v7_3 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkInputCallback_v7_3 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkInputCallback_v7_3 * This); HRESULT ( STDMETHODCALLTYPE *VideoInputFormatChanged )( IDeckLinkInputCallback_v7_3 * This, /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, /* [in] */ IDeckLinkDisplayMode_v7_6 *newDisplayMode, /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags); HRESULT ( STDMETHODCALLTYPE *VideoInputFrameArrived )( IDeckLinkInputCallback_v7_3 * This, /* [in] */ IDeckLinkVideoInputFrame_v7_3 *videoFrame, /* [in] */ IDeckLinkAudioInputPacket *audioPacket); END_INTERFACE } IDeckLinkInputCallback_v7_3Vtbl; interface IDeckLinkInputCallback_v7_3 { CONST_VTBL struct IDeckLinkInputCallback_v7_3Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkInputCallback_v7_3_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkInputCallback_v7_3_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkInputCallback_v7_3_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkInputCallback_v7_3_VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) \ ( (This)->lpVtbl -> VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) ) #define IDeckLinkInputCallback_v7_3_VideoInputFrameArrived(This,videoFrame,audioPacket) \ ( (This)->lpVtbl -> VideoInputFrameArrived(This,videoFrame,audioPacket) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkInputCallback_v7_3_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkOutput_v7_3_INTERFACE_DEFINED__ #define __IDeckLinkOutput_v7_3_INTERFACE_DEFINED__ /* interface IDeckLinkOutput_v7_3 */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkOutput_v7_3; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("271C65E3-C323-4344-A30F-D908BCB20AA3") IDeckLinkOutput_v7_3 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* [out] */ BMDDisplayModeSupport *result) = 0; virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput( BMDDisplayMode displayMode, BMDVideoOutputFlags flags) = 0; virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator( /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0; virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame( long width, long height, long rowBytes, BMDPixelFormat pixelFormat, BMDFrameFlags flags, /* [out] */ IDeckLinkMutableVideoFrame_v7_6 **outFrame) = 0; virtual HRESULT STDMETHODCALLTYPE CreateAncillaryData( BMDPixelFormat pixelFormat, /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync( /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame) = 0; virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame( /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame, BMDTimeValue displayTime, BMDTimeValue displayDuration, BMDTimeScale timeScale) = 0; virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback( /* [in] */ IDeckLinkVideoOutputCallback *theCallback) = 0; virtual HRESULT STDMETHODCALLTYPE GetBufferedVideoFrameCount( /* [out] */ unsigned long *bufferedFrameCount) = 0; virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput( BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType, unsigned long channelCount, BMDAudioOutputStreamType streamType) = 0; virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0; virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync( /* [in] */ void *buffer, unsigned long sampleFrameCount, /* [out] */ unsigned long *sampleFramesWritten) = 0; virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0; virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0; virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples( /* [in] */ void *buffer, unsigned long sampleFrameCount, BMDTimeValue streamTime, BMDTimeScale timeScale, /* [out] */ unsigned long *sampleFramesWritten) = 0; virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( /* [out] */ unsigned long *bufferedSampleFrameCount) = 0; virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetAudioCallback( /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0; virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback( BMDTimeValue playbackStartTime, BMDTimeScale timeScale, double playbackSpeed) = 0; virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback( BMDTimeValue stopPlaybackAtTime, /* [out] */ BMDTimeValue *actualStopTime, BMDTimeScale timeScale) = 0; virtual HRESULT STDMETHODCALLTYPE IsScheduledPlaybackRunning( /* [out] */ BOOL *active) = 0; virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( BMDTimeScale desiredTimeScale, /* [out] */ BMDTimeValue *elapsedTimeSinceSchedulerBegan) = 0; }; #else /* C style interface */ typedef struct IDeckLinkOutput_v7_3Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkOutput_v7_3 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkOutput_v7_3 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkOutput_v7_3 * This); HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( IDeckLinkOutput_v7_3 * This, BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* [out] */ BMDDisplayModeSupport *result); HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( IDeckLinkOutput_v7_3 * This, /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator); HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( IDeckLinkOutput_v7_3 * This, /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback); HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )( IDeckLinkOutput_v7_3 * This, BMDDisplayMode displayMode, BMDVideoOutputFlags flags); HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )( IDeckLinkOutput_v7_3 * This); HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )( IDeckLinkOutput_v7_3 * This, /* [in] */ IDeckLinkMemoryAllocator *theAllocator); HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )( IDeckLinkOutput_v7_3 * This, long width, long height, long rowBytes, BMDPixelFormat pixelFormat, BMDFrameFlags flags, /* [out] */ IDeckLinkMutableVideoFrame_v7_6 **outFrame); HRESULT ( STDMETHODCALLTYPE *CreateAncillaryData )( IDeckLinkOutput_v7_3 * This, BMDPixelFormat pixelFormat, /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer); HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )( IDeckLinkOutput_v7_3 * This, /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame); HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )( IDeckLinkOutput_v7_3 * This, /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame, BMDTimeValue displayTime, BMDTimeValue displayDuration, BMDTimeScale timeScale); HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )( IDeckLinkOutput_v7_3 * This, /* [in] */ IDeckLinkVideoOutputCallback *theCallback); HRESULT ( STDMETHODCALLTYPE *GetBufferedVideoFrameCount )( IDeckLinkOutput_v7_3 * This, /* [out] */ unsigned long *bufferedFrameCount); HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )( IDeckLinkOutput_v7_3 * This, BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType, unsigned long channelCount, BMDAudioOutputStreamType streamType); HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )( IDeckLinkOutput_v7_3 * This); HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )( IDeckLinkOutput_v7_3 * This, /* [in] */ void *buffer, unsigned long sampleFrameCount, /* [out] */ unsigned long *sampleFramesWritten); HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )( IDeckLinkOutput_v7_3 * This); HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )( IDeckLinkOutput_v7_3 * This); HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )( IDeckLinkOutput_v7_3 * This, /* [in] */ void *buffer, unsigned long sampleFrameCount, BMDTimeValue streamTime, BMDTimeScale timeScale, /* [out] */ unsigned long *sampleFramesWritten); HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( IDeckLinkOutput_v7_3 * This, /* [out] */ unsigned long *bufferedSampleFrameCount); HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )( IDeckLinkOutput_v7_3 * This); HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )( IDeckLinkOutput_v7_3 * This, /* [in] */ IDeckLinkAudioOutputCallback *theCallback); HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )( IDeckLinkOutput_v7_3 * This, BMDTimeValue playbackStartTime, BMDTimeScale timeScale, double playbackSpeed); HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )( IDeckLinkOutput_v7_3 * This, BMDTimeValue stopPlaybackAtTime, /* [out] */ BMDTimeValue *actualStopTime, BMDTimeScale timeScale); HRESULT ( STDMETHODCALLTYPE *IsScheduledPlaybackRunning )( IDeckLinkOutput_v7_3 * This, /* [out] */ BOOL *active); HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( IDeckLinkOutput_v7_3 * This, BMDTimeScale desiredTimeScale, /* [out] */ BMDTimeValue *elapsedTimeSinceSchedulerBegan); END_INTERFACE } IDeckLinkOutput_v7_3Vtbl; interface IDeckLinkOutput_v7_3 { CONST_VTBL struct IDeckLinkOutput_v7_3Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkOutput_v7_3_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkOutput_v7_3_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkOutput_v7_3_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkOutput_v7_3_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) #define IDeckLinkOutput_v7_3_GetDisplayModeIterator(This,iterator) \ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) #define IDeckLinkOutput_v7_3_SetScreenPreviewCallback(This,previewCallback) \ ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) #define IDeckLinkOutput_v7_3_EnableVideoOutput(This,displayMode,flags) \ ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode,flags) ) #define IDeckLinkOutput_v7_3_DisableVideoOutput(This) \ ( (This)->lpVtbl -> DisableVideoOutput(This) ) #define IDeckLinkOutput_v7_3_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \ ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) ) #define IDeckLinkOutput_v7_3_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \ ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) ) #define IDeckLinkOutput_v7_3_CreateAncillaryData(This,pixelFormat,outBuffer) \ ( (This)->lpVtbl -> CreateAncillaryData(This,pixelFormat,outBuffer) ) #define IDeckLinkOutput_v7_3_DisplayVideoFrameSync(This,theFrame) \ ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) ) #define IDeckLinkOutput_v7_3_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \ ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) ) #define IDeckLinkOutput_v7_3_SetScheduledFrameCompletionCallback(This,theCallback) \ ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) ) #define IDeckLinkOutput_v7_3_GetBufferedVideoFrameCount(This,bufferedFrameCount) \ ( (This)->lpVtbl -> GetBufferedVideoFrameCount(This,bufferedFrameCount) ) #define IDeckLinkOutput_v7_3_EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) \ ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) ) #define IDeckLinkOutput_v7_3_DisableAudioOutput(This) \ ( (This)->lpVtbl -> DisableAudioOutput(This) ) #define IDeckLinkOutput_v7_3_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \ ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) ) #define IDeckLinkOutput_v7_3_BeginAudioPreroll(This) \ ( (This)->lpVtbl -> BeginAudioPreroll(This) ) #define IDeckLinkOutput_v7_3_EndAudioPreroll(This) \ ( (This)->lpVtbl -> EndAudioPreroll(This) ) #define IDeckLinkOutput_v7_3_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \ ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) ) #define IDeckLinkOutput_v7_3_GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) \ ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) ) #define IDeckLinkOutput_v7_3_FlushBufferedAudioSamples(This) \ ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) ) #define IDeckLinkOutput_v7_3_SetAudioCallback(This,theCallback) \ ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) ) #define IDeckLinkOutput_v7_3_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \ ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) ) #define IDeckLinkOutput_v7_3_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \ ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) ) #define IDeckLinkOutput_v7_3_IsScheduledPlaybackRunning(This,active) \ ( (This)->lpVtbl -> IsScheduledPlaybackRunning(This,active) ) #define IDeckLinkOutput_v7_3_GetHardwareReferenceClock(This,desiredTimeScale,elapsedTimeSinceSchedulerBegan) \ ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,elapsedTimeSinceSchedulerBegan) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkOutput_v7_3_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkInput_v7_3_INTERFACE_DEFINED__ #define __IDeckLinkInput_v7_3_INTERFACE_DEFINED__ /* interface IDeckLinkInput_v7_3 */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkInput_v7_3; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("4973F012-9925-458C-871C-18774CDBBECB") IDeckLinkInput_v7_3 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* [out] */ BMDDisplayModeSupport *result) = 0; virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; virtual HRESULT STDMETHODCALLTYPE EnableVideoInput( BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDVideoInputFlags flags) = 0; virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoFrameCount( /* [out] */ unsigned long *availableFrameCount) = 0; virtual HRESULT STDMETHODCALLTYPE EnableAudioInput( BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType, unsigned long channelCount) = 0; virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetAvailableAudioSampleFrameCount( /* [out] */ unsigned long *availableSampleFrameCount) = 0; virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0; virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0; virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0; virtual HRESULT STDMETHODCALLTYPE FlushStreams( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetCallback( /* [in] */ IDeckLinkInputCallback_v7_3 *theCallback) = 0; }; #else /* C style interface */ typedef struct IDeckLinkInput_v7_3Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkInput_v7_3 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkInput_v7_3 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkInput_v7_3 * This); HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( IDeckLinkInput_v7_3 * This, BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* [out] */ BMDDisplayModeSupport *result); HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( IDeckLinkInput_v7_3 * This, /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator); HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( IDeckLinkInput_v7_3 * This, /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback); HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )( IDeckLinkInput_v7_3 * This, BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDVideoInputFlags flags); HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )( IDeckLinkInput_v7_3 * This); HRESULT ( STDMETHODCALLTYPE *GetAvailableVideoFrameCount )( IDeckLinkInput_v7_3 * This, /* [out] */ unsigned long *availableFrameCount); HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )( IDeckLinkInput_v7_3 * This, BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType, unsigned long channelCount); HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )( IDeckLinkInput_v7_3 * This); HRESULT ( STDMETHODCALLTYPE *GetAvailableAudioSampleFrameCount )( IDeckLinkInput_v7_3 * This, /* [out] */ unsigned long *availableSampleFrameCount); HRESULT ( STDMETHODCALLTYPE *StartStreams )( IDeckLinkInput_v7_3 * This); HRESULT ( STDMETHODCALLTYPE *StopStreams )( IDeckLinkInput_v7_3 * This); HRESULT ( STDMETHODCALLTYPE *PauseStreams )( IDeckLinkInput_v7_3 * This); HRESULT ( STDMETHODCALLTYPE *FlushStreams )( IDeckLinkInput_v7_3 * This); HRESULT ( STDMETHODCALLTYPE *SetCallback )( IDeckLinkInput_v7_3 * This, /* [in] */ IDeckLinkInputCallback_v7_3 *theCallback); END_INTERFACE } IDeckLinkInput_v7_3Vtbl; interface IDeckLinkInput_v7_3 { CONST_VTBL struct IDeckLinkInput_v7_3Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkInput_v7_3_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkInput_v7_3_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkInput_v7_3_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkInput_v7_3_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) #define IDeckLinkInput_v7_3_GetDisplayModeIterator(This,iterator) \ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) #define IDeckLinkInput_v7_3_SetScreenPreviewCallback(This,previewCallback) \ ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) #define IDeckLinkInput_v7_3_EnableVideoInput(This,displayMode,pixelFormat,flags) \ ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) ) #define IDeckLinkInput_v7_3_DisableVideoInput(This) \ ( (This)->lpVtbl -> DisableVideoInput(This) ) #define IDeckLinkInput_v7_3_GetAvailableVideoFrameCount(This,availableFrameCount) \ ( (This)->lpVtbl -> GetAvailableVideoFrameCount(This,availableFrameCount) ) #define IDeckLinkInput_v7_3_EnableAudioInput(This,sampleRate,sampleType,channelCount) \ ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) ) #define IDeckLinkInput_v7_3_DisableAudioInput(This) \ ( (This)->lpVtbl -> DisableAudioInput(This) ) #define IDeckLinkInput_v7_3_GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) \ ( (This)->lpVtbl -> GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) ) #define IDeckLinkInput_v7_3_StartStreams(This) \ ( (This)->lpVtbl -> StartStreams(This) ) #define IDeckLinkInput_v7_3_StopStreams(This) \ ( (This)->lpVtbl -> StopStreams(This) ) #define IDeckLinkInput_v7_3_PauseStreams(This) \ ( (This)->lpVtbl -> PauseStreams(This) ) #define IDeckLinkInput_v7_3_FlushStreams(This) \ ( (This)->lpVtbl -> FlushStreams(This) ) #define IDeckLinkInput_v7_3_SetCallback(This,theCallback) \ ( (This)->lpVtbl -> SetCallback(This,theCallback) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkInput_v7_3_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkVideoInputFrame_v7_3_INTERFACE_DEFINED__ #define __IDeckLinkVideoInputFrame_v7_3_INTERFACE_DEFINED__ /* interface IDeckLinkVideoInputFrame_v7_3 */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkVideoInputFrame_v7_3; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("CF317790-2894-11DE-8C30-0800200C9A66") IDeckLinkVideoInputFrame_v7_3 : public IDeckLinkVideoFrame_v7_6 { public: virtual HRESULT STDMETHODCALLTYPE GetStreamTime( /* [out] */ BMDTimeValue *frameTime, /* [out] */ BMDTimeValue *frameDuration, BMDTimeScale timeScale) = 0; }; #else /* C style interface */ typedef struct IDeckLinkVideoInputFrame_v7_3Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkVideoInputFrame_v7_3 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkVideoInputFrame_v7_3 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkVideoInputFrame_v7_3 * This); long ( STDMETHODCALLTYPE *GetWidth )( IDeckLinkVideoInputFrame_v7_3 * This); long ( STDMETHODCALLTYPE *GetHeight )( IDeckLinkVideoInputFrame_v7_3 * This); long ( STDMETHODCALLTYPE *GetRowBytes )( IDeckLinkVideoInputFrame_v7_3 * This); BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( IDeckLinkVideoInputFrame_v7_3 * This); BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( IDeckLinkVideoInputFrame_v7_3 * This); HRESULT ( STDMETHODCALLTYPE *GetBytes )( IDeckLinkVideoInputFrame_v7_3 * This, /* [out] */ void **buffer); HRESULT ( STDMETHODCALLTYPE *GetTimecode )( IDeckLinkVideoInputFrame_v7_3 * This, BMDTimecodeFormat format, /* [out] */ IDeckLinkTimecode_v7_6 **timecode); HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( IDeckLinkVideoInputFrame_v7_3 * This, /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); HRESULT ( STDMETHODCALLTYPE *GetStreamTime )( IDeckLinkVideoInputFrame_v7_3 * This, /* [out] */ BMDTimeValue *frameTime, /* [out] */ BMDTimeValue *frameDuration, BMDTimeScale timeScale); END_INTERFACE } IDeckLinkVideoInputFrame_v7_3Vtbl; interface IDeckLinkVideoInputFrame_v7_3 { CONST_VTBL struct IDeckLinkVideoInputFrame_v7_3Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkVideoInputFrame_v7_3_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkVideoInputFrame_v7_3_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkVideoInputFrame_v7_3_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkVideoInputFrame_v7_3_GetWidth(This) \ ( (This)->lpVtbl -> GetWidth(This) ) #define IDeckLinkVideoInputFrame_v7_3_GetHeight(This) \ ( (This)->lpVtbl -> GetHeight(This) ) #define IDeckLinkVideoInputFrame_v7_3_GetRowBytes(This) \ ( (This)->lpVtbl -> GetRowBytes(This) ) #define IDeckLinkVideoInputFrame_v7_3_GetPixelFormat(This) \ ( (This)->lpVtbl -> GetPixelFormat(This) ) #define IDeckLinkVideoInputFrame_v7_3_GetFlags(This) \ ( (This)->lpVtbl -> GetFlags(This) ) #define IDeckLinkVideoInputFrame_v7_3_GetBytes(This,buffer) \ ( (This)->lpVtbl -> GetBytes(This,buffer) ) #define IDeckLinkVideoInputFrame_v7_3_GetTimecode(This,format,timecode) \ ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) #define IDeckLinkVideoInputFrame_v7_3_GetAncillaryData(This,ancillary) \ ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) #define IDeckLinkVideoInputFrame_v7_3_GetStreamTime(This,frameTime,frameDuration,timeScale) \ ( (This)->lpVtbl -> GetStreamTime(This,frameTime,frameDuration,timeScale) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkVideoInputFrame_v7_3_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkDisplayModeIterator_v7_1_INTERFACE_DEFINED__ #define __IDeckLinkDisplayModeIterator_v7_1_INTERFACE_DEFINED__ /* interface IDeckLinkDisplayModeIterator_v7_1 */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkDisplayModeIterator_v7_1; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("B28131B6-59AC-4857-B5AC-CD75D5883E2F") IDeckLinkDisplayModeIterator_v7_1 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE Next( /* [out] */ IDeckLinkDisplayMode_v7_1 **deckLinkDisplayMode) = 0; }; #else /* C style interface */ typedef struct IDeckLinkDisplayModeIterator_v7_1Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkDisplayModeIterator_v7_1 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkDisplayModeIterator_v7_1 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkDisplayModeIterator_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *Next )( IDeckLinkDisplayModeIterator_v7_1 * This, /* [out] */ IDeckLinkDisplayMode_v7_1 **deckLinkDisplayMode); END_INTERFACE } IDeckLinkDisplayModeIterator_v7_1Vtbl; interface IDeckLinkDisplayModeIterator_v7_1 { CONST_VTBL struct IDeckLinkDisplayModeIterator_v7_1Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkDisplayModeIterator_v7_1_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkDisplayModeIterator_v7_1_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkDisplayModeIterator_v7_1_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkDisplayModeIterator_v7_1_Next(This,deckLinkDisplayMode) \ ( (This)->lpVtbl -> Next(This,deckLinkDisplayMode) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkDisplayModeIterator_v7_1_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkDisplayMode_v7_1_INTERFACE_DEFINED__ #define __IDeckLinkDisplayMode_v7_1_INTERFACE_DEFINED__ /* interface IDeckLinkDisplayMode_v7_1 */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkDisplayMode_v7_1; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("AF0CD6D5-8376-435E-8433-54F9DD530AC3") IDeckLinkDisplayMode_v7_1 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE GetName( /* [out] */ BSTR *name) = 0; virtual BMDDisplayMode STDMETHODCALLTYPE GetDisplayMode( void) = 0; virtual long STDMETHODCALLTYPE GetWidth( void) = 0; virtual long STDMETHODCALLTYPE GetHeight( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetFrameRate( /* [out] */ BMDTimeValue *frameDuration, /* [out] */ BMDTimeScale *timeScale) = 0; }; #else /* C style interface */ typedef struct IDeckLinkDisplayMode_v7_1Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkDisplayMode_v7_1 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkDisplayMode_v7_1 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkDisplayMode_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *GetName )( IDeckLinkDisplayMode_v7_1 * This, /* [out] */ BSTR *name); BMDDisplayMode ( STDMETHODCALLTYPE *GetDisplayMode )( IDeckLinkDisplayMode_v7_1 * This); long ( STDMETHODCALLTYPE *GetWidth )( IDeckLinkDisplayMode_v7_1 * This); long ( STDMETHODCALLTYPE *GetHeight )( IDeckLinkDisplayMode_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *GetFrameRate )( IDeckLinkDisplayMode_v7_1 * This, /* [out] */ BMDTimeValue *frameDuration, /* [out] */ BMDTimeScale *timeScale); END_INTERFACE } IDeckLinkDisplayMode_v7_1Vtbl; interface IDeckLinkDisplayMode_v7_1 { CONST_VTBL struct IDeckLinkDisplayMode_v7_1Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkDisplayMode_v7_1_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkDisplayMode_v7_1_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkDisplayMode_v7_1_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkDisplayMode_v7_1_GetName(This,name) \ ( (This)->lpVtbl -> GetName(This,name) ) #define IDeckLinkDisplayMode_v7_1_GetDisplayMode(This) \ ( (This)->lpVtbl -> GetDisplayMode(This) ) #define IDeckLinkDisplayMode_v7_1_GetWidth(This) \ ( (This)->lpVtbl -> GetWidth(This) ) #define IDeckLinkDisplayMode_v7_1_GetHeight(This) \ ( (This)->lpVtbl -> GetHeight(This) ) #define IDeckLinkDisplayMode_v7_1_GetFrameRate(This,frameDuration,timeScale) \ ( (This)->lpVtbl -> GetFrameRate(This,frameDuration,timeScale) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkDisplayMode_v7_1_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkVideoFrame_v7_1_INTERFACE_DEFINED__ #define __IDeckLinkVideoFrame_v7_1_INTERFACE_DEFINED__ /* interface IDeckLinkVideoFrame_v7_1 */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkVideoFrame_v7_1; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("333F3A10-8C2D-43CF-B79D-46560FEEA1CE") IDeckLinkVideoFrame_v7_1 : public IUnknown { public: virtual long STDMETHODCALLTYPE GetWidth( void) = 0; virtual long STDMETHODCALLTYPE GetHeight( void) = 0; virtual long STDMETHODCALLTYPE GetRowBytes( void) = 0; virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat( void) = 0; virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetBytes( void **buffer) = 0; }; #else /* C style interface */ typedef struct IDeckLinkVideoFrame_v7_1Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkVideoFrame_v7_1 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkVideoFrame_v7_1 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkVideoFrame_v7_1 * This); long ( STDMETHODCALLTYPE *GetWidth )( IDeckLinkVideoFrame_v7_1 * This); long ( STDMETHODCALLTYPE *GetHeight )( IDeckLinkVideoFrame_v7_1 * This); long ( STDMETHODCALLTYPE *GetRowBytes )( IDeckLinkVideoFrame_v7_1 * This); BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( IDeckLinkVideoFrame_v7_1 * This); BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( IDeckLinkVideoFrame_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *GetBytes )( IDeckLinkVideoFrame_v7_1 * This, void **buffer); END_INTERFACE } IDeckLinkVideoFrame_v7_1Vtbl; interface IDeckLinkVideoFrame_v7_1 { CONST_VTBL struct IDeckLinkVideoFrame_v7_1Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkVideoFrame_v7_1_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkVideoFrame_v7_1_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkVideoFrame_v7_1_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkVideoFrame_v7_1_GetWidth(This) \ ( (This)->lpVtbl -> GetWidth(This) ) #define IDeckLinkVideoFrame_v7_1_GetHeight(This) \ ( (This)->lpVtbl -> GetHeight(This) ) #define IDeckLinkVideoFrame_v7_1_GetRowBytes(This) \ ( (This)->lpVtbl -> GetRowBytes(This) ) #define IDeckLinkVideoFrame_v7_1_GetPixelFormat(This) \ ( (This)->lpVtbl -> GetPixelFormat(This) ) #define IDeckLinkVideoFrame_v7_1_GetFlags(This) \ ( (This)->lpVtbl -> GetFlags(This) ) #define IDeckLinkVideoFrame_v7_1_GetBytes(This,buffer) \ ( (This)->lpVtbl -> GetBytes(This,buffer) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkVideoFrame_v7_1_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkVideoInputFrame_v7_1_INTERFACE_DEFINED__ #define __IDeckLinkVideoInputFrame_v7_1_INTERFACE_DEFINED__ /* interface IDeckLinkVideoInputFrame_v7_1 */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkVideoInputFrame_v7_1; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("C8B41D95-8848-40EE-9B37-6E3417FB114B") IDeckLinkVideoInputFrame_v7_1 : public IDeckLinkVideoFrame_v7_1 { public: virtual HRESULT STDMETHODCALLTYPE GetFrameTime( BMDTimeValue *frameTime, BMDTimeValue *frameDuration, BMDTimeScale timeScale) = 0; }; #else /* C style interface */ typedef struct IDeckLinkVideoInputFrame_v7_1Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkVideoInputFrame_v7_1 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkVideoInputFrame_v7_1 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkVideoInputFrame_v7_1 * This); long ( STDMETHODCALLTYPE *GetWidth )( IDeckLinkVideoInputFrame_v7_1 * This); long ( STDMETHODCALLTYPE *GetHeight )( IDeckLinkVideoInputFrame_v7_1 * This); long ( STDMETHODCALLTYPE *GetRowBytes )( IDeckLinkVideoInputFrame_v7_1 * This); BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( IDeckLinkVideoInputFrame_v7_1 * This); BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( IDeckLinkVideoInputFrame_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *GetBytes )( IDeckLinkVideoInputFrame_v7_1 * This, void **buffer); HRESULT ( STDMETHODCALLTYPE *GetFrameTime )( IDeckLinkVideoInputFrame_v7_1 * This, BMDTimeValue *frameTime, BMDTimeValue *frameDuration, BMDTimeScale timeScale); END_INTERFACE } IDeckLinkVideoInputFrame_v7_1Vtbl; interface IDeckLinkVideoInputFrame_v7_1 { CONST_VTBL struct IDeckLinkVideoInputFrame_v7_1Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkVideoInputFrame_v7_1_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkVideoInputFrame_v7_1_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkVideoInputFrame_v7_1_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkVideoInputFrame_v7_1_GetWidth(This) \ ( (This)->lpVtbl -> GetWidth(This) ) #define IDeckLinkVideoInputFrame_v7_1_GetHeight(This) \ ( (This)->lpVtbl -> GetHeight(This) ) #define IDeckLinkVideoInputFrame_v7_1_GetRowBytes(This) \ ( (This)->lpVtbl -> GetRowBytes(This) ) #define IDeckLinkVideoInputFrame_v7_1_GetPixelFormat(This) \ ( (This)->lpVtbl -> GetPixelFormat(This) ) #define IDeckLinkVideoInputFrame_v7_1_GetFlags(This) \ ( (This)->lpVtbl -> GetFlags(This) ) #define IDeckLinkVideoInputFrame_v7_1_GetBytes(This,buffer) \ ( (This)->lpVtbl -> GetBytes(This,buffer) ) #define IDeckLinkVideoInputFrame_v7_1_GetFrameTime(This,frameTime,frameDuration,timeScale) \ ( (This)->lpVtbl -> GetFrameTime(This,frameTime,frameDuration,timeScale) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkVideoInputFrame_v7_1_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkAudioInputPacket_v7_1_INTERFACE_DEFINED__ #define __IDeckLinkAudioInputPacket_v7_1_INTERFACE_DEFINED__ /* interface IDeckLinkAudioInputPacket_v7_1 */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkAudioInputPacket_v7_1; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("C86DE4F6-A29F-42E3-AB3A-1363E29F0788") IDeckLinkAudioInputPacket_v7_1 : public IUnknown { public: virtual long STDMETHODCALLTYPE GetSampleCount( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetBytes( void **buffer) = 0; virtual HRESULT STDMETHODCALLTYPE GetAudioPacketTime( BMDTimeValue *packetTime, BMDTimeScale timeScale) = 0; }; #else /* C style interface */ typedef struct IDeckLinkAudioInputPacket_v7_1Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkAudioInputPacket_v7_1 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkAudioInputPacket_v7_1 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkAudioInputPacket_v7_1 * This); long ( STDMETHODCALLTYPE *GetSampleCount )( IDeckLinkAudioInputPacket_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *GetBytes )( IDeckLinkAudioInputPacket_v7_1 * This, void **buffer); HRESULT ( STDMETHODCALLTYPE *GetAudioPacketTime )( IDeckLinkAudioInputPacket_v7_1 * This, BMDTimeValue *packetTime, BMDTimeScale timeScale); END_INTERFACE } IDeckLinkAudioInputPacket_v7_1Vtbl; interface IDeckLinkAudioInputPacket_v7_1 { CONST_VTBL struct IDeckLinkAudioInputPacket_v7_1Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkAudioInputPacket_v7_1_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkAudioInputPacket_v7_1_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkAudioInputPacket_v7_1_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkAudioInputPacket_v7_1_GetSampleCount(This) \ ( (This)->lpVtbl -> GetSampleCount(This) ) #define IDeckLinkAudioInputPacket_v7_1_GetBytes(This,buffer) \ ( (This)->lpVtbl -> GetBytes(This,buffer) ) #define IDeckLinkAudioInputPacket_v7_1_GetAudioPacketTime(This,packetTime,timeScale) \ ( (This)->lpVtbl -> GetAudioPacketTime(This,packetTime,timeScale) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkAudioInputPacket_v7_1_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkVideoOutputCallback_v7_1_INTERFACE_DEFINED__ #define __IDeckLinkVideoOutputCallback_v7_1_INTERFACE_DEFINED__ /* interface IDeckLinkVideoOutputCallback_v7_1 */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkVideoOutputCallback_v7_1; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("EBD01AFA-E4B0-49C6-A01D-EDB9D1B55FD9") IDeckLinkVideoOutputCallback_v7_1 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted( /* [in] */ IDeckLinkVideoFrame_v7_1 *completedFrame, /* [in] */ BMDOutputFrameCompletionResult result) = 0; }; #else /* C style interface */ typedef struct IDeckLinkVideoOutputCallback_v7_1Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkVideoOutputCallback_v7_1 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkVideoOutputCallback_v7_1 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkVideoOutputCallback_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *ScheduledFrameCompleted )( IDeckLinkVideoOutputCallback_v7_1 * This, /* [in] */ IDeckLinkVideoFrame_v7_1 *completedFrame, /* [in] */ BMDOutputFrameCompletionResult result); END_INTERFACE } IDeckLinkVideoOutputCallback_v7_1Vtbl; interface IDeckLinkVideoOutputCallback_v7_1 { CONST_VTBL struct IDeckLinkVideoOutputCallback_v7_1Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkVideoOutputCallback_v7_1_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkVideoOutputCallback_v7_1_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkVideoOutputCallback_v7_1_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkVideoOutputCallback_v7_1_ScheduledFrameCompleted(This,completedFrame,result) \ ( (This)->lpVtbl -> ScheduledFrameCompleted(This,completedFrame,result) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkVideoOutputCallback_v7_1_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkInputCallback_v7_1_INTERFACE_DEFINED__ #define __IDeckLinkInputCallback_v7_1_INTERFACE_DEFINED__ /* interface IDeckLinkInputCallback_v7_1 */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkInputCallback_v7_1; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("7F94F328-5ED4-4E9F-9729-76A86BDC99CC") IDeckLinkInputCallback_v7_1 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( /* [in] */ IDeckLinkVideoInputFrame_v7_1 *videoFrame, /* [in] */ IDeckLinkAudioInputPacket_v7_1 *audioPacket) = 0; }; #else /* C style interface */ typedef struct IDeckLinkInputCallback_v7_1Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkInputCallback_v7_1 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkInputCallback_v7_1 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkInputCallback_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *VideoInputFrameArrived )( IDeckLinkInputCallback_v7_1 * This, /* [in] */ IDeckLinkVideoInputFrame_v7_1 *videoFrame, /* [in] */ IDeckLinkAudioInputPacket_v7_1 *audioPacket); END_INTERFACE } IDeckLinkInputCallback_v7_1Vtbl; interface IDeckLinkInputCallback_v7_1 { CONST_VTBL struct IDeckLinkInputCallback_v7_1Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkInputCallback_v7_1_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkInputCallback_v7_1_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkInputCallback_v7_1_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkInputCallback_v7_1_VideoInputFrameArrived(This,videoFrame,audioPacket) \ ( (This)->lpVtbl -> VideoInputFrameArrived(This,videoFrame,audioPacket) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkInputCallback_v7_1_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkOutput_v7_1_INTERFACE_DEFINED__ #define __IDeckLinkOutput_v7_1_INTERFACE_DEFINED__ /* interface IDeckLinkOutput_v7_1 */ /* [helpstring][local][uuid][object] */ EXTERN_C const IID IID_IDeckLinkOutput_v7_1; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("AE5B3E9B-4E1E-4535-B6E8-480FF52F6CE5") IDeckLinkOutput_v7_1 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* [out] */ BMDDisplayModeSupport *result) = 0; virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( /* [out] */ IDeckLinkDisplayModeIterator_v7_1 **iterator) = 0; virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput( BMDDisplayMode displayMode) = 0; virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator( /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0; virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame( long width, long height, long rowBytes, BMDPixelFormat pixelFormat, BMDFrameFlags flags, IDeckLinkVideoFrame_v7_1 **outFrame) = 0; virtual HRESULT STDMETHODCALLTYPE CreateVideoFrameFromBuffer( void *buffer, long width, long height, long rowBytes, BMDPixelFormat pixelFormat, BMDFrameFlags flags, IDeckLinkVideoFrame_v7_1 **outFrame) = 0; virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync( IDeckLinkVideoFrame_v7_1 *theFrame) = 0; virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame( IDeckLinkVideoFrame_v7_1 *theFrame, BMDTimeValue displayTime, BMDTimeValue displayDuration, BMDTimeScale timeScale) = 0; virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback( /* [in] */ IDeckLinkVideoOutputCallback_v7_1 *theCallback) = 0; virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput( BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType, unsigned long channelCount) = 0; virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0; virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync( void *buffer, unsigned long sampleFrameCount, /* [out] */ unsigned long *sampleFramesWritten) = 0; virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0; virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0; virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples( void *buffer, unsigned long sampleFrameCount, BMDTimeValue streamTime, BMDTimeScale timeScale, /* [out] */ unsigned long *sampleFramesWritten) = 0; virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( /* [out] */ unsigned long *bufferedSampleCount) = 0; virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetAudioCallback( /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0; virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback( BMDTimeValue playbackStartTime, BMDTimeScale timeScale, double playbackSpeed) = 0; virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback( BMDTimeValue stopPlaybackAtTime, BMDTimeValue *actualStopTime, BMDTimeScale timeScale) = 0; virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( BMDTimeScale desiredTimeScale, BMDTimeValue *elapsedTimeSinceSchedulerBegan) = 0; }; #else /* C style interface */ typedef struct IDeckLinkOutput_v7_1Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkOutput_v7_1 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkOutput_v7_1 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkOutput_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( IDeckLinkOutput_v7_1 * This, BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* [out] */ BMDDisplayModeSupport *result); HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( IDeckLinkOutput_v7_1 * This, /* [out] */ IDeckLinkDisplayModeIterator_v7_1 **iterator); HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )( IDeckLinkOutput_v7_1 * This, BMDDisplayMode displayMode); HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )( IDeckLinkOutput_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )( IDeckLinkOutput_v7_1 * This, /* [in] */ IDeckLinkMemoryAllocator *theAllocator); HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )( IDeckLinkOutput_v7_1 * This, long width, long height, long rowBytes, BMDPixelFormat pixelFormat, BMDFrameFlags flags, IDeckLinkVideoFrame_v7_1 **outFrame); HRESULT ( STDMETHODCALLTYPE *CreateVideoFrameFromBuffer )( IDeckLinkOutput_v7_1 * This, void *buffer, long width, long height, long rowBytes, BMDPixelFormat pixelFormat, BMDFrameFlags flags, IDeckLinkVideoFrame_v7_1 **outFrame); HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )( IDeckLinkOutput_v7_1 * This, IDeckLinkVideoFrame_v7_1 *theFrame); HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )( IDeckLinkOutput_v7_1 * This, IDeckLinkVideoFrame_v7_1 *theFrame, BMDTimeValue displayTime, BMDTimeValue displayDuration, BMDTimeScale timeScale); HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )( IDeckLinkOutput_v7_1 * This, /* [in] */ IDeckLinkVideoOutputCallback_v7_1 *theCallback); HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )( IDeckLinkOutput_v7_1 * This, BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType, unsigned long channelCount); HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )( IDeckLinkOutput_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )( IDeckLinkOutput_v7_1 * This, void *buffer, unsigned long sampleFrameCount, /* [out] */ unsigned long *sampleFramesWritten); HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )( IDeckLinkOutput_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )( IDeckLinkOutput_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )( IDeckLinkOutput_v7_1 * This, void *buffer, unsigned long sampleFrameCount, BMDTimeValue streamTime, BMDTimeScale timeScale, /* [out] */ unsigned long *sampleFramesWritten); HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( IDeckLinkOutput_v7_1 * This, /* [out] */ unsigned long *bufferedSampleCount); HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )( IDeckLinkOutput_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )( IDeckLinkOutput_v7_1 * This, /* [in] */ IDeckLinkAudioOutputCallback *theCallback); HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )( IDeckLinkOutput_v7_1 * This, BMDTimeValue playbackStartTime, BMDTimeScale timeScale, double playbackSpeed); HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )( IDeckLinkOutput_v7_1 * This, BMDTimeValue stopPlaybackAtTime, BMDTimeValue *actualStopTime, BMDTimeScale timeScale); HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( IDeckLinkOutput_v7_1 * This, BMDTimeScale desiredTimeScale, BMDTimeValue *elapsedTimeSinceSchedulerBegan); END_INTERFACE } IDeckLinkOutput_v7_1Vtbl; interface IDeckLinkOutput_v7_1 { CONST_VTBL struct IDeckLinkOutput_v7_1Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkOutput_v7_1_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkOutput_v7_1_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkOutput_v7_1_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkOutput_v7_1_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) #define IDeckLinkOutput_v7_1_GetDisplayModeIterator(This,iterator) \ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) #define IDeckLinkOutput_v7_1_EnableVideoOutput(This,displayMode) \ ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode) ) #define IDeckLinkOutput_v7_1_DisableVideoOutput(This) \ ( (This)->lpVtbl -> DisableVideoOutput(This) ) #define IDeckLinkOutput_v7_1_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \ ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) ) #define IDeckLinkOutput_v7_1_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \ ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) ) #define IDeckLinkOutput_v7_1_CreateVideoFrameFromBuffer(This,buffer,width,height,rowBytes,pixelFormat,flags,outFrame) \ ( (This)->lpVtbl -> CreateVideoFrameFromBuffer(This,buffer,width,height,rowBytes,pixelFormat,flags,outFrame) ) #define IDeckLinkOutput_v7_1_DisplayVideoFrameSync(This,theFrame) \ ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) ) #define IDeckLinkOutput_v7_1_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \ ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) ) #define IDeckLinkOutput_v7_1_SetScheduledFrameCompletionCallback(This,theCallback) \ ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) ) #define IDeckLinkOutput_v7_1_EnableAudioOutput(This,sampleRate,sampleType,channelCount) \ ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount) ) #define IDeckLinkOutput_v7_1_DisableAudioOutput(This) \ ( (This)->lpVtbl -> DisableAudioOutput(This) ) #define IDeckLinkOutput_v7_1_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \ ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) ) #define IDeckLinkOutput_v7_1_BeginAudioPreroll(This) \ ( (This)->lpVtbl -> BeginAudioPreroll(This) ) #define IDeckLinkOutput_v7_1_EndAudioPreroll(This) \ ( (This)->lpVtbl -> EndAudioPreroll(This) ) #define IDeckLinkOutput_v7_1_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \ ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) ) #define IDeckLinkOutput_v7_1_GetBufferedAudioSampleFrameCount(This,bufferedSampleCount) \ ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleCount) ) #define IDeckLinkOutput_v7_1_FlushBufferedAudioSamples(This) \ ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) ) #define IDeckLinkOutput_v7_1_SetAudioCallback(This,theCallback) \ ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) ) #define IDeckLinkOutput_v7_1_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \ ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) ) #define IDeckLinkOutput_v7_1_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \ ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) ) #define IDeckLinkOutput_v7_1_GetHardwareReferenceClock(This,desiredTimeScale,elapsedTimeSinceSchedulerBegan) \ ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,elapsedTimeSinceSchedulerBegan) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkOutput_v7_1_INTERFACE_DEFINED__ */ #ifndef __IDeckLinkInput_v7_1_INTERFACE_DEFINED__ #define __IDeckLinkInput_v7_1_INTERFACE_DEFINED__ /* interface IDeckLinkInput_v7_1 */ /* [helpstring][uuid][object] */ EXTERN_C const IID IID_IDeckLinkInput_v7_1; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("2B54EDEF-5B32-429F-BA11-BB990596EACD") IDeckLinkInput_v7_1 : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* [out] */ BMDDisplayModeSupport *result) = 0; virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( /* [out] */ IDeckLinkDisplayModeIterator_v7_1 **iterator) = 0; virtual HRESULT STDMETHODCALLTYPE EnableVideoInput( BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDVideoInputFlags flags) = 0; virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0; virtual HRESULT STDMETHODCALLTYPE EnableAudioInput( BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType, unsigned long channelCount) = 0; virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0; virtual HRESULT STDMETHODCALLTYPE ReadAudioSamples( void *buffer, unsigned long sampleFrameCount, /* [out] */ unsigned long *sampleFramesRead, /* [out] */ BMDTimeValue *audioPacketTime, BMDTimeScale timeScale) = 0; virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( /* [out] */ unsigned long *bufferedSampleCount) = 0; virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0; virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0; virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetCallback( /* [in] */ IDeckLinkInputCallback_v7_1 *theCallback) = 0; }; #else /* C style interface */ typedef struct IDeckLinkInput_v7_1Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDeckLinkInput_v7_1 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IDeckLinkInput_v7_1 * This); ULONG ( STDMETHODCALLTYPE *Release )( IDeckLinkInput_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( IDeckLinkInput_v7_1 * This, BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* [out] */ BMDDisplayModeSupport *result); HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( IDeckLinkInput_v7_1 * This, /* [out] */ IDeckLinkDisplayModeIterator_v7_1 **iterator); HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )( IDeckLinkInput_v7_1 * This, BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDVideoInputFlags flags); HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )( IDeckLinkInput_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )( IDeckLinkInput_v7_1 * This, BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType, unsigned long channelCount); HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )( IDeckLinkInput_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *ReadAudioSamples )( IDeckLinkInput_v7_1 * This, void *buffer, unsigned long sampleFrameCount, /* [out] */ unsigned long *sampleFramesRead, /* [out] */ BMDTimeValue *audioPacketTime, BMDTimeScale timeScale); HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( IDeckLinkInput_v7_1 * This, /* [out] */ unsigned long *bufferedSampleCount); HRESULT ( STDMETHODCALLTYPE *StartStreams )( IDeckLinkInput_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *StopStreams )( IDeckLinkInput_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *PauseStreams )( IDeckLinkInput_v7_1 * This); HRESULT ( STDMETHODCALLTYPE *SetCallback )( IDeckLinkInput_v7_1 * This, /* [in] */ IDeckLinkInputCallback_v7_1 *theCallback); END_INTERFACE } IDeckLinkInput_v7_1Vtbl; interface IDeckLinkInput_v7_1 { CONST_VTBL struct IDeckLinkInput_v7_1Vtbl *lpVtbl; }; #ifdef COBJMACROS #define IDeckLinkInput_v7_1_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IDeckLinkInput_v7_1_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IDeckLinkInput_v7_1_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IDeckLinkInput_v7_1_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) #define IDeckLinkInput_v7_1_GetDisplayModeIterator(This,iterator) \ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) #define IDeckLinkInput_v7_1_EnableVideoInput(This,displayMode,pixelFormat,flags) \ ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) ) #define IDeckLinkInput_v7_1_DisableVideoInput(This) \ ( (This)->lpVtbl -> DisableVideoInput(This) ) #define IDeckLinkInput_v7_1_EnableAudioInput(This,sampleRate,sampleType,channelCount) \ ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) ) #define IDeckLinkInput_v7_1_DisableAudioInput(This) \ ( (This)->lpVtbl -> DisableAudioInput(This) ) #define IDeckLinkInput_v7_1_ReadAudioSamples(This,buffer,sampleFrameCount,sampleFramesRead,audioPacketTime,timeScale) \ ( (This)->lpVtbl -> ReadAudioSamples(This,buffer,sampleFrameCount,sampleFramesRead,audioPacketTime,timeScale) ) #define IDeckLinkInput_v7_1_GetBufferedAudioSampleFrameCount(This,bufferedSampleCount) \ ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleCount) ) #define IDeckLinkInput_v7_1_StartStreams(This) \ ( (This)->lpVtbl -> StartStreams(This) ) #define IDeckLinkInput_v7_1_StopStreams(This) \ ( (This)->lpVtbl -> StopStreams(This) ) #define IDeckLinkInput_v7_1_PauseStreams(This) \ ( (This)->lpVtbl -> PauseStreams(This) ) #define IDeckLinkInput_v7_1_SetCallback(This,theCallback) \ ( (This)->lpVtbl -> SetCallback(This,theCallback) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IDeckLinkInput_v7_1_INTERFACE_DEFINED__ */ #endif /* __DeckLinkAPI_LIBRARY_DEFINED__ */ /* Additional Prototypes for ALL interfaces */ /* end of Additional Prototypes */ #ifdef __cplusplus } #endif #endif mlt-0.9.0/src/modules/decklink/win/DeckLinkAPI_i.cpp000066400000000000000000000210461215300731300221640ustar00rootroot00000000000000 /* this ALWAYS GENERATED file contains the IIDs and CLSIDs */ /* link this file in with the server and any clients */ /* File created by MIDL compiler version 7.00.0555 */ /* at Tue Sep 07 12:00:00 2010 */ /* Compiler settings for video\DeckLinkAPI.idl: Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 protocol : dce , ms_ext, c_ext, robust error checks: allocation ref bounds_check enum stub_data VC __declspec() decoration level: __declspec(uuid()), __declspec(selectany), __declspec(novtable) DECLSPEC_UUID(), MIDL_INTERFACE() */ /* @@MIDL_FILE_HEADING( ) */ //#pragma warning( disable: 4049 ) /* more than 64k source lines */ #ifdef __cplusplus extern "C"{ #endif #include "DeckLinkAPI_h.h" #include #include #ifdef _MIDL_USE_GUIDDEF_ #ifndef INITGUID #define INITGUID #include #undef INITGUID #else #include #endif #define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) #else // !_MIDL_USE_GUIDDEF_ #ifndef __IID_DEFINED__ #define __IID_DEFINED__ typedef struct _IID { unsigned long x; unsigned short s1; unsigned short s2; unsigned char c[8]; } IID; #endif // __IID_DEFINED__ #ifndef CLSID_DEFINED #define CLSID_DEFINED typedef IID CLSID; #endif // CLSID_DEFINED #define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} #endif // !_MIDL_USE_GUIDDEF_ MIDL_DEFINE_GUID(IID, LIBID_DeckLinkAPI,0xD864517A,0xEDD5,0x466D,0x86,0x7D,0xC8,0x19,0xF1,0xC0,0x52,0xBB); MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoOutputCallback,0x20AA5225,0x1958,0x47CB,0x82,0x0B,0x80,0xA8,0xD5,0x21,0xA6,0xEE); MIDL_DEFINE_GUID(IID, IID_IDeckLinkInputCallback,0xDD04E5EC,0x7415,0x42AB,0xAE,0x4A,0xE8,0x0C,0x4D,0xFC,0x04,0x4A); MIDL_DEFINE_GUID(IID, IID_IDeckLinkMemoryAllocator,0xB36EB6E7,0x9D29,0x4AA8,0x92,0xEF,0x84,0x3B,0x87,0xA2,0x89,0xE8); MIDL_DEFINE_GUID(IID, IID_IDeckLinkAudioOutputCallback,0x403C681B,0x7F46,0x4A12,0xB9,0x93,0x2B,0xB1,0x27,0x08,0x4E,0xE6); MIDL_DEFINE_GUID(IID, IID_IDeckLinkIterator,0x74E936FC,0xCC28,0x4A67,0x81,0xA0,0x1E,0x94,0xE5,0x2D,0x4E,0x69); MIDL_DEFINE_GUID(IID, IID_IDeckLinkAPIInformation,0x7BEA3C68,0x730D,0x4322,0xAF,0x34,0x8A,0x71,0x52,0xB5,0x32,0xA4); MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayModeIterator,0x9C88499F,0xF601,0x4021,0xB8,0x0B,0x03,0x2E,0x4E,0xB4,0x1C,0x35); MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayMode,0x3EB2C1AB,0x0A3D,0x4523,0xA3,0xAD,0xF4,0x0D,0x7F,0xB1,0x4E,0x78); MIDL_DEFINE_GUID(IID, IID_IDeckLink,0x62BFF75D,0x6569,0x4E55,0x8D,0x4D,0x66,0xAA,0x03,0x82,0x9A,0xBC); MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput,0xA3EF0963,0x0862,0x44ED,0x92,0xA9,0xEE,0x89,0xAB,0xF4,0x31,0xC7); MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput,0x6D40EF78,0x28B9,0x4E21,0x99,0x0D,0x95,0xBB,0x77,0x50,0xA0,0x4F); MIDL_DEFINE_GUID(IID, IID_IDeckLinkTimecode,0xBC6CFBD3,0x8317,0x4325,0xAC,0x1C,0x12,0x16,0x39,0x1E,0x93,0x40); MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrame,0x3F716FE0,0xF023,0x4111,0xBE,0x5D,0xEF,0x44,0x14,0xC0,0x5B,0x17); MIDL_DEFINE_GUID(IID, IID_IDeckLinkMutableVideoFrame,0x69E2639F,0x40DA,0x4E19,0xB6,0xF2,0x20,0xAC,0xE8,0x15,0xC3,0x90); MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrame3DExtensions,0xDA0F7E4A,0xEDC7,0x48A8,0x9C,0xDD,0x2D,0xB5,0x1C,0x72,0x9C,0xD7); MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoInputFrame,0x05CFE374,0x537C,0x4094,0x9A,0x57,0x68,0x05,0x25,0x11,0x8F,0x44); MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrameAncillary,0x732E723C,0xD1A4,0x4E29,0x9E,0x8E,0x4A,0x88,0x79,0x7A,0x00,0x04); MIDL_DEFINE_GUID(IID, IID_IDeckLinkAudioInputPacket,0xE43D5870,0x2894,0x11DE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66); MIDL_DEFINE_GUID(IID, IID_IDeckLinkScreenPreviewCallback,0xB1D3F49A,0x85FE,0x4C5D,0x95,0xC8,0x0B,0x5D,0x5D,0xCC,0xD4,0x38); MIDL_DEFINE_GUID(IID, IID_IDeckLinkGLScreenPreviewHelper,0x504E2209,0xCAC7,0x4C1A,0x9F,0xB4,0xC5,0xBB,0x62,0x74,0xD2,0x2F); MIDL_DEFINE_GUID(IID, IID_IDeckLinkConfiguration,0xC679A35B,0x610C,0x4D09,0xB7,0x48,0x1D,0x04,0x78,0x10,0x0F,0xC0); MIDL_DEFINE_GUID(IID, IID_IDeckLinkAttributes,0xABC11843,0xD966,0x44CB,0x96,0xE2,0xA1,0xCB,0x5D,0x31,0x35,0xC4); MIDL_DEFINE_GUID(IID, IID_IDeckLinkKeyer,0x89AFCAF5,0x65F8,0x421E,0x98,0xF7,0x96,0xFE,0x5F,0x5B,0xFB,0xA3); MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoConversion,0x3BBCB8A2,0xDA2C,0x42D9,0xB5,0xD8,0x88,0x08,0x36,0x44,0xE9,0x9A); MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControlStatusCallback,0xE5F693C1,0x4283,0x4716,0xB1,0x8F,0xC1,0x43,0x15,0x21,0x95,0x5B); MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControl,0xA4D81043,0x0619,0x42B7,0x8E,0xD6,0x60,0x2D,0x29,0x04,0x1D,0xF7); MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkIterator,0xD9EDA3B3,0x2887,0x41FA,0xB7,0x24,0x01,0x7C,0xF1,0xEB,0x1D,0x37); MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkGLScreenPreviewHelper,0xF63E77C7,0xB655,0x4A4A,0x9A,0xD0,0x3C,0xA8,0x5D,0x39,0x43,0x43); MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkVideoConversion,0x7DBBBB11,0x5B7B,0x467D,0xAE,0xA4,0xCE,0xA4,0x68,0xFD,0x36,0x8C); MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayModeIterator_v7_6,0x455D741F,0x1779,0x4800,0x86,0xF5,0x0B,0x5D,0x13,0xD7,0x97,0x51); MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayMode_v7_6,0x87451E84,0x2B7E,0x439E,0xA6,0x29,0x43,0x93,0xEA,0x4A,0x85,0x50); MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput_v7_6,0x29228142,0xEB8C,0x4141,0xA6,0x21,0xF7,0x40,0x26,0x45,0x09,0x55); MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput_v7_6,0x300C135A,0x9F43,0x48E2,0x99,0x06,0x6D,0x79,0x11,0xD9,0x3C,0xF1); MIDL_DEFINE_GUID(IID, IID_IDeckLinkTimecode_v7_6,0xEFB9BCA6,0xA521,0x44F7,0xBD,0x69,0x23,0x32,0xF2,0x4D,0x9E,0xE6); MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrame_v7_6,0xA8D8238E,0x6B18,0x4196,0x99,0xE1,0x5A,0xF7,0x17,0xB8,0x3D,0x32); MIDL_DEFINE_GUID(IID, IID_IDeckLinkMutableVideoFrame_v7_6,0x46FCEE00,0xB4E6,0x43D0,0x91,0xC0,0x02,0x3A,0x7F,0xCE,0xB3,0x4F); MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoInputFrame_v7_6,0x9A74FA41,0xAE9F,0x47AC,0x8C,0xF4,0x01,0xF4,0x2D,0xD5,0x99,0x65); MIDL_DEFINE_GUID(IID, IID_IDeckLinkScreenPreviewCallback_v7_6,0x373F499D,0x4B4D,0x4518,0xAD,0x22,0x63,0x54,0xE5,0xA5,0x82,0x5E); MIDL_DEFINE_GUID(IID, IID_IDeckLinkGLScreenPreviewHelper_v7_6,0xBA575CD9,0xA15E,0x497B,0xB2,0xC2,0xF9,0xAF,0xE7,0xBE,0x4E,0xBA); MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoConversion_v7_6,0x3EB504C9,0xF97D,0x40FE,0xA1,0x58,0xD4,0x07,0xD4,0x8C,0xB5,0x3B); MIDL_DEFINE_GUID(IID, IID_IDeckLinkConfiguration_v7_6,0xB8EAD569,0xB764,0x47F0,0xA7,0x3F,0xAE,0x40,0xDF,0x6C,0xBF,0x10); MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoOutputCallback_v7_6,0xE763A626,0x4A3C,0x49D1,0xBF,0x13,0xE7,0xAD,0x36,0x92,0xAE,0x52); MIDL_DEFINE_GUID(IID, IID_IDeckLinkInputCallback_v7_6,0x31D28EE7,0x88B6,0x4CB1,0x89,0x7A,0xCD,0xBF,0x79,0xA2,0x64,0x14); MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkGLScreenPreviewHelper_v7_6,0xD398CEE7,0x4434,0x4CA3,0x9B,0xA6,0x5A,0xE3,0x45,0x56,0xB9,0x05); MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkVideoConversion_v7_6,0xFFA84F77,0x73BE,0x4FB7,0xB0,0x3E,0xB5,0xE4,0x4B,0x9F,0x75,0x9B); MIDL_DEFINE_GUID(IID, IID_IDeckLinkInputCallback_v7_3,0xFD6F311D,0x4D00,0x444B,0x9E,0xD4,0x1F,0x25,0xB5,0x73,0x0A,0xD0); MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput_v7_3,0x271C65E3,0xC323,0x4344,0xA3,0x0F,0xD9,0x08,0xBC,0xB2,0x0A,0xA3); MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput_v7_3,0x4973F012,0x9925,0x458C,0x87,0x1C,0x18,0x77,0x4C,0xDB,0xBE,0xCB); MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoInputFrame_v7_3,0xCF317790,0x2894,0x11DE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66); MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayModeIterator_v7_1,0xB28131B6,0x59AC,0x4857,0xB5,0xAC,0xCD,0x75,0xD5,0x88,0x3E,0x2F); MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayMode_v7_1,0xAF0CD6D5,0x8376,0x435E,0x84,0x33,0x54,0xF9,0xDD,0x53,0x0A,0xC3); MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrame_v7_1,0x333F3A10,0x8C2D,0x43CF,0xB7,0x9D,0x46,0x56,0x0F,0xEE,0xA1,0xCE); MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoInputFrame_v7_1,0xC8B41D95,0x8848,0x40EE,0x9B,0x37,0x6E,0x34,0x17,0xFB,0x11,0x4B); MIDL_DEFINE_GUID(IID, IID_IDeckLinkAudioInputPacket_v7_1,0xC86DE4F6,0xA29F,0x42E3,0xAB,0x3A,0x13,0x63,0xE2,0x9F,0x07,0x88); MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoOutputCallback_v7_1,0xEBD01AFA,0xE4B0,0x49C6,0xA0,0x1D,0xED,0xB9,0xD1,0xB5,0x5F,0xD9); MIDL_DEFINE_GUID(IID, IID_IDeckLinkInputCallback_v7_1,0x7F94F328,0x5ED4,0x4E9F,0x97,0x29,0x76,0xA8,0x6B,0xDC,0x99,0xCC); MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput_v7_1,0xAE5B3E9B,0x4E1E,0x4535,0xB6,0xE8,0x48,0x0F,0xF5,0x2F,0x6C,0xE5); MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput_v7_1,0x2B54EDEF,0x5B32,0x429F,0xBA,0x11,0xBB,0x99,0x05,0x96,0xEA,0xCD); #undef MIDL_DEFINE_GUID #ifdef __cplusplus } #endif mlt-0.9.0/src/modules/dgraft/000077500000000000000000000000001215300731300160155ustar00rootroot00000000000000mlt-0.9.0/src/modules/dgraft/Makefile000066400000000000000000000007661215300731300174660ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt include ../../../config.mak TARGET = ../libmltdgraft$(LIBSUF) OBJS = factory.o \ filter_telecide.o SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/dgraft/factory.c000066400000000000000000000020541215300731300176310ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2008 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include extern mlt_filter filter_telecide_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); MLT_REPOSITORY { MLT_REGISTER( filter_type, "telecide", filter_telecide_init ); } mlt-0.9.0/src/modules/dgraft/filter_telecide.c000066400000000000000000001146501215300731300213130ustar00rootroot00000000000000/* * filter_telecide.c -- Donald Graft's Inverse Telecine Filter * Copyright (C) 2003 Donald A. Graft * Copyright (C) 2008 Dan Dennedy * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include //#define DEBUG_PATTERN_GUIDANCE #define MAX_CYCLE 6 #define BLKSIZE 24 #define BLKSIZE_TIMES2 (2 * BLKSIZE) #define GUIDE_32 1 #define GUIDE_22 2 #define GUIDE_32322 3 #define AHEAD 0 #define BEHIND 1 #define POST_METRICS 1 #define POST_FULL 2 #define POST_FULL_MAP 3 #define POST_FULL_NOMATCH 4 #define POST_FULL_NOMATCH_MAP 5 #define CACHE_SIZE 100000 #define P 0 #define C 1 #define N 2 #define PBLOCK 3 #define CBLOCK 4 #define NO_BACK 0 #define BACK_ON_COMBED 1 #define ALWAYS_BACK 2 struct CACHE_ENTRY { unsigned int frame; unsigned int metrics[5]; unsigned int chosen; }; struct PREDICTION { unsigned int metric; unsigned int phase; unsigned int predicted; unsigned int predicted_metric; }; struct context_s { int is_configured; mlt_properties image_cache; int out; int tff, chroma, blend, hints, show, debug; float dthresh, gthresh, vthresh, vthresh_saved, bthresh; int y0, y1, nt, guide, post, back, back_saved; int pitch, dpitch, pitchover2, pitchtimes4; int w, h, wover2, hover2, hplus1over2, hminus2; int xblocks, yblocks; #ifdef WINDOWED_MATCH unsigned int *matchc, *matchp, highest_matchc, highest_matchp; #endif unsigned int *sumc, *sump, highest_sumc, highest_sump; int vmetric; unsigned int *overrides, *overrides_p; int film, override, inpattern, found; int force; // Used by field matching. unsigned char *fprp, *fcrp, *fcrp_saved, *fnrp; // unsigned char *fprpU, *fcrpU, *fcrp_savedU, *fnrpU; // unsigned char *fprpV, *fcrpV, *fcrp_savedV, *fnrpV; unsigned char *dstp, *finalp; // unsigned char *dstpU, *dstpV; int chosen; unsigned int p, c, pblock, cblock, lowest, predicted, predicted_metric; unsigned int np, nc, npblock, ncblock, nframe; float mismatch; int pframe, x, y; unsigned char *crp, *prp; unsigned char *crpU, *prpU; unsigned char *crpV, *prpV; int hard; char status[80]; // Metrics cache. struct CACHE_ENTRY *cache; // Pattern guidance data. int cycle; struct PREDICTION pred[MAX_CYCLE+1]; }; typedef struct context_s *context; static inline void BitBlt(uint8_t* dstp, int dst_pitch, const uint8_t* srcp, int src_pitch, int row_size, int height) { uint32_t y; for(y=0;ychosen == P) use = 'p'; else if (cx->chosen == C) use = 'c'; else use = 'n'; snprintf(buf, sizeof(buf), "Telecide: frame %d: matches: %d %d %d\n", frame, cx->p, cx->c, cx->np); if ( cx->post ) snprintf(buf, sizeof(buf), "%sTelecide: frame %d: vmetrics: %d %d %d [chosen=%d]\n", buf, frame, cx->pblock, cx->cblock, cx->npblock, cx->vmetric); if ( cx->guide ) snprintf(buf, sizeof(buf), "%spattern mismatch=%0.2f%%\n", buf, cx->mismatch); snprintf(buf, sizeof(buf), "%sTelecide: frame %d: [%s %c]%s %s\n", buf, frame, cx->found ? "forcing" : "using", use, cx->post ? (cx->film ? " [progressive]" : " [interlaced]") : "", cx->guide ? cx->status : ""); mlt_properties_set( properties, "meta.attr.telecide.markup", buf ); } static void Debug(context cx, int frame) { char use; if (cx->chosen == P) use = 'p'; else if (cx->chosen == C) use = 'c'; else use = 'n'; fprintf(stderr, "Telecide: frame %d: matches: %d %d %d\n", frame, cx->p, cx->c, cx->np); if ( cx->post ) fprintf(stderr, "Telecide: frame %d: vmetrics: %d %d %d [chosen=%d]\n", frame, cx->pblock, cx->cblock, cx->npblock, cx->vmetric); if ( cx->guide ) fprintf(stderr, "pattern mismatch=%0.2f%%\n", cx->mismatch); fprintf(stderr, "Telecide: frame %d: [%s %c]%s %s\n", frame, cx->found ? "forcing" : "using", use, cx->post ? (cx->film ? " [progressive]" : " [interlaced]") : "", cx->guide ? cx->status : ""); } static void WriteHints(int film, int inpattern, mlt_properties frame_properties) { mlt_properties_set_int( frame_properties, "telecide.progressive", film); mlt_properties_set_int( frame_properties, "telecide.in_pattern", inpattern); } static void PutChosen(context cx, int frame, unsigned int chosen) { int f = frame % CACHE_SIZE; if (frame < 0 || frame > cx->out || cx->cache[f].frame != frame) return; cx->cache[f].chosen = chosen; } static void CacheInsert(context cx, int frame, unsigned int p, unsigned int pblock, unsigned int c, unsigned int cblock) { int f = frame % CACHE_SIZE; if (frame < 0 || frame > cx->out) fprintf( stderr, "%s: internal error: invalid frame %d for CacheInsert", __FUNCTION__, frame); cx->cache[f].frame = frame; cx->cache[f].metrics[P] = p; if (f) cx->cache[f-1].metrics[N] = p; cx->cache[f].metrics[C] = c; cx->cache[f].metrics[PBLOCK] = pblock; cx->cache[f].metrics[CBLOCK] = cblock; cx->cache[f].chosen = 0xff; } static int CacheQuery(context cx, int frame, unsigned int *p, unsigned int *pblock, unsigned int *c, unsigned int *cblock) { int f; f = frame % CACHE_SIZE; if (frame < 0 || frame > cx->out) fprintf( stderr, "%s: internal error: invalid frame %d for CacheQuery", __FUNCTION__, frame); if (cx->cache[f].frame != frame) { return 0; } *p = cx->cache[f].metrics[P]; *c = cx->cache[f].metrics[C]; *pblock = cx->cache[f].metrics[PBLOCK]; *cblock = cx->cache[f].metrics[CBLOCK]; return 1; } static int PredictHardYUY2(context cx, int frame, unsigned int *predicted, unsigned int *predicted_metric) { // Look for pattern in the actual delivered matches of the previous cycle of frames. // If a pattern is found, use that to predict the current match. if ( cx->guide == GUIDE_22 ) { if (cx->cache[(frame- cx->cycle)%CACHE_SIZE ].chosen == 0xff || cx->cache[(frame- cx->cycle+1)%CACHE_SIZE].chosen == 0xff) return 0; switch ((cx->cache[(frame- cx->cycle)%CACHE_SIZE ].chosen << 4) + (cx->cache[(frame- cx->cycle+1)%CACHE_SIZE].chosen)) { case 0x11: *predicted = C; *predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[C]; break; case 0x22: *predicted = N; *predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[N]; break; default: return 0; } } else if ( cx->guide == GUIDE_32 ) { if (cx->cache[(frame-cx->cycle)%CACHE_SIZE ].chosen == 0xff || cx->cache[(frame-cx->cycle+1)%CACHE_SIZE].chosen == 0xff || cx->cache[(frame-cx->cycle+2)%CACHE_SIZE].chosen == 0xff || cx->cache[(frame-cx->cycle+3)%CACHE_SIZE].chosen == 0xff || cx->cache[(frame-cx->cycle+4)%CACHE_SIZE].chosen == 0xff) return 0; switch ((cx->cache[(frame-cx->cycle)%CACHE_SIZE ].chosen << 16) + (cx->cache[(frame-cx->cycle+1)%CACHE_SIZE].chosen << 12) + (cx->cache[(frame-cx->cycle+2)%CACHE_SIZE].chosen << 8) + (cx->cache[(frame-cx->cycle+3)%CACHE_SIZE].chosen << 4) + (cx->cache[(frame-cx->cycle+4)%CACHE_SIZE].chosen)) { case 0x11122: case 0x11221: case 0x12211: case 0x12221: case 0x21122: case 0x11222: *predicted = C; *predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[C]; break; case 0x22111: case 0x21112: case 0x22112: case 0x22211: *predicted = N; *predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[N]; break; default: return 0; } } else if ( cx->guide == GUIDE_32322 ) { if (cx->cache[(frame- cx->cycle)%CACHE_SIZE ].chosen == 0xff || cx->cache[(frame- cx->cycle +1)%CACHE_SIZE].chosen == 0xff || cx->cache[(frame- cx->cycle +2)%CACHE_SIZE].chosen == 0xff || cx->cache[(frame- cx->cycle +3)%CACHE_SIZE].chosen == 0xff || cx->cache[(frame- cx->cycle +4)%CACHE_SIZE].chosen == 0xff || cx->cache[(frame- cx->cycle +5)%CACHE_SIZE].chosen == 0xff) return 0; switch ((cx->cache[(frame- cx->cycle)%CACHE_SIZE ].chosen << 20) + (cx->cache[(frame- cx->cycle +1)%CACHE_SIZE].chosen << 16) + (cx->cache[(frame- cx->cycle +2)%CACHE_SIZE].chosen << 12) + (cx->cache[(frame- cx->cycle +3)%CACHE_SIZE].chosen << 8) + (cx->cache[(frame- cx->cycle +4)%CACHE_SIZE].chosen << 4) + (cx->cache[(frame- cx->cycle +5)%CACHE_SIZE].chosen)) { case 0x111122: case 0x111221: case 0x112211: case 0x122111: case 0x111222: case 0x112221: case 0x122211: case 0x222111: *predicted = C; *predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[C]; break; case 0x221111: case 0x211112: case 0x221112: case 0x211122: *predicted = N; *predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[N]; break; default: return 0; } } #ifdef DEBUG_PATTERN_GUIDANCE fprintf( stderr, "%s: pos=%d HARD: predicted=%d\n", __FUNCTION__, frame, *predicted); #endif return 1; } static struct PREDICTION *PredictSoftYUY2(context cx, int frame ) { // Use heuristics to look forward for a match. int i, j, y, c, n, phase; unsigned int metric; cx->pred[0].metric = 0xffffffff; if (frame < 0 || frame > cx->out - cx->cycle) return cx->pred; // Look at the next cycle of frames. for (y = frame + 1; y <= frame + cx->cycle; y++) { // Look for a frame where the current and next match values are // very close. Those are candidates to predict the phase, because // that condition should occur only once per cycle. Store the candidate // phases and predictions in a list sorted by goodness. The list will // be used by the caller to try the phases in order. c = cx->cache[y%CACHE_SIZE].metrics[C]; n = cx->cache[y%CACHE_SIZE].metrics[N]; if (c == 0) c = 1; metric = (100 * abs (c - n)) / c; phase = y % cx->cycle; if (metric < 5) { // Place the new candidate phase in sorted order in the list. // Find the insertion point. i = 0; while (metric > cx->pred[i].metric) i++; // Find the end-of-list marker. j = 0; while (cx->pred[j].metric != 0xffffffff) j++; // Shift all items below the insertion point down by one to make // room for the insertion. j++; for (; j > i; j--) { cx->pred[j].metric = cx->pred[j-1].metric; cx->pred[j].phase = cx->pred[j-1].phase; cx->pred[j].predicted = cx->pred[j-1].predicted; cx->pred[j].predicted_metric = cx->pred[j-1].predicted_metric; } // Insert the new candidate data. cx->pred[j].metric = metric; cx->pred[j].phase = phase; if ( cx->guide == GUIDE_32 ) { switch ((frame % cx->cycle) - phase) { case -4: cx->pred[j].predicted = N; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[N]; break; case -3: cx->pred[j].predicted = N; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[N]; break; case -2: cx->pred[j].predicted = C; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[C]; break; case -1: cx->pred[j].predicted = C; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[C]; break; case 0: cx->pred[j].predicted = C; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[C]; break; case +1: cx->pred[j].predicted = N; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[N]; break; case +2: cx->pred[j].predicted = N; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[N]; break; case +3: cx->pred[j].predicted = C; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[C]; break; case +4: cx->pred[j].predicted = C; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[C]; break; } } else if ( cx->guide == GUIDE_32322 ) { switch ((frame % cx->cycle) - phase) { case -5: cx->pred[j].predicted = N; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[N]; break; case -4: cx->pred[j].predicted = N; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[N]; break; case -3: cx->pred[j].predicted = C; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[C]; break; case -2: cx->pred[j].predicted = C; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[C]; break; case -1: cx->pred[j].predicted = C; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[C]; break; case 0: cx->pred[j].predicted = C; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[C]; break; case +1: cx->pred[j].predicted = N; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[N]; break; case +2: cx->pred[j].predicted = N; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[N]; break; case +3: cx->pred[j].predicted = C; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[C]; break; case +4: cx->pred[j].predicted = C; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[C]; break; case +5: cx->pred[j].predicted = C; cx->pred[j].predicted_metric = cx->cache[frame%CACHE_SIZE].metrics[C]; break; } } } #ifdef DEBUG_PATTERN_GUIDANCE fprintf( stderr, "%s: pos=%d metric=%d phase=%d\n", __FUNCTION__, frame, metric, phase); #endif } return cx->pred; } static void CalculateMetrics(context cx, int frame, unsigned char *fcrp, unsigned char *fcrpU, unsigned char *fcrpV, unsigned char *fprp, unsigned char *fprpU, unsigned char *fprpV) { int x, y, p, c, tmp1, tmp2, skip; int vc; unsigned char *currbot0, *currbot2, *prevbot0, *prevbot2; unsigned char *prevtop0, *prevtop2, *prevtop4, *currtop0, *currtop2, *currtop4; unsigned char *a0, *a2, *b0, *b2, *b4; unsigned int diff, index; # define T 4 /* Clear the block sums. */ for (y = 0; y < cx->yblocks; y++) { for (x = 0; x < cx->xblocks; x++) { #ifdef WINDOWED_MATCH matchp[y*xblocks+x] = 0; matchc[y*xblocks+x] = 0; #endif cx->sump[y * cx->xblocks + x] = 0; cx->sumc[y * cx->xblocks + x] = 0; } } /* Find the best field match. Subsample the frames for speed. */ currbot0 = fcrp + cx->pitch; currbot2 = fcrp + 3 * cx->pitch; currtop0 = fcrp; currtop2 = fcrp + 2 * cx->pitch; currtop4 = fcrp + 4 * cx->pitch; prevbot0 = fprp + cx->pitch; prevbot2 = fprp + 3 * cx->pitch; prevtop0 = fprp; prevtop2 = fprp + 2 * cx->pitch; prevtop4 = fprp + 4 * cx->pitch; if ( cx->tff ) { a0 = prevbot0; a2 = prevbot2; b0 = currtop0; b2 = currtop2; b4 = currtop4; } else { a0 = currbot0; a2 = currbot2; b0 = prevtop0; b2 = prevtop2; b4 = prevtop4; } p = c = 0; // Calculate the field match and film/video metrics. // if (vi.IsYV12()) skip = 1; // else skip = 1 + ( !cx->chroma ); for (y = 0, index = 0; y < cx->h - 4; y+=4) { /* Exclusion band. Good for ignoring subtitles. */ if (cx->y0 == cx->y1 || y < cx->y0 || y > cx->y1) { for (x = 0; x < cx->w;) { // if (vi.IsYV12()) // index = (y/BLKSIZE)*xblocks + x/BLKSIZE; // else index = (y/BLKSIZE) * cx->xblocks + x/BLKSIZE_TIMES2; // Test combination with current frame. tmp1 = ((long)currbot0[x] + (long)currbot2[x]); // diff = abs((long)currtop0[x] - (tmp1 >> 1)); diff = abs((((long)currtop0[x] + (long)currtop2[x] + (long)currtop4[x])) - (tmp1 >> 1) - tmp1); if (diff > cx->nt) { c += diff; #ifdef WINDOWED_MATCH matchc[index] += diff; #endif } tmp1 = currbot0[x] + T; tmp2 = currbot0[x] - T; vc = (tmp1 < currtop0[x] && tmp1 < currtop2[x]) || (tmp2 > currtop0[x] && tmp2 > currtop2[x]); if (vc) { cx->sumc[index]++; } // Test combination with previous frame. tmp1 = ((long)a0[x] + (long)a2[x]); diff = abs((((long)b0[x] + (long)b2[x] + (long)b4[x])) - (tmp1 >> 1) - tmp1); if (diff > cx->nt) { p += diff; #ifdef WINDOWED_MATCH matchp[index] += diff; #endif } tmp1 = a0[x] + T; tmp2 = a0[x] - T; vc = (tmp1 < b0[x] && tmp1 < b2[x]) || (tmp2 > b0[x] && tmp2 > b2[x]); if (vc) { cx->sump[index]++; } x += skip; if (!(x&3)) x += 4; } } currbot0 += cx->pitchtimes4; currbot2 += cx->pitchtimes4; currtop0 += cx->pitchtimes4; currtop2 += cx->pitchtimes4; currtop4 += cx->pitchtimes4; a0 += cx->pitchtimes4; a2 += cx->pitchtimes4; b0 += cx->pitchtimes4; b2 += cx->pitchtimes4; b4 += cx->pitchtimes4; } // if (vi.IsYV12() && chroma == true) // { // int z; // // for (z = 0; z < 2; z++) // { // // Do the same for the U plane. // if (z == 0) // { // currbot0 = fcrpU + pitchover2; // currbot2 = fcrpU + 3 * pitchover2; // currtop0 = fcrpU; // currtop2 = fcrpU + 2 * pitchover2; // currtop4 = fcrpU + 4 * pitchover2; // prevbot0 = fprpU + pitchover2; // prevbot2 = fprpU + 3 * pitchover2; // prevtop0 = fprpU; // prevtop2 = fprpU + 2 * pitchover2; // prevtop4 = fprpU + 4 * pitchover2; // } // else // { // currbot0 = fcrpV + pitchover2; // currbot2 = fcrpV + 3 * pitchover2; // currtop0 = fcrpV; // currtop2 = fcrpV + 2 * pitchover2; // currtop4 = fcrpV + 4 * pitchover2; // prevbot0 = fprpV + pitchover2; // prevbot2 = fprpV + 3 * pitchover2; // prevtop0 = fprpV; // prevtop2 = fprpV + 2 * pitchover2; // prevtop4 = fprpV + 4 * pitchover2; // } // if (tff == true) // { // a0 = prevbot0; // a2 = prevbot2; // b0 = currtop0; // b2 = currtop2; // b4 = currtop4; // } // else // { // a0 = currbot0; // a2 = currbot2; // b0 = prevtop0; // b2 = prevtop2; // b4 = prevtop4; // } // // for (y = 0, index = 0; y < hover2 - 4; y+=4) // { // /* Exclusion band. Good for ignoring subtitles. */ // if (y0 == y1 || y < y0/2 || y > y1/2) // { // for (x = 0; x < wover2;) // { // if (vi.IsYV12()) // index = (y/BLKSIZE)*xblocks + x/BLKSIZE; // else // index = (y/BLKSIZE)*xblocks + x/BLKSIZE_TIMES2; // // // Test combination with current frame. // tmp1 = ((long)currbot0[x] + (long)currbot2[x]); // diff = abs((((long)currtop0[x] + (long)currtop2[x] + (long)currtop4[x])) - (tmp1 >> 1) - tmp1); // if (diff > nt) // { // c += diff; //#ifdef WINDOWED_MATCH // matchc[index] += diff; //#endif // } // // tmp1 = currbot0[x] + T; // tmp2 = currbot0[x] - T; // vc = (tmp1 < currtop0[x] && tmp1 < currtop2[x]) || // (tmp2 > currtop0[x] && tmp2 > currtop2[x]); // if (vc) // { // sumc[index]++; // } // // // Test combination with previous frame. // tmp1 = ((long)a0[x] + (long)a2[x]); // diff = abs((((long)b0[x] + (long)b2[x] + (long)b4[x])) - (tmp1 >> 1) - tmp1); // if (diff > nt) // { // p += diff; //#ifdef WINDOWED_MATCH // matchp[index] += diff; //#endif // } // // tmp1 = a0[x] + T; // tmp2 = a0[x] - T; // vc = (tmp1 < b0[x] && tmp1 < b2[x]) || // (tmp2 > b0[x] && tmp2 > b2[x]); // if (vc) // { // sump[index]++; // } // // x ++; // if (!(x&3)) x += 4; // } // } // currbot0 += 4*pitchover2; // currbot2 += 4*pitchover2; // currtop0 += 4*pitchover2; // currtop2 += 4*pitchover2; // currtop4 += 4*pitchover2; // a0 += 4*pitchover2; // a2 += 4*pitchover2; // b0 += 4*pitchover2; // b2 += 4*pitchover2; // b4 += 4*pitchover2; // } // } // } // // // Now find the blocks that have the greatest differences. //#ifdef WINDOWED_MATCH // highest_matchp = 0; // for (y = 0; y < yblocks; y++) // { // for (x = 0; x < xblocks; x++) // { //if (frame == 45 && matchp[y * xblocks + x] > 2500) //{ // sprintf(buf, "%d/%d = %d\n", x, y, matchp[y * xblocks + x]); // OutputDebugString(buf); //} // if (matchp[y * xblocks + x] > highest_matchp) // { // highest_matchp = matchp[y * xblocks + x]; // } // } // } // highest_matchc = 0; // for (y = 0; y < yblocks; y++) // { // for (x = 0; x < xblocks; x++) // { //if (frame == 44 && matchc[y * xblocks + x] > 2500) //{ // sprintf(buf, "%d/%d = %d\n", x, y, matchc[y * xblocks + x]); // OutputDebugString(buf); //} // if (matchc[y * xblocks + x] > highest_matchc) // { // highest_matchc = matchc[y * xblocks + x]; // } // } // } //#endif if ( cx->post ) { cx->highest_sump = 0; for (y = 0; y < cx->yblocks; y++) { for (x = 0; x < cx->xblocks; x++) { if (cx->sump[y * cx->xblocks + x] > cx->highest_sump) { cx->highest_sump = cx->sump[y * cx->xblocks + x]; } } } cx->highest_sumc = 0; for (y = 0; y < cx->yblocks; y++) { for (x = 0; x < cx->xblocks; x++) { if (cx->sumc[y * cx->xblocks + x] > cx->highest_sumc) { cx->highest_sumc = cx->sumc[y * cx->xblocks + x]; } } } } #ifdef WINDOWED_MATCH CacheInsert(frame, highest_matchp, highest_sump, highest_matchc, highest_sumc); #else CacheInsert( cx, frame, p, cx->highest_sump, c, cx->highest_sumc); #endif } /** Process the image. */ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter service mlt_filter filter = mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties frame_properties = mlt_frame_properties( frame ); context cx = mlt_properties_get_data( properties, "context", NULL ); mlt_service producer = mlt_service_producer( mlt_filter_service( filter ) ); cx->out = producer? mlt_producer_get_playtime( MLT_PRODUCER( producer ) ) : 999999; if ( ! cx->is_configured ) { cx->back = mlt_properties_get_int( properties, "back" ); cx->chroma = mlt_properties_get_int( properties, "chroma" ); cx->guide = mlt_properties_get_int( properties, "guide" ); cx->gthresh = mlt_properties_get_double( properties, "gthresh" ); cx->post = mlt_properties_get_int( properties, "post" ); cx->vthresh = mlt_properties_get_double( properties, "vthresh" ); cx->bthresh = mlt_properties_get_double( properties, "bthresh" ); cx->dthresh = mlt_properties_get_double( properties, "dthresh" ); cx->blend = mlt_properties_get_int( properties, "blend" ); cx->nt = mlt_properties_get_int( properties, "nt" ); cx->y0 = mlt_properties_get_int( properties, "y0" ); cx->y1 = mlt_properties_get_int( properties, "y1" ); cx->hints = mlt_properties_get_int( properties, "hints" ); cx->debug = mlt_properties_get_int( properties, "debug" ); cx->show = mlt_properties_get_int( properties, "show" ); } // Get the image int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); if ( ! cx->sump ) { int guide = mlt_properties_get_int( properties, "guide" ); cx->cycle = 0; if ( guide == GUIDE_32 ) { // 24fps to 30 fps telecine. cx->cycle = 5; } else if ( guide == GUIDE_22 ) { // PAL guidance (expect the current match to be continued). cx->cycle = 2; } else if ( guide == GUIDE_32322 ) { // 25fps to 30 fps telecine. cx->cycle = 6; } cx->xblocks = (*width+BLKSIZE-1) / BLKSIZE; cx->yblocks = (*height+BLKSIZE-1) / BLKSIZE; cx->sump = (unsigned int *) mlt_pool_alloc( cx->xblocks * cx->yblocks * sizeof(unsigned int) ); cx->sumc = (unsigned int *) mlt_pool_alloc( cx->xblocks * cx->yblocks * sizeof(unsigned int) ); mlt_properties_set_data( properties, "sump", cx->sump, cx->xblocks * cx->yblocks * sizeof(unsigned int), (mlt_destructor)mlt_pool_release, NULL ); mlt_properties_set_data( properties, "sumc", cx->sumc, cx->xblocks * cx->yblocks * sizeof(unsigned int), (mlt_destructor)mlt_pool_release, NULL ); cx->tff = mlt_properties_get_int( frame_properties, "top_field_first" ); // fprintf(stderr, "%s: TOP FIELD FIRST %d\n", __FUNCTION__, cx->tff ); } // Only process if we have no error and a valid colour space if ( error == 0 && *format == mlt_image_yuv422 ) { // Put the current image into the image cache, keyed on position size_t image_size = (*width * *height) << 1; mlt_position pos = mlt_filter_get_position( filter, frame ); uint8_t *image_copy = mlt_pool_alloc( image_size ); memcpy( image_copy, *image, image_size ); char key[20]; sprintf( key, MLT_POSITION_FMT, pos ); mlt_properties_set_data( cx->image_cache, key, image_copy, image_size, (mlt_destructor)mlt_pool_release, NULL ); // Only if we have enough frame images cached if ( pos > 1 && pos > cx->cycle + 1 ) { pos -= cx->cycle + 1; // Get the current frame image sprintf( key, MLT_POSITION_FMT, pos ); cx->fcrp = mlt_properties_get_data( cx->image_cache, key, NULL ); if (!cx->fcrp) return error; // Get the previous frame image cx->pframe = pos == 0 ? 0 : pos - 1; sprintf( key, "%d", cx->pframe ); cx->fprp = mlt_properties_get_data( cx->image_cache, key, NULL ); if (!cx->fprp) return error; // Get the next frame image cx->nframe = pos > cx->out ? cx->out : pos + 1; sprintf( key, "%d", cx->nframe ); cx->fnrp = mlt_properties_get_data( cx->image_cache, key, NULL ); if (!cx->fnrp) return error; cx->pitch = *width << 1; cx->pitchover2 = cx->pitch >> 1; cx->pitchtimes4 = cx->pitch << 2; cx->w = *width << 1; cx->h = *height; if ((cx->w/2) & 1) fprintf( stderr, "%s: width must be a multiple of 2\n", __FUNCTION__ ); if (cx->h & 1) fprintf( stderr, "%s: height must be a multiple of 2\n", __FUNCTION__ ); cx->wover2 = cx->w/2; cx->hover2 = cx->h/2; cx->hplus1over2 = (cx->h+1)/2; cx->hminus2 = cx->h - 2; cx->dpitch = cx->pitch; // Ensure that the metrics for the frames // after the current frame are in the cache. They will be used for // pattern guidance. if ( cx->guide ) { for ( cx->y = pos + 1; (cx->y <= pos + cx->cycle + 1) && (cx->y <= cx->out); cx->y++ ) { if ( ! CacheQuery( cx, cx->y, &cx->p, &cx->pblock, &cx->c, &cx->cblock ) ) { sprintf( key, "%d", cx->y ); cx->crp = (unsigned char *) mlt_properties_get_data( cx->image_cache, key, NULL ); sprintf( key, "%d", cx->y ? cx->y - 1 : 1 ); cx->prp = (unsigned char *) mlt_properties_get_data( cx->image_cache, key, NULL ); CalculateMetrics( cx, cx->y, cx->crp, NULL, NULL, cx->prp, NULL, NULL ); } } } // Check for manual overrides of the field matching. cx->found = 0; cx->film = 1; cx->override = 0; cx->inpattern = 0; cx->vthresh = cx->vthresh; cx->back = cx->back_saved; // Get the metrics for the current-previous (p), current-current (c), and current-next (n) match candidates. if ( ! CacheQuery( cx, pos, &cx->p, &cx->pblock, &cx->c, &cx->cblock ) ) { CalculateMetrics( cx, pos, cx->fcrp, NULL, NULL, cx->fprp, NULL, NULL ); CacheQuery( cx, pos, &cx->p, &cx->pblock, &cx->c, &cx->cblock ); } if ( ! CacheQuery( cx, cx->nframe, &cx->np, &cx->npblock, &cx->nc, &cx->ncblock ) ) { CalculateMetrics( cx, cx->nframe, cx->fnrp, NULL, NULL, cx->fcrp, NULL, NULL ); CacheQuery( cx, cx->nframe, &cx->np, &cx->npblock, &cx->nc, &cx->ncblock ); } // Determine the best candidate match. if ( !cx->found ) { cx->lowest = cx->c; cx->chosen = C; if ( cx->back == ALWAYS_BACK && cx->p < cx->lowest ) { cx->lowest = cx->p; cx->chosen = P; } if ( cx->np < cx->lowest ) { cx->lowest = cx->np; cx->chosen = N; } } if ((pos == 0 && cx->chosen == P) || (pos == cx->out && cx->chosen == N)) { cx->chosen = C; cx->lowest = cx->c; } // See if we can apply pattern guidance. cx->mismatch = 100.0; if ( cx->guide ) { cx->hard = 0; if ( pos >= cx->cycle && PredictHardYUY2( cx, pos, &cx->predicted, &cx->predicted_metric) ) { cx->inpattern = 1; cx->mismatch = 0.0; cx->hard = 1; if ( cx->chosen != cx->predicted ) { // The chosen frame doesn't match the prediction. if ( cx->predicted_metric == 0 ) cx->mismatch = 0.0; else cx->mismatch = (100.0 * abs( cx->predicted_metric - cx->lowest ) ) / cx->predicted_metric; if ( cx->mismatch < cx->gthresh ) { // It's close enough, so use the predicted one. if ( !cx->found ) { cx->chosen = cx->predicted; cx->override = 1; } } else { cx->hard = 0; cx->inpattern = 0; } } } if ( !cx->hard && cx->guide != GUIDE_22 ) { int i; struct PREDICTION *pred = PredictSoftYUY2( cx, pos ); if ( ( pos <= cx->out - cx->cycle) && ( pred[0].metric != 0xffffffff ) ) { // Apply pattern guidance. // If the predicted match metric is within defined percentage of the // best calculated one, then override the calculated match with the // predicted match. i = 0; while ( pred[i].metric != 0xffffffff ) { cx->predicted = pred[i].predicted; cx->predicted_metric = pred[i].predicted_metric; #ifdef DEBUG_PATTERN_GUIDANCE fprintf(stderr, "%s: pos=%d predicted=%d\n", __FUNCTION__, pos, cx->predicted); #endif if ( cx->chosen != cx->predicted ) { // The chosen frame doesn't match the prediction. if ( cx->predicted_metric == 0 ) cx->mismatch = 0.0; else cx->mismatch = (100.0 * abs( cx->predicted_metric - cx->lowest )) / cx->predicted_metric; if ( (int) cx->mismatch <= cx->gthresh ) { // It's close enough, so use the predicted one. if ( !cx->found ) { cx->chosen = cx->predicted; cx->override = 1; } cx->inpattern = 1; break; } else { // Looks like we're not in a predictable pattern. cx->inpattern = 0; } } else { cx->inpattern = 1; cx->mismatch = 0.0; break; } i++; } } } } // Check the match for progressive versus interlaced. if ( cx->post ) { if (cx->chosen == P) cx->vmetric = cx->pblock; else if (cx->chosen == C) cx->vmetric = cx->cblock; else if (cx->chosen == N) cx->vmetric = cx->npblock; if ( !cx->found && cx->back == BACK_ON_COMBED && cx->vmetric > cx->bthresh && cx->p < cx->lowest ) { // Backward match. cx->vmetric = cx->pblock; cx->chosen = P; cx->inpattern = 0; cx->mismatch = 100; } if ( cx->vmetric > cx->vthresh ) { // After field matching and pattern guidance the frame is still combed. cx->film = 0; if ( !cx->found && ( cx->post == POST_FULL_NOMATCH || cx->post == POST_FULL_NOMATCH_MAP ) ) { cx->chosen = C; cx->vmetric = cx->cblock; cx->inpattern = 0; cx->mismatch = 100; } } } cx->vthresh = cx->vthresh_saved; // Setup strings for debug info. if ( cx->inpattern && !cx->override ) strcpy( cx->status, "[in-pattern]" ); else if ( cx->inpattern && cx->override ) strcpy( cx->status, "[in-pattern*]" ); else strcpy( cx->status, "[out-of-pattern]" ); // Assemble and output the reconstructed frame according to the final match. cx->dstp = *image; if ( cx->chosen == N ) { // The best match was with the next frame. if ( cx->tff ) { BitBlt( cx->dstp, 2 * cx->dpitch, cx->fnrp, 2 * cx->pitch, cx->w, cx->hover2 ); BitBlt( cx->dstp + cx->dpitch, 2 * cx->dpitch, cx->fcrp + cx->pitch, 2 * cx->pitch, cx->w, cx->hover2 ); } else { BitBlt( cx->dstp, 2 * cx->dpitch, cx->fcrp, 2 * cx->pitch, cx->w, cx->hplus1over2 ); BitBlt( cx->dstp + cx->dpitch, 2 * cx->dpitch, cx->fnrp + cx->pitch, 2 * cx->pitch, cx->w, cx->hover2 ); } } else if ( cx->chosen == C ) { // The best match was with the current frame. BitBlt( cx->dstp, 2 * cx->dpitch, cx->fcrp, 2 * cx->pitch, cx->w, cx->hplus1over2 ); BitBlt( cx->dstp + cx->dpitch, 2 * cx->dpitch, cx->fcrp + cx->pitch, 2 * cx->pitch, cx->w, cx->hover2 ); } else if ( ! cx->tff ) { // The best match was with the previous frame. BitBlt( cx->dstp, 2 * cx->dpitch, cx->fprp, 2 * cx->pitch, cx->w, cx->hplus1over2 ); BitBlt( cx->dstp + cx->dpitch, 2 * cx->dpitch, cx->fcrp + cx->pitch, 2 * cx->pitch, cx->w, cx->hover2 ); } else { // The best match was with the previous frame. BitBlt( cx->dstp, 2 * cx->dpitch, cx->fcrp, 2 * cx->pitch, cx->w, cx->hplus1over2 ); BitBlt( cx->dstp + cx->dpitch, 2 * cx->dpitch, cx->fprp + cx->pitch, 2 * cx->pitch, cx->w, cx->hover2 ); } if ( cx->guide ) PutChosen( cx, pos, cx->chosen ); if ( !cx->post || cx->post == POST_METRICS ) { if ( cx->force == '+') cx->film = 0; else if ( cx->force == '-' ) cx->film = 1; } else if ((cx->force == '+') || ((cx->post == POST_FULL || cx->post == POST_FULL_MAP || cx->post == POST_FULL_NOMATCH || cx->post == POST_FULL_NOMATCH_MAP) && (cx->film == 0 && cx->force != '-'))) { unsigned char *dstpp, *dstpn; int v1, v2; if ( cx->blend ) { // Do first and last lines. uint8_t *final = mlt_pool_alloc( image_size ); cx->finalp = final; mlt_frame_set_image( frame, final, image_size, mlt_pool_release ); dstpn = cx->dstp + cx->dpitch; for ( cx->x = 0; cx->x < cx->w; cx->x++ ) { cx->finalp[cx->x] = (((int)cx->dstp[cx->x] + (int)dstpn[cx->x]) >> 1); } cx->finalp = final + (cx->h-1)*cx->dpitch; cx->dstp = *image + (cx->h-1)*cx->dpitch; dstpp = cx->dstp - cx->dpitch; for ( cx->x = 0; cx->x < cx->w; cx->x++ ) { cx->finalp[cx->x] = (((int)cx->dstp[cx->x] + (int)dstpp[cx->x]) >> 1); } // Now do the rest. cx->dstp = *image + cx->dpitch; dstpp = cx->dstp - cx->dpitch; dstpn = cx->dstp + cx->dpitch; cx->finalp = final + cx->dpitch; for ( cx->y = 1; cx->y < cx->h - 1; cx->y++ ) { for ( cx->x = 0; cx->x < cx->w; cx->x++ ) { v1 = (int) cx->dstp[cx->x] - cx->dthresh; if ( v1 < 0 ) v1 = 0; v2 = (int) cx->dstp[cx->x] + cx->dthresh; if (v2 > 235) v2 = 235; if ((v1 > dstpp[cx->x] && v1 > dstpn[cx->x]) || (v2 < dstpp[cx->x] && v2 < dstpn[cx->x])) { if ( cx->post == POST_FULL_MAP || cx->post == POST_FULL_NOMATCH_MAP ) { if (cx->x & 1) cx->finalp[cx->x] = 128; else cx->finalp[cx->x] = 235; } else cx->finalp[cx->x] = ((int)dstpp[cx->x] + (int)dstpn[cx->x] + (int)cx->dstp[cx->x] + (int)cx->dstp[cx->x]) >> 2; } else cx->finalp[cx->x] = cx->dstp[cx->x]; } cx->finalp += cx->dpitch; cx->dstp += cx->dpitch; dstpp += cx->dpitch; dstpn += cx->dpitch; } if (cx->show ) Show( cx, pos, frame_properties); if (cx->debug) Debug(cx, pos); if (cx->hints) WriteHints(cx->film, cx->inpattern, frame_properties); goto final; } // Interpolate mode. cx->dstp = *image + cx->dpitch; dstpp = cx->dstp - cx->dpitch; dstpn = cx->dstp + cx->dpitch; for ( cx->y = 1; cx->y < cx->h - 1; cx->y+=2 ) { for ( cx->x = 0; cx->x < cx->w; cx->x++ ) { v1 = (int) cx->dstp[cx->x] - cx->dthresh; if (v1 < 0) v1 = 0; v2 = (int) cx->dstp[cx->x] + cx->dthresh; if (v2 > 235) v2 = 235; if ((v1 > dstpp[cx->x] && v1 > dstpn[cx->x]) || (v2 < dstpp[cx->x] && v2 < dstpn[cx->x])) { if ( cx->post == POST_FULL_MAP || cx->post == POST_FULL_NOMATCH_MAP ) { if (cx->x & 1) cx->dstp[cx->x] = 128; else cx->dstp[cx->x] = 235; } else cx->dstp[cx->x] = (dstpp[cx->x] + dstpn[cx->x]) >> 1; } } cx->dstp += 2 * cx->dpitch; dstpp += 2 * cx->dpitch; dstpn += 2 * cx->dpitch; } } if (cx->show ) Show( cx, pos, frame_properties); if (cx->debug) Debug(cx, pos); if (cx->hints) WriteHints(cx->film, cx->inpattern, frame_properties); final: // Flush frame at tail of period from the cache sprintf( key, MLT_POSITION_FMT, pos - 1 ); mlt_properties_set_data( cx->image_cache, key, NULL, 0, NULL, NULL ); } else { // Signal the first {cycle} frames as invalid mlt_properties_set_int( frame_properties, "garbage", 1 ); } } else if ( error == 0 && *format == mlt_image_yuv420p ) { fprintf(stderr,"%s: %d pos " MLT_POSITION_FMT "\n", __FUNCTION__, *width * *height * 3/2, mlt_frame_get_position(frame) ); } return error; } /** Process the frame object. */ static mlt_frame process( mlt_filter this, mlt_frame frame ) { // Push the filter on to the stack mlt_frame_push_service( frame, this ); // Push the frame filter mlt_frame_push_get_image( frame, get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_telecide_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = process; // Allocate the context and set up for garbage collection context cx = (context) mlt_pool_alloc( sizeof(struct context_s) ); memset( cx, 0, sizeof( struct context_s ) ); mlt_properties properties = MLT_FILTER_PROPERTIES( this ); mlt_properties_set_data( properties, "context", cx, sizeof(struct context_s), (mlt_destructor)mlt_pool_release, NULL ); // Allocate the metrics cache and set up for garbage collection cx->cache = (struct CACHE_ENTRY *) mlt_pool_alloc(CACHE_SIZE * sizeof(struct CACHE_ENTRY )); mlt_properties_set_data( properties, "cache", cx->cache, CACHE_SIZE * sizeof(struct CACHE_ENTRY), (mlt_destructor)mlt_pool_release, NULL ); int i; for (i = 0; i < CACHE_SIZE; i++) { cx->cache[i].frame = 0xffffffff; cx->cache[i].chosen = 0xff; } // Allocate the image cache and set up for garbage collection cx->image_cache = mlt_properties_new(); mlt_properties_set_data( properties, "image_cache", cx->image_cache, 0, (mlt_destructor)mlt_properties_close, NULL ); // Initialize the parameter defaults mlt_properties_set_int( properties, "guide", 0 ); mlt_properties_set_int( properties, "back", 0 ); mlt_properties_set_int( properties, "chroma", 0 ); mlt_properties_set_int( properties, "post", POST_FULL ); mlt_properties_set_double( properties, "gthresh", 10.0 ); mlt_properties_set_double( properties, "vthresh", 50.0 ); mlt_properties_set_double( properties, "bthresh", 50.0 ); mlt_properties_set_double( properties, "dthresh", 7.0 ); mlt_properties_set_int( properties, "blend", 0 ); mlt_properties_set_int( properties, "nt", 10 ); mlt_properties_set_int( properties, "y0", 0 ); mlt_properties_set_int( properties, "y1", 0 ); mlt_properties_set_int( properties, "hints", 1 ); } return this; } mlt-0.9.0/src/modules/dgraft/gpl000066400000000000000000000000001215300731300165100ustar00rootroot00000000000000mlt-0.9.0/src/modules/dv/000077500000000000000000000000001215300731300151575ustar00rootroot00000000000000mlt-0.9.0/src/modules/dv/Makefile000066400000000000000000000012731215300731300166220ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lpthread include ../../../config.mak TARGET = ../libmltdv$(LIBSUF) OBJS = factory.o \ producer_libdv.o \ consumer_libdv.o CFLAGS += `pkg-config --cflags libdv` LDFLAGS += `pkg-config --libs libdv` SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/dv" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/dv" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/dv/configure000077500000000000000000000003151215300731300170650ustar00rootroot00000000000000#!/bin/sh if [ "$help" != "1" ] then pkg-config libdv 2> /dev/null disable_libdv=$? if [ "$disable_libdv" != "0" ] then echo "- libdv not found: disabling" touch ../disable-dv exit 0 fi fi mlt-0.9.0/src/modules/dv/consumer_libdv.c000066400000000000000000000304611215300731300203420ustar00rootroot00000000000000/* * consumer_libdv.c -- a DV encoder based on libdv * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // mlt Header files #include #include // System header files #include #include #include #include // libdv header files #include #define FRAME_SIZE_525_60 10 * 150 * 80 #define FRAME_SIZE_625_50 12 * 150 * 80 // Forward references. static int consumer_start( mlt_consumer this ); static int consumer_stop( mlt_consumer this ); static int consumer_is_stopped( mlt_consumer this ); static int consumer_encode_video( mlt_consumer this, uint8_t *dv_frame, mlt_frame frame ); static void consumer_encode_audio( mlt_consumer this, uint8_t *dv_frame, mlt_frame frame ); static void consumer_output( mlt_consumer this, uint8_t *dv_frame, int size, mlt_frame frame ); static void *consumer_thread( void *arg ); static void consumer_close( mlt_consumer this ); /** Initialise the dv consumer. */ mlt_consumer consumer_libdv_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Allocate the consumer mlt_consumer this = calloc( 1, sizeof( struct mlt_consumer_s ) ); // If memory allocated and initialises without error if ( this != NULL && mlt_consumer_init( this, NULL, profile ) == 0 ) { // Get properties from the consumer mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); // Assign close callback this->close = consumer_close; // Interpret the argument if ( arg != NULL ) mlt_properties_set( properties, "target", arg ); // Set the encode and output handling method mlt_properties_set_data( properties, "video", consumer_encode_video, 0, NULL, NULL ); mlt_properties_set_data( properties, "audio", consumer_encode_audio, 0, NULL, NULL ); mlt_properties_set_data( properties, "output", consumer_output, 0, NULL, NULL ); // Terminate at end of the stream by default mlt_properties_set_int( properties, "terminate_on_pause", 1 ); // Set up start/stop/terminated callbacks this->start = consumer_start; this->stop = consumer_stop; this->is_stopped = consumer_is_stopped; } else { // Clean up in case of init failure free( this ); this = NULL; } // Return this return this; } /** Start the consumer. */ static int consumer_start( mlt_consumer this ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); // Check that we're not already running if ( !mlt_properties_get_int( properties, "running" ) ) { // Allocate a thread pthread_t *thread = calloc( 1, sizeof( pthread_t ) ); // Assign the thread to properties mlt_properties_set_data( properties, "thread", thread, sizeof( pthread_t ), free, NULL ); // Set the running state mlt_properties_set_int( properties, "running", 1 ); // Create the thread pthread_create( thread, NULL, consumer_thread, this ); } return 0; } /** Stop the consumer. */ static int consumer_stop( mlt_consumer this ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); // Check that we're running if ( mlt_properties_get_int( properties, "running" ) ) { // Get the thread pthread_t *thread = mlt_properties_get_data( properties, "thread", NULL ); // Stop the thread mlt_properties_set_int( properties, "running", 0 ); // Wait for termination pthread_join( *thread, NULL ); // Close the output file :-) - this is obtuse - doesn't matter if output file // exists or not - the destructor will kick in if it does mlt_properties_set_data( properties, "output_file", NULL, 0, NULL, NULL ); } return 0; } /** Determine if the consumer is stopped. */ static int consumer_is_stopped( mlt_consumer this ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); return !mlt_properties_get_int( properties, "running" ); } /** Get or create a new libdv encoder. */ static dv_encoder_t *libdv_get_encoder( mlt_consumer this, mlt_frame frame ) { // Get the properties of the consumer mlt_properties this_properties = MLT_CONSUMER_PROPERTIES( this ); // Obtain the dv_encoder dv_encoder_t *encoder = mlt_properties_get_data( this_properties, "dv_encoder", NULL ); // Construct one if we don't have one if ( encoder == NULL ) { // Get the fps of the consumer (for now - should be from frame) double fps = mlt_properties_get_double( this_properties, "fps" ); // Create the encoder encoder = dv_encoder_new( 0, 0, 0 ); // Encoder settings encoder->isPAL = fps == 25; encoder->is16x9 = 0; encoder->vlc_encode_passes = 1; encoder->static_qno = 0; encoder->force_dct = DV_DCT_AUTO; // Store the encoder on the properties mlt_properties_set_data( this_properties, "dv_encoder", encoder, 0, ( mlt_destructor )dv_encoder_free, NULL ); } // Return the encoder return encoder; } /** The libdv encode video method. */ static int consumer_encode_video( mlt_consumer this, uint8_t *dv_frame, mlt_frame frame ) { // Obtain the dv_encoder dv_encoder_t *encoder = libdv_get_encoder( this, frame ); // Get the properties of the consumer mlt_properties this_properties = MLT_CONSUMER_PROPERTIES( this ); // This will hold the size of the dv frame int size = 0; // Is the image rendered int rendered = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "rendered" ); // Get width and height int width = mlt_properties_get_int( this_properties, "width" ); int height = mlt_properties_get_int( this_properties, "height" ); // If we get an encoder, then encode the image if ( rendered && encoder != NULL ) { // Specify desired image properties mlt_image_format fmt = mlt_image_yuv422; uint8_t *image = NULL; // Get the image mlt_frame_get_image( frame, &image, &fmt, &width, &height, 0 ); // Check that we get what we expected if ( fmt != mlt_image_yuv422 || width != mlt_properties_get_int( this_properties, "width" ) || height != mlt_properties_get_int( this_properties, "height" ) || image == NULL ) { // We should try to recover here fprintf( stderr, "We have a problem houston...\n" ); } else { // Calculate the size of the dv frame size = height == 576 ? FRAME_SIZE_625_50 : FRAME_SIZE_525_60; } // Process the frame if ( size != 0 ) { // Encode the image dv_encode_full_frame( encoder, &image, e_dv_color_yuv, dv_frame ); } mlt_events_fire( this_properties, "consumer-frame-show", frame, NULL ); } else if ( encoder != NULL ) { // Calculate the size of the dv frame (duplicate of previous) size = height == 576 ? FRAME_SIZE_625_50 : FRAME_SIZE_525_60; } return size; } /** The libdv encode audio method. */ static void consumer_encode_audio( mlt_consumer this, uint8_t *dv_frame, mlt_frame frame ) { // Get the properties of the consumer mlt_properties this_properties = MLT_CONSUMER_PROPERTIES( this ); // Get the properties of the frame mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); // Obtain the dv_encoder dv_encoder_t *encoder = libdv_get_encoder( this, frame ); // Only continue if we have an encoder if ( encoder != NULL ) { // Get the frame count int count = mlt_properties_get_int( this_properties, "count" ); // Default audio args mlt_audio_format fmt = mlt_audio_s16; int channels = 2; int frequency = mlt_properties_get_int( this_properties, "frequency" ); int samples = mlt_sample_calculator( mlt_properties_get_double( this_properties, "fps" ), frequency, count ); int16_t *pcm = NULL; // Get the frame number time_t start = time( NULL ); int height = mlt_properties_get_int( this_properties, "height" ); int is_pal = height == 576; int is_wide = mlt_properties_get_int( this_properties, "display_aspect_num" ) == 16; // Temporary - audio buffer allocation int16_t *audio_buffers[ 4 ]; int i = 0; int j = 0; for ( i = 0 ; i < 4; i ++ ) audio_buffers[ i ] = mlt_pool_alloc( 2 * DV_AUDIO_MAX_SAMPLES ); // Get the audio mlt_frame_get_audio( frame, (void**) &pcm, &fmt, &frequency, &channels, &samples ); // Inform the encoder of the number of audio samples encoder->samples_this_frame = samples; // Fill the audio buffers correctly if ( mlt_properties_get_double( frame_properties, "_speed" ) == 1.0 ) { for ( i = 0; i < samples; i ++ ) for ( j = 0; j < channels; j++ ) audio_buffers[ j ][ i ] = *pcm ++; } else { for ( j = 0; j < channels; j++ ) memset( audio_buffers[ j ], 0, 2 * DV_AUDIO_MAX_SAMPLES ); } // Encode audio on frame dv_encode_full_audio( encoder, audio_buffers, channels, frequency, dv_frame ); // Specify meta data on the frame dv_encode_metadata( dv_frame, is_pal, is_wide, &start, count ); dv_encode_timecode( dv_frame, is_pal, count ); // Update properties mlt_properties_set_int( this_properties, "count", ++ count ); // Temporary - free audio buffers for ( i = 0 ; i < 4; i ++ ) mlt_pool_release( audio_buffers[ i ] ); } } /** The libdv output method. */ static void consumer_output( mlt_consumer this, uint8_t *dv_frame, int size, mlt_frame frame ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); FILE *output = stdout; char *target = mlt_properties_get( properties, "target" ); if ( target != NULL ) { output = mlt_properties_get_data( properties, "output_file", NULL ); if ( output == NULL ) { output = fopen( target, "w" ); if ( output != NULL ) mlt_properties_set_data( properties, "output_file", output, 0, ( mlt_destructor )fclose, 0 ); } } if ( output != NULL ) { fwrite( dv_frame, size, 1, output ); fflush( output ); } else { fprintf( stderr, "Unable to open %s\n", target ); } } /** The main thread - the argument is simply the consumer. */ static void *consumer_thread( void *arg ) { // Map the argument to the object mlt_consumer this = arg; // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); // Get the terminate_on_pause property int top = mlt_properties_get_int( properties, "terminate_on_pause" ); // Get the handling methods int ( *video )( mlt_consumer, uint8_t *, mlt_frame ) = mlt_properties_get_data( properties, "video", NULL ); int ( *audio )( mlt_consumer, uint8_t *, mlt_frame ) = mlt_properties_get_data( properties, "audio", NULL ); int ( *output )( mlt_consumer, uint8_t *, int, mlt_frame ) = mlt_properties_get_data( properties, "output", NULL ); // Allocate a single PAL frame for encoding uint8_t *dv_frame = mlt_pool_alloc( FRAME_SIZE_625_50 ); // Frame and size mlt_frame frame = NULL; int size = 0; // Loop while running while( mlt_properties_get_int( properties, "running" ) ) { // Get the frame frame = mlt_consumer_rt_frame( this ); // Check that we have a frame to work with if ( frame != NULL ) { // Terminate on pause if ( top && mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0 ) { mlt_frame_close( frame ); break; } // Obtain the dv_encoder if ( libdv_get_encoder( this, frame ) != NULL ) { // Encode the image size = video( this, dv_frame, frame ); // Encode the audio if ( size > 0 ) audio( this, dv_frame, frame ); // Output the frame output( this, dv_frame, size, frame ); // Close the frame mlt_frame_close( frame ); } else { fprintf( stderr, "Unable to obtain dv encoder.\n" ); } } } // Tidy up mlt_pool_release( dv_frame ); mlt_consumer_stopped( this ); return NULL; } /** Close the consumer. */ static void consumer_close( mlt_consumer this ) { // Stop the consumer mlt_consumer_stop( this ); // Close the parent mlt_consumer_close( this ); // Free the memory free( this ); } mlt-0.9.0/src/modules/dv/consumer_libdv.yml000066400000000000000000000006321215300731300207160ustar00rootroot00000000000000schema_version: 0.1 type: consumer identifier: libdv title: libdv version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Audio - Video description: > DV consumer using libdv. parameters: - identifier: argument title: File type: string description: The filename to write to, e.g. /dev/dv1394. required: yes widget: filesave mlt-0.9.0/src/modules/dv/factory.c000066400000000000000000000033241215300731300167740ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include extern mlt_consumer consumer_libdv_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_libdv_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/dv/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( consumer_type, "libdv", consumer_libdv_init ); MLT_REGISTER( producer_type, "libdv", producer_libdv_init ); MLT_REGISTER_METADATA( consumer_type, "libdv", metadata, "consumer_libdv.yml" ); MLT_REGISTER_METADATA( producer_type, "libdv", metadata, "producer_libdv.yml" ); } mlt-0.9.0/src/modules/dv/producer_libdv.c000066400000000000000000000402051215300731300203270ustar00rootroot00000000000000/* * producer_libdv.c -- simple libdv test case * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define FRAME_SIZE_525_60 10 * 150 * 80 #define FRAME_SIZE_625_50 12 * 150 * 80 /** To conserve resources, we maintain a stack of dv decoders. */ static pthread_mutex_t decoder_lock = PTHREAD_MUTEX_INITIALIZER; static mlt_properties dv_decoders = NULL; dv_decoder_t *dv_decoder_alloc( ) { // We'll return a dv_decoder dv_decoder_t *this = NULL; // Lock the mutex pthread_mutex_lock( &decoder_lock ); // Create the properties if necessary if ( dv_decoders == NULL ) { // Create the properties dv_decoders = mlt_properties_new( ); // Create the stack mlt_properties_set_data( dv_decoders, "stack", mlt_deque_init( ), 0, ( mlt_destructor )mlt_deque_close, NULL ); // Register the properties for clean up mlt_factory_register_for_clean_up( dv_decoders, ( mlt_destructor )mlt_properties_close ); } // Now try to obtain a decoder if ( dv_decoders != NULL ) { // Obtain the stack mlt_deque stack = mlt_properties_get_data( dv_decoders, "stack", NULL ); // Pop the top of the stack this = mlt_deque_pop_back( stack ); // Create a new decoder if none available if ( this == NULL ) { // We'll need a unique property ID for this char label[ 256 ]; // Configure the decoder this = dv_decoder_new( FALSE, FALSE, FALSE ); this->quality = DV_QUALITY_COLOR | DV_QUALITY_AC_2; this->audio->arg_audio_emphasis = 2; dv_set_audio_correction( this, DV_AUDIO_CORRECT_AVERAGE ); dv_set_error_log( this, NULL ); // Register it with the properties to ensure clean up sprintf( label, "%p", this ); mlt_properties_set_data( dv_decoders, label, this, 0, ( mlt_destructor )dv_decoder_free, NULL ); } } // Unlock the mutex pthread_mutex_unlock( &decoder_lock ); return this; } void dv_decoder_return( dv_decoder_t *this ) { // Lock the mutex pthread_mutex_lock( &decoder_lock ); // Now try to return the decoder if ( dv_decoders != NULL ) { // Obtain the stack mlt_deque stack = mlt_properties_get_data( dv_decoders, "stack", NULL ); // Push it back mlt_deque_push_back( stack, this ); } // Unlock the mutex pthread_mutex_unlock( &decoder_lock ); } typedef struct producer_libdv_s *producer_libdv; struct producer_libdv_s { struct mlt_producer_s parent; int fd; int is_pal; uint64_t file_size; int frame_size; long frames_in_file; mlt_producer alternative; }; static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ); static void producer_close( mlt_producer parent ); static int producer_collect_info( producer_libdv this, mlt_profile profile ); mlt_producer producer_libdv_init( mlt_profile profile, mlt_service_type type, const char *id, char *filename ) { producer_libdv this = calloc( 1, sizeof( struct producer_libdv_s ) ); if ( filename != NULL && this != NULL && mlt_producer_init( &this->parent, this ) == 0 ) { int destroy = 0; mlt_producer producer = &this->parent; mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); // Set the resource property (required for all producers) mlt_properties_set( properties, "resource", filename ); // Register transport implementation with the producer producer->close = ( mlt_destructor )producer_close; // Register our get_frame implementation with the producer producer->get_frame = producer_get_frame; // If we have mov or dv, then we'll use an alternative producer if ( strchr( filename, '.' ) != NULL && ( strncasecmp( strrchr( filename, '.' ), ".avi", 4 ) == 0 || strncasecmp( strrchr( filename, '.' ), ".mov", 4 ) == 0 ) ) { // Load via an alternative mechanism mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); this->alternative = mlt_factory_producer( profile, "kino", filename ); // If it's unavailable, then clean up if ( this->alternative == NULL ) destroy = 1; else mlt_properties_pass( properties, MLT_PRODUCER_PROPERTIES( this->alternative ), "" ); this->is_pal = ( ( int ) mlt_producer_get_fps( producer ) ) == 25; } else { // Open the file if specified this->fd = open( filename, O_RDONLY ); // Collect info if ( this->fd == -1 || !producer_collect_info( this, profile ) ) destroy = 1; } // If we couldn't open the file, then destroy it now if ( destroy ) { mlt_producer_close( producer ); producer = NULL; } // Return the producer return producer; } free( this ); return NULL; } static int read_frame( int fd, uint8_t* frame_buf, int *isPAL ) { int result = read( fd, frame_buf, FRAME_SIZE_525_60 ) == FRAME_SIZE_525_60; if ( result ) { *isPAL = ( frame_buf[3] & 0x80 ); if ( *isPAL ) { int diff = FRAME_SIZE_625_50 - FRAME_SIZE_525_60; result = read( fd, frame_buf + FRAME_SIZE_525_60, diff ) == diff; } } return result; } static int producer_collect_info( producer_libdv this, mlt_profile profile ) { int valid = 0; uint8_t *dv_data = mlt_pool_alloc( FRAME_SIZE_625_50 ); if ( dv_data != NULL ) { // Read the first frame valid = read_frame( this->fd, dv_data, &this->is_pal ); // If it looks like a valid frame, the get stats if ( valid ) { double aspect_ratio; // Get the properties mlt_properties properties = MLT_PRODUCER_PROPERTIES( &this->parent ); // Get a dv_decoder dv_decoder_t *dv_decoder = dv_decoder_alloc( ); // Determine the file size struct stat buf; fstat( this->fd, &buf ); // Store the file size this->file_size = buf.st_size; // Determine the frame size this->frame_size = this->is_pal ? FRAME_SIZE_625_50 : FRAME_SIZE_525_60; // Determine the number of frames in the file this->frames_in_file = this->file_size / this->frame_size; // Calculate default in/out points int fps = 1000 * ( this->is_pal ? 25 : ( 30000.0 / 1001.0 ) ); if ( ( int )( mlt_profile_fps( profile ) * 1000 ) == fps ) { if ( this->frames_in_file > 0 ) { mlt_properties_set_position( properties, "length", this->frames_in_file ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", this->frames_in_file - 1 ); } } else { valid = 0; } // Parse the header for meta info dv_parse_header( dv_decoder, dv_data ); if ( this->is_pal ) { if ( dv_format_wide( dv_decoder ) ) aspect_ratio = 64.0 / 45.0; else aspect_ratio = 16.0 / 15.0; } else { if ( dv_format_wide( dv_decoder ) ) aspect_ratio = 32.0 / 27.0; else aspect_ratio = 8 / 9; } mlt_properties_set_double( properties, "aspect_ratio", aspect_ratio); mlt_properties_set_int( properties, "meta.media.nb_streams", 2 ); mlt_properties_set_int( properties, "video_index", 0 ); mlt_properties_set( properties, "meta.media.0.stream.type", "video" ); mlt_properties_set( properties, "meta.media.0.codec.name", "dvvideo" ); mlt_properties_set( properties, "meta.media.0.codec.long_name", "DV (Digital Video)" ); mlt_properties_set_int( properties, "audio_index", 1 ); mlt_properties_set( properties, "meta.media.1.stream.type", "audio" ); mlt_properties_set( properties, "meta.media.1.codec.name", "pcm_s16le" ); mlt_properties_set( properties, "meta.media.1.codec.long_name", "signed 16-bit little-endian PCM" ); mlt_properties_set_int( properties, "meta.media.width", 720 ); mlt_properties_set_int( properties, "meta.media.height", this->is_pal ? 576 : 480 ); mlt_properties_set_int( properties, "meta.media.frame_rate_num", this->is_pal? 25 : 30000 ); mlt_properties_set_int( properties, "meta.media.frame_rate_den", this->is_pal? 1 : 1001 ); // Return the decoder dv_decoder_return( dv_decoder ); } mlt_pool_release( dv_data ); } return valid; } static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { int pitches[3] = { 0, 0, 0 }; uint8_t *pixels[3] = { NULL, NULL, NULL }; // Get the frames properties mlt_properties properties = MLT_FRAME_PROPERTIES( this ); // Get a dv_decoder dv_decoder_t *decoder = dv_decoder_alloc( ); // Get the dv data uint8_t *dv_data = mlt_properties_get_data( properties, "dv_data", NULL ); // Get and set the quality request char *quality = mlt_frame_pop_service( this ); if ( quality != NULL ) { if ( strncmp( quality, "fast", 4 ) == 0 ) decoder->quality = ( DV_QUALITY_COLOR | DV_QUALITY_DC ); else if ( strncmp( quality, "best", 4 ) == 0 ) decoder->quality = ( DV_QUALITY_COLOR | DV_QUALITY_AC_2 ); else decoder->quality = ( DV_QUALITY_COLOR | DV_QUALITY_AC_1 ); } // Parse the header for meta info dv_parse_header( decoder, dv_data ); // Assign width and height according to the frame *width = 720; *height = dv_data[ 3 ] & 0x80 ? 576 : 480; // Extract an image of the format requested if ( *format != mlt_image_rgb24 ) { // Allocate an image uint8_t *image = mlt_pool_alloc( *width * ( *height + 1 ) * 2 ); // Pass to properties for clean up mlt_frame_set_image( this, image, *width * ( *height + 1 ) * 2, mlt_pool_release ); // Decode the image pitches[ 0 ] = *width * 2; pixels[ 0 ] = image; dv_decode_full_frame( decoder, dv_data, e_dv_color_yuv, pixels, pitches ); // Assign result *buffer = image; *format = mlt_image_yuv422; } else { // Allocate an image uint8_t *image = mlt_pool_alloc( *width * ( *height + 1 ) * 3 ); // Pass to properties for clean up mlt_frame_set_image( this, image, *width * ( *height + 1 ) * 3, mlt_pool_release ); // Decode the frame pitches[ 0 ] = 720 * 3; pixels[ 0 ] = image; dv_decode_full_frame( decoder, dv_data, e_dv_color_rgb, pixels, pitches ); // Assign result *buffer = image; *format = mlt_image_rgb24; } // Return the decoder dv_decoder_return( decoder ); return 0; } static int producer_get_audio( mlt_frame this, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { int16_t *p; int i, j; int16_t *audio_channels[ 4 ]; // Get the frames properties mlt_properties properties = MLT_FRAME_PROPERTIES( this ); // Get a dv_decoder dv_decoder_t *decoder = dv_decoder_alloc( ); // Get the dv data uint8_t *dv_data = mlt_properties_get_data( properties, "dv_data", NULL ); // Parse the header for meta info dv_parse_header( decoder, dv_data ); // Check that we have audio if ( decoder->audio->num_channels > 0 ) { int size = *channels * DV_AUDIO_MAX_SAMPLES * sizeof( int16_t ); // Obtain required values *frequency = decoder->audio->frequency; *samples = decoder->audio->samples_this_frame; *channels = decoder->audio->num_channels; *format = mlt_audio_s16; // Create a temporary workspace for ( i = 0; i < 4; i++ ) audio_channels[ i ] = mlt_pool_alloc( DV_AUDIO_MAX_SAMPLES * sizeof( int16_t ) ); // Create a workspace for the result *buffer = mlt_pool_alloc( size ); // Pass the allocated audio buffer as a property mlt_frame_set_audio( this, *buffer, *format, size, mlt_pool_release ); // Decode the audio dv_decode_full_audio( decoder, dv_data, audio_channels ); // Interleave the audio p = *buffer; for ( i = 0; i < *samples; i++ ) for ( j = 0; j < *channels; j++ ) *p++ = audio_channels[ j ][ i ]; // Free the temporary work space for ( i = 0; i < 4; i++ ) mlt_pool_release( audio_channels[ i ] ); } else { // No audio available on the frame, so get test audio (silence) mlt_frame_get_audio( this, buffer, format, frequency, channels, samples ); } // Return the decoder dv_decoder_return( decoder ); return 0; } static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Access the private data producer_libdv this = producer->child; // Will carry the frame data uint8_t *data = NULL; // Obtain the current frame number uint64_t position = mlt_producer_frame( producer ); if ( this->alternative == NULL ) { // Convert timecode to a file position (ensuring that we're on a frame boundary) uint64_t offset = position * this->frame_size; // Allocate space data = mlt_pool_alloc( FRAME_SIZE_625_50 ); // Create an empty frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); // Seek and fetch if ( this->fd != 0 && lseek( this->fd, offset, SEEK_SET ) == offset && read_frame( this->fd, data, &this->is_pal ) ) { // Pass the dv data mlt_properties_set_data( MLT_FRAME_PROPERTIES( *frame ), "dv_data", data, FRAME_SIZE_625_50, ( mlt_destructor )mlt_pool_release, NULL ); } else { mlt_pool_release( data ); data = NULL; } } else { // Seek mlt_producer_seek( this->alternative, position ); // Fetch mlt_service_get_frame( MLT_PRODUCER_SERVICE( this->alternative ), frame, 0 ); // Verify if ( *frame != NULL ) data = mlt_properties_get_data( MLT_FRAME_PROPERTIES( *frame ), "dv_data", NULL ); } if ( data != NULL ) { // Get the frames properties mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Get a dv_decoder dv_decoder_t *dv_decoder = dv_decoder_alloc( ); mlt_properties_set_int( properties, "test_image", 0 ); mlt_properties_set_int( properties, "test_audio", 0 ); // Update other info on the frame mlt_properties_set_int( properties, "width", 720 ); mlt_properties_set_int( properties, "height", this->is_pal ? 576 : 480 ); mlt_properties_set_int( properties, "top_field_first", !this->is_pal ? 0 : ( data[ 5 ] & 0x07 ) == 0 ? 0 : 1 ); mlt_properties_set_int( properties, "colorspace", 601 ); // Parse the header for meta info dv_parse_header( dv_decoder, data ); //mlt_properties_set_int( properties, "progressive", dv_is_progressive( dv_decoder ) ); mlt_properties_set_double( properties, "aspect_ratio", dv_format_wide( dv_decoder ) ? ( this->is_pal ? 118.0/81.0 : 40.0/33.0 ) : ( this->is_pal ? 59.0/54.0 : 10.0/11.0 ) ); mlt_properties_set_int( properties, "audio_frequency", dv_decoder->audio->frequency ); mlt_properties_set_int( properties, "audio_channels", dv_decoder->audio->num_channels ); // Register audio callback if ( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( producer ), "audio_index" ) > 0 ) mlt_frame_push_audio( *frame, producer_get_audio ); if ( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( producer ), "video_index" ) > -1 ) { // Push the quality string mlt_frame_push_service( *frame, mlt_properties_get( MLT_PRODUCER_PROPERTIES( producer ), "quality" ) ); // Push the get_image method on to the stack mlt_frame_push_get_image( *frame, producer_get_image ); } // Return the decoder dv_decoder_return( dv_decoder ); } // Update timecode on the frame we're creating if ( *frame != NULL ) mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; } static void producer_close( mlt_producer parent ) { // Obtain this producer_libdv this = parent->child; // Close the file if ( this->fd > 0 ) close( this->fd ); if ( this->alternative ) mlt_producer_close( this->alternative ); // Close the parent parent->close = NULL; mlt_producer_close( parent ); // Free the memory free( this ); } mlt-0.9.0/src/modules/dv/producer_libdv.yml000066400000000000000000000011121215300731300207000ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: libdv title: libdv version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Audio - Video description: A libdv based decoder for video and audio. parameters: - identifier: argument title: File type: string required: yes readonly: no widget: fileopen - identifier: quality title: Quality type: string description: One of "best," "fast" or anything else chooses medium. readonly: no mutable: yes widget: combo default: best mlt-0.9.0/src/modules/effectv/000077500000000000000000000000001215300731300161705ustar00rootroot00000000000000mlt-0.9.0/src/modules/effectv/Makefile000066400000000000000000000011721215300731300176310ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lm include ../../../config.mak TARGET = ../libmlteffectv$(LIBSUF) OBJS = factory.o \ filter_burn.o \ image.o \ utils.o SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/effectv" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/effectv" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/effectv/factory.c000066400000000000000000000030141215300731300200010ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2007 Stephane Fillod * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include extern mlt_filter filter_burn_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/effectv/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( filter_type, "BurningTV", filter_burn_init ); MLT_REGISTER( filter_type, "burningtv", filter_burn_init ); MLT_REGISTER_METADATA( filter_type, "BurningTV", metadata, "filter_burningtv.yml" ); MLT_REGISTER_METADATA( filter_type, "burningtv", metadata, "filter_burningtv.yml" ); } mlt-0.9.0/src/modules/effectv/filter_burn.c000066400000000000000000000132071215300731300206520ustar00rootroot00000000000000/* * filter_burn.c -- burning filter * Copyright (C) 2007 Stephane Fillod * * Filter taken from EffecTV - Realtime Digital Video Effector * Copyright (C) 2001-2006 FUKUCHI Kentaro * * BurningTV - burns incoming objects. * Copyright (C) 2001-2002 FUKUCHI Kentaro * * Fire routine is taken from Frank Jan Sorensen's demo program. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include "utils.h" #define MaxColor 120 #define Decay 15 #define MAGIC_THRESHOLD "50" static RGB32 palette[256]; static void makePalette(void) { int i, r, g, b; uint8_t *p = (uint8_t*) palette; for(i=0; i> 8)); i++; } i += 2; } } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Push the frame filter mlt_frame_push_service( frame, this ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_burn_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "foreground", "0" ); mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "threshold", MAGIC_THRESHOLD ); } if (!palette[128]) { makePalette(); } return this; } mlt-0.9.0/src/modules/effectv/filter_burningtv.yml000066400000000000000000000003631215300731300223000ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: burningtv title: BurningTV version: 1 copyright: FUKUCHI Kentaro, Stephane Fillod creator: FUKUCHI Kentaro, Stephane Fillod contributor: - Jan Sorensen license: GPLv2 language: en tags: - Video mlt-0.9.0/src/modules/effectv/gpl000066400000000000000000000000001215300731300166630ustar00rootroot00000000000000mlt-0.9.0/src/modules/effectv/image.c000066400000000000000000000136021215300731300174200ustar00rootroot00000000000000/* * EffecTV - Realtime Digital Video Effector * Copyright (C) 2001-2006 FUKUCHI Kentaro * * image.c: utilities for image processing. * */ #include #include #include "utils.h" /* * Collection of background subtraction functions */ /* checks only fake-Y value */ /* In these function Y value is treated as R*2+G*4+B. */ int image_set_threshold_y(int threshold) { int y_threshold = threshold * 7; /* fake-Y value is timed by 7 */ return y_threshold; } void image_bgset_y(RGB32 *background, const RGB32 *src, int video_area, int y_threshold) { int i; int R, G, B; const RGB32 *p; short *q; p = src; q = (short *)background; for(i=0; i>(16-1); G = ((*p)&0xff00)>>(8-2); B = (*p)&0xff; *q = (short)(R + G + B); p++; q++; } } void image_bgsubtract_y(unsigned char *diff, const RGB32 *background, const RGB32 *src, int video_area, int y_threshold) { int i; int R, G, B; const RGB32 *p; const short *q; unsigned char *r; int v; p = src; q = (const short *)background; r = diff; for(i=0; i>(16-1); G = ((*p)&0xff00)>>(8-2); B = (*p)&0xff; v = (R + G + B) - (int)(*q); *r = ((v + y_threshold)>>24) | ((y_threshold - v)>>24); p++; q++; r++; } /* The origin of subtraction function is; * diff(src, dest) = (abs(src - dest) > threshold) ? 0xff : 0; * * This functions is transformed to; * (threshold > (src - dest) > -threshold) ? 0 : 0xff; * * (v + threshold)>>24 is 0xff when v is less than -threshold. * (v - threshold)>>24 is 0xff when v is less than threshold. * So, ((v + threshold)>>24) | ((threshold - v)>>24) will become 0xff when * abs(src - dest) > threshold. */ } /* Background image is refreshed every frame */ void image_bgsubtract_update_y(unsigned char *diff, RGB32 *background, const RGB32 *src, int video_area, int y_threshold) { int i; int R, G, B; const RGB32 *p; short *q; unsigned char *r; int v; p = src; q = (short *)background; r = diff; for(i=0; i>(16-1); G = ((*p)&0xff00)>>(8-2); B = (*p)&0xff; v = (R + G + B) - (int)(*q); *q = (short)(R + G + B); *r = ((v + y_threshold)>>24) | ((y_threshold - v)>>24); p++; q++; r++; } } /* checks each RGB value */ /* The range of r, g, b are [0..7] */ RGB32 image_set_threshold_RGB(int r, int g, int b) { unsigned char R, G, B; RGB32 rgb_threshold; R = G = B = 0xff; R = R<>8); b = b ^ 0xffffff; a = a ^ b; a = a & rgb_threshold; *r++ = (0 - a)>>24; } } void image_bgsubtract_update_RGB(unsigned char *diff, RGB32 *background, const RGB32 *src, int video_area, RGB32 rgb_threshold) { int i; const RGB32 *p; RGB32 *q; unsigned a, b; unsigned char *r; p = src; q = background; r = diff; for(i=0; i>8); b = b ^ 0xffffff; a = a ^ b; a = a & rgb_threshold; *r++ = (0 - a)>>24; } } /* noise filter for subtracted image. */ void image_diff_filter(unsigned char *diff2, const unsigned char *diff, int width, int height) { int x, y; const unsigned char *src; unsigned char *dest; unsigned int count; unsigned int sum1, sum2, sum3; src = diff; dest = diff2 + width +1; for(y=1; y>24; src++; } dest += 2; } } /* Y value filters */ void image_y_over(unsigned char *diff, const RGB32 *src, int video_area, int y_threshold) { int i; int R, G, B, v; unsigned char *p = diff; for(i = video_area; i>0; i--) { R = ((*src)&0xff0000)>>(16-1); G = ((*src)&0xff00)>>(8-2); B = (*src)&0xff; v = y_threshold - (R + G + B); *p = (unsigned char)(v>>24); src++; p++; } } void image_y_under(unsigned char *diff, const RGB32 *src, int video_area, int y_threshold) { int i; int R, G, B, v; unsigned char *p = diff; for(i = video_area; i>0; i--) { R = ((*src)&0xff0000)>>(16-1); G = ((*src)&0xff00)>>(8-2); B = (*src)&0xff; v = (R + G + B) - y_threshold; *p = (unsigned char)(v>>24); src++; p++; } } /* tiny edge detection */ void image_edge(unsigned char *diff2, const RGB32 *src, int width, int height, int y_threshold) { int x, y; const unsigned char *p; unsigned char *q; int r, g, b; int ar, ag, ab; int w; p = (const unsigned char *)src; q = diff2; w = width * sizeof(RGB32); for(y=0; y y_threshold) { *q = 255; } else { *q = 0; } q++; p += 4; } p += 4; *q++ = 0; } memset(q, 0, width); } /* horizontal flipping */ void image_hflip(const RGB32 *src, RGB32 *dest, int width, int height) { int x, y; src += width - 1; for(y=0; y #include "utils.h" /* * HSI color system utilities */ static int itrunc(double f) { int i; i=(int)f; if(i<0)i=0; if(i>255)i=255; return i; } void HSItoRGB(double H, double S, double I, int *r, int *g, int *b) { double T,Rv,Gv,Bv; Rv=1+S*sin(H-2*M_PI/3); Gv=1+S*sin(H); Bv=1+S*sin(H+2*M_PI/3); T=255.999*I/2; *r=itrunc(Rv*T); *g=itrunc(Gv*T); *b=itrunc(Bv*T); } /* * fastrand - fast fake random number generator * Warning: The low-order bits of numbers generated by fastrand() * are bad as random numbers. For example, fastrand()%4 * generates 1,2,3,0,1,2,3,0... * You should use high-order bits. */ #ifdef __DARWIN__ static #endif unsigned int fastrand_val; unsigned int fastrand(void) { return (fastrand_val=fastrand_val*1103515245+12345); } void fastsrand(unsigned int seed) { fastrand_val = seed; } mlt-0.9.0/src/modules/effectv/utils.h000066400000000000000000000037361215300731300175120ustar00rootroot00000000000000/* * EffecTV - Realtime Digital Video Effector * Copyright (C) 2001-2006 FUKUCHI Kentaro * * utils.h: header file for utils * */ #ifndef __UTILS_H__ #define __UTILS_H__ #include typedef uint32_t RGB32; /* DEFINE's by nullset@dookie.net */ #define RED(n) ((n>>16) & 0x000000FF) #define GREEN(n) ((n>>8) & 0x000000FF) #define BLUE(n) ((n>>0) & 0x000000FF) #define RGB(r,g,b) ((0<<24) + (r<<16) + (g <<8) + (b)) #define INTENSITY(n) ( ( (RED(n)+GREEN(n)+BLUE(n))/3)) /* utils.c */ void HSItoRGB(double H, double S, double I, int *r, int *g, int *b); #ifndef __DARWIN__ extern unsigned int fastrand_val; #define inline_fastrand() (fastrand_val=fastrand_val*1103515245+12345) #endif unsigned int fastrand(void); void fastsrand(unsigned int); /* image.c */ int image_set_threshold_y(int threshold); void image_bgset_y(RGB32 *background, const RGB32 *src, int video_area, int y_threshold); void image_bgsubtract_y(unsigned char *diff, const RGB32 *background, const RGB32 *src, int video_area, int y_threshold); void image_bgsubtract_update_y(unsigned char *diff, RGB32 *background, const RGB32 *src, int video_area, int y_threshold); RGB32 image_set_threshold_RGB(int r, int g, int b); void image_bgset_RGB(RGB32 *background, const RGB32 *src, int video_area); void image_bgsubtract_RGB(unsigned char *diff, const RGB32 *background, const RGB32 *src, int video_area, RGB32 rgb_threshold); void image_bgsubtract_update_RGB(unsigned char *diff, RGB32 *background, const RGB32 *src, int video_area, RGB32 rgb_threshold); void image_diff_filter(unsigned char *diff2, const unsigned char *diff, int width, int height); void image_y_over(unsigned char *diff, const RGB32 *src, int video_area, int y_threshold); void image_y_under(unsigned char *diff, const RGB32 *src, int video_area, int y_threshold); void image_edge(unsigned char *diff2, const RGB32 *src, int width, int height, int y_threshold); void image_hflip(const RGB32 *src, RGB32 *dest, int width, int height); #endif /* __UTILS_H__ */ mlt-0.9.0/src/modules/feeds/000077500000000000000000000000001215300731300156345ustar00rootroot00000000000000mlt-0.9.0/src/modules/feeds/Makefile000066400000000000000000000004511215300731300172740ustar00rootroot00000000000000include ../../../config.mak all: depend: distclean: clean: install: all install -d "$(DESTDIR)$(mltdatadir)/feeds/PAL" install -d "$(DESTDIR)$(mltdatadir)/feeds/NTSC" install -m 644 PAL/*.* "$(DESTDIR)$(mltdatadir)/feeds/PAL" install -m 644 NTSC/*.* "$(DESTDIR)$(mltdatadir)/feeds/NTSC" mlt-0.9.0/src/modules/feeds/NTSC/000077500000000000000000000000001215300731300164035ustar00rootroot00000000000000mlt-0.9.0/src/modules/feeds/NTSC/data_fx.properties000066400000000000000000000043211215300731300221270ustar00rootroot00000000000000# This properties file describes the fx available to the data_feed and # data_show filters # # Syntax is as follows: # # name= # name.description= # name.properties.= # name.=value # etc # # Typically, the is a 'region' and additional filters are # included as properties using the normal region filter syntax. # # # The titles filter definition # titles=region .description=Titles .properties.markup=filter[1].producer.markup .type.markup=text .period=2 .properties.length[0]=filter[0].composite.out .properties.length[1]=filter[1].composite.out .composite.geometry=5%/70%:90%x20% .filter[0]=watermark .filter[0].resource=colour:0x000000ff .filter[0].composite.geometry=0%/0%:100%x100%:0;5=0%/0%:100%x100%:40 .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup=Shotcut .filter[1].composite.geometry=0%/0%:100%x100%:0;8=0%/0%:100%x100%:100 .filter[1].composite.titles=1 # # The top titles filter definition # top-titles=region .description=Top Titles .properties.markup=filter[1].producer.markup .type.markup=text .period=2 .properties.length[0]=filter[0].composite.out .properties.length[1]=filter[1].composite.out .composite.geometry=5%/5%:90%x20% .filter[0]=watermark .filter[0].resource=colour:0x000000ff .filter[0].composite.geometry=0%/0%:100%x100%:0;5=0%/0%:100%x100%:40 .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup=Shotcut .filter[1].composite.geometry=0%/0%:100%x100%:0;8=0%/0%:100%x100%:100 .filter[1].composite.halign=centre .filter[1].composite.titles=1 # # OK - Silly example... # tickertape=region .description=Tickertape .properties.markup=filter[1].producer.markup .type.markup=text .properties.length[0]=filter[1].composite.out .composite.geometry=0%/93%:100%x7% .filter[0]=watermark .filter[0].resource=colour:0x000000ff .filter[0].composite.geometry=0%/0%:100%x100%:100 .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup=Shotcut .filter[1].composite.geometry=100%/0%:300%x100%:100;-1=-300%/0%:300%x100%:100 .filter[1].producer.family=San .filter[1].producer.size=32 .filter[1].composite.titles=1 mlt-0.9.0/src/modules/feeds/NTSC/etv.properties000066400000000000000000000127631215300731300213300ustar00rootroot00000000000000# This properties file describes the fx available to the data_feed and # data_show filters # # Syntax is as follows: # # name= # name.description= # name.properties.= # name.=value # etc # # Typically, the is a 'region' and additional filters are # included as properties using the normal region filter syntax. # location=region .description=Titles .properties.markup=filter[1].producer.text .properties.family=filter[1].producer.family .properties.size=filter[1].producer.size .period=2 .properties.length[0]=composite.out .composite.geometry=0/14%:32%x5%:0;15=/:x:100 .composite.luma=%luma01.pgm .composite.softness=.3 .filter[0]=watermark .filter[0].resource=colour:0x6c0101ff .filter[0].composite.distort=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.text= .filter[1].producer.family=Sans .filter[1].producer.size=24 .filter[1].composite.geometry=0/0:95%x100% .filter[1].composite.titles=1 .filter[1].composite.halign=right .filter[1].composite.valign=center courtesy=region .description=Courtesy .properties.markup=filter[1].producer.text .properties.family=filter[1].producer.family .properties.size=filter[1].producer.size .period=2 .properties.length[0]=composite.out .composite.geometry=0/20%:32%x5%:0;15=/:x:100 .composite.luma=%luma01.pgm .composite.softness=.3 .filter[0]=watermark .filter[0].resource=colour:0x6c0101ff .filter[0].composite.distort=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.text= .filter[1].producer.family=Sans .filter[1].producer.size=24 .filter[1].composite.geometry=0/0:95%x100% .filter[1].composite.titles=1 .filter[1].composite.halign=right .filter[1].composite.valign=centre exclusive=region .description=Exclusive .properties.markup=filter[1].producer.text .properties.family=filter[1].producer.family .properties.size=filter[1].producer.size .period=2 .properties.length[0]=composite.out .composite.geometry=-32%/20%:32%x5%;15=0 .filter[0]=watermark .filter[0].resource=colour:0x6c0101ff .filter[0].composite.distort=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.text=ETV Exclusive .filter[1].producer.family=Sans .filter[1].producer.size=24 .filter[1].producer.weight=700 .filter[1].composite.geometry=0/0:95%x100% .filter[1].composite.titles=1 .filter[1].composite.halign=right .filter[1].composite.valign=centre file_shot=region .description=Titles .period=2 .properties.family=filter[1].producer.family .properties.size=filter[1].producer.size .properties.length[0]=composite.out .composite.geometry=82%/28%:11%x4%:0;15=/:x:100 .filter[0]=watermark .filter[0].resource=colour:0x6c0101ff .filter[0].composite.distort=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.text=File Shot .filter[1].producer.family=Sans .filter[1].producer.size=18 .filter[1].producer.weight=700 .filter[1].composite.titles=1 .filter[1].composite.halign=centre .filter[1].composite.valign=centre special=region .description=Special .period=2 .properties.family=filter[1].producer.family .properties.size=filter[1].producer.size .properties.length[0]=filter[0].composite.out .properties.length[1]=filter[1].composite.out .composite.geometry=65%/65%:35%x6% .filter[0]=watermark .filter[0].resource=colour:0x6c0101ff .filter[0].composite.geometry=100%/0%:100%x100%:0;15=0%/0%:x:100 .filter[0].composite.distort=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.text=Special .filter[1].producer.family=Sans .filter[1].producer.size=24 .filter[1].producer.weight=700 .filter[1].composite.geometry=100%/0%:100%x100%:0;15=0%/0%:x:100 .filter[1].composite.titles=1 .filter[1].composite.halign=centre .filter[1].composite.valign=centre ticker=region .description=Tickertape .properties.markup=filter[1].producer.text .properties.family=filter[1].producer.family .properties.size=filter[1].producer.size .properties.length[0]=filter[1].composite.out .composite.geometry=0/87%:101%x13% .filter[0]=watermark .filter[0].resource=colour:0x6c0101ff .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.text=Ticker - provided for reference .filter[1].producer.family=Sans .filter[1].producer.size=24 .filter[1].producer.weight=700 .filter[1].composite.titles=1 .filter[1].composite.halign=centre .filter[1].composite.valign=centre super=region .description=Transcription .properties.0=filter[1].producer.text .properties.1=filter[2].producer.text .properties.align=filter[1].composite.valign .properties.weight=filter[1].producer.weight .properties.f0=filter[1].producer.family .properties.s0=filter[1].producer.size .properties.f1=filter[2].producer.family .properties.s1=filter[2].producer.size .properties.length[0]=composite.out .period=2 .composite.geometry=0/71%:100%x16%:0;30=/:x:100 .composite.luma=%luma01.pgm .composite.luma_invert=1 .composite.softness=.3 .filter[0]=watermark .filter[0].resource=colour:0xbbbbbbff .filter[0].composite.geometry=0/0:100%:100%:70 .filter[0].composite.distort=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.text= .filter[1].producer.family=Sans .filter[1].producer.size=32 .filter[1].producer.weight=700 .filter[1].producer.fgcolour=0x6c0101ff .filter[1].composite.titles=1 .filter[1].composite.halign=centre .filter[1].composite.valign=top .filter[2]=watermark .filter[2].resource=pango: .filter[2].producer.text= .filter[2].producer.family=Sans .filter[2].producer.size=32 .filter[2].producer.fgcolour=0x6c0101ff .filter[2].composite.titles=1 .filter[2].composite.halign=centre .filter[2].composite.valign=bottom mlt-0.9.0/src/modules/feeds/NTSC/obscure.properties000066400000000000000000000011751215300731300221670ustar00rootroot00000000000000# This properties file describes the fx available to the data_feed and # data_show filters # # Syntax is as follows: # # name= # name.description= # name.properties.= # name.=value # etc # # Typically, the is a 'region' and additional filters are # included as properties using the normal region filter syntax. # obscure=region .description=Obscure .properties.geometry=composite.geometry .properties.resource=resource .properties.length[0]=composite.out .composite.geometry= .resource=rectangle .composite.refresh=1 .filter[0]=obscure .filter[0].start=0/0:100%x100% mlt-0.9.0/src/modules/feeds/PAL/000077500000000000000000000000001215300731300162505ustar00rootroot00000000000000mlt-0.9.0/src/modules/feeds/PAL/border.properties000066400000000000000000000007471215300731300216530ustar00rootroot00000000000000border_left=watermark .description=Border Left .resource=colour:black .reverse=1 .period=2 .properties.length[0]=composite.out .composite.geometry=0/0:100%x100%;25=2.5%/17.5%:45%x45% .composite.halign=c .composite.valign=c .composite.fill=1 border_right=watermark .description=Border Right .resource=colour:black .reverse=1 .period=2 .properties.length[0]=composite.out .composite.geometry=0/0:100%x100%;25=52.5%/17.5%:45%x45% .composite.halign=c .composite.valign=c .composite.fill=1 mlt-0.9.0/src/modules/feeds/PAL/data_fx.properties000066400000000000000000000041741215300731300220020ustar00rootroot00000000000000# This properties file describes the fx available to the data_send and # data_show filters # # Syntax is as follows: # # name= # name.description= # name.properties.= # name.=value # etc # # Typically, the is a 'region' and additional filters are # included as properties using the normal region filter syntax. # # # The titles filter definition # titles=region .description=Titles .properties.markup=filter[1].producer.markup .type.markup=text .period=2 .properties.length[0]=filter[0].composite.out .properties.length[1]=filter[1].composite.out .composite.geometry=5%/70%:90%x20% .filter[0]=watermark .filter[0].resource=colour:0x000000ff .filter[0].composite.geometry=0%/0%:100%x100%:0;5=0%/0%:100%x100%:40 .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup=Shotcut .filter[1].composite.geometry=0%/0%:100%x100%:0;8=0%/0%:100%x100%:100 .filter[1].composite.titles=1 # # The top titles filter definition # top-titles=region .description=Top Titles .properties.markup=filter[1].producer.markup .type.markup=text .period=2 .properties.length[0]=filter[0].composite.out .properties.length[1]=filter[1].composite.out .composite.geometry=5%/5%:90%x20% .filter[0]=watermark .filter[0].resource=colour:0x000000ff .filter[0].composite.geometry=0%/0%:100%x100%:0;5=0%/0%:100%x100%:40 .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup=Shotcut .filter[1].composite.geometry=0%/0%:100%x100%:0;8=0%/0%:100%x100%:100 .filter[1].composite.titles=1 # # OK - Silly example... # tickertape=region .description=Tickertape .properties.markup=filter[1].producer.markup .type.markup=text .properties.length[0]=filter[1].composite.out .composite.geometry=0%/93%:100%x7% .filter[0]=watermark .filter[0].resource=colour:0x000000ff .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup=Shotcut .filter[1].composite.geometry=100%/0%:300%x100%:100;-1=-300%/0%:300%x100%:100 .filter[1].producer.family=San .filter[1].producer.size=32 .filter[1].composite.titles=1 mlt-0.9.0/src/modules/feeds/PAL/etv.properties000066400000000000000000000127631215300731300211750ustar00rootroot00000000000000# This properties file describes the fx available to the data_feed and # data_show filters # # Syntax is as follows: # # name= # name.description= # name.properties.= # name.=value # etc # # Typically, the is a 'region' and additional filters are # included as properties using the normal region filter syntax. # location=region .description=Titles .properties.markup=filter[1].producer.text .properties.family=filter[1].producer.family .properties.size=filter[1].producer.size .period=2 .properties.length[0]=composite.out .composite.geometry=0/14%:32%x5%:0;12=/:x:100 .composite.luma=%luma01.pgm .composite.softness=.3 .filter[0]=watermark .filter[0].resource=colour:0x6c0101ff .filter[0].composite.distort=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.text= .filter[1].producer.family=Sans .filter[1].producer.size=24 .filter[1].composite.geometry=0/0:95%x100% .filter[1].composite.titles=1 .filter[1].composite.halign=right .filter[1].composite.valign=center courtesy=region .description=Courtesy .properties.markup=filter[1].producer.text .properties.family=filter[1].producer.family .properties.size=filter[1].producer.size .period=2 .properties.length[0]=composite.out .composite.geometry=0/20%:32%x5%:0;12=/:x:100 .composite.luma=%luma01.pgm .composite.softness=.3 .filter[0]=watermark .filter[0].resource=colour:0x6c0101ff .filter[0].composite.distort=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.text= .filter[1].producer.family=Sans .filter[1].producer.size=24 .filter[1].composite.geometry=0/0:95%x100% .filter[1].composite.titles=1 .filter[1].composite.halign=right .filter[1].composite.valign=centre exclusive=region .description=Exclusive .properties.markup=filter[1].producer.text .properties.family=filter[1].producer.family .properties.size=filter[1].producer.size .period=2 .properties.length[0]=composite.out .composite.geometry=-32%/20%:32%x5%;12=0 .filter[0]=watermark .filter[0].resource=colour:0x6c0101ff .filter[0].composite.distort=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.text=ETV Exclusive .filter[1].producer.family=Sans .filter[1].producer.size=24 .filter[1].producer.weight=700 .filter[1].composite.geometry=0/0:95%x100% .filter[1].composite.titles=1 .filter[1].composite.halign=right .filter[1].composite.valign=centre file_shot=region .description=Titles .period=2 .properties.family=filter[1].producer.family .properties.size=filter[1].producer.size .properties.length[0]=composite.out .composite.geometry=82%/28%:11%x4%:0;12=/:x:100 .filter[0]=watermark .filter[0].resource=colour:0x6c0101ff .filter[0].composite.distort=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.text=File Shot .filter[1].producer.family=Sans .filter[1].producer.size=18 .filter[1].producer.weight=700 .filter[1].composite.titles=1 .filter[1].composite.halign=centre .filter[1].composite.valign=centre special=region .description=Special .period=2 .properties.family=filter[1].producer.family .properties.size=filter[1].producer.size .properties.length[0]=filter[0].composite.out .properties.length[1]=filter[1].composite.out .composite.geometry=65%/65%:35%x6% .filter[0]=watermark .filter[0].resource=colour:0x6c0101ff .filter[0].composite.geometry=100%/0%:100%x100%:0;12=0%/0%:x:100 .filter[0].composite.distort=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.text=Special .filter[1].producer.family=Sans .filter[1].producer.size=24 .filter[1].producer.weight=700 .filter[1].composite.geometry=100%/0%:100%x100%:0;12=0%/0%:x:100 .filter[1].composite.titles=1 .filter[1].composite.halign=centre .filter[1].composite.valign=centre ticker=region .description=Tickertape .properties.markup=filter[1].producer.text .properties.family=filter[1].producer.family .properties.size=filter[1].producer.size .properties.length[0]=filter[1].composite.out .composite.geometry=0/87%:101%x13% .filter[0]=watermark .filter[0].resource=colour:0x6c0101ff .filter[0].composite.titles=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.text=Ticker - provided for reference .filter[1].producer.family=Sans .filter[1].producer.size=24 .filter[1].producer.weight=700 .filter[1].composite.titles=1 .filter[1].composite.halign=centre .filter[1].composite.valign=centre super=region .description=Transcription .properties.0=filter[1].producer.text .properties.1=filter[2].producer.text .properties.align=filter[1].composite.valign .properties.weight=filter[1].producer.weight .properties.f0=filter[1].producer.family .properties.s0=filter[1].producer.size .properties.f1=filter[2].producer.family .properties.s1=filter[2].producer.size .properties.length[0]=composite.out .period=2 .composite.geometry=0/71%:100%x16%:0;25=/:x:100 .composite.luma=%luma01.pgm .composite.luma_invert=1 .composite.softness=.3 .filter[0]=watermark .filter[0].resource=colour:0xbbbbbbff .filter[0].composite.geometry=0/0:100%:100%:70 .filter[0].composite.distort=1 .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.text= .filter[1].producer.family=Sans .filter[1].producer.size=32 .filter[1].producer.weight=700 .filter[1].producer.fgcolour=0x6c0101ff .filter[1].composite.titles=1 .filter[1].composite.halign=centre .filter[1].composite.valign=top .filter[2]=watermark .filter[2].resource=pango: .filter[2].producer.text= .filter[2].producer.family=Sans .filter[2].producer.size=32 .filter[2].producer.fgcolour=0x6c0101ff .filter[2].composite.titles=1 .filter[2].composite.halign=centre .filter[2].composite.valign=bottom mlt-0.9.0/src/modules/feeds/PAL/example.properties000066400000000000000000000002301215300731300220140ustar00rootroot00000000000000greyscale=greyscale .description=Greyscale sepia=sepia .description=Sepia charcoal=charcoal .description=Charcoal invert=invert .description=Invert mlt-0.9.0/src/modules/feeds/PAL/obscure.properties000066400000000000000000000015221215300731300220300ustar00rootroot00000000000000# This properties file describes the fx available to the data_feed and # data_show filters # # Syntax is as follows: # # name= # name.description= # name.properties.= # name.=value # etc # # Typically, the is a 'region' and additional filters are # included as properties using the normal region filter syntax. # obscure0=region .description=Primary Obscure .properties.geometry=composite.geometry .properties.resource=resource .properties.length[0]=composite.out .composite.geometry= .resource=rectangle .composite.refresh=1 .filter[0]=obscure obscure1=region .description=Secondary Obscure .properties.geometry=composite.geometry .properties.resource=resource .properties.length[0]=composite.out .composite.geometry= .resource=rectangle .composite.refresh=1 .filter[0]=obscure mlt-0.9.0/src/modules/frei0r/000077500000000000000000000000001215300731300157355ustar00rootroot00000000000000mlt-0.9.0/src/modules/frei0r/Makefile000066400000000000000000000016631215300731300174030ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt include ../../../config.mak TARGET = ../libmltfrei0r$(LIBSUF) OBJS = factory.o \ producer_frei0r.o \ filter_frei0r.o \ transition_frei0r.o \ frei0r_helper.o CFLAGS += `pkg-config --cflags frei0r 2> /dev/null` LDFLAGS += -lm $(LIBDL) LDFLAGS += `pkg-config --libs frei0r 2> /dev/null` SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/frei0r" install -m 644 blacklist.txt "$(DESTDIR)$(mltdatadir)/frei0r" install -m 644 not_thread_safe.txt "$(DESTDIR)$(mltdatadir)/frei0r" install -m 644 param_name_map.yaml "$(DESTDIR)$(mltdatadir)/frei0r" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/frei0r/blacklist.txt000066400000000000000000000000141215300731300204410ustar00rootroot00000000000000perspective mlt-0.9.0/src/modules/frei0r/configure000077500000000000000000000005371215300731300176510ustar00rootroot00000000000000#! /bin/sh if [ "$help" != "1" ] then echo "#include int main(){ f0r_plugin_info_t test; test.name;return 0;}"| $CC $(pkg-config --cflags frei0r) $CFLAGS -c -x c - >/dev/null 2>&1 if [ "$?" = "1" ] then touch ../disable-frei0r echo "- frei0r plugin disabled. Install frei0r-plugins and make sure frei0r.h is available." fi fi mlt-0.9.0/src/modules/frei0r/factory.c000066400000000000000000000423211215300731300175520ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (c) 2008 Marco Gittler * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #if defined(WIN32) #define LIBSUF ".dll" #define FREI0R_PLUGIN_PATH "\\lib\\frei0r-1" #elif defined(__DARWIN__) && defined(RELOCATABLE) #define LIBSUF ".so" #define FREI0R_PLUGIN_PATH "/lib/frei0r-1" #else #define LIBSUF ".so" #define FREI0R_PLUGIN_PATH "/usr/lib/frei0r-1:/usr/lib64/frei0r-1:/opt/local/lib/frei0r-1:/usr/local/lib/frei0r-1:$HOME/.frei0r-1/lib" #endif #define GET_FREI0R_PATH (getenv("FREI0R_PATH") ? getenv("FREI0R_PATH") : getenv("MLT_FREI0R_PLUGIN_PATH") ? getenv("MLT_FREI0R_PLUGIN_PATH") : FREI0R_PLUGIN_PATH) #define CLAMP( x, min, max ) ((x) < (min) ? (min) : (x) > (max) ? (max) : (x)) extern mlt_filter filter_frei0r_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_frame filter_process( mlt_filter this, mlt_frame frame ); extern void filter_close( mlt_filter this ); extern int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ); extern void producer_close( mlt_producer this ); extern void transition_close( mlt_transition this ); extern mlt_frame transition_process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ); static char* get_frei0r_path() { #ifdef WIN32 char *dirname = malloc( strlen( mlt_environment( "MLT_APPDIR" ) ) + strlen( FREI0R_PLUGIN_PATH ) + 1 ); strcpy( dirname, mlt_environment( "MLT_APPDIR" ) ); strcat( dirname, FREI0R_PLUGIN_PATH ); return dirname; #elif defined(__DARWIN__) && defined(RELOCATABLE) char *dirname = malloc( strlen( mlt_environment( "MLT_APPDIR" ) ) + strlen( FREI0R_PLUGIN_PATH ) + 1 ); strcpy( dirname, mlt_environment( "MLT_APPDIR" ) ); strcat( dirname, FREI0R_PLUGIN_PATH ); return dirname; #else return strdup( GET_FREI0R_PATH ); #endif } static void check_thread_safe( mlt_properties properties, const char *name ) { char dirname[PATH_MAX]; snprintf( dirname, PATH_MAX, "%s/frei0r/not_thread_safe.txt", mlt_environment( "MLT_DATA" ) ); mlt_properties not_thread_safe = mlt_properties_load( dirname ); int i; for ( i = 0; i < mlt_properties_count( not_thread_safe ); i++ ) { if ( strcmp( name, mlt_properties_get_name( not_thread_safe, i ) ) == 0 ) { mlt_properties_set_int( properties, "_not_thread_safe", 1 ); break; } } mlt_properties_close( not_thread_safe ); } static mlt_properties fill_param_info ( mlt_service_type type, const char *service_name, char *name ) { char file[ PATH_MAX ]; char servicetype[ 1024 ]=""; struct stat stat_buff; switch ( type ) { case producer_type: strcpy ( servicetype , "producer" ); break; case filter_type: strcpy ( servicetype , "filter" ); break; case transition_type: strcpy ( servicetype , "transition" ) ; break; default: strcpy ( servicetype , "" ); }; snprintf( file, PATH_MAX, "%s/frei0r/%s_%s.yml", mlt_environment( "MLT_DATA" ), servicetype, service_name ); memset(&stat_buff, 0, sizeof(stat_buff)); stat(file,&stat_buff); if (S_ISREG(stat_buff.st_mode)){ return mlt_properties_parse_yaml( file ); } void* handle=dlopen(name,RTLD_LAZY); if (!handle) return NULL; void (*plginfo)(f0r_plugin_info_t*)=dlsym(handle,"f0r_get_plugin_info"); void (*param_info)(f0r_param_info_t*,int param_index)=dlsym(handle,"f0r_get_param_info"); void (*f0r_init)(void)=dlsym(handle,"f0r_init"); void (*f0r_deinit)(void)=dlsym(handle,"f0r_deinit"); f0r_instance_t (*f0r_construct)(unsigned int , unsigned int)=dlsym(handle, "f0r_construct"); void (*f0r_destruct)(f0r_instance_t)=dlsym(handle, "f0r_destruct"); void (*f0r_get_param_value)(f0r_instance_t instance, f0r_param_t param, int param_index)=dlsym(handle,"f0r_get_param_value" ); if (!plginfo || !param_info) { dlclose(handle); return NULL; } mlt_properties metadata = mlt_properties_new(); f0r_plugin_info_t info; char string[48]; int j=0; f0r_init(); f0r_instance_t instance = f0r_construct(720, 576); if (!instance) { f0r_deinit(); dlclose(handle); mlt_properties_close(metadata); return NULL; } plginfo(&info); snprintf ( string, sizeof(string) , "%d" , info.minor_version ); mlt_properties_set_double ( metadata, "schema_version" , 0.1 ); mlt_properties_set ( metadata, "title" , info.name ); mlt_properties_set_double ( metadata, "version", info.major_version + info.minor_version / pow( 10, strlen( string ) ) ); mlt_properties_set ( metadata, "identifier" , service_name ); mlt_properties_set ( metadata, "description" , info.explanation ); mlt_properties_set ( metadata, "creator" , info.author ); switch (type){ case producer_type: mlt_properties_set ( metadata, "type" , "producer" ); break; case filter_type: mlt_properties_set ( metadata, "type" , "filter" ); break; case transition_type: mlt_properties_set ( metadata, "type" , "transition" ); break; default: break; } mlt_properties tags = mlt_properties_new ( ); mlt_properties_set_data ( metadata , "tags" , tags , 0 , ( mlt_destructor )mlt_properties_close, NULL ); mlt_properties_set ( tags , "0" , "Video" ); mlt_properties parameter = mlt_properties_new ( ); mlt_properties_set_data ( metadata , "parameters" , parameter , 0 , ( mlt_destructor )mlt_properties_close, NULL ); for (j=0;jget_frame = producer_get_frame; this->close = ( mlt_destructor )producer_close; f0r_init(); properties=MLT_PRODUCER_PROPERTIES ( this ); for (i=0;iprocess = filter_process; this->close = filter_close; f0r_init(); properties=MLT_FILTER_PROPERTIES ( this ); for (i=0;iprocess = transition_process; transition->close = transition_close; properties=MLT_TRANSITION_PROPERTIES( transition ); mlt_properties_set_int(properties, "_transition_type", 1 ); ret=transition; } } check_thread_safe( properties, name ); mlt_properties_set_data(properties, "_dlclose_handle", handle , sizeof ( handle ) , NULL , NULL ); mlt_properties_set_data(properties, "_dlclose", dlclose , sizeof (void*) , NULL , NULL ); mlt_properties_set_data(properties, "f0r_construct", f0r_construct , sizeof( f0r_construct ),NULL,NULL); mlt_properties_set_data(properties, "f0r_update", f0r_update , sizeof( f0r_update ),NULL,NULL); if (f0r_update2) mlt_properties_set_data(properties, "f0r_update2", f0r_update2 , sizeof( f0r_update2 ),NULL,NULL); mlt_properties_set_data(properties, "f0r_destruct", f0r_destruct , sizeof( f0r_destruct ),NULL,NULL); mlt_properties_set_data(properties, "f0r_get_plugin_info", f0r_get_plugin_info , sizeof(void*),NULL,NULL); mlt_properties_set_data(properties, "f0r_get_param_info", f0r_get_param_info , sizeof(void*),NULL,NULL); mlt_properties_set_data(properties, "f0r_set_param_value", f0r_set_param_value , sizeof(void*),NULL,NULL); mlt_properties_set_data(properties, "f0r_get_param_value", f0r_get_param_value , sizeof(void*),NULL,NULL); // Let frei0r plugin version be serialized using same format as metadata snprintf( minor, sizeof( minor ), "%d", info.minor_version ); mlt_properties_set_double( properties, "version", info.major_version + info.minor_version / pow( 10, strlen( minor ) ) ); // Use the global param name map for backwards compatibility when // param names change and setting frei0r params by name instead of index. mlt_properties param_name_map = mlt_properties_get_data( mlt_global_properties(), "frei0r.param_name_map", NULL ); if ( param_name_map ) { // Lookup my plugin in the map param_name_map = mlt_properties_get_data( param_name_map, name, NULL ); mlt_properties_set_data( properties, "_param_name_map", param_name_map, 0, NULL, NULL ); } return ret; }else{ mlt_log_error( NULL, "frei0r plugin \"%s\" is missing a function\n", name ); dlerror(); } return NULL; } static void * create_frei0r_item ( mlt_profile profile, mlt_service_type type, const char *id, void *arg){ mlt_tokeniser tokeniser = mlt_tokeniser_init ( ); char *frei0r_path = get_frei0r_path(); int dircount=mlt_tokeniser_parse_new ( tokeniser, frei0r_path, ":" ); void* ret=NULL; while (dircount--){ char soname[PATH_MAX]; char *myid = strdup( id ); #ifdef WIN32 char *firstname = strtok( myid, "." ); #else char *save_firstptr = NULL; char *firstname = strtok_r( myid, ".", &save_firstptr ); #endif char* directory = mlt_tokeniser_get_string (tokeniser, dircount); #ifdef WIN32 firstname = strtok( NULL, "." ); #else firstname = strtok_r( NULL, ".", &save_firstptr ); #endif if (strncmp(directory, "$HOME", 5)) snprintf(soname, PATH_MAX, "%s/%s" LIBSUF, directory, firstname ); else snprintf(soname, PATH_MAX, "%s%s/%s" LIBSUF, getenv("HOME"), strchr(directory, '/'), firstname ); if (firstname){ void* handle=dlopen(soname,RTLD_LAZY); if (handle ){ ret=load_lib ( profile , type , handle, firstname ); }else{ dlerror(); } } free( myid ); } mlt_tokeniser_close ( tokeniser ); free( frei0r_path ); return ret; } MLT_REPOSITORY { int i=0; mlt_tokeniser tokeniser = mlt_tokeniser_init ( ); char *frei0r_path = get_frei0r_path(); int dircount=mlt_tokeniser_parse_new ( tokeniser , frei0r_path, ":" ); char dirname[PATH_MAX]; snprintf( dirname, PATH_MAX, "%s/frei0r/blacklist.txt", mlt_environment( "MLT_DATA" ) ); mlt_properties blacklist = mlt_properties_load( dirname ); // Load a param name map into global properties for backwards compatibility when // param names change and setting frei0r params by name instead of index. snprintf( dirname, PATH_MAX, "%s/frei0r/param_name_map.yaml", mlt_environment( "MLT_DATA" ) ); mlt_properties_set_data( mlt_global_properties(), "frei0r.param_name_map", mlt_properties_parse_yaml( dirname ), 0, (mlt_destructor) mlt_properties_close, NULL ); while (dircount--){ mlt_properties direntries = mlt_properties_new(); char* directory = mlt_tokeniser_get_string (tokeniser, dircount); if (strncmp(directory, "$HOME", 5)) snprintf(dirname, PATH_MAX, "%s", directory); else snprintf(dirname, PATH_MAX, "%s%s", getenv("HOME"), strchr(directory, '/')); mlt_properties_dir_list(direntries, dirname ,"*" LIBSUF, 1); for (i=0; i * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "frei0r_helper.h" #include static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = mlt_frame_pop_service( this ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); *format = mlt_image_rgb24a; mlt_log_debug( MLT_FILTER_SERVICE( filter ), "frei0r %dx%d\n", *width, *height ); int error = mlt_frame_get_image( this, image, format, width, height, 0 ); if ( error == 0 && *image ) { double position = mlt_filter_get_position( filter, this ); mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); double time = position / mlt_profile_fps( profile ); process_frei0r_item( MLT_FILTER_SERVICE(filter), position, time, properties, this, image, width, height ); } return error; } mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { mlt_frame_push_service( frame, this ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } void filter_close( mlt_filter this ) { destruct( MLT_FILTER_PROPERTIES ( this ) ); } mlt-0.9.0/src/modules/frei0r/frei0r_helper.c000066400000000000000000000154541215300731300206400ustar00rootroot00000000000000/* * frei0r_helper.c -- frei0r helper * Copyright (c) 2008 Marco Gittler * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "frei0r_helper.h" #include #include #include static void parse_color( int color, f0r_param_color_t *fcolor ) { fcolor->r = ( color >> 24 ) & 0xff; fcolor->r /= 255; fcolor->g = ( color >> 16 ) & 0xff; fcolor->g /= 255; fcolor->b = ( color >> 8 ) & 0xff; fcolor->b /= 255; } static void rgba_bgra( uint8_t *src, uint8_t* dst, int width, int height ) { int n = width * height + 1; while ( --n ) { *dst++ = src[2]; *dst++ = src[1]; *dst++ = src[0]; *dst++ = src[3]; src += 4; } } int process_frei0r_item( mlt_service service, double position, double time, mlt_properties prop, mlt_frame this, uint8_t **image, int *width, int *height ) { int i=0; f0r_instance_t ( *f0r_construct ) ( unsigned int , unsigned int ) = mlt_properties_get_data( prop , "f0r_construct" ,NULL); void (*f0r_update)(f0r_instance_t instance, double time, const uint32_t* inframe, uint32_t* outframe)=mlt_properties_get_data( prop , "f0r_update" ,NULL); void (*f0r_destruct)(f0r_instance_t instance)=mlt_properties_get_data( prop , "f0r_destruct" ,NULL); void (*f0r_get_plugin_info)(f0r_plugin_info_t*)=mlt_properties_get_data( prop, "f0r_get_plugin_info" ,NULL); void (*f0r_get_param_info)(f0r_param_info_t* info, int param_index)=mlt_properties_get_data( prop , "f0r_get_param_info" ,NULL); void (*f0r_set_param_value)(f0r_instance_t instance, f0r_param_t param, int param_index)=mlt_properties_get_data( prop , "f0r_set_param_value" ,NULL); void (*f0r_update2) (f0r_instance_t instance, double time, const uint32_t* inframe1,const uint32_t* inframe2,const uint32_t* inframe3, uint32_t* outframe)=mlt_properties_get_data( prop , "f0r_update2" ,NULL); mlt_service_type type = mlt_service_identify( service ); int not_thread_safe = mlt_properties_get_int( prop, "_not_thread_safe" ); //use as name the width and height f0r_instance_t inst; f0r_plugin_info_t info; char ctorname[1024]=""; sprintf(ctorname,"ctor-%dx%d",*width,*height); mlt_service_lock( service ); void* neu=mlt_properties_get_data( prop , ctorname ,NULL ); if (!f0r_construct){ //printf("no ctor\n"); return -1; } if ( neu == 0 ){ inst= f0r_construct(*width,*height); mlt_properties_set_data( prop , ctorname , inst, sizeof( inst ) , f0r_destruct , NULL );; }else{ inst=mlt_properties_get_data( prop , ctorname , NULL ); } if ( !not_thread_safe ) mlt_service_unlock( service ); if (f0r_get_plugin_info){ f0r_get_plugin_info(&info); for (i=0;i * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include int process_frei0r_item( mlt_service, double position, double time, mlt_properties, mlt_frame, uint8_t **image, int *width, int *height ); void destruct (mlt_properties prop ); mlt-0.9.0/src/modules/frei0r/not_thread_safe.txt000066400000000000000000000003321215300731300216210ustar00rootroot00000000000000facebl0r facedetect cluster squareblur primaries rgbparade scale0tilt sobel hqdn3d sharpness baltan cartoon edgeglow equaliz0r lightgraffiti mask0mate tehRoxx0r vectorscope vertigo delay0r threelay0r twolay0r select0r mlt-0.9.0/src/modules/frei0r/param_name_map.yaml000066400000000000000000000003701215300731300215560ustar00rootroot00000000000000# MLT frei0r param name mapping from old name to current index # plugin: # param_name: index lenscorrection: xcenter: 0 ycenter: 1 correctionnearcenter: 2 correctionnearedges: 3 brightness: 4 pixeliz0r: BlockSizeX: 0 BlockSizeY: 1 mlt-0.9.0/src/modules/frei0r/producer_frei0r.c000066400000000000000000000066451215300731300212060ustar00rootroot00000000000000/* * producer_frei0r.c -- frei0r producer * Copyright (c) 2009 Jean-Baptiste Mardelle * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "frei0r_helper.h" #include #include static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { // Obtain properties of frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Obtain the producer for this frame mlt_producer producer = mlt_properties_get_data( properties, "producer_frei0r", NULL ); // Obtain properties of producer mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Choose suitable out values if nothing specific requested if ( *width <= 0 ) *width = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->width; if ( *height <= 0 ) *height = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->height; // Allocate the image int size = *width * ( *height + 1 ) * 4; // Allocate the image *buffer = mlt_pool_alloc( size ); // Update the frame mlt_frame_set_image( frame, *buffer, size, mlt_pool_release ); *format = mlt_image_rgb24a; if ( *buffer != NULL ) { double position = mlt_frame_get_position( frame ); mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); double time = position / mlt_profile_fps( profile ); process_frei0r_item( MLT_PRODUCER_SERVICE(producer), position, time, producer_props, frame, buffer, width, height ); } return 0; } int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL ) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Obtain properties of producer mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Set the producer on the frame properties mlt_properties_set_data( properties, "producer_frei0r", producer, 0, NULL, NULL ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Set producer-specific frame properties mlt_properties_set_int( properties, "progressive", 1 ); mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) ); // Push the get_image method mlt_frame_push_get_image( *frame, producer_get_image ); } // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; } void producer_close( mlt_producer producer ) { producer->close = NULL; mlt_producer_close( producer ); free( producer ); } mlt-0.9.0/src/modules/frei0r/transition_frei0r.c000066400000000000000000000050641215300731300215470ustar00rootroot00000000000000/* * transition_frei0r.c -- frei0r transition * Copyright (c) 2008 Marco Gittler * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "frei0r_helper.h" #include static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ){ mlt_frame b_frame = mlt_frame_pop_frame( a_frame ); mlt_transition transition = mlt_frame_pop_service( a_frame ); mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); int invert = mlt_properties_get_int( properties, "invert" ); uint8_t *images[]={NULL,NULL,NULL}; *format = mlt_image_rgb24a; mlt_frame_get_image( a_frame, &images[0], format, width, height, 0 ); mlt_frame_get_image( b_frame, &images[1], format, width, height, 0 ); double position = mlt_transition_get_position( transition, a_frame ); mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) ); double time = position / mlt_profile_fps( profile ); process_frei0r_item( MLT_TRANSITION_SERVICE(transition), position, time, properties, !invert ? a_frame : b_frame, images, width, height ); *width = mlt_properties_get_int( !invert ? a_props : b_props, "width" ); *height = mlt_properties_get_int( !invert ? a_props : b_props, "height" ); *image = mlt_properties_get_data( !invert ? a_props : b_props , "image", NULL ); return 0; } mlt_frame transition_process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ) { mlt_frame_push_service( a_frame, transition ); mlt_frame_push_frame( a_frame, b_frame ); mlt_frame_push_get_image( a_frame, transition_get_image ); return a_frame; } void transition_close( mlt_transition this ){ destruct ( MLT_TRANSITION_PROPERTIES ( this ) ); } mlt-0.9.0/src/modules/gtk2/000077500000000000000000000000001215300731300154155ustar00rootroot00000000000000mlt-0.9.0/src/modules/gtk2/Makefile000066400000000000000000000032321215300731300170550ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lpthread -lm include ../../../config.mak include config.mak TARGET = ../libmltgtk2$(LIBSUF) OBJS = factory.o ifdef USE_GTK2 OBJS += consumer_gtk2.o CFLAGS += `pkg-config $(PKGCONFIG_PREFIX) --cflags gtk+-2.0` LDFLAGS += `pkg-config $(PKGCONFIG_PREFIX) --libs gtk+-2.0` endif ifdef USE_PIXBUF OBJS += producer_pixbuf.o pixops.o filter_rescale.o CFLAGS += `pkg-config $(PKGCONFIG_PREFIX) --cflags gdk-pixbuf-2.0` LDFLAGS += `pkg-config $(PKGCONFIG_PREFIX) --libs gdk-pixbuf-2.0` endif ifdef USE_EXIF CFLAGS += $(EXIFCXXFLAGS) LDFLAGS += $(EXIFLIBS) endif ifdef MMX_FLAGS ifndef ARCH_X86_64 ASM_OBJS = have_mmx.o scale_line_22_yuv_mmx.o endif endif ifdef USE_PANGO OBJS += producer_pango.o OBJS += producer_count.o OBJS += filter_dynamictext.o CFLAGS += `pkg-config $(PKGCONFIG_PREFIX) --cflags pangoft2` LDFLAGS += `pkg-config $(PKGCONFIG_PREFIX) --libs pangoft2` ifeq ($(targetos),Darwin) LDFLAGS += -liconv endif ifeq ($(targetos),FreeBSD) LDFLAGS += -liconv endif ifeq ($(targetos), MinGW) LDFLAGS += -liconv endif endif SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(ASM_OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(ASM_OBJS) $(LDFLAGS) have_mmx.o: $(CC) -o $@ -c have_mmx.S scale_line_22_yuv_mmx.o: scale_line_22_yuv_mmx.S $(CC) -o $@ -c scale_line_22_yuv_mmx.S depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(ASM_OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/gtk2" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/gtk2" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/gtk2/configure000077500000000000000000000044621215300731300173320ustar00rootroot00000000000000#!/bin/sh if [ "$help" = "1" ] then cat << EOF GTK+ options: --gtk2-prefix=path - Override the gtk+-2.0 prefix for pkg-config EOF else pkgconfig_prefix= for i in "$@" do case $i in --gtk2-prefix=* ) pkgconfig_prefix="${i#--gtk2-prefix=}" ;; esac done [ "$pkgconfig_prefix" != "" ] && pkgconfig_prefix="--define-variable=prefix=\"$pkgconfig_prefix\"" pkg-config $pkgconfig_prefix gtk+-2.0 2> /dev/null disable_gtk2=$? pkg-config $pkgconfig_prefix gdk-pixbuf-2.0 2> /dev/null disable_pixbuf=$? pkg-config $pkgconfig_prefix gdk-pixbuf-2.0 pangoft2 2> /dev/null disable_pango=$? if [ "$disable_gtk2" != "0" -a "$disable_pixbuf" != 0 -a "$disable_pango" != "0" ] then echo "- GTK2 components not found: disabling" touch ../disable-gtk2 exit 0 fi [ "$disable_gtk2" != "0" ] && echo "- gtk2 not found: gtk2 preview disabled" [ "$disable_pixbuf" != "0" ] && echo "- pixbuf not found: pixbuf loader and rescaler disabled" [ "$disable_pango" != "0" ] && echo "- pango not found: pango titler disabled" echo > config.h [ "$disable_gtk2" = "0" ] && echo "#define USE_GTK2" >> config.h [ "$disable_pixbuf" = "0" ] && echo "#define USE_PIXBUF" >> config.h [ "$disable_pango" = "0" ] && echo "#define USE_PANGO" >> config.h echo > config.mak [ "$disable_gtk2" = "0" ] && echo "USE_GTK2=1" >> config.mak [ "$disable_pixbuf" = "0" ] && echo "USE_PIXBUF=1" >> config.mak [ "$disable_pango" = "0" ] && echo "USE_PANGO=1" >> config.mak [ "$pkgconfig_prefix" != "" ] && echo "PKGCONFIG_PREFIX=$pkgconfig_prefix" >> config.mak pkg-config --exists 'libexif' if [ $? -eq 0 ] then echo "Libexif found, enabling auto rotate" echo "#define USE_EXIF" >> config.h echo "USE_EXIF=1" >> config.mak echo EXIFCXXFLAGS=$(pkg-config --cflags libexif ) >> config.mak echo EXIFLIBS=$(pkg-config --libs libexif) >> config.mak elif [ -d "$exif_libdir" -a -d "$exif_includedir" ] then # test if we have a libexif if [ -f "$exif_libdir/exif-data.h" ] then echo "Libexif found, enabling auto rotate" echo "#define USE_EXIF" >> config.h echo "USE_EXIF=1" >> config.mak echo EXIFCXXFLAGS=-I$exif_includedir >> config.mak echo EXIFLIBS=-L$exif_libdir lexif >> config.mak else echo "Libexif not found, disabling exif features (auto rotate)" fi fi exit 0 fi mlt-0.9.0/src/modules/gtk2/consumer_gtk2.c000066400000000000000000000040341215300731300203440ustar00rootroot00000000000000/* * consumer_gtk2.c -- A consumer for GTK2 apps * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #ifdef WIN32 #include #else #include #endif #include mlt_consumer consumer_gtk2_preview_init( mlt_profile profile, GtkWidget *widget ) { // Create an sdl preview consumer mlt_consumer consumer = NULL; // This is a nasty little hack which is required by SDL if ( widget != NULL ) { #ifdef WIN32 HWND xwin = GDK_WINDOW_HWND( widget->window ); #else Window xwin = GDK_WINDOW_XWINDOW( widget->window ); #endif char windowhack[ 32 ]; sprintf( windowhack, "%ld", (long) xwin ); setenv( "SDL_WINDOWID", windowhack, 1 ); } // Create an sdl preview consumer consumer = mlt_factory_consumer( profile, "sdl_preview", NULL ); // Now assign the lock/unlock callbacks if ( consumer != NULL ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_properties_set_int( properties, "app_locked", 1 ); mlt_properties_set_data( properties, "app_lock", gdk_threads_enter, 0, NULL, NULL ); mlt_properties_set_data( properties, "app_unlock", gdk_threads_leave, 0, NULL, NULL ); } return consumer; } mlt-0.9.0/src/modules/gtk2/consumer_gtk2_preview.yml000066400000000000000000000004431215300731300224640ustar00rootroot00000000000000schema_version: 0.1 type: consumer identifier: gtk_preview title: GTK+ description: A wrapper for sdl_preview that makes it easy to embed in GTK+ applications. version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Audio - Video mlt-0.9.0/src/modules/gtk2/factory.c000066400000000000000000000066261215300731300172420ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #ifdef USE_PIXBUF extern mlt_producer producer_pixbuf_init( char *filename ); extern mlt_filter filter_rescale_init( mlt_profile profile, char *arg ); #endif #ifdef USE_GTK2 extern mlt_consumer consumer_gtk2_preview_init( mlt_profile profile, void *widget ); #endif #ifdef USE_PANGO extern mlt_producer producer_pango_init( const char *filename ); extern mlt_producer producer_count_init( const char *arg ); extern mlt_filter filter_dynamictext_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); #endif static void initialise( ) { static int init = 0; if ( init == 0 ) { init = 1; g_type_init( ); } } void *create_service( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { initialise( ); #ifdef USE_PIXBUF if ( !strcmp( id, "pixbuf" ) ) return producer_pixbuf_init( arg ); #endif #ifdef USE_PANGO if ( !strcmp( id, "pango" ) ) return producer_pango_init( arg ); if ( !strcmp( id, "count" ) ) return producer_count_init( arg ); if ( !strcmp( id, "dynamictext" ) ) return filter_dynamictext_init( profile, type, id, arg ); #endif #ifdef USE_PIXBUF if ( !strcmp( id, "gtkrescale" ) ) return filter_rescale_init( profile, arg ); #endif #ifdef USE_GTK2 if ( !strcmp( id, "gtk2_preview" ) ) return consumer_gtk2_preview_init( profile, arg ); #endif return NULL; } static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/gtk2/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( producer_type, "count", create_service ); MLT_REGISTER( filter_type, "dynamictext", create_service ); MLT_REGISTER( consumer_type, "gtk2_preview", create_service ); MLT_REGISTER( filter_type, "gtkrescale", create_service ); MLT_REGISTER( producer_type, "pango", create_service ); MLT_REGISTER( producer_type, "pixbuf", create_service ); MLT_REGISTER_METADATA( producer_type, "count", metadata, "producer_count.yml" ); MLT_REGISTER_METADATA( filter_type, "dynamictext", metadata, "filter_dynamictext.yml" ); MLT_REGISTER_METADATA( consumer_type, "gtk2_preview", metadata, "consumer_gtk2_preview.yml" ); MLT_REGISTER_METADATA( filter_type, "gtkrescale", metadata, "filter_rescale.yml" ); MLT_REGISTER_METADATA( producer_type, "pango", metadata, "producer_pango.yml" ); MLT_REGISTER_METADATA( producer_type, "pixbuf", metadata, "producer_pixbuf.yml" ); } mlt-0.9.0/src/modules/gtk2/filter_dynamictext.c000066400000000000000000000302361215300731300214630ustar00rootroot00000000000000/* * filter_dynamictext.c -- dynamic text overlay filter * Copyright (C) 2011 Ushodaya Enterprises Limited * Author: Brian Matherly * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include // for stat() #include // for stat() #include // for stat() #include // for strftime() and gtime() #define MAX_TEXT_LEN 512 /** Get the next token and indicate whether it is enclosed in "# #". */ static int get_next_token(char* str, int* pos, char* token, int* is_keyword) { int token_pos = 0; int str_len = strlen( str ); if( (*pos) >= str_len || str[*pos] == '\0' ) { return 0; } if( str[*pos] == '#' ) { *is_keyword = 1; (*pos)++; } else { *is_keyword = 0; } while( *pos < str_len && token_pos < MAX_TEXT_LEN - 1) { if( str[*pos] == '\\' && str[(*pos) + 1] == '#' ) { // Escape Sequence - "#" preceeded by "\" - copy the # into the token. token[token_pos] = '#'; token_pos++; (*pos)++; // skip "\" (*pos)++; // skip "#" } else if( str[*pos] == '#' ) { if( *is_keyword ) { // Found the end of the keyword (*pos)++; } break; } else { token[token_pos] = str[*pos]; token_pos++; (*pos)++; } } token[token_pos] = '\0'; return 1; } static void get_timecode_str( mlt_filter filter, mlt_frame frame, char* text ) { int frames = mlt_frame_get_position( frame ); double fps = mlt_profile_fps( mlt_service_profile( MLT_FILTER_SERVICE( filter ) ) ); char tc[12] = ""; if (fps == 0) { strncat( text, "-", MAX_TEXT_LEN - strlen( text ) - 1 ); } else { int seconds = frames / fps; frames = frames % lrint( fps ); int minutes = seconds / 60; seconds = seconds % 60; int hours = minutes / 60; minutes = minutes % 60; sprintf(tc, "%.2d:%.2d:%.2d:%.2d", hours, minutes, seconds, frames); strncat( text, tc, MAX_TEXT_LEN - strlen( text ) - 1 ); } } static void get_frame_str( mlt_filter filter, mlt_frame frame, char* text ) { int pos = mlt_frame_get_position( frame ); char s[12]; snprintf( s, sizeof( s ) - 1, "%d", pos ); strncat( text, s, MAX_TEXT_LEN - strlen( text ) - 1 ); } static void get_filedate_str( mlt_filter filter, mlt_frame frame, char* text ) { mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); char* filename = mlt_properties_get( producer_properties, "resource"); struct stat file_info; if( !stat(filename, &file_info)) { struct tm* time_info = gmtime( &(file_info.st_mtime) ); char date[11] = ""; strftime( date, 11, "%Y/%m/%d", time_info ); strncat( text, date, MAX_TEXT_LEN - strlen( text ) - 1); } } static void get_localfiledate_str( mlt_filter filter, mlt_frame frame, char* text ) { mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); char* filename = mlt_properties_get( producer_properties, "resource" ); struct stat file_info; if( !stat( filename, &file_info ) ) { struct tm* time_info = localtime( &(file_info.st_mtime) ); char date[11] = ""; strftime( date, 11, "%Y/%m/%d", time_info ); strncat( text, date, MAX_TEXT_LEN - strlen( text ) - 1); } } static void get_resource_str( mlt_filter filter, mlt_frame frame, char* text ) { mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); strncat( text, mlt_properties_get( producer_properties, "resource" ), MAX_TEXT_LEN - strlen( text ) - 1 ); } /** Perform substitution for keywords that are enclosed in "# #". */ static void substitute_keywords(mlt_filter filter, char* result, char* value, mlt_frame frame) { char keyword[MAX_TEXT_LEN] = ""; int pos = 0; int is_keyword = 0; while ( get_next_token(value, &pos, keyword, &is_keyword) ) { if(!is_keyword) { strncat( result, keyword, MAX_TEXT_LEN - strlen( result ) - 1 ); } else if ( !strcmp( keyword, "timecode" ) ) { get_timecode_str( filter, frame, result ); } else if ( !strcmp( keyword, "frame" ) ) { get_frame_str( filter, frame, result ); } else if ( !strcmp( keyword, "filedate" ) ) { get_filedate_str( filter, frame, result ); } else if ( !strcmp( keyword, "localfiledate" ) ) { get_localfiledate_str( filter, frame, result ); } else if ( !strcmp( keyword, "resource" ) ) { get_resource_str( filter, frame, result ); } else { // replace keyword with property value from this frame mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); char *frame_value = mlt_properties_get( frame_properties, keyword ); if( frame_value ) { strncat( result, frame_value, MAX_TEXT_LEN - strlen(result) - 1 ); } } } } static void setup_producer( mlt_filter filter, mlt_producer producer, mlt_frame frame ) { mlt_properties my_properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); char* dynamic_text = mlt_properties_get( my_properties, "argument" ); // Check for keywords in dynamic text if ( dynamic_text ) { // Apply keyword substitution before passing the text to the filter. char result[MAX_TEXT_LEN] = ""; substitute_keywords( filter, result, dynamic_text, frame ); mlt_properties_set( producer_properties, "markup", (char*)result ); } // Pass the properties to the pango producer mlt_properties_set( producer_properties, "family", mlt_properties_get( my_properties, "family" ) ); mlt_properties_set( producer_properties, "size", mlt_properties_get( my_properties, "size" ) ); mlt_properties_set( producer_properties, "weight", mlt_properties_get( my_properties, "weight" ) ); mlt_properties_set( producer_properties, "fgcolour", mlt_properties_get( my_properties, "fgcolour" ) ); mlt_properties_set( producer_properties, "bgcolour", mlt_properties_get( my_properties, "bgcolour" ) ); mlt_properties_set( producer_properties, "olcolour", mlt_properties_get( my_properties, "olcolour" ) ); mlt_properties_set( producer_properties, "pad", mlt_properties_get( my_properties, "pad" ) ); mlt_properties_set( producer_properties, "outline", mlt_properties_get( my_properties, "outline" ) ); mlt_properties_set( producer_properties, "align", mlt_properties_get( my_properties, "halign" ) ); } static void setup_transition( mlt_filter filter, mlt_transition transition ) { mlt_properties my_properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties transition_properties = MLT_TRANSITION_PROPERTIES( transition ); mlt_properties_set( transition_properties, "geometry", mlt_properties_get( my_properties, "geometry" ) ); mlt_properties_set( transition_properties, "halign", mlt_properties_get( my_properties, "halign" ) ); mlt_properties_set( transition_properties, "valign", mlt_properties_get( my_properties, "valign" ) ); mlt_properties_set_int( transition_properties, "out", mlt_properties_get_int( my_properties, "_out" ) ); mlt_properties_set_int( transition_properties, "refresh", 1 ); } /** Get the image. */ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; mlt_filter filter = mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_producer producer = mlt_properties_get_data( properties, "_producer", NULL ); mlt_transition transition = mlt_properties_get_data( properties, "_transition", NULL ); mlt_frame text_frame = NULL; mlt_position position = 0; // Configure this filter mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); setup_producer( filter, producer, frame ); setup_transition( filter, transition ); mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); // Make sure the producer is in the correct position position = mlt_filter_get_position( filter, frame ); mlt_producer_seek( producer, position ); // Get the b frame and process with transition if successful if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &text_frame, 0 ) == 0 ) { // Get the a and b frame properties mlt_properties a_props = MLT_FRAME_PROPERTIES( frame ); mlt_properties b_props = MLT_FRAME_PROPERTIES( text_frame ); // Set the frame and text_frame to be in the same position and have same consumer requirements mlt_frame_set_position( text_frame, position ); mlt_frame_set_position( frame, position ); mlt_properties_set_int( b_props, "consumer_deinterlace", mlt_properties_get_int( a_props, "consumer_deinterlace" ) ); // Apply all filters that are attached to this filter to the b frame mlt_service_apply_filters( MLT_FILTER_SERVICE( filter ), text_frame, 0 ); // Process the frame mlt_transition_process( transition, frame, text_frame ); // Get the image *format = mlt_image_yuv422; error = mlt_frame_get_image( frame, image, format, width, height, 1 ); // Close the b frame mlt_frame_close( text_frame ); } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { // Get the properties of the frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Save the frame out point mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "_out", mlt_properties_get_int( properties, "out" ) ); // Push the filter on to the stack mlt_frame_push_service( frame, filter ); // Push the get_image on to the stack mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_dynamictext_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = mlt_filter_new(); mlt_transition transition = mlt_factory_transition( profile, "composite", NULL ); mlt_producer producer = mlt_factory_producer( profile, mlt_environment( "MLT_PRODUCER" ), "pango:" ); if ( filter && transition && producer ) { mlt_properties my_properties = MLT_FILTER_PROPERTIES( filter ); // Register the transition for reuse/destruction mlt_properties_set_data( my_properties, "_transition", transition, 0, ( mlt_destructor )mlt_transition_close, NULL ); // Register the producer for reuse/destruction mlt_properties_set_data( my_properties, "_producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); // Ensure that we loop mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "loop" ); // Assign default values mlt_properties_set( my_properties, "argument", arg ? arg: "#timecode#" ); mlt_properties_set( my_properties, "geometry", "0%/0%:100%x100%:100" ); mlt_properties_set( my_properties, "family", "Sans" ); mlt_properties_set( my_properties, "size", "48" ); mlt_properties_set( my_properties, "weight", "400" ); mlt_properties_set( my_properties, "fgcolour", "0x000000ff" ); mlt_properties_set( my_properties, "bgcolour", "0x00000020" ); mlt_properties_set( my_properties, "olcolour", "0x00000000" ); mlt_properties_set( my_properties, "pad", "0" ); mlt_properties_set( my_properties, "halign", "left" ); mlt_properties_set( my_properties, "valign", "top" ); mlt_properties_set( my_properties, "outline", "0" ); mlt_properties_set_int( my_properties, "_filter_private", 1 ); filter->process = filter_process; } else { if( filter ) { mlt_filter_close( filter ); } if( transition ) { mlt_transition_close( transition ); } if( producer ) { mlt_producer_close( producer ); } filter = NULL; } return filter; } mlt-0.9.0/src/modules/gtk2/filter_dynamictext.yml000066400000000000000000000075031215300731300220430ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: dynamictext title: Dynamic text version: 1 copyright: Ushodaya Enterprises Limited creator: Brian Matherly license: LGPLv2.1 language: en tags: - Video description: Overlay dynamic text onto the video notes: > The dynamic text filter will search for keywords in the text to be overlayed and will replace those keywords on a frame-by-frame basis. parameters: - identifier: argument title: Dynamic text type: string description: | The text to overlay. May include keywords enclosed in "#". Keywords include: * #timecode# - timecode of the frame (based on framerate and position) * #frame# - frame number of the frame * #filedate# - modification date of the file Keywords may also be any frame property (e.g. #meta.media.0.codec.frame_rate#) The # may be escaped with "\". required: yes readonly: no default: > #trick to escape "#" character #timecode# widget: text - identifier: geometry title: Geometry type: geometry description: A set of X/Y coordinates by which to adjust the text. default: 0%/0%:100%x100%:100 - identifier: family title: Font family type: string description: > The typeface of the font. default: Sans readonly: no mutable: yes widget: combo - identifier: size title: Font size type: integer description: > The size in pixels of the font. default: 48 readonly: no mutable: yes widget: spinner - identifier: weight title: Font weight type: integer description: The weight of the font. minimum: 100 maximum: 1000 default: 400 readonly: no mutable: yes widget: spinner - identifier: fgcolour title: Foreground color type: string description: > A color value is a hexadecimal representation of RGB plus alpha channel as 0xrrggbbaa. Colors can also be the words: white, black, red, green, or blue. You can also use a HTML-style color values #rrggbb or #aarrggbb. default: 0x000000ff readonly: no mutable: yes widget: color - identifier: bgcolour title: Background color type: string description: > A color value is a hexadecimal representation of RGB plus alpha channel as 0xrrggbbaa. Colors can also be the words: white, black, red, green, or blue. You can also use a HTML-style color values #rrggbb or #aarrggbb. default: 0x00000020 readonly: no mutable: yes widget: color - identifier: olcolour title: Outline color type: string description: > A color value is a hexadecimal representation of RGB plus alpha channel as 0xrrggbbaa. Colors can also be the words: white, black, red, green, or blue. You can also use a HTML-style color values #rrggbb or #aarrggbb. readonly: no mutable: yes widget: color - identifier: outline title: Outline Width type: string description: > The width of the outline in pixels. readonly: no default: 0 minimum: 0 maximum: 3 mutable: yes widget: spinner - identifier: pad title: Padding type: integer description: > The number of pixels to pad the background rectangle beyond edges of text. readonly: no default: 0 mutable: yes widget: spinner - identifier: halign title: Horizontal alignment description: > Set the horizontal alignment within the geometry rectangle. type: string default: left values: - left - centre - right mutable: yes widget: combo - identifier: valign title: Vertical alignment description: > Set the vertical alignment within the geometry rectangle. type: string default: top values: - top - middle - bottom mutable: yes widget: combo mlt-0.9.0/src/modules/gtk2/filter_rescale.c000066400000000000000000000100771215300731300205510ustar00rootroot00000000000000/* * filter_rescale.c -- scale the producer video frame size to match the consumer * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "pixops.h" #include #include #include #include #include #include #include static int filter_scale( mlt_frame this, uint8_t **image, mlt_image_format *format, int iwidth, int iheight, int owidth, int oheight ) { // Get the properties mlt_properties properties = MLT_FRAME_PROPERTIES( this ); // Get the requested interpolation method char *interps = mlt_properties_get( properties, "rescale.interp" ); // Convert to the GTK flag int interp = PIXOPS_INTERP_BILINEAR; if ( strcmp( interps, "nearest" ) == 0 ) interp = PIXOPS_INTERP_NEAREST; else if ( strcmp( interps, "tiles" ) == 0 ) interp = PIXOPS_INTERP_TILES; else if ( strcmp( interps, "hyper" ) == 0 || strcmp( interps, "bicubic" ) == 0 ) interp = PIXOPS_INTERP_HYPER; int bpp; int size = mlt_image_format_size( *format, owidth, oheight, &bpp ); // Carry out the rescaling switch ( *format ) { case mlt_image_yuv422: { // Create the output image uint8_t *output = mlt_pool_alloc( size ); // Calculate strides int istride = iwidth * 2; int ostride = owidth * 2; yuv422_scale_simple( output, owidth, oheight, ostride, *image, iwidth, iheight, istride, interp ); // Now update the frame mlt_frame_set_image( this, output, size, mlt_pool_release ); // Return the output *image = output; break; } case mlt_image_rgb24: case mlt_image_rgb24a: case mlt_image_opengl: { if ( strcmp( interps, "none" ) && ( iwidth != owidth || iheight != oheight ) ) { // Create the output image uint8_t *output = mlt_pool_alloc( size ); GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data( *image, GDK_COLORSPACE_RGB, ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ), 8, iwidth, iheight, iwidth * bpp, NULL, NULL ); GdkPixbuf *scaled = gdk_pixbuf_scale_simple( pixbuf, owidth, oheight, interp ); g_object_unref( pixbuf ); int src_stride = gdk_pixbuf_get_rowstride( scaled ); int dst_stride = owidth * bpp; if ( src_stride != dst_stride ) { int y = oheight; uint8_t *src = gdk_pixbuf_get_pixels( scaled ); uint8_t *dst = output; while ( y-- ) { memcpy( dst, src, dst_stride ); dst += dst_stride; src += src_stride; } } else { memcpy( output, gdk_pixbuf_get_pixels( scaled ), owidth * oheight * bpp ); } g_object_unref( scaled ); // Now update the frame mlt_frame_set_image( this, output, size, mlt_pool_release ); // Return the output *image = output; } break; } default: break; } return 0; } /** Constructor for the filter. */ mlt_filter filter_rescale_init( mlt_profile profile, char *arg ) { // Create a new scaler mlt_filter this = mlt_factory_filter( profile, "rescale", arg ); // If successful, then initialise it if ( this != NULL ) { // Get the properties mlt_properties properties = MLT_FILTER_PROPERTIES( this ); // Set the inerpolation mlt_properties_set( properties, "interpolation", arg == NULL ? "bilinear" : arg ); // Set the method mlt_properties_set_data( properties, "method", filter_scale, 0, NULL, NULL ); } return this; } mlt-0.9.0/src/modules/gtk2/filter_rescale.yml000066400000000000000000000022211215300731300211200ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: gtkrescale title: Gtk Rescale version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Video - Hidden description: > Scale the producer video frame size to match the consumer. This filter is designed for use as a normaliser for the loader producer. notes: > If a property "consumer_aspect_ratio" exists on the frame, then rescaler normalises the producer's aspect ratio and maximises the size of the frame, but may not produce the consumer's requested dimension. Therefore, this option works best in conjunction with the resize filter. This behavior can be disabled by another service by either removing the property, setting it to zero, or setting frame property "distort" to 1. parameters: - identifier: argument title: Interpolation type: string description: The rescaling method. values: - nearest (lowest quality, fastest) - tiles - bilinear (good quality, moderate speed) - hyper (best quality, slowest) required: no readonly: no default: bilinear widget: combo mlt-0.9.0/src/modules/gtk2/have_mmx.S000066400000000000000000000030431215300731300173450ustar00rootroot00000000000000/* * Copyright (C) 2000 Red Hat, Inc * * This library 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 of the License, or (at your option) any later version. * * This library 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 this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ .file "have_mmx.S" .version "01.01" gcc2_compiled.: .text .align 16 #if !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(__INTERIX) /* Magic indicating no need for an executable stack */ #if !defined __powerpc64__ && !defined __ia64__ .section .note.GNU-stack; .previous #endif .globl _pixops_have_mmx .type _pixops_have_mmx,@function _pixops_have_mmx: #else .globl __pixops_have_mmx __pixops_have_mmx: #endif push %ebx # Check if bit 21 in flags word is writeable pushfl popl %eax movl %eax,%ebx xorl $0x00200000, %eax pushl %eax popfl pushfl popl %eax cmpl %eax, %ebx je .notfound # OK, we have CPUID movl $1, %eax cpuid test $0x00800000, %edx jz .notfound movl $1, %eax jmp .out .notfound: movl $0, %eax .out: popl %ebx ret mlt-0.9.0/src/modules/gtk2/pixops.c000066400000000000000000000476641215300731300171240ustar00rootroot00000000000000/* GdkPixbuf library - Scaling and compositing functions * * Original: * Copyright (C) 2000 Red Hat, Inc * Author: Owen Taylor * * Modification for MLT: * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 of the License, or (at your option) any later version. * * This library 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 this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include "pixops.h" #define SUBSAMPLE_BITS 4 #define SUBSAMPLE (1 << SUBSAMPLE_BITS) #define SUBSAMPLE_MASK ((1 << SUBSAMPLE_BITS)-1) #define SCALE_SHIFT 16 typedef struct _PixopsFilter PixopsFilter; typedef struct _PixopsFilterDimension PixopsFilterDimension; struct _PixopsFilterDimension { int n; double offset; double *weights; }; struct _PixopsFilter { PixopsFilterDimension x; PixopsFilterDimension y; double overall_alpha; }; typedef guchar *( *PixopsLineFunc ) ( int *weights, int n_x, int n_y, guchar *dest, int dest_x, guchar *dest_end, guchar **src, int x_init, int x_step, int src_width ); typedef void ( *PixopsPixelFunc ) ( guchar *dest, guint y1, guint cr, guint y2, guint cb ); /* mmx function declarations */ #if defined(USE_MMX) && !defined(ARCH_X86_64) guchar *pixops_scale_line_22_yuv_mmx ( guint32 weights[ 16 ][ 8 ], guchar *p, guchar *q1, guchar *q2, int x_step, guchar *p_stop, int x_init, int destx ); int _pixops_have_mmx ( void ); #endif static inline int get_check_shift ( int check_size ) { int check_shift = 0; g_return_val_if_fail ( check_size >= 0, 4 ); while ( !( check_size & 1 ) ) { check_shift++; check_size >>= 1; } return check_shift; } static inline void pixops_scale_nearest ( guchar *dest_buf, int render_x0, int render_y0, int render_x1, int render_y1, int dest_rowstride, const guchar *src_buf, int src_width, int src_height, int src_rowstride, double scale_x, double scale_y ) { register int i, j; register int x_step = ( 1 << SCALE_SHIFT ) / scale_x; register int y_step = ( 1 << SCALE_SHIFT ) / scale_y; register int x, x_scaled; for ( i = 0; i < ( render_y1 - render_y0 ); i++ ) { const guchar *src = src_buf + ( ( ( i + render_y0 ) * y_step + ( y_step >> 1 ) ) >> SCALE_SHIFT ) * src_rowstride; guchar *dest = dest_buf + i * dest_rowstride; x = render_x0 * x_step + ( x_step >> 1 ); for ( j = 0; j < ( render_x1 - render_x0 ); j++ ) { x_scaled = x >> SCALE_SHIFT; *dest++ = src[ x_scaled << 1 ]; *dest++ = src[ ( ( x_scaled >> 1 ) << 2 ) + ( ( j & 1 ) << 1 ) + 1 ]; x += x_step; } } } static inline guchar * scale_line ( int *weights, int n_x, int n_y, guchar *dest, int dest_x, guchar *dest_end, guchar **src, int x_init, int x_step, int src_width ) { register int x = x_init; register int i, j, x_scaled, y_index, uv_index; while ( dest < dest_end ) { unsigned int y = 0, uv = 0; int *pixel_weights = weights + ( ( x >> ( SCALE_SHIFT - SUBSAMPLE_BITS ) ) & SUBSAMPLE_MASK ) * n_x * n_y; x_scaled = x >> SCALE_SHIFT; y_index = x_scaled << 1; uv_index = ( ( x_scaled >> 1 ) << 2 ) + ( ( dest_x & 1 ) << 1 ) + 1; for ( i = 0; i < n_y; i++ ) { int *line_weights = pixel_weights + n_x * i; guchar *q = src[ i ]; for ( j = 0; j < n_x; j ++ ) { unsigned int ta = line_weights[ j ]; y += ta * q[ y_index ]; uv += ta * q[ uv_index ]; } } *dest++ = ( y + 0xffff ) >> SCALE_SHIFT; *dest++ = ( uv + 0xffff ) >> SCALE_SHIFT; x += x_step; dest_x++; } return dest; } #if defined(USE_MMX) && !defined(ARCH_X86_64) static inline guchar * scale_line_22_yuv_mmx_stub ( int *weights, int n_x, int n_y, guchar *dest, int dest_x, guchar *dest_end, guchar **src, int x_init, int x_step, int src_width ) { guint32 mmx_weights[ 16 ][ 8 ]; int j; for ( j = 0; j < 16; j++ ) { mmx_weights[ j ][ 0 ] = 0x00010001 * ( weights[ 4 * j ] >> 8 ); mmx_weights[ j ][ 1 ] = 0x00010001 * ( weights[ 4 * j ] >> 8 ); mmx_weights[ j ][ 2 ] = 0x00010001 * ( weights[ 4 * j + 1 ] >> 8 ); mmx_weights[ j ][ 3 ] = 0x00010001 * ( weights[ 4 * j + 1 ] >> 8 ); mmx_weights[ j ][ 4 ] = 0x00010001 * ( weights[ 4 * j + 2 ] >> 8 ); mmx_weights[ j ][ 5 ] = 0x00010001 * ( weights[ 4 * j + 2 ] >> 8 ); mmx_weights[ j ][ 6 ] = 0x00010001 * ( weights[ 4 * j + 3 ] >> 8 ); mmx_weights[ j ][ 7 ] = 0x00010001 * ( weights[ 4 * j + 3 ] >> 8 ); } return pixops_scale_line_22_yuv_mmx ( mmx_weights, dest, src[ 0 ], src[ 1 ], x_step, dest_end, x_init, dest_x ); } #endif /* USE_MMX */ static inline guchar * scale_line_22_yuv ( int *weights, int n_x, int n_y, guchar *dest, int dest_x, guchar *dest_end, guchar **src, int x_init, int x_step, int src_width ) { register int x = x_init; register guchar *src0 = src[ 0 ]; register guchar *src1 = src[ 1 ]; register unsigned int p; register guchar *q0, *q1; register int w1, w2, w3, w4; register int x_scaled, x_aligned, uv_index; while ( dest < dest_end ) { int *pixel_weights = weights + ( ( x >> ( SCALE_SHIFT - SUBSAMPLE_BITS ) ) & SUBSAMPLE_MASK ) * 4; x_scaled = x >> SCALE_SHIFT; w1 = pixel_weights[ 0 ]; w2 = pixel_weights[ 1 ]; w3 = pixel_weights[ 2 ]; w4 = pixel_weights[ 3 ]; /* process Y */ q0 = src0 + ( x_scaled << 1 ); q1 = src1 + ( x_scaled << 1 ); p = w1 * q0[ 0 ]; p += w2 * q0[ 2 ]; p += w3 * q1[ 0 ]; p += w4 * q1[ 2 ]; *dest++ = ( p + 0x8000 ) >> SCALE_SHIFT; /* process U/V */ x_aligned = ( ( x_scaled >> 1 ) << 2 ); uv_index = ( ( dest_x & 1 ) << 1 ) + 1; q0 = src0 + x_aligned; q1 = src1 + x_aligned; p = w1 * q0[ uv_index ]; p += w3 * q1[ uv_index ]; p += w2 * q0[ uv_index ]; p += w4 * q1[ uv_index ]; x += x_step; dest_x ++; *dest++ = ( p + 0x8000 ) >> SCALE_SHIFT; } return dest; } static inline void process_pixel ( int *weights, int n_x, int n_y, guchar *dest, int dest_x, int dest_channels, guchar **src, int src_channels, int x_start, int src_width ) { register unsigned int y = 0, uv = 0; register int i, j; int uv_index = ( ( dest_x & 1 ) << 1 ) + 1; for ( i = 0; i < n_y; i++ ) { int *line_weights = weights + n_x * i; for ( j = 0; j < n_x; j++ ) { unsigned int ta = 0xff * line_weights[ j ]; if ( x_start + j < 0 ) { y += ta * src[ i ][ 0 ]; uv += ta * src[ i ][ uv_index ]; } else if ( x_start + j < src_width ) { y += ta * src[ i ][ ( x_start + j ) << 1 ]; uv += ta * src[ i ][ ( ( ( x_start + j ) >> 1 ) << 2) + uv_index ]; } else { y += ta * src[ i ][ ( src_width - 1 ) << 1 ]; uv += ta * src[ i ][ ( ( ( src_width - 1 ) >> 1 ) << 2) + uv_index ]; } } } *dest++ = ( y + 0xffffff ) >> 24; *dest++ = ( uv + 0xffffff ) >> 24; } static inline void correct_total ( int *weights, int n_x, int n_y, int total, double overall_alpha ) { int correction = ( int ) ( 0.5 + 65536 * overall_alpha ) - total; int remaining, c, d, i; if ( correction != 0 ) { remaining = correction; for ( d = 1, c = correction; c != 0 && remaining != 0; d++, c = correction / d ) for ( i = n_x * n_y - 1; i >= 0 && c != 0 && remaining != 0; i-- ) if ( *( weights + i ) + c >= 0 ) { *( weights + i ) += c; remaining -= c; if ( ( 0 < remaining && remaining < c ) || ( 0 > remaining && remaining > c ) ) c = remaining; } } } static inline int * make_filter_table ( PixopsFilter *filter ) { int i_offset, j_offset; int n_x = filter->x.n; int n_y = filter->y.n; int *weights = g_new ( int, SUBSAMPLE * SUBSAMPLE * n_x * n_y ); for ( i_offset = 0; i_offset < SUBSAMPLE; i_offset++ ) for ( j_offset = 0; j_offset < SUBSAMPLE; j_offset++ ) { double weight; int *pixel_weights = weights + ( ( i_offset * SUBSAMPLE ) + j_offset ) * n_x * n_y; int total = 0; int i, j; for ( i = 0; i < n_y; i++ ) for ( j = 0; j < n_x; j++ ) { weight = filter->x.weights[ ( j_offset * n_x ) + j ] * filter->y.weights[ ( i_offset * n_y ) + i ] * filter->overall_alpha * 65536 + 0.5; total += ( int ) weight; *( pixel_weights + n_x * i + j ) = weight; } correct_total ( pixel_weights, n_x, n_y, total, filter->overall_alpha ); } return weights; } static inline void pixops_process ( guchar *dest_buf, int render_x0, int render_y0, int render_x1, int render_y1, int dest_rowstride, int dest_channels, gboolean dest_has_alpha, const guchar *src_buf, int src_width, int src_height, int src_rowstride, int src_channels, gboolean src_has_alpha, double scale_x, double scale_y, int check_x, int check_y, int check_size, guint32 color1, guint32 color2, PixopsFilter *filter, PixopsLineFunc line_func ) { int i, j; int x, y; /* X and Y position in source (fixed_point) */ guchar **line_bufs = g_new ( guchar *, filter->y.n ); int *filter_weights = make_filter_table ( filter ); int x_step = ( 1 << SCALE_SHIFT ) / scale_x; /* X step in source (fixed point) */ int y_step = ( 1 << SCALE_SHIFT ) / scale_y; /* Y step in source (fixed point) */ int check_shift = check_size ? get_check_shift ( check_size ) : 0; int scaled_x_offset = floor ( filter->x.offset * ( 1 << SCALE_SHIFT ) ); /* Compute the index where we run off the end of the source buffer. The furthest * source pixel we access at index i is: * * ((render_x0 + i) * x_step + scaled_x_offset) >> SCALE_SHIFT + filter->x.n - 1 * * So, run_end_index is the smallest i for which this pixel is src_width, i.e, for which: * * (i + render_x0) * x_step >= ((src_width - filter->x.n + 1) << SCALE_SHIFT) - scaled_x_offset * */ #define MYDIV(a,b) ((a) > 0 ? (a) / (b) : ((a) - (b) + 1) / (b)) /* Division so that -1/5 = -1 */ int run_end_x = ( ( ( src_width - filter->x.n + 1 ) << SCALE_SHIFT ) - scaled_x_offset ); int run_end_index = MYDIV ( run_end_x + x_step - 1, x_step ) - render_x0; run_end_index = MIN ( run_end_index, render_x1 - render_x0 ); y = render_y0 * y_step + floor ( filter->y.offset * ( 1 << SCALE_SHIFT ) ); for ( i = 0; i < ( render_y1 - render_y0 ); i++ ) { int dest_x; int y_start = y >> SCALE_SHIFT; int x_start; int *run_weights = filter_weights + ( ( y >> ( SCALE_SHIFT - SUBSAMPLE_BITS ) ) & SUBSAMPLE_MASK ) * filter->x.n * filter->y.n * SUBSAMPLE; guchar *new_outbuf; guint32 tcolor1, tcolor2; guchar *outbuf = dest_buf + dest_rowstride * i; guchar *outbuf_end = outbuf + dest_channels * ( render_x1 - render_x0 ); if ( ( ( i + check_y ) >> check_shift ) & 1 ) { tcolor1 = color2; tcolor2 = color1; } else { tcolor1 = color1; tcolor2 = color2; } for ( j = 0; j < filter->y.n; j++ ) { if ( y_start < 0 ) line_bufs[ j ] = ( guchar * ) src_buf; else if ( y_start < src_height ) line_bufs[ j ] = ( guchar * ) src_buf + src_rowstride * y_start; else line_bufs[ j ] = ( guchar * ) src_buf + src_rowstride * ( src_height - 1 ); y_start++; } dest_x = check_x; x = render_x0 * x_step + scaled_x_offset; x_start = x >> SCALE_SHIFT; while ( x_start < 0 && outbuf < outbuf_end ) { process_pixel ( run_weights + ( ( x >> ( SCALE_SHIFT - SUBSAMPLE_BITS ) ) & SUBSAMPLE_MASK ) * ( filter->x.n * filter->y.n ), filter->x.n, filter->y.n, outbuf, dest_x, dest_channels, line_bufs, src_channels, x >> SCALE_SHIFT, src_width ); x += x_step; x_start = x >> SCALE_SHIFT; dest_x++; outbuf += dest_channels; } new_outbuf = ( *line_func ) ( run_weights, filter->x.n, filter->y.n, outbuf, dest_x, dest_buf + dest_rowstride * i + run_end_index * dest_channels, line_bufs, x, x_step, src_width ); dest_x += ( new_outbuf - outbuf ) / dest_channels; x = ( dest_x - check_x + render_x0 ) * x_step + scaled_x_offset; outbuf = new_outbuf; while ( outbuf < outbuf_end ) { process_pixel ( run_weights + ( ( x >> ( SCALE_SHIFT - SUBSAMPLE_BITS ) ) & SUBSAMPLE_MASK ) * ( filter->x.n * filter->y.n ), filter->x.n, filter->y.n, outbuf, dest_x, dest_channels, line_bufs, src_channels, x >> SCALE_SHIFT, src_width ); x += x_step; dest_x++; outbuf += dest_channels; } y += y_step; } g_free ( line_bufs ); g_free ( filter_weights ); } /* Compute weights for reconstruction by replication followed by * sampling with a box filter */ static inline void tile_make_weights ( PixopsFilterDimension *dim, double scale ) { int n = ceil ( 1 / scale + 1 ); double *pixel_weights = g_new ( double, SUBSAMPLE * n ); int offset; int i; dim->n = n; dim->offset = 0; dim->weights = pixel_weights; for ( offset = 0; offset < SUBSAMPLE; offset++ ) { double x = ( double ) offset / SUBSAMPLE; double a = x + 1 / scale; for ( i = 0; i < n; i++ ) { if ( i < x ) { if ( i + 1 > x ) * ( pixel_weights++ ) = ( MIN ( i + 1, a ) - x ) * scale; else *( pixel_weights++ ) = 0; } else { if ( a > i ) * ( pixel_weights++ ) = ( MIN ( i + 1, a ) - i ) * scale; else *( pixel_weights++ ) = 0; } } } } /* Compute weights for a filter that, for minification * is the same as 'tiles', and for magnification, is bilinear * reconstruction followed by a sampling with a delta function. */ static inline void bilinear_magnify_make_weights ( PixopsFilterDimension *dim, double scale ) { double * pixel_weights; int n; int offset; int i; if ( scale > 1.0 ) /* Linear */ { n = 2; dim->offset = 0.5 * ( 1 / scale - 1 ); } else /* Tile */ { n = ceil ( 1.0 + 1.0 / scale ); dim->offset = 0.0; } dim->n = n; dim->weights = g_new ( double, SUBSAMPLE * n ); pixel_weights = dim->weights; for ( offset = 0; offset < SUBSAMPLE; offset++ ) { double x = ( double ) offset / SUBSAMPLE; if ( scale > 1.0 ) /* Linear */ { for ( i = 0; i < n; i++ ) *( pixel_weights++ ) = ( ( ( i == 0 ) ? ( 1 - x ) : x ) / scale ) * scale; } else /* Tile */ { double a = x + 1 / scale; /* x * ---------|--.-|----|--.-|------- SRC * ------------|---------|--------- DEST */ for ( i = 0; i < n; i++ ) { if ( i < x ) { if ( i + 1 > x ) * ( pixel_weights++ ) = ( MIN ( i + 1, a ) - x ) * scale; else *( pixel_weights++ ) = 0; } else { if ( a > i ) * ( pixel_weights++ ) = ( MIN ( i + 1, a ) - i ) * scale; else *( pixel_weights++ ) = 0; } } } } } /* Computes the integral from b0 to b1 of * * f(x) = x; 0 <= x < 1 * f(x) = 0; otherwise * * We combine two of these to compute the convolution of * a box filter with a triangular spike. */ static inline double linear_box_half ( double b0, double b1 ) { double a0, a1; double x0, x1; a0 = 0.; a1 = 1.; if ( a0 < b0 ) { if ( a1 > b0 ) { x0 = b0; x1 = MIN ( a1, b1 ); } else return 0; } else { if ( b1 > a0 ) { x0 = a0; x1 = MIN ( a1, b1 ); } else return 0; } return 0.5 * ( x1 * x1 - x0 * x0 ); } /* Compute weights for reconstructing with bilinear * interpolation, then sampling with a box filter */ static inline void bilinear_box_make_weights ( PixopsFilterDimension *dim, double scale ) { int n = ceil ( 1 / scale + 2.0 ); double *pixel_weights = g_new ( double, SUBSAMPLE * n ); double w; int offset, i; dim->offset = -1.0; dim->n = n; dim->weights = pixel_weights; for ( offset = 0 ; offset < SUBSAMPLE; offset++ ) { double x = ( double ) offset / SUBSAMPLE; double a = x + 1 / scale; for ( i = 0; i < n; i++ ) { w = linear_box_half ( 0.5 + i - a, 0.5 + i - x ); w += linear_box_half ( 1.5 + x - i, 1.5 + a - i ); *( pixel_weights++ ) = w * scale; } } } static inline void make_weights ( PixopsFilter *filter, PixopsInterpType interp_type, double scale_x, double scale_y ) { switch ( interp_type ) { case PIXOPS_INTERP_NEAREST: g_assert_not_reached (); break; case PIXOPS_INTERP_TILES: tile_make_weights ( &filter->x, scale_x ); tile_make_weights ( &filter->y, scale_y ); break; case PIXOPS_INTERP_BILINEAR: bilinear_magnify_make_weights ( &filter->x, scale_x ); bilinear_magnify_make_weights ( &filter->y, scale_y ); break; case PIXOPS_INTERP_HYPER: bilinear_box_make_weights ( &filter->x, scale_x ); bilinear_box_make_weights ( &filter->y, scale_y ); break; } } void yuv422_scale ( guchar *dest_buf, int render_x0, int render_y0, int render_x1, int render_y1, int dest_rowstride, int dest_channels, gboolean dest_has_alpha, const guchar *src_buf, int src_width, int src_height, int src_rowstride, int src_channels, gboolean src_has_alpha, double scale_x, double scale_y, PixopsInterpType interp_type ) { PixopsFilter filter = { { 0, 0, 0}, { 0, 0, 0 }, 0 }; PixopsLineFunc line_func; #if defined(USE_MMX) && !defined(ARCH_X86_64) gboolean found_mmx = _pixops_have_mmx(); #endif //g_return_if_fail ( !( dest_channels == 3 && dest_has_alpha ) ); //g_return_if_fail ( !( src_channels == 3 && src_has_alpha ) ); //g_return_if_fail ( !( src_has_alpha && !dest_has_alpha ) ); if ( scale_x == 0 || scale_y == 0 ) return ; if ( interp_type == PIXOPS_INTERP_NEAREST ) { pixops_scale_nearest ( dest_buf, render_x0, render_y0, render_x1, render_y1, dest_rowstride, src_buf, src_width, src_height, src_rowstride, scale_x, scale_y ); return; } filter.overall_alpha = 1.0; make_weights ( &filter, interp_type, scale_x, scale_y ); if ( filter.x.n == 2 && filter.y.n == 2 ) { #if defined(USE_MMX) && !defined(ARCH_X86_64) if ( found_mmx ) { //fprintf( stderr, "rescale: using mmx\n" ); line_func = scale_line_22_yuv_mmx_stub; } else #endif line_func = scale_line_22_yuv; } else line_func = scale_line; pixops_process ( dest_buf, render_x0, render_y0, render_x1, render_y1, dest_rowstride, dest_channels, dest_has_alpha, src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0, &filter, line_func ); g_free ( filter.x.weights ); g_free ( filter.y.weights ); } mlt-0.9.0/src/modules/gtk2/pixops.h000066400000000000000000000050221215300731300171070ustar00rootroot00000000000000/* GdkPixbuf library - Scaling and compositing functions * * Original: * Copyright (C) 2000 Red Hat, Inc * Author: Owen Taylor * * Modification for MLT: * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 of the License, or (at your option) any later version. * * This library 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 this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef PIXOPS_H #define PIXOPS_H #include /* Interpolation modes; must match GdkInterpType */ typedef enum { PIXOPS_INTERP_NEAREST, PIXOPS_INTERP_TILES, PIXOPS_INTERP_BILINEAR, PIXOPS_INTERP_HYPER } PixopsInterpType; /* Scale src_buf from src_width / src_height by factors scale_x, scale_y * and composite the portion corresponding to * render_x, render_y, render_width, render_height in the new * coordinate system into dest_buf starting at 0, 0 */ void yuv422_scale (guchar *dest_buf, int render_x0, int render_y0, int render_x1, int render_y1, int dest_rowstride, int dest_channels, int dest_has_alpha, const guchar *src_buf, int src_width, int src_height, int src_rowstride, int src_channels, int src_has_alpha, double scale_x, double scale_y, PixopsInterpType interp_type); #define yuv422_scale_simple( dest_buf, dest_width, dest_height, dest_rowstride, src_buf, src_width, src_height, src_rowstride, interp_type ) \ yuv422_scale( (dest_buf), 0, 0, \ (dest_width), (dest_height), \ (dest_rowstride), 2, 0, \ (src_buf), (src_width), (src_height), \ (src_rowstride), 2, 0, \ (double) (dest_width) / (src_width), (double) (dest_height) / (src_height), \ (PixopsInterpType) interp_type ); #endif mlt-0.9.0/src/modules/gtk2/producer_count.c000066400000000000000000000454271215300731300206300ustar00rootroot00000000000000/* * producer_count.c -- counting producer * Copyright (C) 2013 Brian Matherly * Author: Brian Matherly * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include /* Private Constants */ #define MAX_TEXT_LEN 512 #define LINE_PIXEL_VALUE 0x00 #define RING_PIXEL_VALUE 0xff #define CLOCK_PIXEL_VALUE 0x50 #define FRAME_BACKGROUND_COLOR "0xd0d0d0ff" #define TEXT_BACKGROUND_COLOR "0x00000000" #define TEXT_FOREGROUND_COLOR "0x000000ff" // Ratio of graphic elements relative to image size #define LINE_WIDTH_RATIO 1 #define OUTER_RING_RATIO 90 #define INNER_RING_RATIO 80 #define TEXT_SIZE_RATIO 70 static inline void mix_pixel( uint8_t* image, int width, int x, int y, int value, float mix ) { uint8_t* p = image + (( y * width ) + x ) * 4; if( mix != 1.0 ) { value = ((float)value * mix) + ((float)*p * (1.0 - mix)); } *p = value; p++; *p = value; p++; *p = value; } /** Fill an audio buffer with 1kHz samples. */ static void fill_beep( mlt_properties producer_properties, float* buffer, int frequency, int channels, int samples ) { int s = 0; int c = 0; for( s = 0; s < samples; s++ ) { float f = 1000.0; float t = (float)s/(float)frequency; float value = sin( 2*M_PI*f*t ); for( c = 0; c < channels; c++ ) { float* sample_ptr = buffer + (c * samples) + s; *sample_ptr = value; } } } static int producer_get_audio( mlt_frame frame, int16_t** buffer, mlt_audio_format* format, int* frequency, int* channels, int* samples ) { mlt_producer producer = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "_producer_count", NULL ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); char* sound = mlt_properties_get( producer_properties, "sound" ); double fps = mlt_producer_get_fps( producer ); int position = mlt_frame_get_position( frame ); int size = 0; int do_beep = 0; if( fps == 0 ) fps = 25; // Correct the returns if necessary *format = mlt_audio_float; *frequency = *frequency <= 0 ? 48000 : *frequency; *channels = *channels <= 0 ? 2 : *channels; *samples = *samples <= 0 ? mlt_sample_calculator( fps, *frequency, position ) : *samples; // Allocate the buffer size = *samples * *channels * sizeof( float ); *buffer = mlt_pool_alloc( size ); // Determine if this should be a tone or silence. if( strcmp( sound, "none") ) { if( !strcmp( sound, "2pop" ) ) { int out = mlt_properties_get_int( producer_properties, "out" ); int frames = out - position; if( frames == lrint( fps * 2 ) ) { do_beep = 1; } } else if( !strcmp( sound, "frame0" ) ) { int frames = position; // Apply the direction char* direction = mlt_properties_get( producer_properties, "direction" ); if( !strcmp( direction, "down" ) ) { int out = mlt_properties_get_int( producer_properties, "out" ); frames = out - position; } frames = position % lrint( fps ); if( frames == 0 ) { do_beep = 1; } } } if( do_beep ) { fill_beep( producer_properties, (float*)*buffer, *frequency, *channels, *samples ); } else { // Fill silence. memset( *buffer, 0, size ); } // Set the buffer for destruction mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); return 0; } static mlt_frame get_background_frame( mlt_producer producer ) { mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_frame bg_frame = NULL; mlt_producer color_producer = mlt_properties_get_data( producer_properties, "_color_producer", NULL ); if( !color_producer ) { mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); color_producer = mlt_factory_producer( profile, mlt_environment( "MLT_PRODUCER" ), "colour:" ); mlt_properties_set_data( producer_properties, "_color_producer", color_producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); mlt_properties color_properties = MLT_PRODUCER_PROPERTIES( color_producer ); mlt_properties_set( color_properties, "colour", FRAME_BACKGROUND_COLOR ); } if( color_producer ) { mlt_producer_seek( color_producer, 0 ); mlt_service_get_frame( MLT_PRODUCER_SERVICE( color_producer ), &bg_frame, 0 ); } return bg_frame; } static mlt_frame get_text_frame( mlt_producer producer, mlt_position position ) { mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_producer pango_producer = mlt_properties_get_data( producer_properties, "_pango_producer", NULL ); mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); mlt_frame text_frame = NULL; if( !pango_producer ) { pango_producer = mlt_factory_producer( profile, mlt_environment( "MLT_PRODUCER" ), "pango:" ); // Save the producer for future use. mlt_properties_set_data( producer_properties, "_pango_producer", pango_producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); // Calculate the font size. char font_size[MAX_TEXT_LEN]; snprintf( font_size, MAX_TEXT_LEN - 1, "%dpx", profile->height * TEXT_SIZE_RATIO / 100 ); // Configure the producer. mlt_properties pango_properties = MLT_PRODUCER_PROPERTIES( pango_producer ); mlt_properties_set( pango_properties, "size", font_size ); mlt_properties_set( pango_properties, "weight", "400" ); mlt_properties_set( pango_properties, "fgcolour", TEXT_FOREGROUND_COLOR ); mlt_properties_set( pango_properties, "bgcolour", TEXT_BACKGROUND_COLOR ); mlt_properties_set( pango_properties, "pad", "0" ); mlt_properties_set( pango_properties, "outline", "0" ); mlt_properties_set( pango_properties, "align", "center" ); } if( pango_producer ) { mlt_properties pango_properties = MLT_PRODUCER_PROPERTIES( pango_producer ); char* direction = mlt_properties_get( producer_properties, "direction" ); char* style = mlt_properties_get( producer_properties, "style" ); char text[MAX_TEXT_LEN] = ""; int fps = lrint(mlt_profile_fps( profile )); if( fps == 0 ) fps = 25; // Apply the direction if( !strcmp( direction, "down" ) ) { int out = mlt_properties_get_int( producer_properties, "out" ); position = out - position; } // Calculate clock values int seconds = position / fps; int frames = MLT_POSITION_MOD(position, fps); int minutes = seconds / 60; seconds = seconds % 60; int hours = minutes / 60; minutes = minutes % 60; // Apply the time style if( !strcmp( style, "frames" ) ) { snprintf( text, MAX_TEXT_LEN - 1, MLT_POSITION_FMT, position ); } else if( !strcmp( style, "timecode" ) ) { snprintf( text, MAX_TEXT_LEN - 1, "%.2d:%.2d:%.2d:%.2d", hours, minutes, seconds, frames ); } else if( !strcmp( style, "clock" ) ) { snprintf( text, MAX_TEXT_LEN - 1, "%.2d:%.2d:%.2d", hours, minutes, seconds ); } else if( !strcmp( style, "seconds+1" ) ) { snprintf( text, MAX_TEXT_LEN - 1, "%d", seconds + 1 ); } else // seconds { snprintf( text, MAX_TEXT_LEN - 1, "%d", seconds ); } mlt_properties_set( pango_properties, "markup", text ); // Get the frame. mlt_service_get_frame( MLT_PRODUCER_SERVICE( pango_producer ), &text_frame, 0 ); } return text_frame; } static void draw_ring( uint8_t* image, mlt_profile profile, int radius, int line_width ) { float sar = mlt_profile_sar( profile ); int x_center = profile->width / 2; int y_center = profile->height / 2; int max_radius = radius + line_width; int a = max_radius + 1; int b = 0; line_width += 1; // Compensate for aliasing. // Scan through each pixel in one quadrant of the circle. while( a-- ) { b = ( max_radius / sar ) + 1.0; while( b-- ) { // Use Pythagorean theorem to determine the distance from this pixel to the center. float a2 = a*a; float b2 = b*sar*b*sar; float c = sqrtf( a2 + b2 ); float distance = c - radius; if( distance > 0 && distance < line_width ) { // This pixel is within the ring. float mix = 1.0; if( distance < 1.0 ) { // Antialias the outside of the ring mix = distance; } else if( (float)line_width - distance < 1.0 ) { // Antialias the inside of the ring mix = (float)line_width - distance; } // Apply this value to all 4 quadrants of the circle. mix_pixel( image, profile->width, x_center + b, y_center - a, RING_PIXEL_VALUE, mix ); mix_pixel( image, profile->width, x_center - b, y_center - a, RING_PIXEL_VALUE, mix ); mix_pixel( image, profile->width, x_center + b, y_center + a, RING_PIXEL_VALUE, mix ); mix_pixel( image, profile->width, x_center - b, y_center + a, RING_PIXEL_VALUE, mix ); } } } } static void draw_cross( uint8_t* image, mlt_profile profile, int line_width ) { int x = 0; int y = 0; int i = 0; // Draw a horizontal line i = line_width; while( i-- ) { y = ( profile->height - line_width ) / 2 + i; x = profile->width - 1; while( x-- ) { mix_pixel( image, profile->width, x, y, LINE_PIXEL_VALUE, 1.0 ); } } // Draw a vertical line line_width = lrint((float)line_width * mlt_profile_sar( profile )); i = line_width; while( i-- ) { x = ( profile->width - line_width ) / 2 + i; y = profile->height - 1; while( y-- ) { mix_pixel( image, profile->width, x, y, LINE_PIXEL_VALUE, 1.0 ); } } } static void draw_clock( uint8_t* image, mlt_profile profile, int angle, int line_width ) { float sar = mlt_profile_sar( profile ); int q = 0; int x_center = profile->width / 2; int y_center = profile->height / 2; line_width += 1; // Compensate for aliasing. // Look at each quadrant of the frame to see what should be done. for( q = 1; q <= 4; q++ ) { int max_angle = q * 90; int x_sign = ( q == 1 || q == 2 ) ? 1 : -1; int y_sign = ( q == 1 || q == 4 ) ? 1 : -1; int x_start = x_center * x_sign; int y_start = y_center * y_sign; // Compensate for rounding error of even lengths // (there is no "middle" pixel so everything is offset). if( x_sign == 1 && profile->width % 2 == 0 ) x_start--; if( y_sign == -1 && profile->height % 2 == 0 ) y_start++; if( angle >= max_angle ) { // This quadrant is completely behind the clock hand. Fill it in. int dx = x_start + x_sign; while( dx ) { dx -= x_sign; int dy = y_start + y_sign; while( dy ) { dy -= y_sign; mix_pixel( image, profile->width, x_center + dx, y_center - dy, CLOCK_PIXEL_VALUE, 1.0 ); } } } else if ( max_angle - angle < 90 ) { // This quadrant is partially filled // Calculate a point (vx,vy) that lies on the line created by the angle from 0,0. int vx = 0; int vy = y_start; float lv = 0; // Assume maximum y and calculate the corresponding x value // for a point at the other end of this line. if( x_sign * y_sign == 1 ) { vx = x_sign * sar * y_center / tan( ( max_angle - angle ) * M_PI / 180.0 ); } else { vx = x_sign * sar * y_center * tan( ( max_angle - angle ) * M_PI / 180.0 ); } // Calculate the length of the line defined by vx,vy lv = sqrtf((float)(vx*vx)*sar*sar + (float)vy*vy); // Scan through each pixel in the quadrant counting up/down to 0,0. int dx = x_start + x_sign; while( dx ) { dx -= x_sign; int dy = y_start + y_sign; while( dy ) { dy -= y_sign; // Calculate the cross product to determine which side of // the line this pixel lies on. int xp = vx * (vy - dy) - vy * (vx - dx); xp = xp * -1; // Easier to work with positive. Positive number means "behind" the line. if( xp > 0 ) { // This pixel is behind the clock hand and should be filled in. // Calculate the distance from the pixel to the line to determine // if it is part of the clock hand. float distance = (float)xp / lv; int val = CLOCK_PIXEL_VALUE; float mix = 1.0; if( distance < line_width ) { // This pixel makes up the clock hand. val = LINE_PIXEL_VALUE; if( distance < 1.0 ) { // Antialias the outside of the clock hand mix = distance; } else if( (float)line_width - distance < 1.0 ) { // Antialias the inside of the clock hand mix_pixel( image, profile->width, x_center + dx, y_center - dy, CLOCK_PIXEL_VALUE, 1.0 ); mix = (float)line_width - distance; } } mix_pixel( image, profile->width, x_center + dx, y_center - dy, val, mix ); } } } } } } static void add_clock_to_frame( mlt_producer producer, mlt_frame frame, mlt_position position ) { mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); uint8_t* image = NULL; mlt_image_format format = mlt_image_rgb24a; int size = 0; int width = profile->width; int height = profile->height; int line_width = LINE_WIDTH_RATIO * (width > height ? height : width) / 100; int fps = lrint(mlt_profile_fps( profile )); if( fps == 0 ) fps = 25; int radius = (width > height ? height : width) / 2; char* direction = mlt_properties_get( producer_properties, "direction" ); int clock_angle = 0; mlt_frame_get_image( frame, &image, &format, &width, &height, 1 ); // Calculate the angle for the clock. if( !strcmp( direction, "down" ) ) { int out = mlt_producer_get_out( producer ); int frames = fps - MLT_POSITION_MOD(out - position, fps); clock_angle = lrint( (frames + 1) * 360 / fps ); } else { int frames = MLT_POSITION_MOD(position, fps); clock_angle = lrint( (frames + 1) * 360 / fps ); } draw_clock( image, profile, clock_angle, line_width ); draw_cross( image, profile, line_width ); draw_ring( image, profile, ( radius * OUTER_RING_RATIO ) / 100, line_width ); draw_ring( image, profile, ( radius * INNER_RING_RATIO ) / 100, line_width ); size = mlt_image_format_size( format, width, height, NULL ); mlt_frame_set_image( frame, image, size, mlt_pool_release ); } static void add_text_to_bg( mlt_producer producer, mlt_frame bg_frame, mlt_frame text_frame ) { mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_transition transition = mlt_properties_get_data( producer_properties, "_transition", NULL ); if( !transition ) { mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); transition = mlt_factory_transition( profile, "composite", NULL ); // Save the transition for future use. mlt_properties_set_data( producer_properties, "_transition", transition, 0, ( mlt_destructor )mlt_transition_close, NULL ); // Configure the transition. mlt_properties transition_properties = MLT_TRANSITION_PROPERTIES( transition ); mlt_properties_set( transition_properties, "geometry", "0%/0%:100%x100%:100" ); mlt_properties_set( transition_properties, "halign", "center" ); mlt_properties_set( transition_properties, "valign", "middle" ); } if( transition && bg_frame && text_frame ) { // Apply the transition. mlt_transition_process( transition, bg_frame, text_frame ); } } static int producer_get_image( mlt_frame frame, uint8_t** image, mlt_image_format* format, int* width, int* height, int writable ) { mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_position position = mlt_frame_original_position( frame ); mlt_producer producer = mlt_properties_get_data( properties, "_producer_count", NULL ); mlt_frame bg_frame = NULL; mlt_frame text_frame = NULL; int error = 1; int size = 0; char* background = mlt_properties_get( MLT_PRODUCER_PROPERTIES( producer ), "background" ); mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); bg_frame = get_background_frame( producer ); if( !strcmp( background, "clock" ) ) { add_clock_to_frame( producer, bg_frame, position ); } text_frame = get_text_frame( producer, position ); add_text_to_bg( producer, bg_frame, text_frame ); if( bg_frame ) { // Get the image from the background frame. error = mlt_frame_get_image( bg_frame, image, format, width, height, writable ); size = mlt_image_format_size( *format, *width, *height, NULL ); // Detach the image from the bg_frame so it is not released. mlt_frame_set_image( bg_frame, *image, size, NULL ); // Attach the image to the input frame. mlt_frame_set_image( frame, *image, size, mlt_pool_release ); mlt_frame_close( bg_frame ); } if( text_frame ) { mlt_frame_close( text_frame ); } mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); return error; } static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL ) { // Obtain properties of frame mlt_properties frame_properties = MLT_FRAME_PROPERTIES( *frame ); // Save the producer to be used later mlt_properties_set_data( frame_properties, "_producer_count", producer, 0, NULL, NULL ); // Update time code on the frame mlt_frame_set_position( *frame, mlt_producer_frame( producer ) ); mlt_properties_set_int( frame_properties, "progressive", 1 ); mlt_properties_set_double( frame_properties, "aspect_ratio", mlt_profile_sar( profile ) ); mlt_properties_set_int( frame_properties, "meta.media.width", profile->width ); mlt_properties_set_int( frame_properties, "meta.media.height", profile->height ); // Configure callbacks mlt_frame_push_get_image( *frame, producer_get_image ); mlt_frame_push_audio( *frame, producer_get_audio ); } // Calculate the next time code mlt_producer_prepare_next( producer ); return 0; } static void producer_close( mlt_producer this ) { this->close = NULL; mlt_producer_close( this ); free( this ); } /** Initialize. */ mlt_producer producer_count_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create a new producer object mlt_producer producer = mlt_producer_new( profile ); // Initialize the producer if ( producer ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_properties_set( properties, "direction", "down" ); mlt_properties_set( properties, "style", "seconds+1" ); mlt_properties_set( properties, "sound", "none" ); mlt_properties_set( properties, "background", "clock" ); // Callback registration producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )producer_close; } return producer; } mlt-0.9.0/src/modules/gtk2/producer_count.yml000066400000000000000000000032351215300731300211760ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: count title: Count version: 1 copyright: Brian Matherly creator: Brian Matherly license: LGPLv2.1 language: en tags: - Audio - Video description: > Generate frames with a counter and synchronized tone. The counter can go up or down. parameters: - identifier: direction title: Count Direction description: Whether to count up or down. type: string default: down values: - up - down mutable: yes widget: combo - identifier: style title: Counter Style description: | The style of the counter. * seconds - seconds counting up from or down to 0 * seconds+1 - seconds counting up from or down to 1 * frames - frames * timecode - timecode in the format HH:MM:SS:FF * clock - clock in the format HH:MM:SS type: string default: seconds+1 values: - seconds - seconds+1 - frames - timecode - clock mutable: yes widget: combo - identifier: sound title: Sound description: | The sound to be produced. * silent - No sound * 2pop - A 1kHz beep exactly two seconds before the out point * frame0 - A 1kHz beep at frame 0 of every second type: string default: silent values: - none - 2pop - frame0 mutable: yes widget: combo - identifier: background title: Background description: | The background style. * none - No background * clock - Film style clock animation type: string default: clock values: - none - clock mutable: yes widget: combo mlt-0.9.0/src/modules/gtk2/producer_pango.c000066400000000000000000000634261215300731300206030ustar00rootroot00000000000000/* * producer_pango.c -- a pango-based titler * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include typedef struct producer_pango_s *producer_pango; typedef enum { pango_align_left = 0, pango_align_center, pango_align_right } pango_align; static pthread_mutex_t pango_mutex = PTHREAD_MUTEX_INITIALIZER; struct producer_pango_s { struct mlt_producer_s parent; int width; int height; GdkPixbuf *pixbuf; char *fgcolor; char *bgcolor; char *olcolor; int align; int pad; int outline; char *markup; char *text; char *font; char *family; int size; int style; int weight; }; // special color type used by internal pango routines typedef struct { uint8_t r, g, b, a; } rgba_color; // Forward declarations static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ); static void producer_close( mlt_producer parent ); static void pango_draw_background( GdkPixbuf *pixbuf, rgba_color bg ); static GdkPixbuf *pango_get_pixbuf( const char *markup, const char *text, const char *font, rgba_color fg, rgba_color bg, rgba_color ol, int pad, int align, char* family, int style, int weight, int size, int outline ); static void fill_pixbuf( GdkPixbuf* pixbuf, FT_Bitmap* bitmap, int w, int h, int pad, int align, rgba_color fg, rgba_color bg ); static void fill_pixbuf_with_outline( GdkPixbuf* pixbuf, FT_Bitmap* bitmap, int w, int h, int pad, int align, rgba_color fg, rgba_color bg, rgba_color ol, int outline ); /** Return nonzero if the two strings are equal, ignoring case, up to the first n characters. */ int strncaseeq(const char *s1, const char *s2, size_t n) { for ( ; n > 0; n--) { if (tolower(*s1++) != tolower(*s2++)) return 0; } return 1; } /** Parse the alignment property. */ static int parse_alignment( char* align ) { int ret = pango_align_left; if ( align == NULL ); else if ( isdigit( align[ 0 ] ) ) ret = atoi( align ); else if ( align[ 0 ] == 'c' || align[ 0 ] == 'm' ) ret = pango_align_center; else if ( align[ 0 ] == 'r' ) ret = pango_align_right; return ret; } /** Parse the style property. */ static int parse_style( char* style ) { int ret = PANGO_STYLE_NORMAL; if( !strncmp(style, "italic", 6) ) ret = PANGO_STYLE_ITALIC; return ret; } static PangoFT2FontMap *fontmap = NULL; mlt_producer producer_pango_init( const char *filename ) { producer_pango this = calloc( 1, sizeof( struct producer_pango_s ) ); if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 ) { mlt_producer producer = &this->parent; pthread_mutex_lock( &pango_mutex ); if ( fontmap == NULL ) fontmap = (PangoFT2FontMap*) pango_ft2_font_map_new(); g_type_init(); pthread_mutex_unlock( &pango_mutex ); producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )producer_close; // Get the properties interface mlt_properties properties = MLT_PRODUCER_PROPERTIES( &this->parent ); // Set the default properties mlt_properties_set( properties, "fgcolour", "0xffffffff" ); mlt_properties_set( properties, "bgcolour", "0x00000000" ); mlt_properties_set( properties, "olcolour", "0x00000000" ); mlt_properties_set_int( properties, "align", pango_align_left ); mlt_properties_set_int( properties, "pad", 0 ); mlt_properties_set_int( properties, "outline", 0 ); mlt_properties_set( properties, "text", "" ); mlt_properties_set( properties, "font", NULL ); mlt_properties_set( properties, "family", "Sans" ); mlt_properties_set_int( properties, "size", 48 ); mlt_properties_set( properties, "style", "normal" ); mlt_properties_set( properties, "encoding", "UTF-8" ); mlt_properties_set_int( properties, "weight", PANGO_WEIGHT_NORMAL ); mlt_properties_set_int( properties, "seekable", 1 ); if ( filename == NULL || ( filename && ( !strcmp( filename, "" ) || strstr( filename, "" ) // workaround for old kdenlive countdown generator || strstr( filename, "<producer>" ) ) ) ) { mlt_properties_set( properties, "markup", "" ); } else if ( filename[ 0 ] == '+' || strstr( filename, "/+" ) ) { char *copy = strdup( filename + 1 ); char *markup = copy; if ( strstr( markup, "/+" ) ) markup = strstr( markup, "/+" ) + 2; if ( strrchr( markup, '.' ) ) ( *strrchr( markup, '.' ) ) = '\0'; while ( strchr( markup, '~' ) ) ( *strchr( markup, '~' ) ) = '\n'; mlt_properties_set( properties, "resource", filename ); mlt_properties_set( properties, "markup", markup ); free( copy ); } else if ( strstr( filename, ".mpl" ) ) { int i = 0; mlt_properties contents = mlt_properties_load( filename ); mlt_geometry key_frames = mlt_geometry_init( ); struct mlt_geometry_item_s item; mlt_properties_set( properties, "resource", filename ); mlt_properties_set_data( properties, "contents", contents, 0, ( mlt_destructor )mlt_properties_close, NULL ); mlt_properties_set_data( properties, "key_frames", key_frames, 0, ( mlt_destructor )mlt_geometry_close, NULL ); // Make sure we have at least one entry if ( mlt_properties_get( contents, "0" ) == NULL ) mlt_properties_set( contents, "0", "" ); for ( i = 0; i < mlt_properties_count( contents ); i ++ ) { char *name = mlt_properties_get_name( contents, i ); char *value = mlt_properties_get_value( contents, i ); while ( value != NULL && strchr( value, '~' ) ) ( *strchr( value, '~' ) ) = '\n'; item.frame = atoi( name ); mlt_geometry_insert( key_frames, &item ); } mlt_geometry_interpolate( key_frames ); } else { FILE *f = fopen( filename, "r" ); if ( f != NULL ) { char line[81]; char *markup = NULL; size_t size = 0; line[80] = '\0'; while ( fgets( line, 80, f ) ) { size += strlen( line ) + 1; if ( markup ) { markup = realloc( markup, size ); if ( markup ) strcat( markup, line ); } else { markup = strdup( line ); } } fclose( f ); if ( markup && markup[ strlen( markup ) - 1 ] == '\n' ) markup[ strlen( markup ) - 1 ] = '\0'; mlt_properties_set( properties, "resource", filename ); if ( markup ) mlt_properties_set( properties, "markup", markup ); else mlt_properties_set( properties, "markup", "" ); free( markup ); } else { producer->close = NULL; mlt_producer_close( producer ); producer = NULL; free( this ); } } return producer; } free( this ); return NULL; } static void set_string( char **string, const char *value, const char *fallback ) { if ( value != NULL ) { free( *string ); *string = strdup( value ); } else if ( *string == NULL && fallback != NULL ) { *string = strdup( fallback ); } else if ( *string != NULL && fallback == NULL ) { free( *string ); *string = NULL; } } rgba_color parse_color( char *color, unsigned int color_int ) { rgba_color result = { 0xff, 0xff, 0xff, 0xff }; if ( !strcmp( color, "red" ) ) { result.r = 0xff; result.g = 0x00; result.b = 0x00; } else if ( !strcmp( color, "green" ) ) { result.r = 0x00; result.g = 0xff; result.b = 0x00; } else if ( !strcmp( color, "blue" ) ) { result.r = 0x00; result.g = 0x00; result.b = 0xff; } else if ( strcmp( color, "white" ) ) { result.r = ( color_int >> 24 ) & 0xff; result.g = ( color_int >> 16 ) & 0xff; result.b = ( color_int >> 8 ) & 0xff; result.a = ( color_int ) & 0xff; } return result; } /** Convert a string property to UTF-8 */ static int iconv_utf8( mlt_properties properties, const char *prop_name, const char* encoding ) { char *text = mlt_properties_get( properties, prop_name ); int result = -1; iconv_t cd = iconv_open( "UTF-8", encoding ); if ( text && ( cd != ( iconv_t )-1 ) ) { char *inbuf_p = text; size_t inbuf_n = strlen( text ); size_t outbuf_n = inbuf_n * 6; char *outbuf = mlt_pool_alloc( outbuf_n ); char *outbuf_p = outbuf; memset( outbuf, 0, outbuf_n ); if ( text != NULL && strcmp( text, "" ) && iconv( cd, &inbuf_p, &inbuf_n, &outbuf_p, &outbuf_n ) != -1 ) mlt_properties_set( properties, prop_name, outbuf ); else mlt_properties_set( properties, prop_name, "" ); mlt_pool_release( outbuf ); result = 0; } iconv_close( cd ); return result; } static void refresh_image( mlt_frame frame, int width, int height ) { // Pixbuf GdkPixbuf *pixbuf = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "pixbuf", NULL ); // Obtain properties of frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Obtain the producer pango for this frame producer_pango this = mlt_properties_get_data( properties, "producer_pango", NULL ); // Obtain the producer mlt_producer producer = &this->parent; // Obtain the producer properties mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Get producer properties char *fg = mlt_properties_get( producer_props, "fgcolour" ); char *bg = mlt_properties_get( producer_props, "bgcolour" ); char *ol = mlt_properties_get( producer_props, "olcolour" ); int align = parse_alignment( mlt_properties_get( producer_props, "align" ) ); int pad = mlt_properties_get_int( producer_props, "pad" ); int outline = mlt_properties_get_int( producer_props, "outline" ); char *markup = mlt_properties_get( producer_props, "markup" ); char *text = mlt_properties_get( producer_props, "text" ); char *font = mlt_properties_get( producer_props, "font" ); char *family = mlt_properties_get( producer_props, "family" ); int style = parse_style( mlt_properties_get( producer_props, "style" ) ); char *encoding = mlt_properties_get( producer_props, "encoding" ); int weight = mlt_properties_get_int( producer_props, "weight" ); int size = mlt_properties_get_int( producer_props, "size" ); int property_changed = 0; if ( pixbuf == NULL ) { // Check for file support mlt_properties contents = mlt_properties_get_data( producer_props, "contents", NULL ); mlt_geometry key_frames = mlt_properties_get_data( producer_props, "key_frames", NULL ); struct mlt_geometry_item_s item; if ( contents != NULL ) { char temp[ 20 ]; mlt_geometry_prev_key( key_frames, &item, mlt_frame_original_position( frame ) ); sprintf( temp, "%d", item.frame ); markup = mlt_properties_get( contents, temp ); } // See if any properties changed property_changed = ( align != this->align ); property_changed = property_changed || ( this->fgcolor == NULL || ( fg && strcmp( fg, this->fgcolor ) ) ); property_changed = property_changed || ( this->bgcolor == NULL || ( bg && strcmp( bg, this->bgcolor ) ) ); property_changed = property_changed || ( this->olcolor == NULL || ( ol && strcmp( ol, this->olcolor ) ) ); property_changed = property_changed || ( pad != this->pad ); property_changed = property_changed || ( outline != this->outline ); property_changed = property_changed || ( markup && this->markup && strcmp( markup, this->markup ) ); property_changed = property_changed || ( text && this->text && strcmp( text, this->text ) ); property_changed = property_changed || ( font && this->font && strcmp( font, this->font ) ); property_changed = property_changed || ( family && this->family && strcmp( family, this->family ) ); property_changed = property_changed || ( weight != this->weight ); property_changed = property_changed || ( style != this->style ); property_changed = property_changed || ( size != this->size ); // Save the properties for next comparison this->align = align; this->pad = pad; this->outline = outline; set_string( &this->fgcolor, fg, "0xffffffff" ); set_string( &this->bgcolor, bg, "0x00000000" ); set_string( &this->olcolor, ol, "0x00000000" ); set_string( &this->markup, markup, NULL ); set_string( &this->text, text, NULL ); set_string( &this->font, font, NULL ); set_string( &this->family, family, "Sans" ); this->weight = weight; this->style = style; this->size = size; } if ( pixbuf == NULL && property_changed ) { rgba_color fgcolor = parse_color( this->fgcolor, mlt_properties_get_int( producer_props, "fgcolour" ) ); rgba_color bgcolor = parse_color( this->bgcolor, mlt_properties_get_int( producer_props, "bgcolour" ) ); rgba_color olcolor = parse_color( this->olcolor, mlt_properties_get_int( producer_props, "olcolour" ) ); if ( this->pixbuf ) g_object_unref( this->pixbuf ); this->pixbuf = NULL; // Convert from specified encoding to UTF-8 if ( encoding != NULL && !strncaseeq( encoding, "utf-8", 5 ) && !strncaseeq( encoding, "utf8", 4 ) ) { if ( markup != NULL && iconv_utf8( producer_props, "markup", encoding ) != -1 ) { markup = mlt_properties_get( producer_props, "markup" ); set_string( &this->markup, markup, NULL ); } if ( text != NULL && iconv_utf8( producer_props, "text", encoding ) != -1 ) { text = mlt_properties_get( producer_props, "text" ); set_string( &this->text, text, NULL ); } } // Render the title pixbuf = pango_get_pixbuf( markup, text, font, fgcolor, bgcolor, olcolor, pad, align, family, style, weight, size, outline ); if ( pixbuf != NULL ) { // Register this pixbuf for destruction and reuse mlt_properties_set_data( producer_props, "pixbuf", pixbuf, 0, ( mlt_destructor )g_object_unref, NULL ); g_object_ref( pixbuf ); mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "pixbuf", pixbuf, 0, ( mlt_destructor )g_object_unref, NULL ); mlt_properties_set_int( producer_props, "meta.media.width", gdk_pixbuf_get_width( pixbuf ) ); mlt_properties_set_int( producer_props, "meta.media.height", gdk_pixbuf_get_height( pixbuf ) ); // Store the width/height of the pixbuf temporarily this->width = gdk_pixbuf_get_width( pixbuf ); this->height = gdk_pixbuf_get_height( pixbuf ); } } else if ( pixbuf == NULL && width > 0 && ( this->pixbuf == NULL || width != this->width || height != this->height ) ) { if ( this->pixbuf ) g_object_unref( this->pixbuf ); this->pixbuf = NULL; pixbuf = mlt_properties_get_data( producer_props, "pixbuf", NULL ); } // If we have a pixbuf and a valid width if ( pixbuf && width > 0 ) { char *interps = mlt_properties_get( properties, "rescale.interp" ); int interp = GDK_INTERP_BILINEAR; if ( strcmp( interps, "nearest" ) == 0 ) interp = GDK_INTERP_NEAREST; else if ( strcmp( interps, "tiles" ) == 0 ) interp = GDK_INTERP_TILES; else if ( strcmp( interps, "hyper" ) == 0 || strcmp( interps, "bicubic" ) == 0 ) interp = GDK_INTERP_HYPER; // fprintf(stderr,"%s: scaling from %dx%d to %dx%d\n", __FILE__, this->width, this->height, width, height); // Note - the original pixbuf is already safe and ready for destruction this->pixbuf = gdk_pixbuf_scale_simple( pixbuf, width, height, interp ); // Store width and height this->width = width; this->height = height; } // Set width/height mlt_properties_set_int( properties, "width", this->width ); mlt_properties_set_int( properties, "height", this->height ); } static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; producer_pango this = ( producer_pango ) mlt_frame_pop_service( frame ); // Obtain properties of frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); *width = mlt_properties_get_int( properties, "rescale_width" ); *height = mlt_properties_get_int( properties, "rescale_height" ); mlt_service_lock( MLT_PRODUCER_SERVICE( &this->parent ) ); // Refresh the image pthread_mutex_lock( &pango_mutex ); refresh_image( frame, *width, *height ); // Get width and height *width = this->width; *height = this->height; *format = mlt_image_rgb24a; // Always clone here to allow 'animated' text if ( this->pixbuf ) { // Clone the image int image_size = this->width * this->height * 4; *buffer = mlt_pool_alloc( image_size ); memcpy( *buffer, gdk_pixbuf_get_pixels( this->pixbuf ), image_size ); // Now update properties so we free the copy after mlt_frame_set_image( frame, *buffer, image_size, mlt_pool_release ); } else { error = 1; } pthread_mutex_unlock( &pango_mutex ); mlt_service_unlock( MLT_PRODUCER_SERVICE( &this->parent ) ); return error; } static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { producer_pango this = producer->child; // Fetch the producers properties mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Set the producer on the frame properties mlt_properties_set_data( properties, "producer_pango", this, 0, NULL, NULL ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Refresh the pango image pthread_mutex_lock( &pango_mutex ); refresh_image( *frame, 0, 0 ); pthread_mutex_unlock( &pango_mutex ); // Set producer-specific frame properties mlt_properties_set_int( properties, "progressive", 1 ); double force_ratio = mlt_properties_get_double( producer_properties, "force_aspect_ratio" ); if ( force_ratio > 0.0 ) mlt_properties_set_double( properties, "aspect_ratio", force_ratio ); else mlt_properties_set_double( properties, "aspect_ratio", 1.0); // Stack the get image callback mlt_frame_push_service( *frame, this ); mlt_frame_push_get_image( *frame, producer_get_image ); // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; } static void producer_close( mlt_producer parent ) { producer_pango this = parent->child; if ( this->pixbuf ) g_object_unref( this->pixbuf ); free( this->fgcolor ); free( this->bgcolor ); free( this->olcolor ); free( this->markup ); free( this->text ); free( this->font ); free( this->family ); parent->close = NULL; mlt_producer_close( parent ); free( this ); } static void pango_draw_background( GdkPixbuf *pixbuf, rgba_color bg ) { int ww = gdk_pixbuf_get_width( pixbuf ); int hh = gdk_pixbuf_get_height( pixbuf ); uint8_t *p = gdk_pixbuf_get_pixels( pixbuf ); int i, j; for ( j = 0; j < hh; j++ ) { for ( i = 0; i < ww; i++ ) { *p++ = bg.r; *p++ = bg.g; *p++ = bg.b; *p++ = bg.a; } } } static GdkPixbuf *pango_get_pixbuf( const char *markup, const char *text, const char *font, rgba_color fg, rgba_color bg, rgba_color ol, int pad, int align, char* family, int style, int weight, int size, int outline ) { PangoContext *context = pango_ft2_font_map_create_context( fontmap ); PangoLayout *layout = pango_layout_new( context ); int w, h; GdkPixbuf *pixbuf = NULL; FT_Bitmap bitmap; PangoFontDescription *desc = NULL; if( font ) { // Support for deprecated "font" property. desc = pango_font_description_from_string( font ); pango_ft2_font_map_set_resolution( fontmap, 72, 72 ); } else { desc = pango_font_description_from_string( family ); pango_font_description_set_size( desc, PANGO_SCALE * size ); pango_font_description_set_style( desc, (PangoStyle) style ); } pango_font_description_set_weight( desc, ( PangoWeight ) weight ); pango_layout_set_width( layout, -1 ); // set wrapping constraints pango_layout_set_font_description( layout, desc ); pango_layout_set_alignment( layout, ( PangoAlignment ) align ); if ( markup != NULL && strcmp( markup, "" ) != 0 ) { pango_layout_set_markup( layout, markup, strlen( markup ) ); } else if ( text != NULL && strcmp( text, "" ) != 0 ) { // Replace all ~'s with a line feed (silly convention, but handy) char *copy = strdup( text ); while ( strchr( copy, '~' ) ) ( *strchr( copy, '~' ) ) = '\n'; pango_layout_set_text( layout, copy, strlen( copy ) ); free( copy ); } else { // Pango doesn't like empty strings pango_layout_set_text( layout, " ", 2 ); } pango_layout_get_pixel_size( layout, &w, &h ); if ( pad == 0 ) pad = 1; pixbuf = gdk_pixbuf_new( GDK_COLORSPACE_RGB, TRUE /* has alpha */, 8, w + 2 * pad, h + 2 * pad ); pango_draw_background( pixbuf, bg ); bitmap.width = w; bitmap.pitch = 32 * ( ( w + 31 ) / 31 ); bitmap.rows = h; bitmap.buffer = mlt_pool_alloc( h * bitmap.pitch ); bitmap.num_grays = 256; bitmap.pixel_mode = ft_pixel_mode_grays; memset( bitmap.buffer, 0, h * bitmap.pitch ); pango_ft2_render_layout( &bitmap, layout, 0, 0 ); if ( outline ) { fill_pixbuf_with_outline( pixbuf, &bitmap, w, h, pad, align, fg, bg, ol, outline ); } else { fill_pixbuf( pixbuf, &bitmap, w, h, pad, align, fg, bg ); } mlt_pool_release( bitmap.buffer ); pango_font_description_free( desc ); g_object_unref( layout ); g_object_unref( context ); return pixbuf; } static void fill_pixbuf( GdkPixbuf* pixbuf, FT_Bitmap* bitmap, int w, int h, int pad, int align, rgba_color fg, rgba_color bg ) { int stride = gdk_pixbuf_get_rowstride( pixbuf ); uint8_t* src = bitmap->buffer; int x = ( gdk_pixbuf_get_width( pixbuf ) - w - 2 * pad ) * align / 2 + pad; uint8_t* dest = gdk_pixbuf_get_pixels( pixbuf ) + 4 * x + pad * stride; int j = h; int i = 0; uint8_t *d, *s, a; while( j -- ) { d = dest; s = src; i = w; while( i -- ) { a = *s ++; *d++ = ( a * fg.r + ( 255 - a ) * bg.r ) >> 8; *d++ = ( a * fg.g + ( 255 - a ) * bg.g ) >> 8; *d++ = ( a * fg.b + ( 255 - a ) * bg.b ) >> 8; *d++ = ( a * fg.a + ( 255 - a ) * bg.a ) >> 8; } dest += stride; src += bitmap->pitch; } } static void fill_pixbuf_with_outline( GdkPixbuf* pixbuf, FT_Bitmap* bitmap, int w, int h, int pad, int align, rgba_color fg, rgba_color bg, rgba_color ol, int outline ) { int stride = gdk_pixbuf_get_rowstride( pixbuf ); int x = ( gdk_pixbuf_get_width( pixbuf ) - w - 2 * pad ) * align / 2 + pad; uint8_t* dest = gdk_pixbuf_get_pixels( pixbuf ) + 4 * x + pad * stride; int j ,i; uint8_t *d = NULL; float a_ol = 0; float a_fg = 0; for ( j = 0; j < h; j++ ) { d = dest; for ( i = 0; i < w; i++ ) { #define geta(x, y) (float) bitmap->buffer[ (y) * bitmap->pitch + (x) ] / 255.0 a_ol = geta(i, j); // One pixel fake circle if ( i > 0 ) a_ol = MAX( a_ol, geta(i - 1, j) ); if ( i < w - 1 ) a_ol = MAX( a_ol, geta(i + 1, j) ); if ( j > 0 ) a_ol = MAX( a_ol, geta(i, j - 1) ); if ( j < h - 1 ) a_ol = MAX( a_ol, geta(i, j + 1) ); if ( outline >= 2 ) { // Two pixels fake circle if ( i > 1 ) { a_ol = MAX( a_ol, geta(i - 2, j) ); if ( j > 0 ) a_ol = MAX( a_ol, geta(i - 2, j - 1) ); if ( j < h - 1 ) a_ol = MAX( a_ol, geta(i - 2, j + 1) ); } if ( i > 0 ) { if ( j > 0 ) a_ol = MAX( a_ol, geta(i - 1, j - 1) ); if ( j > 1 ) a_ol = MAX( a_ol, geta(i - 1, j - 2) ); if ( j < h - 1 ) a_ol = MAX( a_ol, geta(i - 1, j + 1) ); if ( j < h - 2 ) a_ol = MAX( a_ol, geta(i - 1, j + 2) ); } if ( j > 1 ) a_ol = MAX( a_ol, geta(i, j - 2) ); if ( j < h - 2 ) a_ol = MAX( a_ol, geta(i, j + 2) ); if ( i < w - 1 ) { if ( j > 0 ) a_ol = MAX( a_ol, geta(i + 1, j - 1) ); if ( j > 1 ) a_ol = MAX( a_ol, geta(i + 1, j - 2) ); if ( j < h - 1 ) a_ol = MAX( a_ol, geta(i + 1, j + 1) ); if ( j < h - 2 ) a_ol = MAX( a_ol, geta(i + 1, j + 2) ); } if ( i < w - 2 ) { a_ol = MAX( a_ol, geta(i + 2, j) ); if ( j > 0 ) a_ol = MAX( a_ol, geta(i + 2, j - 1) ); if ( j < h - 1 ) a_ol = MAX( a_ol, geta(i + 2, j + 1) ); } } if ( outline >= 3 ) { // Three pixels fake circle if ( i > 2 ) { a_ol = MAX( a_ol, geta(i - 3, j) ); if ( j > 0 ) a_ol = MAX( a_ol, geta(i - 3, j - 1) ); if ( j < h - 1 ) a_ol = MAX( a_ol, geta(i - 3, j + 1) ); } if ( i > 1 ) { if ( j > 1 ) a_ol = MAX( a_ol, geta(i - 2, j - 2) ); if ( j < h - 2 ) a_ol = MAX( a_ol, geta(i - 2, j + 2) ); } if ( i > 0 ) { if ( j > 2 ) a_ol = MAX( a_ol, geta(i - 1, j - 3) ); if ( j < h - 3 ) a_ol = MAX( a_ol, geta(i - 1, j + 3) ); } if ( j > 2 ) a_ol = MAX( a_ol, geta(i, j - 3) ); if ( j < h - 3 ) a_ol = MAX( a_ol, geta(i, j + 3) ); if ( i < w - 1 ) { if ( j > 2 ) a_ol = MAX( a_ol, geta(i + 1, j - 3) ); if ( j < h - 3 ) a_ol = MAX( a_ol, geta(i + 1, j + 3) ); } if ( i < w - 2 ) { if ( j > 1 ) a_ol = MAX( a_ol, geta(i + 2, j - 2) ); if ( j < h - 2 ) a_ol = MAX( a_ol, geta(i + 2, j + 2) ); } if ( i < w - 3 ) { a_ol = MAX( a_ol, geta(i + 3, j) ); if ( j > 0 ) a_ol = MAX( a_ol, geta(i + 3, j - 1) ); if ( j < h - 1 ) a_ol = MAX( a_ol, geta(i + 3, j + 1) ); } } a_fg = ( float ) bitmap->buffer[ j * bitmap->pitch + i ] / 255.0; *d++ = ( int ) ( a_fg * fg.r + ( 1 - a_fg ) * ( a_ol * ol.r + ( 1 - a_ol ) * bg.r ) ); *d++ = ( int ) ( a_fg * fg.g + ( 1 - a_fg ) * ( a_ol * ol.g + ( 1 - a_ol ) * bg.g ) ); *d++ = ( int ) ( a_fg * fg.b + ( 1 - a_fg ) * ( a_ol * ol.b + ( 1 - a_ol ) * bg.b ) ); *d++ = ( int ) ( a_fg * fg.a + ( 1 - a_fg ) * ( a_ol * ol.a + ( 1 - a_ol ) * bg.a ) ); } dest += stride; } } mlt-0.9.0/src/modules/gtk2/producer_pango.yml000066400000000000000000000134551215300731300211570ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: pango title: Pango version: 2 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Video description: > A title generator that uses the Pango international text layout and Freetype2 font renderer. notes: > Supplying a filename with extension ".txt" causes the loader producer to load with pango. If the filename begins with "+" the pango producer interprets the filename as pango text. This is a shortcut to embed titles in melt commands. For MLT XML, it is recommended that you embed the title text in the property value. Pango has builtin scaling. It will rescale the originally rendered title to whatever the consumer requests. Therefore, it will lose its aspect ratio if so requested, and it is up to the consumer to request a proper width and height that maintains the image aspect. parameters: - identifier: argument title: File type: string description: | A text file containing Pango markup, see: http://developer.gnome.org/doc/API/2.0/pango/PangoMarkupFormat.html requires xml-like encoding special chars from: <, >, & -to- <, >, & readonly: no required: yes mutable: no widget: fileopen - identifier: markup title: Markup type: string description: | A string containing Pango markup see: http://developer.gnome.org/doc/API/2.0/pango/PangoMarkupFormat.html requires xml-like encoding special chars from: <, >, & -to- <, >, & readonly: no mutable: yes widget: textbox - identifier: fgcolour title: Foreground color type: string description: > A color value is a hexadecimal representation of RGB plus alpha channel as 0xrrggbbaa. Colors can also be the words: white, black, red, green, or blue. You can also use a HTML-style color values #rrggbb or #aarrggbb. readonly: no mutable: yes widget: color - identifier: bgcolour title: Background color type: string description: > A color value is a hexadecimal representation of RGB plus alpha channel as 0xrrggbbaa. Colors can also be the words: white, black, red, green, or blue. You can also use a HTML-style color values #rrggbb or #aarrggbb. readonly: no mutable: yes widget: color - identifier: olcolour title: Outline color type: string description: > A color value is a hexadecimal representation of RGB plus alpha channel as 0xrrggbbaa. Colors can also be the words: white, black, red, green, or blue. You can also use a HTML-style color values #rrggbb or #aarrggbb. readonly: no mutable: yes widget: color - identifier: outline title: Outline Width type: string description: > The width of the outline in pixels. readonly: no default: 0 minimum: 0 maximum: 3 mutable: yes widget: spinner - identifier: align title: Paragraph alignment type: string description: > left, centre, right (also, numbers 0, 1 and 2 can be used respectively) readonly: no default: left mutable: yes widget: combo - identifier: pad title: Padding type: integer description: > The number of pixels to pad the background rectangle beyond edges of text. readonly: no default: 0 mutable: yes widget: spinner - identifier: text title: Text type: string description: | A non-markup string in UTF-8 encoding (can contain markup chars un-encoded) readonly: no mutable: yes widget: textbox - identifier: font title: Font type: string description: > The default typeface to use when not using markup. FreeType2 renders at 72 dpi. This property is deprecated. Use family, size and style instead. readonly: no mutable: yes widget: combo - identifier: family title: Font family type: string description: > The default typeface to use when not using markup. default: Sans readonly: no mutable: yes widget: combo - identifier: size title: Font size type: integer description: > The size in pixels of the font to use when not using markup. default: 48 readonly: no mutable: yes widget: spinner - identifier: style title: Font style type: string description: > The style of the font to use when not using markup. values: - normal - italic default: normal readonly: no mutable: yes widget: combo - identifier: weight title: Font weight type: integer description: The weight of the font. minimum: 100 maximum: 1000 default: 400 readonly: no mutable: yes widget: spinner - identifier: encoding title: Encoding type: string description: > The text encoding type of the input if not UTF-8. See 'iconv --list' for a list of possible inputs. default: UTF-8 readonly: no mutable: yes widget: combo - identifier: real_width title: Real width type: integer description: The original, unscaled width of the rendered title. readonly: yes - identifier: real_height title: Real height type: integer description: The original, unscaled height of the rendered title. readonly: yes - identifier: width title: Width type: integer description: The last requested scaled image width. readonly: yes - identifier: height title: Height type: integer description: The last requested scaled image height. readonly: yes - identifier: force_aspect_ratio title: Sample aspect ratio type: float description: Optionally override a (mis)detected aspect ratio mutable: yes mlt-0.9.0/src/modules/gtk2/producer_pixbuf.c000066400000000000000000000527041215300731300207710ustar00rootroot00000000000000/* * producer_pixbuf.c -- raster image loader based upon gdk-pixbuf * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include "config.h" #ifdef USE_EXIF #include #endif #include #include #include #include #include #include #include #include #include #include // this protects concurrent access to gdk_pixbuf static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; typedef struct producer_pixbuf_s *producer_pixbuf; struct producer_pixbuf_s { struct mlt_producer_s parent; // File name list mlt_properties filenames; int count; int image_idx; int pixbuf_idx; int width; int height; uint8_t *alpha; uint8_t *image; mlt_cache_item image_cache; mlt_cache_item alpha_cache; mlt_cache_item pixbuf_cache; GdkPixbuf *pixbuf; mlt_image_format format; }; static void load_filenames( producer_pixbuf self, mlt_properties producer_properties ); static int refresh_pixbuf( producer_pixbuf self, mlt_frame frame ); static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ); static void producer_close( mlt_producer parent ); mlt_producer producer_pixbuf_init( char *filename ) { producer_pixbuf self = calloc( 1, sizeof( struct producer_pixbuf_s ) ); if ( self != NULL && mlt_producer_init( &self->parent, self ) == 0 ) { mlt_producer producer = &self->parent; // Get the properties interface mlt_properties properties = MLT_PRODUCER_PROPERTIES( &self->parent ); // Callback registration producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )producer_close; // Set the default properties mlt_properties_set( properties, "resource", filename ); mlt_properties_set_int( properties, "ttl", 25 ); mlt_properties_set_int( properties, "aspect_ratio", 1 ); mlt_properties_set_int( properties, "progressive", 1 ); mlt_properties_set_int( properties, "seekable", 1 ); mlt_properties_set_int( properties, "loop", 1 ); // Validate the resource if ( filename ) load_filenames( self, properties ); if ( self->count ) { mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( frame ) { mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); mlt_properties_set_data( frame_properties, "producer_pixbuf", self, 0, NULL, NULL ); mlt_frame_set_position( frame, mlt_producer_position( producer ) ); refresh_pixbuf( self, frame ); mlt_cache_item_close( self->pixbuf_cache ); mlt_frame_close( frame ); } } if ( self->width == 0 ) { producer_close( producer ); producer = NULL; } return producer; } free( self ); return NULL; } static int load_svg( producer_pixbuf self, mlt_properties properties, const char *filename ) { int result = 0; // Read xml string if ( strstr( filename, " -1 ) { // Write the svg into the temp file ssize_t remaining_bytes; const char *xml = filename; // Strip leading crap while ( xml[0] != '<' ) xml++; remaining_bytes = strlen( xml ); while ( remaining_bytes > 0 ) remaining_bytes -= write( fd, xml + strlen( xml ) - remaining_bytes, remaining_bytes ); close( fd ); mlt_properties_set( self->filenames, "0", fullname ); // Teehe - when the producer closes, delete the temp file and the space allo mlt_properties_set_data( properties, "__temporary_file__", fullname, 0, ( mlt_destructor )unlink, NULL ); result = 1; } } return result; } static int load_sequence_sprintf( producer_pixbuf self, mlt_properties properties, const char *filename ) { int result = 0; // Obtain filenames with pattern if ( strchr( filename, '%' ) != NULL ) { // handle picture sequences int i = mlt_properties_get_int( properties, "begin" ); int gap = 0; char full[1024]; int keyvalue = 0; char key[ 50 ]; while ( gap < 100 ) { struct stat buf; snprintf( full, 1023, filename, i ++ ); if ( stat( full, &buf ) == 0 ) { sprintf( key, "%d", keyvalue ++ ); mlt_properties_set( self->filenames, key, full ); gap = 0; } else { gap ++; } } if ( mlt_properties_count( self->filenames ) > 0 ) { mlt_properties_set_int( properties, "ttl", 1 ); result = 1; } } return result; } static int load_sequence_deprecated( producer_pixbuf self, mlt_properties properties, const char *filename ) { int result = 0; const char *start; // This approach is deprecated in favor of the begin querystring parameter. // Obtain filenames with pattern containing a begin value, e.g. foo%1234d.png if ( ( start = strchr( filename, '%' ) ) ) { const char *end = ++start; while ( isdigit( *end ) ) end++; if ( end > start && ( end[0] == 'd' || end[0] == 'i' || end[0] == 'u' ) ) { int n = end - start; char *s = calloc( 1, n + 1 ); strncpy( s, start, n ); mlt_properties_set( properties, "begin", s ); free( s ); s = calloc( 1, strlen( filename ) + 2 ); strncpy( s, filename, start - filename ); sprintf( s + ( start - filename ), ".%d%s", n, end ); result = load_sequence_sprintf( self, properties, s ); free( s ); } } return result; } static int load_sequence_querystring( producer_pixbuf self, mlt_properties properties, const char *filename ) { int result = 0; // Obtain filenames with pattern and begin value in query string if ( strchr( filename, '%' ) && strchr( filename, '?' ) ) { // Split filename into pattern and query string char *s = strdup( filename ); char *querystring = strrchr( s, '?' ); *querystring++ = '\0'; if ( strstr( filename, "begin=" ) ) mlt_properties_set( properties, "begin", strstr( querystring, "begin=" ) + 6 ); else if ( strstr( filename, "begin:" ) ) mlt_properties_set( properties, "begin", strstr( querystring, "begin:" ) + 6 ); // Coerce to an int value so serialization does not have any extra query string cruft mlt_properties_set_int( properties, "begin", mlt_properties_get_int( properties, "begin" ) ); result = load_sequence_sprintf( self, properties, s ); free( s ); } return result; } static int load_folder( producer_pixbuf self, mlt_properties properties, const char *filename ) { int result = 0; // Obtain filenames with folder if ( strstr( filename, "/.all." ) != NULL ) { char wildcard[ 1024 ]; char *dir_name = strdup( filename ); char *extension = strrchr( dir_name, '.' ); *( strstr( dir_name, "/.all." ) + 1 ) = '\0'; sprintf( wildcard, "*%s", extension ); mlt_properties_dir_list( self->filenames, dir_name, wildcard, 1 ); free( dir_name ); result = 1; } return result; } static void load_filenames( producer_pixbuf self, mlt_properties properties ) { char *filename = mlt_properties_get( properties, "resource" ); self->filenames = mlt_properties_new( ); if (!load_svg( self, properties, filename ) && !load_sequence_querystring( self, properties, filename ) && !load_sequence_sprintf( self, properties, filename ) && !load_sequence_deprecated( self, properties, filename ) && !load_folder( self, properties, filename ) ) { mlt_properties_set( self->filenames, "0", filename ); } self->count = mlt_properties_count( self->filenames ); } static GdkPixbuf* reorient_with_exif( producer_pixbuf self, int image_idx, GdkPixbuf *pixbuf ) { #ifdef USE_EXIF mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( &self->parent ); ExifData *d = exif_data_new_from_file( mlt_properties_get_value( self->filenames, image_idx ) ); ExifEntry *entry; int exif_orientation = 0; /* get orientation and rotate image accordingly if necessary */ if (d) { if ( ( entry = exif_content_get_entry ( d->ifd[EXIF_IFD_0], EXIF_TAG_ORIENTATION ) ) ) exif_orientation = exif_get_short (entry->data, exif_data_get_byte_order (d)); /* Free the EXIF data */ exif_data_unref(d); } // Remember EXIF value, might be useful for someone mlt_properties_set_int( producer_props, "_exif_orientation" , exif_orientation ); if ( exif_orientation > 1 ) { GdkPixbuf *processed = NULL; GdkPixbufRotation matrix = GDK_PIXBUF_ROTATE_NONE; // Rotate image according to exif data switch ( exif_orientation ) { case 2: processed = gdk_pixbuf_flip ( pixbuf, TRUE ); break; case 3: matrix = GDK_PIXBUF_ROTATE_UPSIDEDOWN; processed = pixbuf; break; case 4: processed = gdk_pixbuf_flip ( pixbuf, FALSE ); break; case 5: matrix = GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE; processed = gdk_pixbuf_flip ( pixbuf, TRUE ); break; case 6: matrix = GDK_PIXBUF_ROTATE_CLOCKWISE; processed = pixbuf; break; case 7: matrix = GDK_PIXBUF_ROTATE_CLOCKWISE; processed = gdk_pixbuf_flip ( pixbuf, TRUE ); break; case 8: matrix = GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE; processed = pixbuf; break; } if ( processed ) { pixbuf = gdk_pixbuf_rotate_simple( processed, matrix ); g_object_unref( processed ); } } #endif return pixbuf; } static int refresh_pixbuf( producer_pixbuf self, mlt_frame frame ) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_producer producer = &self->parent; mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Check if user wants us to reload the image if ( mlt_properties_get_int( producer_props, "force_reload" ) ) { self->pixbuf = NULL; self->image = NULL; mlt_properties_set_int( producer_props, "force_reload", 0 ); } // Get the time to live for each frame double ttl = mlt_properties_get_int( producer_props, "ttl" ); // Get the original position of this frame mlt_position position = mlt_frame_original_position( frame ); position += mlt_producer_get_in( producer ); // Image index int loop = mlt_properties_get_int( producer_props, "loop" ); int current_idx; if (loop) { current_idx = ( int )floor( ( double )position / ttl ) % self->count; } else { current_idx = MIN(( double )position / ttl, self->count - 1); } // Key for the cache char image_key[ 10 ]; sprintf( image_key, "%d", current_idx ); int disable_exif = mlt_properties_get_int( producer_props, "disable_exif" ); if ( current_idx != self->pixbuf_idx ) self->pixbuf = NULL; if ( !self->pixbuf || mlt_properties_get_int( producer_props, "_disable_exif" ) != disable_exif ) { GError *error = NULL; self->image = NULL; pthread_mutex_lock( &g_mutex ); self->pixbuf = gdk_pixbuf_new_from_file( mlt_properties_get_value( self->filenames, current_idx ), &error ); if ( self->pixbuf ) { // Read the exif value for this file if ( !disable_exif ) self->pixbuf = reorient_with_exif( self, current_idx, self->pixbuf ); // Register this pixbuf for destruction and reuse mlt_cache_item_close( self->pixbuf_cache ); mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "pixbuf.pixbuf", self->pixbuf, 0, ( mlt_destructor )g_object_unref ); self->pixbuf_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "pixbuf.pixbuf" ); self->pixbuf_idx = current_idx; // Store the width/height of the pixbuf temporarily self->width = gdk_pixbuf_get_width( self->pixbuf ); self->height = gdk_pixbuf_get_height( self->pixbuf ); mlt_events_block( producer_props, NULL ); mlt_properties_set_int( producer_props, "meta.media.width", self->width ); mlt_properties_set_int( producer_props, "meta.media.height", self->height ); mlt_properties_set_int( producer_props, "_disable_exif", disable_exif ); mlt_events_unblock( producer_props, NULL ); } pthread_mutex_unlock( &g_mutex ); } // Set width/height of frame mlt_properties_set_int( properties, "width", self->width ); mlt_properties_set_int( properties, "height", self->height ); return current_idx; } static void refresh_image( producer_pixbuf self, mlt_frame frame, mlt_image_format format, int width, int height ) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_producer producer = &self->parent; // Get index and pixbuf int current_idx = refresh_pixbuf( self, frame ); // optimization for subsequent iterations on single picture if ( current_idx != self->image_idx || width != self->width || height != self->height ) self->image = NULL; mlt_log_debug( MLT_PRODUCER_SERVICE( producer ), "image %p pixbuf %p idx %d current_idx %d pixbuf_idx %d width %d\n", self->image, self->pixbuf, current_idx, self->image_idx, self->pixbuf_idx, width ); // If we have a pixbuf and we need an image if ( self->pixbuf && ( !self->image || ( format != mlt_image_none && format != self->format ) ) ) { char *interps = mlt_properties_get( properties, "rescale.interp" ); int interp = GDK_INTERP_BILINEAR; if ( !interps ) { // Keep bilinear by default } else if ( strcmp( interps, "nearest" ) == 0 ) interp = GDK_INTERP_NEAREST; else if ( strcmp( interps, "tiles" ) == 0 ) interp = GDK_INTERP_TILES; else if ( strcmp( interps, "hyper" ) == 0 || strcmp( interps, "bicubic" ) == 0 ) interp = GDK_INTERP_HYPER; // Note - the original pixbuf is already safe and ready for destruction pthread_mutex_lock( &g_mutex ); GdkPixbuf* pixbuf = gdk_pixbuf_scale_simple( self->pixbuf, width, height, interp ); // Store width and height self->width = width; self->height = height; // Allocate/define image int has_alpha = gdk_pixbuf_get_has_alpha( pixbuf ); int src_stride = gdk_pixbuf_get_rowstride( pixbuf ); int dst_stride = self->width * ( has_alpha ? 4 : 3 ); int image_size = dst_stride * ( height + 1 ); self->image = mlt_pool_alloc( image_size ); self->alpha = NULL; self->format = has_alpha ? mlt_image_rgb24a : mlt_image_rgb24; if ( src_stride != dst_stride ) { int y = self->height; uint8_t *src = gdk_pixbuf_get_pixels( pixbuf ); uint8_t *dst = self->image; while ( y-- ) { memcpy( dst, src, dst_stride ); dst += dst_stride; src += src_stride; } } else { memcpy( self->image, gdk_pixbuf_get_pixels( pixbuf ), src_stride * height ); } pthread_mutex_unlock( &g_mutex ); // Convert image to requested format if ( format != mlt_image_none && format != self->format ) { uint8_t *buffer = NULL; // First, set the image so it can be converted when we get it mlt_frame_replace_image( frame, self->image, self->format, width, height ); mlt_frame_set_image( frame, self->image, image_size, mlt_pool_release ); self->format = format; // get_image will do the format conversion mlt_frame_get_image( frame, &buffer, &format, &width, &height, 0 ); // cache copies of the image and alpha buffers if ( buffer ) { image_size = mlt_image_format_size( format, width, height, NULL ); self->image = mlt_pool_alloc( image_size ); memcpy( self->image, buffer, image_size ); } if ( ( buffer = mlt_frame_get_alpha_mask( frame ) ) ) { self->alpha = mlt_pool_alloc( width * height ); memcpy( self->alpha, buffer, width * height ); } } // Update the cache mlt_cache_item_close( self->image_cache ); mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "pixbuf.image", self->image, image_size, mlt_pool_release ); self->image_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "pixbuf.image" ); self->image_idx = current_idx; mlt_cache_item_close( self->alpha_cache ); self->alpha_cache = NULL; if ( self->alpha ) { mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "pixbuf.alpha", self->alpha, width * height, mlt_pool_release ); self->alpha_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "pixbuf.alpha" ); } // Finished with pixbuf now g_object_unref( pixbuf ); } // Set width/height of frame mlt_properties_set_int( properties, "width", self->width ); mlt_properties_set_int( properties, "height", self->height ); } static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); producer_pixbuf self = mlt_properties_get_data( properties, "producer_pixbuf", NULL ); mlt_producer producer = &self->parent; // Use the width and height suggested by the rescale filter because we can do our own scaling. *width = mlt_properties_get_int( properties, "rescale_width" ); *height = mlt_properties_get_int( properties, "rescale_height" ); // Restore pixbuf and image mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); self->pixbuf_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "pixbuf.pixbuf" ); self->pixbuf = mlt_cache_item_data( self->pixbuf_cache, NULL ); self->image_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "pixbuf.image" ); self->image = mlt_cache_item_data( self->image_cache, NULL ); self->alpha_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "pixbuf.alpha" ); self->alpha = mlt_cache_item_data( self->alpha_cache, NULL ); // Refresh the image refresh_image( self, frame, *format, *width, *height ); // Get width and height (may have changed during the refresh) *width = self->width; *height = self->height; *format = self->format; // NB: Cloning is necessary with this producer (due to processing of images ahead of use) // The fault is not in the design of mlt, but in the implementation of the pixbuf producer... if ( self->image ) { // Clone the image int image_size = mlt_image_format_size( self->format, self->width, self->height, NULL ); uint8_t *image_copy = mlt_pool_alloc( image_size ); memcpy( image_copy, self->image, image_size ); // Now update properties so we free the copy after mlt_frame_set_image( frame, image_copy, image_size, mlt_pool_release ); // We're going to pass the copy on *buffer = image_copy; mlt_log_debug( MLT_PRODUCER_SERVICE( &self->parent ), "%dx%d (%s)\n", self->width, self->height, mlt_image_format_name( *format ) ); // Clone the alpha channel if ( self->alpha ) { image_copy = mlt_pool_alloc( self->width * self->height ); memcpy( image_copy, self->alpha, self->width * self->height ); mlt_frame_set_alpha( frame, image_copy, self->width * self->height, mlt_pool_release ); } } else { error = 1; } // Release references and locks mlt_cache_item_close( self->pixbuf_cache ); mlt_cache_item_close( self->image_cache ); mlt_cache_item_close( self->alpha_cache ); mlt_service_unlock( MLT_PRODUCER_SERVICE( &self->parent ) ); return error; } static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Get the real structure for this producer producer_pixbuf self = producer->child; // Fetch the producers properties mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); if ( self->filenames == NULL && mlt_properties_get( producer_properties, "resource" ) != NULL ) load_filenames( self, producer_properties ); // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL && self->count > 0 ) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Set the producer on the frame properties mlt_properties_set_data( properties, "producer_pixbuf", self, 0, NULL, NULL ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Refresh the pixbuf self->pixbuf_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "pixbuf.pixbuf" ); self->pixbuf = mlt_cache_item_data( self->pixbuf_cache, NULL ); refresh_pixbuf( self, *frame ); mlt_cache_item_close( self->pixbuf_cache ); // Set producer-specific frame properties mlt_properties_set_int( properties, "progressive", mlt_properties_get_int( producer_properties, "progressive" ) ); double force_ratio = mlt_properties_get_double( producer_properties, "force_aspect_ratio" ); if ( force_ratio > 0.0 ) mlt_properties_set_double( properties, "aspect_ratio", force_ratio ); else mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_properties, "aspect_ratio" ) ); // Push the get_image method mlt_frame_push_get_image( *frame, producer_get_image ); } // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; } static void producer_close( mlt_producer parent ) { producer_pixbuf self = parent->child; parent->close = NULL; mlt_service_cache_purge( MLT_PRODUCER_SERVICE(parent) ); mlt_producer_close( parent ); mlt_properties_close( self->filenames ); free( self ); } mlt-0.9.0/src/modules/gtk2/producer_pixbuf.yml000066400000000000000000000066021215300731300213440ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: pixbuf title: GDK-PixBuf version: 2 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Video description: > A still graphics to video generator using gdk-pixbuf notes: > Pixbuf has builtin scaling. It will rescale the originally rendered title to whatever the consumer requests. Therefore, it will lose its aspect ratio if so requested, and it is up to the consumer to request a proper width and height that maintains the image aspect. parameters: - identifier: argument title: File type: string description: > The name of a graphics file loadable by a gdk-pixbuf loader. See the output of gdk-pixbuf-query-loaders. Definitely png, jpeg, tiff, pnm, and xpm will work. If "%" in filename, the filename is used with sprintf to generate a filename from a counter for multi-file/flipbook animation. The file sequence ends when numeric discontinuity >100. If the file sequence does not begin within the count of 100 you can pass the begin property like a query string parameter, for example: anim-%04d.png?begin=1000. If filename contains "/.all.", suffix with an extension to load all pictures with matching extension from a directory. If filename contains the string " Reload the file instead of using its cached image. This property automatically resets itself once it has been set 1 and processed. minimum: 0 maximum: 1 mutable: yes - identifier: disable_exif title: Disable auto-rotation type: integer minimum: 0 maximum: 1 widget: checkbox - identifier: force_aspect_ratio title: Sample aspect ratio type: float description: Optionally override a (mis)detected aspect ratio mutable: yes - identifier: loop title: Loop sequence of images indefinitively description: when 1 (default) loop sequences of images, when 0, play them only once type: integer default: 1 minimum: 0 maximum: 1 widget: checkbox mlt-0.9.0/src/modules/gtk2/scale_line_22_yuv_mmx.S000066400000000000000000000126641215300731300217370ustar00rootroot00000000000000/* * scale_line_22_yuv_mmx.S -- scale line in YUY2 format * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ .file "scale_line_22_yuv_mmx.S" .version "01.01" #if !defined(__MINGW32__) && !defined(__CYGWIN__) .section .note.GNU-stack,"",%progbits #endif .extern printf gcc2_compiled.: .data MSG: .ascii "scale_line_22_yuv_mmx: %d %d\n" .text .align 16 #if !defined(__MINGW32__) && !defined(__CYGWIN__) .globl pixops_scale_line_22_yuv_mmx .type pixops_scale_line_22_yuv_mmx,@function pixops_scale_line_22_yuv_mmx: #else .globl _pixops_scale_line_22_yuv_mmx _pixops_scale_line_22_yuv_mmx: #endif /* * Arguments * * weights: 8(%ebp) * p (dest): 12(%ebp) %esi * q1 (src0): 16(%ebp) * q2 (src1): 20(%ebp) * xstep: 24(%ebp) * p_end: 28(%ebp) * xinit: 32(%ebp) * dest_x: 36(%ebp) * */ /* * Function call entry */ pushl %ebp movl %esp,%ebp subl $28,%esp pushl %edi pushl %esi pushl %ebx /* Locals: * int x %ebx * int x_scaled -24(%ebp) * int dest_x 36(%ebp) */ /* * Setup */ /* Initialize variables */ movl 36(%ebp),%eax # destx movl %eax,36(%ebp) movl 32(%ebp),%ebx # x movl 12(%ebp),%esi # dest cmpl 28(%ebp),%esi # dest == dest_end ? jnb .out /* For the body of this loop, %mm0, %mm1, %mm2, %mm3 hold the 4 adjoining * points we are interpolating between, as: * * 00VV00Y200UU00Y1 */ pxor %mm4, %mm4 /* * Load next component values into mm1 (src0) and mm3 (src1) */ movl %ebx, %eax # x_scaled sarl $15, %eax andl $0xfffffffe, %eax movl %eax, %edx # x_aligned andl $0xfffffffc, %edx movl 16(%ebp), %edi # get src0 movl (%edi,%eax), %ecx # get y andl $0x00ff00ff, %ecx # mask off y movl (%edi,%edx), %eax # get uv andl $0xff00ff00, %eax # mask off uv orl %eax, %ecx # composite y, uv movd %ecx, %mm1 # move to mmx1 punpcklbw %mm4, %mm1 movl 20(%ebp), %edi # get src1 movl (%edi,%edx), %ecx # get y andl $0x00ff00ff, %ecx # mask off y movl (%edi,%edx), %eax # get uv andl $0xff00ff00, %eax # mask off uv orl %eax, %ecx # composite y, uv movd %ecx, %mm3 # move to mmx3 punpcklbw %mm4, %mm3 jmp .newx .p2align 4,,7 .loop: /* short *pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y * 16 4 0xf 2 2 */ movl 8(%ebp), %edi # get weights pointer movl %ebx, %eax andl $0xf000, %eax shrl $7, %eax /* At this point, %edi holds weights. Load the 4 weights into * %mm4,%mm5,%mm6,%mm7, multiply and accumulate. */ movq (%edi,%eax), %mm4 pmullw %mm0, %mm4 movq 8(%edi,%eax), %mm5 pmullw %mm1, %mm5 movq 16(%edi,%eax), %mm6 pmullw %mm2,%mm6 movq 24(%edi,%eax), %mm7 pmullw %mm3,%mm7 paddw %mm4, %mm5 paddw %mm6, %mm7 paddw %mm5, %mm7 /* %mm7 holds the accumulated sum. Compute (C + 0x80) / 256 */ pxor %mm4, %mm4 movl $0x80808080, %eax movd %eax, %mm6 punpcklbw %mm4, %mm6 paddw %mm6, %mm7 psrlw $8, %mm7 /* Pack into %eax and store result */ packuswb %mm7, %mm7 movd %mm7, %eax movb %al, (%esi) # *dest = y movl 36(%ebp), %ecx # get dest_x andl $1, %ecx # select u or v sall $1, %ecx # determine offset addl $1, %ecx # relative to x_aligned sall $3, %ecx # offset * 8 bits/byte movd %mm7, %eax shrl %cl, %eax movb %al, 1(%esi) # *dest = uv addl $2, %esi # dest += 2 cmpl %esi,28(%ebp) # if dest == dest_end je .out # then exit addl $1, 36(%ebp) # dest_x++ .newx: addl 24(%ebp), %ebx # x += x_step /* * Load current component values into mm0 (src0) and mm2 (src1) */ movq %mm1, %mm0 movq %mm3, %mm2 /* * Load next component values into mm1 (src0) and mm3 (src1) */ movl %ebx, %eax # x_scaled sarl $15, %eax andl $0xfffffffe, %eax movl %eax, %edx # x_aligned andl $0xfffffffc, %edx movl 16(%ebp), %edi # get src0 movl (%edi,%eax), %ecx # get y andl $0x00ff00ff, %ecx # mask off y movl (%edi,%edx), %eax # get uv andl $0xff00ff00, %eax # mask off uv orl %eax, %ecx # composite y, uv movd %ecx, %mm1 # move to mmx1 punpcklbw %mm4, %mm1 movl 20(%ebp), %edi # get src1 movl (%edi,%edx), %ecx # get y andl $0x00ff00ff, %ecx # mask off y movl (%edi,%edx), %eax # get uv andl $0xff00ff00, %eax # mask off uv orl %eax, %ecx # composite y, uv movd %ecx, %mm3 # move to mmx3 punpcklbw %mm4, %mm3 jmp .loop .out: movl %esi,%eax emms leal -40(%ebp),%esp popl %ebx popl %esi popl %edi movl %ebp,%esp popl %ebp ret mlt-0.9.0/src/modules/jackrack/000077500000000000000000000000001215300731300163175ustar00rootroot00000000000000mlt-0.9.0/src/modules/jackrack/Makefile000066400000000000000000000027551215300731300177700ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lpthread include ../../../config.mak include config.mak TARGET = ../libmltjackrack$(LIBSUF) GPL_OBJS = jack_rack.o \ lock_free_fifo.o \ plugin.o \ plugin_desc.o \ plugin_mgr.o \ plugin_settings.o \ process.o \ producer_ladspa.o \ filter_jackrack.o \ filter_ladspa.o OBJS = factory.o \ consumer_jack.o CFLAGS += `pkg-config --cflags jack` LDFLAGS += `pkg-config --libs jack` ifdef GPL OBJS += $(GPL_OBJS) CFLAGS += -DGPL CFLAGS += `pkg-config --cflags libxml-2.0` CFLAGS += `pkg-config $(PKGCONFIG_PREFIX) --cflags glib-2.0` LDFLAGS += $(LIBDL) LDFLAGS += `pkg-config --libs libxml-2.0` LDFLAGS += `pkg-config $(PKGCONFIG_PREFIX) --libs glib-2.0` LDFLAGS += -lm YML_FILES = *.yml BLACKLIST = blacklist.txt else YML_FILES = consumer_jack.yml BLACKLIST = dummy endif SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/jackrack" install -m 644 $(YML_FILES) "$(DESTDIR)$(mltdatadir)/jackrack" [ -f $(BLACKLIST) ] && install -m 644 $(BLACKLIST) "$(DESTDIR)$(mltdatadir)/jackrack" || true uninstall: rm "$(DESTDIR)$(moduledir)/libmltjackrack$(LIBSUF)" 2> /dev/null || true rm -rf "$(DESTDIR)$(mltdatadir)/jackrack" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/jackrack/blacklist.txt000066400000000000000000000000141215300731300210230ustar00rootroot00000000000000dssi-vst.so mlt-0.9.0/src/modules/jackrack/configure000077500000000000000000000023171215300731300202310ustar00rootroot00000000000000#!/bin/sh if [ "$help" = "1" ] then cat << EOF JACK Rack options: --gtk2-prefix=path - Override the gtk+-2.0 prefix for pkg-config EOF else pkg-config jack disable_jack=$? echo > config.mak if [ "$gpl" = "true" ] then pkg-config libxml-2.0 > /dev/null 2>&1 disable_xml2=$? ladspa_prefix=`which listplugins 2> /dev/null` if [ "$ladspa_prefix" != "" ] then ladspa_prefix=`dirname "$ladspa_prefix"` ladspa_prefix=`dirname "$ladspa_prefix"` else ladspa_prefix=`pkg-config --variable=prefix jack` fi disable_ladspa=`[ -f "$ladspa_prefix/include/ladspa.h" ] && echo 0 || echo 1` echo GPL=1 > config.mak for i in "$@" do case $i in --gtk2-prefix=* ) pkgconfig_prefix="${i#--gtk2-prefix=}" ;; esac done [ "$pkgconfig_prefix" != "" ] && echo "PKGCONFIG_PREFIX=--define-variable=prefix=\"$pkgconfig_prefix\"" >> config.mak fi if [ "$disable_jack" = "1" -o "$disable_xml2" = "1" -o "$disable_ladspa" = "1" ] then [ "$disable_jack" = "1" ] && echo "- jackrack not found: disabling" [ "$disable_xml2" = "1" ] && echo "- xml2 not found: disabling jackrack" [ "$disable_ladspa" = "1" ] && echo "- ladspa not found; disabling" touch ../disable-jackrack fi exit 0 fi mlt-0.9.0/src/modules/jackrack/consumer_jack.c000066400000000000000000000421041215300731300213070ustar00rootroot00000000000000/* * consumer_jack.c -- a JACK audio consumer * Copyright (C) 2011 Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #define BUFFER_LEN (204800 * 6) pthread_mutex_t g_activate_mutex = PTHREAD_MUTEX_INITIALIZER; /** This classes definition. */ typedef struct consumer_jack_s *consumer_jack; struct consumer_jack_s { struct mlt_consumer_s parent; jack_client_t *jack; mlt_deque queue; pthread_t thread; int joined; int running; pthread_mutex_t video_mutex; pthread_cond_t video_cond; int playing; pthread_cond_t refresh_cond; pthread_mutex_t refresh_mutex; int refresh_count; int counter; jack_ringbuffer_t **ringbuffers; jack_port_t **ports; }; /** Forward references to static functions. */ static int consumer_start( mlt_consumer parent ); static int consumer_stop( mlt_consumer parent ); static int consumer_is_stopped( mlt_consumer parent ); static void consumer_close( mlt_consumer parent ); static void *consumer_thread( void * ); static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer parent, char *name ); static int jack_process( jack_nframes_t frames, void * data ); /** Constructor */ mlt_consumer consumer_jack_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create the consumer object consumer_jack self = calloc( 1, sizeof( struct consumer_jack_s ) ); // If no malloc'd and consumer init ok if ( self != NULL && mlt_consumer_init( &self->parent, self, profile ) == 0 ) { char name[14]; snprintf( name, sizeof( name ), "mlt%d", getpid() ); if (( self->jack = jack_client_open( name, JackNullOption, NULL ) )) { jack_set_process_callback( self->jack, jack_process, self ); // Create the queue self->queue = mlt_deque_init( ); // Get the parent consumer object mlt_consumer parent = &self->parent; // We have stuff to clean up, so override the close method parent->close = consumer_close; // get a handle on properties mlt_service service = MLT_CONSUMER_SERVICE( parent ); mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); // This is the initialisation of the consumer pthread_mutex_init( &self->video_mutex, NULL ); pthread_cond_init( &self->video_cond, NULL); // Default scaler (for now we'll use nearest) mlt_properties_set( properties, "rescale", "nearest" ); mlt_properties_set( properties, "deinterlace_method", "onefield" ); // Default buffer for low latency mlt_properties_set_int( properties, "buffer", 1 ); // Set frequency from JACK mlt_properties_set_int( properties, "frequency", (int) jack_get_sample_rate( self->jack ) ); // Set default volume mlt_properties_set_double( properties, "volume", 1.0 ); // Ensure we don't join on a non-running object self->joined = 1; // Allow thread to be started/stopped parent->start = consumer_start; parent->stop = consumer_stop; parent->is_stopped = consumer_is_stopped; // Initialize the refresh handler pthread_cond_init( &self->refresh_cond, NULL ); pthread_mutex_init( &self->refresh_mutex, NULL ); mlt_events_listen( MLT_CONSUMER_PROPERTIES( parent ), self, "property-changed", ( mlt_listener )consumer_refresh_cb ); // Return the consumer produced return parent; } } // malloc or consumer init failed free( self ); // Indicate failure return NULL; } static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer parent, char *name ) { if ( !strcmp( name, "refresh" ) ) { consumer_jack self = parent->child; pthread_mutex_lock( &self->refresh_mutex ); self->refresh_count = self->refresh_count <= 0 ? 1 : self->refresh_count + 1; pthread_cond_broadcast( &self->refresh_cond ); pthread_mutex_unlock( &self->refresh_mutex ); } } static int consumer_start( mlt_consumer parent ) { consumer_jack self = parent->child; if ( !self->running ) { consumer_stop( parent ); self->running = 1; self->joined = 0; pthread_create( &self->thread, NULL, consumer_thread, self ); } return 0; } static int consumer_stop( mlt_consumer parent ) { // Get the actual object consumer_jack self = parent->child; if ( self->running && !self->joined ) { // Kill the thread and clean up self->joined = 1; self->running = 0; // Unlatch the consumer thread pthread_mutex_lock( &self->refresh_mutex ); pthread_cond_broadcast( &self->refresh_cond ); pthread_mutex_unlock( &self->refresh_mutex ); // Cleanup the main thread #ifndef WIN32 if ( self->thread ) #endif pthread_join( self->thread, NULL ); // Unlatch the video thread pthread_mutex_lock( &self->video_mutex ); pthread_cond_broadcast( &self->video_cond ); pthread_mutex_unlock( &self->video_mutex ); // Cleanup JACK if ( self->playing ) jack_deactivate( self->jack ); if ( self->ringbuffers ) { int n = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "channels" ); while ( n-- ) { jack_ringbuffer_free( self->ringbuffers[n] ); jack_port_unregister( self->jack, self->ports[n] ); } mlt_pool_release( self->ringbuffers ); } self->ringbuffers = NULL; if ( self->ports ) mlt_pool_release( self->ports ); self->ports = NULL; } return 0; } static int consumer_is_stopped( mlt_consumer parent ) { consumer_jack self = parent->child; return !self->running; } static int jack_process( jack_nframes_t frames, void * data ) { int error = 0; consumer_jack self = (consumer_jack) data; mlt_properties properties = MLT_CONSUMER_PROPERTIES( &self->parent ); int channels = mlt_properties_get_int( properties, "channels" ); int i; if ( !self->ringbuffers ) return 1; for ( i = 0; i < channels; i++ ) { size_t jack_size = ( frames * sizeof(float) ); size_t ring_size = jack_ringbuffer_read_space( self->ringbuffers[i] ); char *dest = jack_port_get_buffer( self->ports[i], frames ); jack_ringbuffer_read( self->ringbuffers[i], dest, ring_size < jack_size ? ring_size : jack_size ); if ( ring_size < jack_size ) memset( dest + ring_size, 0, jack_size - ring_size ); } return error; } static void initialise_jack_ports( consumer_jack self ) { int i; char mlt_name[20], con_name[30]; mlt_properties properties = MLT_CONSUMER_PROPERTIES( &self->parent ); const char **ports = NULL; // Propogate these for the Jack processing callback int channels = mlt_properties_get_int( properties, "channels" ); // Allocate buffers and ports self->ringbuffers = mlt_pool_alloc( sizeof( jack_ringbuffer_t *) * channels ); self->ports = mlt_pool_alloc( sizeof(jack_port_t *) * channels ); // Start Jack processing - required before registering ports pthread_mutex_lock( &g_activate_mutex ); jack_activate( self->jack ); pthread_mutex_unlock( &g_activate_mutex ); self->playing = 1; // Register Jack ports for ( i = 0; i < channels; i++ ) { self->ringbuffers[i] = jack_ringbuffer_create( BUFFER_LEN * sizeof(float) ); snprintf( mlt_name, sizeof( mlt_name ), "out_%d", i + 1 ); self->ports[i] = jack_port_register( self->jack, mlt_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0 ); } // Establish connections for ( i = 0; i < channels; i++ ) { snprintf( mlt_name, sizeof( mlt_name ), "%s", jack_port_name( self->ports[i] ) ); if ( mlt_properties_get( properties, con_name ) ) snprintf( con_name, sizeof( con_name ), "%s", mlt_properties_get( properties, con_name ) ); else { if ( !ports ) ports = jack_get_ports( self->jack, NULL, NULL, JackPortIsPhysical | JackPortIsInput ); if ( ports ) strncpy( con_name, ports[i], sizeof( con_name )); else snprintf( con_name, sizeof( con_name ), "system:playback_%d", i + 1); con_name[ sizeof( con_name ) - 1 ] = '\0'; } mlt_log_verbose( NULL, "JACK connect %s to %s\n", mlt_name, con_name ); jack_connect( self->jack, mlt_name, con_name ); } if ( ports ) jack_free( ports ); } static int consumer_play_audio( consumer_jack self, mlt_frame frame, int init_audio, int *duration ) { // Get the properties of this consumer mlt_properties properties = MLT_CONSUMER_PROPERTIES( &self->parent ); mlt_audio_format afmt = mlt_audio_float; // Set the preferred params of the test card signal double speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame), "_speed" ); int channels = mlt_properties_get_int( properties, "channels" ); int frequency = mlt_properties_get_int( properties, "frequency" ); int scrub = mlt_properties_get_int( properties, "scrub_audio" ); int samples = mlt_sample_calculator( mlt_properties_get_double( properties, "fps" ), frequency, self->counter++ ); float *buffer; mlt_frame_get_audio( frame, (void**) &buffer, &afmt, &frequency, &channels, &samples ); *duration = ( ( samples * 1000 ) / frequency ); if ( mlt_properties_get_int( properties, "audio_off" ) ) { init_audio = 1; return init_audio; } if ( init_audio == 1 ) { self->playing = 0; initialise_jack_ports( self ); init_audio = 0; } if ( init_audio == 0 && ( speed == 1.0 || speed == 0.0 ) ) { int i; size_t mlt_size = samples * sizeof(float); float volume = mlt_properties_get_double( properties, "volume" ); if ( !scrub && speed == 0.0 ) volume = 0.0; if ( volume != 1.0 ) { float *p = buffer; i = samples * channels + 1; while (--i) *p++ *= volume; } // Write into output ringbuffer for ( i = 0; i < channels; i++ ) { size_t ring_size = jack_ringbuffer_write_space( self->ringbuffers[i] ); if ( ring_size >= mlt_size ) jack_ringbuffer_write( self->ringbuffers[i], (char*)( buffer + i * samples ), mlt_size ); } } return init_audio; } static int consumer_play_video( consumer_jack self, mlt_frame frame ) { // Get the properties of this consumer mlt_properties properties = MLT_CONSUMER_PROPERTIES( &self->parent ); if ( self->running && !mlt_consumer_is_stopped( &self->parent ) ) mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); return 0; } static void *video_thread( void *arg ) { // Identify the arg consumer_jack self = arg; // Obtain time of thread start struct timeval now; int64_t start = 0; int64_t elapsed = 0; struct timespec tm; mlt_frame next = NULL; mlt_properties properties = NULL; double speed = 0; // Get real time flag int real_time = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( &self->parent ), "real_time" ); // Get the current time gettimeofday( &now, NULL ); // Determine start time start = ( int64_t )now.tv_sec * 1000000 + now.tv_usec; while ( self->running ) { // Pop the next frame pthread_mutex_lock( &self->video_mutex ); next = mlt_deque_pop_front( self->queue ); while ( next == NULL && self->running ) { pthread_cond_wait( &self->video_cond, &self->video_mutex ); next = mlt_deque_pop_front( self->queue ); } pthread_mutex_unlock( &self->video_mutex ); if ( !self->running || next == NULL ) break; // Get the properties properties = MLT_FRAME_PROPERTIES( next ); // Get the speed of the frame speed = mlt_properties_get_double( properties, "_speed" ); // Get the current time gettimeofday( &now, NULL ); // Get the elapsed time elapsed = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec ) - start; // See if we have to delay the display of the current frame if ( mlt_properties_get_int( properties, "rendered" ) == 1 && self->running ) { // Obtain the scheduled playout time int64_t scheduled = mlt_properties_get_int( properties, "playtime" ); // Determine the difference between the elapsed time and the scheduled playout time int64_t difference = scheduled - elapsed; // Smooth playback a bit if ( real_time && ( difference > 20000 && speed == 1.0 ) ) { tm.tv_sec = difference / 1000000; tm.tv_nsec = ( difference % 1000000 ) * 500; nanosleep( &tm, NULL ); } // Show current frame if not too old if ( !real_time || ( difference > -10000 || speed != 1.0 || mlt_deque_count( self->queue ) < 2 ) ) consumer_play_video( self, next ); // If the queue is empty, recalculate start to allow build up again if ( real_time && ( mlt_deque_count( self->queue ) == 0 && speed == 1.0 ) ) { gettimeofday( &now, NULL ); start = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec ) - scheduled + 20000; } } // This frame can now be closed mlt_frame_close( next ); next = NULL; } if ( next != NULL ) mlt_frame_close( next ); mlt_consumer_stopped( &self->parent ); return NULL; } /** Threaded wrapper for pipe. */ static void *consumer_thread( void *arg ) { // Identify the arg consumer_jack self = arg; // Get the consumer mlt_consumer consumer = &self->parent; // Get the properties mlt_properties consumer_props = MLT_CONSUMER_PROPERTIES( consumer ); // Video thread pthread_t thread; // internal intialization int init_audio = 1; int init_video = 1; mlt_frame frame = NULL; mlt_properties properties = NULL; int duration = 0; int64_t playtime = 0; struct timespec tm = { 0, 100000 }; // int last_position = -1; pthread_mutex_lock( &self->refresh_mutex ); self->refresh_count = 0; pthread_mutex_unlock( &self->refresh_mutex ); // Loop until told not to while( self->running ) { // Get a frame from the attached producer frame = mlt_consumer_rt_frame( consumer ); // Ensure that we have a frame if ( frame ) { // Get the frame properties properties = MLT_FRAME_PROPERTIES( frame ); // Get the speed of the frame double speed = mlt_properties_get_double( properties, "_speed" ); // Get refresh request for the current frame int refresh = mlt_properties_get_int( consumer_props, "refresh" ); // Clear refresh mlt_events_block( consumer_props, consumer_props ); mlt_properties_set_int( consumer_props, "refresh", 0 ); mlt_events_unblock( consumer_props, consumer_props ); // Play audio init_audio = consumer_play_audio( self, frame, init_audio, &duration ); // Determine the start time now if ( self->playing && init_video ) { // Create the video thread pthread_create( &thread, NULL, video_thread, self ); // Video doesn't need to be initialised any more init_video = 0; } // Set playtime for this frame mlt_properties_set_int( properties, "playtime", playtime ); while ( self->running && speed != 0 && mlt_deque_count( self->queue ) > 15 ) nanosleep( &tm, NULL ); // Push this frame to the back of the queue if ( self->running && speed ) { pthread_mutex_lock( &self->video_mutex ); mlt_deque_push_back( self->queue, frame ); pthread_cond_broadcast( &self->video_cond ); pthread_mutex_unlock( &self->video_mutex ); // Calculate the next playtime playtime += ( duration * 1000 ); } else if ( self->running ) { pthread_mutex_lock( &self->refresh_mutex ); if ( refresh == 0 && self->refresh_count <= 0 ) { consumer_play_video( self, frame ); pthread_cond_wait( &self->refresh_cond, &self->refresh_mutex ); } mlt_frame_close( frame ); self->refresh_count --; pthread_mutex_unlock( &self->refresh_mutex ); } else { mlt_frame_close( frame ); frame = NULL; } // Optimisation to reduce latency if ( frame && speed == 1.0 ) { // TODO: disabled due to misbehavior on parallel-consumer // if ( last_position != -1 && last_position + 1 != mlt_frame_get_position( frame ) ) // mlt_consumer_purge( consumer ); // last_position = mlt_frame_get_position( frame ); } else { mlt_consumer_purge( consumer ); // last_position = -1; } } } // Kill the video thread if ( init_video == 0 ) { pthread_mutex_lock( &self->video_mutex ); pthread_cond_broadcast( &self->video_cond ); pthread_mutex_unlock( &self->video_mutex ); pthread_join( thread, NULL ); } while( mlt_deque_count( self->queue ) ) mlt_frame_close( mlt_deque_pop_back( self->queue ) ); return NULL; } /** Callback to allow override of the close method. */ static void consumer_close( mlt_consumer parent ) { // Get the actual object consumer_jack self = parent->child; // Stop the consumer mlt_consumer_stop( parent ); // Now clean up the rest mlt_consumer_close( parent ); // Close the queue mlt_deque_close( self->queue ); // Destroy mutexes pthread_mutex_destroy( &self->video_mutex ); pthread_cond_destroy( &self->video_cond ); pthread_mutex_destroy( &self->refresh_mutex ); pthread_cond_destroy( &self->refresh_cond ); // Disconnect from JACK jack_client_close( self->jack ); // Finally deallocate self free( self ); } mlt-0.9.0/src/modules/jackrack/consumer_jack.yml000066400000000000000000000020631215300731300216660ustar00rootroot00000000000000schema_version: 0.1 type: consumer identifier: jack title: JACK version: 1 copyright: Dan Dennedy creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Audio parameters: - identifier: channels title: Channels type: integer minimum: 1 default: 2 - identifier: out_1 title: Send L type: string - identifier: out_2 title: Send R type: string - identifier: volume title: Volume type: float minimum: 0.0 default: 1.0 - identifier: refresh description: > Applications should set this to update the video frame when paused. type: integer minimum: 0 maximum: 1 - identifier: audio_off title: Audio off type: integer description: If 1, disable audio output mutable: yes minimum: 0 maximum: 1 default: 0 widget: checkbox - identifier: scrub_audio title: Audio scrubbing type: integer description: If enabled, sound is played even when the speed is not normal. mutable: yes minimum: 0 maximum: 1 default: 0 widget: checkbox mlt-0.9.0/src/modules/jackrack/factory.c000066400000000000000000000145341215300731300201410ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include extern mlt_consumer consumer_jack_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); #ifdef GPL #include "plugin_mgr.h" extern mlt_filter filter_jackrack_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_ladspa_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_ladspa_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); plugin_mgr_t *g_jackrack_plugin_mgr = NULL; #endif static mlt_properties metadata( mlt_service_type type, const char *id, char *data ) { char file[ PATH_MAX ]; if( type == filter_type ) { snprintf( file, PATH_MAX, "%s/jackrack/%s", mlt_environment( "MLT_DATA" ), strncmp( id, "ladspa.", 7 ) ? data : "filter_ladspa.yml" ); } else { snprintf( file, PATH_MAX, "%s/jackrack/%s", mlt_environment( "MLT_DATA" ), strncmp( id, "ladspa.", 7 ) ? data : "producer_ladspa.yml" ); } mlt_properties result = mlt_properties_parse_yaml( file ); #ifdef GPL if ( !strncmp( id, "ladspa.", 7 ) ) { // Annotate the yaml properties with ladspa control port info. plugin_desc_t *desc = plugin_mgr_get_any_desc( g_jackrack_plugin_mgr, strtol( id + 7, NULL, 10 ) ); if ( desc ) { mlt_properties params = mlt_properties_new(); mlt_properties p; char key[20]; int i; mlt_properties_set( result, "identifier", id ); mlt_properties_set( result, "title", desc->name ); mlt_properties_set( result, "creator", desc->maker ? desc->maker : "unknown" ); mlt_properties_set( result, "description", "LADSPA plugin" ); mlt_properties_set_data( result, "parameters", params, 0, (mlt_destructor) mlt_properties_close, NULL ); for ( i = 0; i < desc->control_port_count; i++ ) { int j = desc->control_port_indicies[i]; LADSPA_Data sample_rate = 48000; LADSPA_PortRangeHintDescriptor hint_descriptor = desc->port_range_hints[j].HintDescriptor; p = mlt_properties_new(); snprintf( key, sizeof(key), "%d", i ); mlt_properties_set_data( params, key, p, 0, (mlt_destructor) mlt_properties_close, NULL ); snprintf( key, sizeof(key), "%d", j ); mlt_properties_set( p, "identifier", key ); mlt_properties_set( p, "title", desc->port_names[ j ] ); if ( LADSPA_IS_HINT_INTEGER( hint_descriptor ) ) { mlt_properties_set( p, "type", "integer" ); mlt_properties_set_int( p, "default", plugin_desc_get_default_control_value( desc, j, sample_rate ) ); } else if ( LADSPA_IS_HINT_TOGGLED( hint_descriptor ) ) { mlt_properties_set( p, "type", "boolean" ); mlt_properties_set_int( p, "default", plugin_desc_get_default_control_value( desc, j, sample_rate ) ); } else { mlt_properties_set( p, "type", "float" ); mlt_properties_set_double( p, "default", plugin_desc_get_default_control_value( desc, j, sample_rate ) ); } /* set upper and lower, possibly adjusted to the sample rate */ if ( LADSPA_IS_HINT_BOUNDED_BELOW( hint_descriptor ) ) { LADSPA_Data lower = desc->port_range_hints[j].LowerBound; if ( LADSPA_IS_HINT_SAMPLE_RATE( hint_descriptor ) ) lower *= sample_rate; if ( LADSPA_IS_HINT_LOGARITHMIC( hint_descriptor ) ) { if (lower < FLT_EPSILON) lower = FLT_EPSILON; } mlt_properties_set_double( p, "minimum", lower ); } if ( LADSPA_IS_HINT_BOUNDED_ABOVE( hint_descriptor ) ) { LADSPA_Data upper = desc->port_range_hints[j].UpperBound; if ( LADSPA_IS_HINT_SAMPLE_RATE( hint_descriptor ) ) upper *= sample_rate; mlt_properties_set_double( p, "maximum", upper ); } if ( LADSPA_IS_HINT_LOGARITHMIC( hint_descriptor ) ) mlt_properties_set( p, "scale", "log" ); } if( type == filter_type ) { p = mlt_properties_new(); snprintf( key, sizeof(key), "%d", i ); mlt_properties_set_data( params, key, p, 0, (mlt_destructor) mlt_properties_close, NULL ); mlt_properties_set( p, "identifier", "wetness" ); mlt_properties_set( p, "title", "Wet/Dry" ); mlt_properties_set( p, "type", "float" ); mlt_properties_set_double( p, "default", 1 ); mlt_properties_set_double( p, "minimum", 0 ); mlt_properties_set_double( p, "maximum", 1 ); } } } #endif return result; } MLT_REPOSITORY { #ifdef GPL GSList *list; g_jackrack_plugin_mgr = plugin_mgr_new(); for ( list = g_jackrack_plugin_mgr->all_plugins; list; list = g_slist_next( list ) ) { plugin_desc_t *desc = (plugin_desc_t *) list->data; char *s = malloc( strlen( "ladpsa." ) + 21 ); sprintf( s, "ladspa.%lu", desc->id ); if( desc->has_input ) { MLT_REGISTER( filter_type, s, filter_ladspa_init ); MLT_REGISTER_METADATA( filter_type, s, metadata, NULL ); } else { MLT_REGISTER( producer_type, s, producer_ladspa_init ); MLT_REGISTER_METADATA( producer_type, s, metadata, NULL ); } free( s ); } mlt_factory_register_for_clean_up( g_jackrack_plugin_mgr, (mlt_destructor) plugin_mgr_destroy ); MLT_REGISTER( filter_type, "jackrack", filter_jackrack_init ); MLT_REGISTER_METADATA( filter_type, "jackrack", metadata, "filter_jackrack.yml" ); MLT_REGISTER( filter_type, "ladspa", filter_ladspa_init ); MLT_REGISTER_METADATA( filter_type, "ladspa", metadata, "filter_ladspa.yml" ); #endif MLT_REGISTER( consumer_type, "jack", consumer_jack_init ); MLT_REGISTER_METADATA( consumer_type, "jack", metadata, "consumer_jack.yml" ); } mlt-0.9.0/src/modules/jackrack/filter_jackrack.c000066400000000000000000000441321215300731300216050ustar00rootroot00000000000000/* * filter_jackrack.c -- filter audio through Jack and/or LADSPA plugins * Copyright (C) 2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include "jack_rack.h" extern pthread_mutex_t g_activate_mutex; #define BUFFER_LEN 204800 * 6 static void jack_started_transmitter( mlt_listener listener, mlt_properties owner, mlt_service service, void **args ) { listener( owner, service, (mlt_position*) args[0] ); } static void jack_stopped_transmitter( mlt_listener listener, mlt_properties owner, mlt_service service, void **args ) { listener( owner, service, (mlt_position*) args[0] ); } static void jack_seek_transmitter( mlt_listener listener, mlt_properties owner, mlt_service service, void **args ) { listener( owner, service, (mlt_position*) args[0] ); } #define JACKSTATE(x) (x==JackTransportStopped?"stopped":x==JackTransportStarting?"starting":x==JackTransportRolling?"rolling":"unknown") static int jack_sync( jack_transport_state_t state, jack_position_t *jack_pos, void *arg ) { mlt_filter filter = (mlt_filter) arg; mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE(filter) ); mlt_position position = mlt_profile_fps( profile ) * jack_pos->frame / jack_pos->frame_rate + 0.5; int result = 1; mlt_log_debug( MLT_FILTER_SERVICE(filter), "%s frame %u rate %u pos %d last_pos %d\n", JACKSTATE(state), jack_pos->frame, jack_pos->frame_rate, position, mlt_properties_get_position( properties, "_last_pos" ) ); if ( state == JackTransportStopped ) { mlt_events_fire( properties, "jack-stopped", &position, NULL ); mlt_properties_set_int( properties, "_sync_guard", 0 ); } else if ( state == JackTransportStarting ) { result = 0; if ( !mlt_properties_get_int( properties, "_sync_guard" ) ) { mlt_properties_set_int( properties, "_sync_guard", 1 ); mlt_events_fire( properties, "jack-started", &position, NULL ); } else if ( position >= mlt_properties_get_position( properties, "_last_pos" ) - 2 ) { mlt_properties_set_int( properties, "_sync_guard", 0 ); result = 1; } } else { mlt_properties_set_int( properties, "_sync_guard", 0 ); } return result; } static void on_jack_start( mlt_properties owner, mlt_properties properties ) { mlt_log_verbose( NULL, "%s\n", __FUNCTION__ ); jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL ); jack_transport_start( jack_client ); } static void on_jack_stop( mlt_properties owner, mlt_properties properties ) { mlt_log_verbose( NULL, "%s\n", __FUNCTION__ ); jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL ); jack_transport_stop( jack_client ); } static void on_jack_seek( mlt_properties owner, mlt_filter filter, mlt_position *position ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_log_verbose( MLT_FILTER_SERVICE(filter), "%s: %d\n", __FUNCTION__, *position ); mlt_properties_set_int( properties, "_sync_guard", 1 ); mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL ); jack_nframes_t jack_frame = jack_get_sample_rate( jack_client ); jack_frame *= *position / mlt_profile_fps( profile ); jack_transport_locate( jack_client, jack_frame ); } static void initialise_jack_ports( mlt_properties properties ) { int i; char mlt_name[20], rack_name[30]; jack_port_t **port = NULL; jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL ); jack_nframes_t jack_buffer_size = jack_get_buffer_size( jack_client ); // Propogate these for the Jack processing callback int channels = mlt_properties_get_int( properties, "channels" ); // Start JackRack if ( mlt_properties_get( properties, "src" ) ) { snprintf( rack_name, sizeof( rack_name ), "jackrack%d", getpid() ); jack_rack_t *jackrack = jack_rack_new( rack_name, mlt_properties_get_int( properties, "channels" ) ); jack_rack_open_file( jackrack, mlt_properties_get( properties, "src" ) ); mlt_properties_set_data( properties, "jackrack", jackrack, 0, (mlt_destructor) jack_rack_destroy, NULL ); mlt_properties_set( properties, "_rack_client_name", rack_name ); } else { // We have to set this to something to prevent re-initialization. mlt_properties_set_data( properties, "jackrack", jack_client, 0, NULL, NULL ); } // Allocate buffers and ports jack_ringbuffer_t **output_buffers = mlt_pool_alloc( sizeof( jack_ringbuffer_t *) * channels ); jack_ringbuffer_t **input_buffers = mlt_pool_alloc( sizeof( jack_ringbuffer_t *) * channels ); jack_port_t **jack_output_ports = mlt_pool_alloc( sizeof(jack_port_t *) * channels ); jack_port_t **jack_input_ports = mlt_pool_alloc( sizeof(jack_port_t *) * channels ); float **jack_output_buffers = mlt_pool_alloc( sizeof(float *) * jack_buffer_size ); float **jack_input_buffers = mlt_pool_alloc( sizeof(float *) * jack_buffer_size ); // Set properties - released inside filter_close mlt_properties_set_data( properties, "output_buffers", output_buffers, sizeof( jack_ringbuffer_t *) * channels, mlt_pool_release, NULL ); mlt_properties_set_data( properties, "input_buffers", input_buffers, sizeof( jack_ringbuffer_t *) * channels, mlt_pool_release, NULL ); mlt_properties_set_data( properties, "jack_output_ports", jack_output_ports, sizeof( jack_port_t *) * channels, mlt_pool_release, NULL ); mlt_properties_set_data( properties, "jack_input_ports", jack_input_ports, sizeof( jack_port_t *) * channels, mlt_pool_release, NULL ); mlt_properties_set_data( properties, "jack_output_buffers", jack_output_buffers, sizeof( float *) * channels, mlt_pool_release, NULL ); mlt_properties_set_data( properties, "jack_input_buffers", jack_input_buffers, sizeof( float *) * channels, mlt_pool_release, NULL ); // Register Jack ports for ( i = 0; i < channels; i++ ) { int in; output_buffers[i] = jack_ringbuffer_create( BUFFER_LEN * sizeof(float) ); input_buffers[i] = jack_ringbuffer_create( BUFFER_LEN * sizeof(float) ); snprintf( mlt_name, sizeof( mlt_name ), "obuf%d", i ); mlt_properties_set_data( properties, mlt_name, output_buffers[i], BUFFER_LEN * sizeof(float), (mlt_destructor) jack_ringbuffer_free, NULL ); snprintf( mlt_name, sizeof( mlt_name ), "ibuf%d", i ); mlt_properties_set_data( properties, mlt_name, input_buffers[i], BUFFER_LEN * sizeof(float), (mlt_destructor) jack_ringbuffer_free, NULL ); for ( in = 0; in < 2; in++ ) { snprintf( mlt_name, sizeof( mlt_name ), "%s_%d", in ? "in" : "out", i + 1); port = ( in ? &jack_input_ports[i] : &jack_output_ports[i] ); *port = jack_port_register( jack_client, mlt_name, JACK_DEFAULT_AUDIO_TYPE, ( in ? JackPortIsInput : JackPortIsOutput ) | JackPortIsTerminal, 0 ); } } // Start Jack processing pthread_mutex_lock( &g_activate_mutex ); jack_activate( jack_client ); pthread_mutex_unlock( &g_activate_mutex ); // Establish connections for ( i = 0; i < channels; i++ ) { int in; for ( in = 0; in < 2; in++ ) { port = ( in ? &jack_input_ports[i] : &jack_output_ports[i] ); snprintf( mlt_name, sizeof( mlt_name ), "%s", jack_port_name( *port ) ); snprintf( rack_name, sizeof( rack_name ), "%s_%d", in ? "in" : "out", i + 1 ); if ( mlt_properties_get( properties, "_rack_client_name" ) ) snprintf( rack_name, sizeof( rack_name ), "%s:%s_%d", mlt_properties_get( properties, "_rack_client_name" ), in ? "out" : "in", i + 1); else if ( mlt_properties_get( properties, rack_name ) ) snprintf( rack_name, sizeof( rack_name ), "%s", mlt_properties_get( properties, rack_name ) ); else snprintf( rack_name, sizeof( rack_name ), "%s:%s_%d", mlt_properties_get( properties, "_client_name" ), in ? "out" : "in", i + 1); if ( in ) { mlt_log_verbose( NULL, "JACK connect %s to %s\n", rack_name, mlt_name ); jack_connect( jack_client, rack_name, mlt_name ); } else { mlt_log_verbose( NULL, "JACK connect %s to %s\n", mlt_name, rack_name ); jack_connect( jack_client, mlt_name, rack_name ); } } } } static int jack_process (jack_nframes_t frames, void * data) { mlt_filter filter = (mlt_filter) data; mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); int channels = mlt_properties_get_int( properties, "channels" ); int frame_size = mlt_properties_get_int( properties, "_samples" ) * sizeof(float); int sync = mlt_properties_get_int( properties, "_sync" ); int err = 0; int i; static int total_size = 0; jack_ringbuffer_t **output_buffers = mlt_properties_get_data( properties, "output_buffers", NULL ); if ( output_buffers == NULL ) return 0; jack_ringbuffer_t **input_buffers = mlt_properties_get_data( properties, "input_buffers", NULL ); jack_port_t **jack_output_ports = mlt_properties_get_data( properties, "jack_output_ports", NULL ); jack_port_t **jack_input_ports = mlt_properties_get_data( properties, "jack_input_ports", NULL ); float **jack_output_buffers = mlt_properties_get_data( properties, "jack_output_buffers", NULL ); float **jack_input_buffers = mlt_properties_get_data( properties, "jack_input_buffers", NULL ); pthread_mutex_t *output_lock = mlt_properties_get_data( properties, "output_lock", NULL ); pthread_cond_t *output_ready = mlt_properties_get_data( properties, "output_ready", NULL ); for ( i = 0; i < channels; i++ ) { size_t jack_size = ( frames * sizeof(float) ); size_t ring_size; // Send audio through out port jack_output_buffers[i] = jack_port_get_buffer( jack_output_ports[i], frames ); if ( ! jack_output_buffers[i] ) { mlt_log_error( MLT_FILTER_SERVICE(filter), "no buffer for output port %d\n", i ); err = 1; break; } ring_size = jack_ringbuffer_read_space( output_buffers[i] ); jack_ringbuffer_read( output_buffers[i], ( char * )jack_output_buffers[i], ring_size < jack_size ? ring_size : jack_size ); if ( ring_size < jack_size ) memset( &jack_output_buffers[i][ring_size], 0, jack_size - ring_size ); // Return audio through in port jack_input_buffers[i] = jack_port_get_buffer( jack_input_ports[i], frames ); if ( ! jack_input_buffers[i] ) { mlt_log_error( MLT_FILTER_SERVICE(filter), "no buffer for input port %d\n", i ); err = 1; break; } // Do not start returning audio until we have sent first mlt frame if ( sync && i == 0 && frame_size > 0 ) total_size += ring_size; mlt_log_debug( MLT_FILTER_SERVICE(filter), "sync %d frame_size %d ring_size %zu jack_size %zu\n", sync, frame_size, ring_size, jack_size ); if ( ! sync || ( frame_size > 0 && total_size >= frame_size ) ) { ring_size = jack_ringbuffer_write_space( input_buffers[i] ); jack_ringbuffer_write( input_buffers[i], ( char * )jack_input_buffers[i], ring_size < jack_size ? ring_size : jack_size ); if ( sync ) { // Tell mlt that audio is available pthread_mutex_lock( output_lock); pthread_cond_signal( output_ready ); pthread_mutex_unlock( output_lock); // Clear sync phase mlt_properties_set_int( properties, "_sync", 0 ); } } } // Often jackd does not send the stopped event through the JackSyncCallback jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL ); jack_position_t jack_pos; jack_transport_state_t state = jack_transport_query( jack_client, &jack_pos ); int transport_state = mlt_properties_get_int( properties, "_transport_state" ); if ( state != transport_state ) { mlt_properties_set_int( properties, "_transport_state", state ); if ( state == JackTransportStopped ) jack_sync( state, &jack_pos, filter ); } return err; } /** Get the audio. */ static int jackrack_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); int jack_frequency = mlt_properties_get_int( filter_properties, "_sample_rate" ); // Get the producer's audio *format = mlt_audio_float; mlt_frame_get_audio( frame, buffer, format, &jack_frequency, channels, samples ); // TODO: Deal with sample rate differences if ( *frequency != jack_frequency ) mlt_log_error( MLT_FILTER_SERVICE( filter ), "mismatching frequencies JACK = %d actual = %d\n", jack_frequency, *frequency ); *frequency = jack_frequency; // Initialise Jack ports and connections if needed if ( mlt_properties_get_int( filter_properties, "_samples" ) == 0 ) mlt_properties_set_int( filter_properties, "_samples", *samples ); // Get the filter-specific properties jack_ringbuffer_t **output_buffers = mlt_properties_get_data( filter_properties, "output_buffers", NULL ); jack_ringbuffer_t **input_buffers = mlt_properties_get_data( filter_properties, "input_buffers", NULL ); // pthread_mutex_t *output_lock = mlt_properties_get_data( filter_properties, "output_lock", NULL ); // pthread_cond_t *output_ready = mlt_properties_get_data( filter_properties, "output_ready", NULL ); // Process the audio float *q = (float*) *buffer; size_t size = *samples * sizeof(float); int j; // struct timespec tm = { 0, 0 }; // Write into output ringbuffer for ( j = 0; j < *channels; j++ ) { if ( jack_ringbuffer_write_space( output_buffers[j] ) >= size ) jack_ringbuffer_write( output_buffers[j], (char*)( q + j * *samples ), size ); } // Synchronization phase - wait for signal from Jack process while ( jack_ringbuffer_read_space( input_buffers[ *channels - 1 ] ) < size ) ; //pthread_cond_wait( output_ready, output_lock ); // Read from input ringbuffer for ( j = 0; j < *channels; j++, q++ ) { if ( jack_ringbuffer_read_space( input_buffers[j] ) >= size ) jack_ringbuffer_read( input_buffers[j], (char*)( q + j * *samples ), size ); } // help jack_sync() indicate when we are rolling mlt_position pos = mlt_frame_get_position( frame ); mlt_properties_set_position( filter_properties, "_last_pos", pos ); return 0; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { { mlt_properties properties = MLT_FILTER_PROPERTIES( this ); mlt_frame_push_audio( frame, this ); mlt_frame_push_audio( frame, jackrack_get_audio ); if ( !mlt_properties_get_data( properties, "jackrack", NULL ) ) initialise_jack_ports( properties ); } return frame; } static void filter_close( mlt_filter this ) { mlt_properties properties = MLT_FILTER_PROPERTIES( this ); jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL ); jack_deactivate( jack_client ); jack_client_close( jack_client ); this->parent.close = NULL; mlt_service_close( &this->parent ); } /** Constructor for the filter. */ mlt_filter filter_jackrack_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { char name[16]; char *jack_client_name; jack_status_t status = 0; snprintf( name, sizeof( name ), "mlt%d", getpid() ); jack_client_t *jack_client = jack_client_open( name, JackNullOption, &status, NULL ); if ( jack_client ) { if ( status & JackNameNotUnique ) { jack_client_name = jack_get_client_name ( jack_client ); strcpy( name, jack_client_name ); } mlt_properties properties = MLT_FILTER_PROPERTIES( this ); pthread_mutex_t *output_lock = mlt_pool_alloc( sizeof( pthread_mutex_t ) ); pthread_cond_t *output_ready = mlt_pool_alloc( sizeof( pthread_cond_t ) ); jack_set_process_callback( jack_client, jack_process, this ); jack_set_sync_callback( jack_client, jack_sync, this ); jack_set_sync_timeout( jack_client, 5000000 ); //TODO: jack_on_shutdown( jack_client, jack_shutdown_cb, this ); this->process = filter_process; this->close = filter_close; pthread_mutex_init( output_lock, NULL ); pthread_cond_init( output_ready, NULL ); mlt_properties_set( properties, "src", arg ); mlt_properties_set( properties, "_client_name", name ); mlt_properties_set_data( properties, "jack_client", jack_client, 0, NULL, NULL ); mlt_properties_set_int( properties, "_sample_rate", jack_get_sample_rate( jack_client ) ); mlt_properties_set_data( properties, "output_lock", output_lock, 0, mlt_pool_release, NULL ); mlt_properties_set_data( properties, "output_ready", output_ready, 0, mlt_pool_release, NULL ); mlt_properties_set_int( properties, "_sync", 1 ); mlt_properties_set_int( properties, "channels", 2 ); mlt_events_register( properties, "jack-started", (mlt_transmitter) jack_started_transmitter ); mlt_events_register( properties, "jack-stopped", (mlt_transmitter) jack_stopped_transmitter ); mlt_events_register( properties, "jack-start", NULL ); mlt_events_register( properties, "jack-stop", NULL ); mlt_events_register( properties, "jack-seek", (mlt_transmitter) jack_seek_transmitter ); mlt_events_listen( properties, properties, "jack-start", (mlt_listener) on_jack_start ); mlt_events_listen( properties, properties, "jack-stop", (mlt_listener) on_jack_stop ); mlt_events_listen( properties, this, "jack-seek", (mlt_listener) on_jack_seek ); mlt_properties_set_position( properties, "_jack_seek", -1 ); } else { mlt_log_error( NULL, "Failed to connect to JACK server\n" ); mlt_filter_close( this ); this = NULL; } } return this; } mlt-0.9.0/src/modules/jackrack/filter_jackrack.yml000066400000000000000000000034001215300731300221550ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: jackrack title: JACK version: 1 copyright: Copyright (C) 2004-2011 Ushodaya Enterprises Limited license: GPLv2 language: en url: http://www.ladspa.org/ creator: Dan Dennedy tags: - Audio description: Process audio using JACK. notes: > This can be used to receive audio from JACK by connecting only input ports. It can be used to output audio to JACK by connecting only the output ports. Or, you can use it as a filter with something like JACK Rack by connecting both output and input ports to send and receive. You can configure as many channels as you need and repeat the in_1/out_1 pattern for as many channels as you have configured. If you are using a MLT consumer that uses ALSA, then you should start jackd with the dummy driver, e.g.: jackd -ddummy -r48000 -p2048. The MLT JACK client name uses the format: mlt{pid}. bugs: - > MLT cannot automatically adapt to the sample rate at which JACK is configured. Please make sure they are configured the same. - Does not automatically reconfigure to the number of channels requested by consumer. - Some effects have a temporal side-effect that may not work well. parameters: - identifier: argument title: JACK Rack file type: string description: > Creates JACK ports and runs a JACK Rack project to process audio through a stack of LADSPA filters. - identifier: src title: JACK Rack file type: string - identifier: channels title: Channels type: integer minimum: 1 default: 2 - identifier: in_1 title: Receive L type: string - identifier: in_2 title: Receive R type: string - identifier: out_1 title: Send L type: string - identifier: out_2 title: Send R type: string mlt-0.9.0/src/modules/jackrack/filter_ladspa.c000066400000000000000000000123671215300731300213050ustar00rootroot00000000000000/* * filter_ladspa.c -- filter audio through LADSPA plugins * Copyright (C) 2004-2005 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include "jack_rack.h" #define BUFFER_LEN 10000 static jack_rack_t* initialise_jack_rack( mlt_properties properties, int channels ) { jack_rack_t *jackrack = NULL; char *resource = mlt_properties_get( properties, "resource" ); if ( !resource && mlt_properties_get( properties, "src" ) ) resource = mlt_properties_get( properties, "src" ); // Start JackRack if ( resource || mlt_properties_get_int64( properties, "_pluginid" ) ) { // Create JackRack without Jack client name so that it only uses LADSPA jackrack = jack_rack_new( NULL, channels ); mlt_properties_set_data( properties, "jackrack", jackrack, 0, (mlt_destructor) jack_rack_destroy, NULL ); if ( resource ) // Load JACK Rack XML file jack_rack_open_file( jackrack, resource ); else if ( mlt_properties_get_int64( properties, "_pluginid" ) ) { // Load one LADSPA plugin by its UniqueID unsigned long id = mlt_properties_get_int64( properties, "_pluginid" ); plugin_desc_t *desc = plugin_mgr_get_any_desc( jackrack->plugin_mgr, id ); plugin_t *plugin; if ( desc && ( plugin = jack_rack_instantiate_plugin( jackrack, desc ) ) ) { // TODO: move this into get_audio when keyframing is ready LADSPA_Data value; int index, c; plugin->enabled = TRUE; for ( index = 0; index < desc->control_port_count; index++ ) { // Apply the control port values char key[20]; value = plugin_desc_get_default_control_value( desc, index, sample_rate ); snprintf( key, sizeof(key), "%d", index ); if ( mlt_properties_get( properties, key ) ) value = mlt_properties_get_double( properties, key ); for ( c = 0; c < plugin->copies; c++ ) plugin->holders[c].control_memory[index] = value; } plugin->wet_dry_enabled = mlt_properties_get( properties, "wetness" ) != NULL; if ( plugin->wet_dry_enabled ) { value = mlt_properties_get_double( properties, "wetness" ); for ( c = 0; c < channels; c++ ) plugin->wet_dry_values[c] = value; } process_add_plugin( jackrack->procinfo, plugin ); } else mlt_log_error( properties, "failed to load plugin %lu\n", id ); } } return jackrack; } /** Get the audio. */ static int ladspa_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); // Get the producer's audio *format = mlt_audio_float; mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); // Initialise LADSPA if needed jack_rack_t *jackrack = mlt_properties_get_data( filter_properties, "jackrack", NULL ); if ( jackrack == NULL ) { sample_rate = *frequency; // global inside jack_rack jackrack = initialise_jack_rack( filter_properties, *channels ); } // Get the filter-specific properties LADSPA_Data **input_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * *channels ); LADSPA_Data **output_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * *channels ); int i; for ( i = 0; i < *channels; i++ ) { input_buffers[i] = (LADSPA_Data*) *buffer + i * *samples; output_buffers[i] = (LADSPA_Data*) *buffer + i * *samples; } // Do LADSPA processing int error = jackrack && process_ladspa( jackrack->procinfo, *samples, input_buffers, output_buffers ); mlt_pool_release( input_buffers ); mlt_pool_release( output_buffers ); return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { if ( mlt_frame_is_test_audio( frame ) == 0 ) { mlt_frame_push_audio( frame, this ); mlt_frame_push_audio( frame, ladspa_get_audio ); } return frame; } /** Constructor for the filter. */ mlt_filter filter_ladspa_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { mlt_properties properties = MLT_FILTER_PROPERTIES( this ); this->process = filter_process; mlt_properties_set( properties, "resource", arg ); if ( !strncmp( id, "ladspa.", 7 ) ) mlt_properties_set( properties, "_pluginid", id + 7 ); } return this; } mlt-0.9.0/src/modules/jackrack/filter_ladspa.yml000066400000000000000000000012271215300731300216550ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: ladspa title: LADSPA version: 1 copyright: Copyright (C) 2004-2011 Ushodaya Enterprises Limited license: GPLv2 language: en url: http://www.ladspa.org/ creator: Dan Dennedy tags: - Audio description: Process audio using LADSPA plugins. notes: > Automatically adapts to the number of channels and sampling rate of the consumer. bugs: - Some effects have a temporal side-effect that may not work well. parameters: - identifier: argument title: JACK Rack XML file type: string description: > Runs a JACK Rack project to process audio through a stack of LADSPA filters without using JACK. mlt-0.9.0/src/modules/jackrack/jack_rack.c000066400000000000000000000264651215300731300204100ustar00rootroot00000000000000/* * JACK Rack * * Original: * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: * Copyright (C) 2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include "jack_rack.h" #include "lock_free_fifo.h" #include "plugin_settings.h" #include "framework/mlt_log.h" #ifndef _ #define _(x) x #endif #define _x (const xmlChar*) #define _s (const char*) extern plugin_mgr_t *g_jackrack_plugin_mgr; jack_rack_t * jack_rack_new (const char * client_name, unsigned long channels) { jack_rack_t *rack; rack = g_malloc (sizeof (jack_rack_t)); rack->saved_plugins = NULL; rack->channels = channels; rack->procinfo = process_info_new (client_name, channels, FALSE, FALSE); if (!rack->procinfo) { g_free (rack); return NULL; } rack->plugin_mgr = g_jackrack_plugin_mgr; plugin_mgr_set_plugins (rack->plugin_mgr, channels); return rack; } void jack_rack_destroy (jack_rack_t * jack_rack) { process_quit (jack_rack->procinfo); // plugin_mgr is shared and global now, so we do not destroy it with each instance // plugin_mgr_destroy (jack_rack->plugin_mgr); process_info_destroy (jack_rack->procinfo); g_slist_free (jack_rack->saved_plugins); g_free (jack_rack); } plugin_t * jack_rack_instantiate_plugin (jack_rack_t * jack_rack, plugin_desc_t * desc) { plugin_t * plugin; /* check whether or not the plugin is RT capable and confirm with the user if it isn't */ if (!LADSPA_IS_HARD_RT_CAPABLE(desc->properties)) { mlt_log_info( NULL, "Plugin not RT capable. The plugin '%s' does not describe itself as being capable of real-time operation. You may experience drop outs or jack may even kick us out if you use it.\n", desc->name); } /* create the plugin */ plugin = plugin_new (desc, jack_rack); if (!plugin) { mlt_log_error( NULL, "Error loading file plugin '%s' from file '%s'\n", desc->name, desc->object_file); } return plugin; } void jack_rack_add_saved_plugin (jack_rack_t * jack_rack, saved_plugin_t * saved_plugin) { plugin_t * plugin = jack_rack_instantiate_plugin (jack_rack, saved_plugin->settings->desc); if (!plugin) return; jack_rack->saved_plugins = g_slist_append (jack_rack->saved_plugins, saved_plugin); process_add_plugin (jack_rack->procinfo, plugin); jack_rack_add_plugin (jack_rack, plugin); } void jack_rack_add_plugin (jack_rack_t * jack_rack, plugin_t * plugin) { saved_plugin_t * saved_plugin = NULL; GSList * list; unsigned long control, channel; LADSPA_Data value; guint copy; /* see if there's any saved settings that match the plugin id */ for (list = jack_rack->saved_plugins; list; list = g_slist_next (list)) { saved_plugin = list->data; if (saved_plugin->settings->desc->id == plugin->desc->id) { /* process the settings! */ jack_rack->saved_plugins = g_slist_remove (jack_rack->saved_plugins, saved_plugin); break; } saved_plugin = NULL; } if ( !saved_plugin ) return; /* initialize plugin parameters */ plugin->enabled = settings_get_enabled (saved_plugin->settings); plugin->wet_dry_enabled = settings_get_wet_dry_enabled (saved_plugin->settings); for (control = 0; control < saved_plugin->settings->desc->control_port_count; control++) for (copy = 0; copy < plugin->copies; copy++) { value = settings_get_control_value (saved_plugin->settings, copy, control); plugin->holders[copy].control_memory[control] = value; //mlt_log_debug( NULL, "setting control value %s (%d) = %f\n", saved_plugin->settings->desc->port_names[control], copy, value); // lff_write (plugin->holders[copy].ui_control_fifos + control, &value); } if (plugin->wet_dry_enabled) for (channel = 0; channel < jack_rack->channels; channel++) { value = settings_get_wet_dry_value (saved_plugin->settings, channel); plugin->wet_dry_values[channel] = value; //mlt_log_debug( NULL, "setting wet/dry value %d = %f\n", channel, value); // lff_write (plugin->wet_dry_fifos + channel, &value); } } static void saved_rack_parse_plugin (jack_rack_t * jack_rack, saved_rack_t * saved_rack, saved_plugin_t * saved_plugin, const char * filename, xmlNodePtr plugin) { plugin_desc_t * desc; settings_t * settings = NULL; xmlNodePtr node; xmlNodePtr sub_node; xmlChar *content; unsigned long num; unsigned long control = 0; #ifdef WIN32 xmlFreeFunc xmlFree = NULL; xmlMemGet( &xmlFree, NULL, NULL, NULL); #endif for (node = plugin->children; node; node = node->next) { if (xmlStrcmp (node->name, _x("id")) == 0) { content = xmlNodeGetContent (node); num = strtoul (_s(content), NULL, 10); xmlFree (content); desc = plugin_mgr_get_any_desc (jack_rack->plugin_mgr, num); if (!desc) { mlt_log_verbose( NULL, _("The file '%s' contains an unknown plugin with ID '%ld'; skipping\n"), filename, num); return; } settings = settings_new (desc, saved_rack->channels, saved_rack->sample_rate); } else if (xmlStrcmp (node->name, _x("enabled")) == 0) { content = xmlNodeGetContent (node); settings_set_enabled (settings, xmlStrcmp (content, _x("true")) == 0 ? TRUE : FALSE); xmlFree (content); } else if (xmlStrcmp (node->name, _x("wet_dry_enabled")) == 0) { content = xmlNodeGetContent (node); settings_set_wet_dry_enabled (settings, xmlStrcmp (content, _x("true")) == 0 ? TRUE : FALSE); xmlFree (content); } else if (xmlStrcmp (node->name, _x("wet_dry_locked")) == 0) { content = xmlNodeGetContent (node); settings_set_wet_dry_locked (settings, xmlStrcmp (content, _x("true")) == 0 ? TRUE : FALSE); xmlFree (content); } else if (xmlStrcmp (node->name, _x("wet_dry_values")) == 0) { unsigned long channel = 0; for (sub_node = node->children; sub_node; sub_node = sub_node->next) { if (xmlStrcmp (sub_node->name, _x("value")) == 0) { content = xmlNodeGetContent (sub_node); settings_set_wet_dry_value (settings, channel, strtod (_s(content), NULL)); xmlFree (content); channel++; } } } else if (xmlStrcmp (node->name, _x("lockall")) == 0) { content = xmlNodeGetContent (node); settings_set_lock_all (settings, xmlStrcmp (content, _x("true")) == 0 ? TRUE : FALSE); xmlFree (content); } else if (xmlStrcmp (node->name, _x("controlrow")) == 0) { gint copy = 0; for (sub_node = node->children; sub_node; sub_node = sub_node->next) { if (xmlStrcmp (sub_node->name, _x("lock")) == 0) { content = xmlNodeGetContent (sub_node); settings_set_lock (settings, control, xmlStrcmp (content, _x("true")) == 0 ? TRUE : FALSE); xmlFree (content); } else if (xmlStrcmp (sub_node->name, _x("value")) == 0) { content = xmlNodeGetContent (sub_node); settings_set_control_value (settings, copy, control, strtod (_s(content), NULL)); xmlFree (content); copy++; } } control++; } } if (settings) saved_plugin->settings = settings; } static void saved_rack_parse_jackrack (jack_rack_t * jack_rack, saved_rack_t * saved_rack, const char * filename, xmlNodePtr jackrack) { xmlNodePtr node; xmlChar *content; saved_plugin_t * saved_plugin; #ifdef WIN32 xmlFreeFunc xmlFree = NULL; xmlMemGet( &xmlFree, NULL, NULL, NULL); #endif for (node = jackrack->children; node; node = node->next) { if (xmlStrcmp (node->name, _x("channels")) == 0) { content = xmlNodeGetContent (node); saved_rack->channels = strtoul (_s(content), NULL, 10); xmlFree (content); } else if (xmlStrcmp (node->name, _x("samplerate")) == 0) { content = xmlNodeGetContent (node); saved_rack->sample_rate = strtoul (_s(content), NULL, 10); xmlFree (content); } else if (xmlStrcmp (node->name, _x("plugin")) == 0) { saved_plugin = g_malloc0 (sizeof (saved_plugin_t)); saved_rack->plugins = g_slist_append (saved_rack->plugins, saved_plugin); saved_rack_parse_plugin (jack_rack, saved_rack, saved_plugin, filename, node); } } } static saved_rack_t * saved_rack_new (jack_rack_t * jack_rack, const char * filename, xmlDocPtr doc) { xmlNodePtr node; saved_rack_t *saved_rack; /* create the saved rack */ saved_rack = g_malloc (sizeof (saved_rack_t)); saved_rack->plugins = NULL; saved_rack->sample_rate = 48000; saved_rack->channels = 2; for (node = doc->children; node; node = node->next) { if (xmlStrcmp (node->name, _x("jackrack")) == 0) saved_rack_parse_jackrack (jack_rack, saved_rack, filename, node); } return saved_rack; } static void saved_rack_destroy (saved_rack_t * saved_rack) { GSList * list; for (list = saved_rack->plugins; list; list = g_slist_next (list)) settings_destroy (((saved_plugin_t *) list->data)->settings); g_slist_free (saved_rack->plugins); g_free (saved_rack); } int jack_rack_open_file (jack_rack_t * jack_rack, const char * filename) { xmlDocPtr doc; saved_rack_t * saved_rack; GSList * list; saved_plugin_t * saved_plugin; doc = xmlParseFile (filename); if (!doc) { mlt_log_error( NULL, _("Could not parse file '%s'\n"), filename); return 1; } if (xmlStrcmp ( ((xmlDtdPtr)doc->children)->name, _x("jackrack")) != 0) { mlt_log_error( NULL, _("The file '%s' is not a JACK Rack settings file\n"), filename); return 1; } saved_rack = saved_rack_new (jack_rack, filename, doc); xmlFreeDoc (doc); if (!saved_rack) return 1; for (list = saved_rack->plugins; list; list = g_slist_next (list)) { saved_plugin = list->data; settings_set_sample_rate (saved_plugin->settings, sample_rate); jack_rack_add_saved_plugin (jack_rack, saved_plugin); } saved_rack_destroy (saved_rack); return 0; } /* EOF */ mlt-0.9.0/src/modules/jackrack/jack_rack.h000066400000000000000000000040231215300731300203770ustar00rootroot00000000000000/* * JACK Rack * * Original: * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: * Copyright (C) 2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __JR_JACK_RACK_H__ #define __JR_JACK_RACK_H__ #include #include #include "plugin.h" #include "plugin_mgr.h" #include "plugin_settings.h" #include "process.h" typedef struct _saved_plugin saved_plugin_t; struct _saved_plugin { settings_t *settings; }; typedef struct _saved_rack saved_rack_t; struct _saved_rack { unsigned long channels; jack_nframes_t sample_rate; GSList * plugins; }; typedef struct _jack_rack jack_rack_t; struct _jack_rack { plugin_mgr_t * plugin_mgr; process_info_t * procinfo; unsigned long channels; GSList * saved_plugins; }; jack_rack_t * jack_rack_new (const char * client_name, unsigned long channels); void jack_rack_destroy (jack_rack_t * jack_rack); int jack_rack_open_file (jack_rack_t * jack_rack, const char * filename); void jack_rack_add_plugin (jack_rack_t * jack_rack, plugin_t * plugin); void jack_rack_add_saved_plugin (jack_rack_t * jack_rack, struct _saved_plugin * saved_plugin); plugin_t * jack_rack_instantiate_plugin (jack_rack_t * jack_rack, plugin_desc_t * desc); #endif /* __JR_JACK_RACK_H__ */ mlt-0.9.0/src/modules/jackrack/lock_free_fifo.c000066400000000000000000000060351215300731300214230ustar00rootroot00000000000000/* * JACK Rack * * Original: * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: * Copyright (C) 2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include "lock_free_fifo.h" /** initialise a lock free fifo */ void lff_init (lff_t * lff, unsigned int size, size_t object_size) { lff->size = size; lff->object_size = object_size; lff->read_index = 0; lff->write_index = 0; lff->data = g_malloc (object_size * size); } lff_t * lff_new (unsigned int size, size_t object_size) { lff_t * lff; lff = g_malloc (sizeof (lff_t)); lff_init (lff, size, object_size); return lff; } void lff_free (lff_t * lff) { g_free (lff->data); } void lff_destroy (lff_t * lff) { lff_free (lff); g_free (lff); } /** read an element from the fifo into data. returns 0 on success, non-zero if there were no elements to read */ int lff_read (lff_t * lff, void * data) { if (lff->read_index == lff->write_index) { return -1; } else { memcpy (data, ((char *)lff->data) + (lff->read_index * lff->object_size), lff->object_size); lff->read_index++; if (lff->read_index >= lff->size) { lff->read_index = 0; } return 0; } } /** write an element from data to the fifo. returns 0 on success, non-zero if there was no space */ int lff_write (lff_t * lff, void * data) { static unsigned int ri; /* got to read read_index only once for safety */ ri = lff->read_index; /* lots of logic for when we're allowed to write to the fifo which basically boils down to "don't write if we're one element behind the read index" */ if ((ri > lff->write_index && ri - lff->write_index > 1) || (lff->write_index >= ri && lff->write_index != lff->size - 1) || (lff->write_index >= ri && lff->write_index == lff->size - 1 && ri != 0)) { /* if ((ri > lff->write_index && ri - lff->write_index > 1) || (lff->write_index >= ri && (lff->write_index != lff->size - 1 || ri != 0))) { */ memcpy (((char *)lff->data) + (lff->write_index * lff->object_size), data, lff->object_size); /* FIXME: is this safe? */ lff->write_index++; if (lff->write_index >= lff->size) { lff->write_index = 0; } return 0; } else { return -1; } } mlt-0.9.0/src/modules/jackrack/lock_free_fifo.h000066400000000000000000000033511215300731300214260ustar00rootroot00000000000000/* * JACK Rack * * Original: * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: * Copyright (C) 2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __JLH_LOCK_FREE_FIFO_H__ #define __JLH_LOCK_FREE_FIFO_H__ /** lock free fifo ring buffer structure */ typedef struct lock_free_fifo { /** Size of the ringbuffer (in elements) */ unsigned int size; /** the memory containing the ringbuffer */ void * data; /** the size of an element */ size_t object_size; /** the current position of the reader */ unsigned int read_index; /** the current position of the writer */ unsigned int write_index; } lff_t; void lff_init (lff_t * lff, unsigned int size, size_t object_size); void lff_free (lff_t * lff); lff_t * lff_new (unsigned int size, size_t object_size); void lff_destroy (lff_t * lock_free_fifo); int lff_read (lff_t * lock_free_fifo, void * data); int lff_write (lff_t * lock_free_fifo, void * data); #endif /* __JLH_LOCK_FREE_FIFO_H__ */ mlt-0.9.0/src/modules/jackrack/plugin.c000066400000000000000000000357131215300731300177720ustar00rootroot00000000000000/* * JACK Rack * * Original: * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: * Copyright (C) 2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include "plugin.h" #include "jack_rack.h" #include "process.h" #include "framework/mlt_log.h" #define CONTROL_FIFO_SIZE 128 /* swap over the jack ports in two plugins */ static void plugin_swap_aux_ports (plugin_t * plugin, plugin_t * other) { guint copy; jack_port_t ** aux_ports_tmp; for (copy = 0; copy < plugin->copies; copy++) { aux_ports_tmp = other->holders[copy].aux_ports; other->holders[copy].aux_ports = plugin->holders[copy].aux_ports; plugin->holders[copy].aux_ports = aux_ports_tmp; } } /** connect up the ladspa instance's input buffers to the previous plugin's audio memory. make sure to check that plugin->prev exists. */ void plugin_connect_input_ports (plugin_t * plugin, LADSPA_Data ** inputs) { gint copy; unsigned long channel; unsigned long rack_channel; if (!plugin || !inputs) return; rack_channel = 0; for (copy = 0; copy < plugin->copies; copy++) { for (channel = 0; channel < plugin->desc->channels; channel++) { plugin->descriptor-> connect_port (plugin->holders[copy].instance, plugin->desc->audio_input_port_indicies[channel], inputs[rack_channel]); rack_channel++; } } plugin->audio_input_memory = inputs; } /** connect up a plugin's output ports to its own audio_output_memory output memory */ void plugin_connect_output_ports (plugin_t * plugin) { gint copy; unsigned long channel; unsigned long rack_channel = 0; if (!plugin) return; for (copy = 0; copy < plugin->copies; copy++) { for (channel = 0; channel < plugin->desc->channels; channel++) { plugin->descriptor-> connect_port (plugin->holders[copy].instance, plugin->desc->audio_output_port_indicies[channel], plugin->audio_output_memory[rack_channel]); rack_channel++; } } } void process_add_plugin (process_info_t * procinfo, plugin_t * plugin) { /* sort out list pointers */ plugin->next = NULL; plugin->prev = procinfo->chain_end; if (procinfo->chain_end) procinfo->chain_end->next = plugin; else procinfo->chain = plugin; procinfo->chain_end = plugin; } /** remove a plugin from the chain */ plugin_t * process_remove_plugin (process_info_t * procinfo, plugin_t *plugin) { /* sort out chain pointers */ if (plugin->prev) plugin->prev->next = plugin->next; else procinfo->chain = plugin->next; if (plugin->next) plugin->next->prev = plugin->prev; else procinfo->chain_end = plugin->prev; /* sort out the aux ports */ if (procinfo->jack_client && plugin->desc->aux_channels > 0) { plugin_t * other; for (other = plugin->next; other; other = other->next) if (other->desc->id == plugin->desc->id) plugin_swap_aux_ports (plugin, other); } return plugin; } /** enable/disable a plugin */ void process_ablise_plugin (process_info_t * procinfo, plugin_t *plugin, gboolean enable) { plugin->enabled = enable; } /** enable/disable a plugin */ void process_ablise_plugin_wet_dry (process_info_t * procinfo, plugin_t *plugin, gboolean enable) { plugin->wet_dry_enabled = enable; } /** move a plugin up or down one place in the chain */ void process_move_plugin (process_info_t * procinfo, plugin_t *plugin, gint up) { /* other plugins in the chain */ plugin_t *pp = NULL, *p, *n, *nn = NULL; /* note that we should never recieve an illogical move request ie, there will always be at least 1 plugin before for an up request or 1 plugin after for a down request */ /* these are pointers to the plugins surrounding the specified one: { pp, p, plugin, n, nn } which makes things much clearer than tptr, tptr2 etc */ p = plugin->prev; if (p) pp = p->prev; n = plugin->next; if (n) nn = n->next; if (up) { if (!p) return; if (pp) pp->next = plugin; else procinfo->chain = plugin; p->next = n; p->prev = plugin; plugin->prev = pp; plugin->next = p; if (n) n->prev = p; else procinfo->chain_end = p; } else { if (!n) return; if (p) p->next = n; else procinfo->chain = n; n->prev = p; n->next = plugin; plugin->prev = n; plugin->next = nn; if (nn) nn->prev = plugin; else procinfo->chain_end = plugin; } if (procinfo->jack_client && plugin->desc->aux_channels > 0) { plugin_t * other; other = up ? plugin->next : plugin->prev; /* swap around the jack ports */ if (other->desc->id == plugin->desc->id) plugin_swap_aux_ports (plugin, other); } } /** exchange an existing plugin for a newly created one */ plugin_t * process_change_plugin (process_info_t * procinfo, plugin_t *plugin, plugin_t * new_plugin) { new_plugin->next = plugin->next; new_plugin->prev = plugin->prev; if (plugin->prev) plugin->prev->next = new_plugin; else procinfo->chain = new_plugin; if (plugin->next) plugin->next->prev = new_plugin; else procinfo->chain_end = new_plugin; /* sort out the aux ports */ if (procinfo->jack_client && plugin->desc->aux_channels > 0) { plugin_t * other; for (other = plugin->next; other; other = other->next) if (other->desc->id == plugin->desc->id) plugin_swap_aux_ports (plugin, other); } return plugin; } /****************************************** ************* non RT stuff *************** ******************************************/ static int plugin_open_plugin (plugin_desc_t * desc, void ** dl_handle_ptr, const LADSPA_Descriptor ** descriptor_ptr) { void * dl_handle; const char * dlerr; LADSPA_Descriptor_Function get_descriptor; /* open the object file */ dl_handle = dlopen (desc->object_file, RTLD_NOW|RTLD_GLOBAL); if (!dl_handle) { mlt_log_warning( NULL, "%s: error opening shared object file '%s': %s\n", __FUNCTION__, desc->object_file, dlerror()); return 1; } /* get the get_descriptor function */ dlerror (); /* clear the error report */ get_descriptor = (LADSPA_Descriptor_Function) dlsym (dl_handle, "ladspa_descriptor"); dlerr = dlerror(); if (dlerr) { mlt_log_warning( NULL, "%s: error finding descriptor symbol in object file '%s': %s\n", __FUNCTION__, desc->object_file, dlerr); dlclose (dl_handle); return 1; } *descriptor_ptr = get_descriptor (desc->index); *dl_handle_ptr = dl_handle; return 0; } static int plugin_instantiate (const LADSPA_Descriptor * descriptor, unsigned long plugin_index, gint copies, LADSPA_Handle * instances) { gint i; for (i = 0; i < copies; i++) { instances[i] = descriptor->instantiate (descriptor, sample_rate); if (!instances[i]) { unsigned long d; for (d = 0; d < i; d++) descriptor->cleanup (instances[d]); return 1; } } return 0; } static void plugin_create_aux_ports (plugin_t * plugin, guint copy, jack_rack_t * jack_rack) { plugin_desc_t * desc; // plugin_slot_t * slot; unsigned long aux_channel = 1; unsigned long plugin_index = 1; unsigned long i; char port_name[64]; char * plugin_name; char * ptr; // GList * list; ladspa_holder_t * holder; desc = plugin->desc; holder = plugin->holders + copy; holder->aux_ports = g_malloc (sizeof (jack_port_t *) * desc->aux_channels); /* make the plugin name jack worthy */ ptr = plugin_name = g_strndup (plugin->desc->name, 7); while (*ptr != '\0') { if (*ptr == ' ') *ptr = '_'; else *ptr = tolower (*ptr); ptr++; } /* for (list = jack_rack->slots; list; list = g_list_next (list)) { slot = (plugin_slot_t *) list->data; if (slot->plugin->desc->id == plugin->desc->id) plugin_index++; } */ for (i = 0; i < desc->aux_channels; i++, aux_channel++) { sprintf (port_name, "%s_%ld-%d_%c%ld", plugin_name, plugin_index, copy + 1, desc->aux_are_input ? 'i' : 'o', aux_channel); holder->aux_ports[i] = jack_port_register (jack_rack->procinfo->jack_client, port_name, JACK_DEFAULT_AUDIO_TYPE, desc->aux_are_input ? JackPortIsInput : JackPortIsOutput, 0); if (!holder->aux_ports[i]) { mlt_log_panic( NULL, "Could not register jack port '%s'; aborting\n", port_name); } } g_free (plugin_name); } static LADSPA_Data unused_control_port_output; static void plugin_init_holder (plugin_t * plugin, guint copy, LADSPA_Handle instance, jack_rack_t * jack_rack) { unsigned long i; plugin_desc_t * desc; ladspa_holder_t * holder; desc = plugin->desc; holder = plugin->holders + copy; holder->instance = instance; if (desc->control_port_count > 0) { holder->ui_control_fifos = g_malloc (sizeof (lff_t) * desc->control_port_count); holder->control_memory = g_malloc (sizeof (LADSPA_Data) * desc->control_port_count); } else { holder->ui_control_fifos = NULL; holder->control_memory = NULL; } for (i = 0; i < desc->control_port_count; i++) { lff_init (holder->ui_control_fifos + i, CONTROL_FIFO_SIZE, sizeof (LADSPA_Data)); holder->control_memory[i] = plugin_desc_get_default_control_value (desc, desc->control_port_indicies[i], sample_rate); plugin->descriptor-> connect_port (instance, desc->control_port_indicies[i], holder->control_memory + i); } for (i = 0; i < desc->port_count; i++) { if (!LADSPA_IS_PORT_CONTROL (desc->port_descriptors[i])) continue; if (LADSPA_IS_PORT_OUTPUT (desc->port_descriptors[i])) plugin->descriptor-> connect_port (instance, i, &unused_control_port_output); } if (jack_rack->procinfo->jack_client && plugin->desc->aux_channels > 0) plugin_create_aux_ports (plugin, copy, jack_rack); if (plugin->descriptor->activate) plugin->descriptor->activate (instance); } plugin_t * plugin_new (plugin_desc_t * desc, jack_rack_t * jack_rack) { void * dl_handle; const LADSPA_Descriptor * descriptor; LADSPA_Handle * instances; gint copies; unsigned long i; int err; plugin_t * plugin; /* open the plugin */ err = plugin_open_plugin (desc, &dl_handle, &descriptor); if (err) return NULL; /* create the instances */ copies = plugin_desc_get_copies (desc, jack_rack->channels); instances = g_malloc (sizeof (LADSPA_Handle) * copies); err = plugin_instantiate (descriptor, desc->index, copies, instances); if (err) { g_free (instances); dlclose (dl_handle); return NULL; } plugin = g_malloc (sizeof (plugin_t)); plugin->descriptor = descriptor; plugin->dl_handle = dl_handle; plugin->desc = desc; plugin->copies = copies; plugin->enabled = FALSE; plugin->next = NULL; plugin->prev = NULL; plugin->wet_dry_enabled = FALSE; plugin->jack_rack = jack_rack; /* create audio memory and wet/dry stuff */ plugin->audio_output_memory = g_malloc (sizeof (LADSPA_Data *) * jack_rack->channels); plugin->wet_dry_fifos = g_malloc (sizeof (lff_t) * jack_rack->channels); plugin->wet_dry_values = g_malloc (sizeof (LADSPA_Data) * jack_rack->channels); for (i = 0; i < jack_rack->channels; i++) { plugin->audio_output_memory[i] = g_malloc (sizeof (LADSPA_Data) * buffer_size); lff_init (plugin->wet_dry_fifos + i, CONTROL_FIFO_SIZE, sizeof (LADSPA_Data)); plugin->wet_dry_values[i] = 1.0; } /* create holders and fill them out */ plugin->holders = g_malloc (sizeof (ladspa_holder_t) * copies); for (i = 0; i < copies; i++) plugin_init_holder (plugin, i, instances[i], jack_rack); return plugin; } void plugin_destroy (plugin_t * plugin) { unsigned long i, j; int err; /* destroy holders */ for (i = 0; i < plugin->copies; i++) { if (plugin->descriptor->deactivate) plugin->descriptor->deactivate (plugin->holders[i].instance); /* if (plugin->descriptor->cleanup) plugin->descriptor->cleanup (plugin->holders[i].instance); */ if (plugin->desc->control_port_count > 0) { for (j = 0; j < plugin->desc->control_port_count; j++) { lff_free (plugin->holders[i].ui_control_fifos + j); } g_free (plugin->holders[i].ui_control_fifos); g_free (plugin->holders[i].control_memory); } /* aux ports */ if (plugin->jack_rack->procinfo->jack_client && plugin->desc->aux_channels > 0) { for (j = 0; j < plugin->desc->aux_channels; j++) { err = jack_port_unregister (plugin->jack_rack->procinfo->jack_client, plugin->holders[i].aux_ports[j]); if (err) mlt_log_warning( NULL, "%s: could not unregister jack port\n", __FUNCTION__); } g_free (plugin->holders[i].aux_ports); } } g_free (plugin->holders); for (i = 0; i < plugin->jack_rack->channels; i++) { g_free (plugin->audio_output_memory[i]); lff_free (plugin->wet_dry_fifos + i); } g_free (plugin->audio_output_memory); g_free (plugin->wet_dry_fifos); g_free (plugin->wet_dry_values); err = dlclose (plugin->dl_handle); if (err) { mlt_log_warning( NULL, "%s: error closing shared object '%s': %s\n", __FUNCTION__, plugin->desc->object_file, dlerror ()); } g_free (plugin); } /* EOF */ mlt-0.9.0/src/modules/jackrack/plugin.h000066400000000000000000000054641215300731300177770ustar00rootroot00000000000000/* * JACK Rack * * Original: * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: * Copyright (C) 2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __JR_PLUGIN_H__ #define __JR_PLUGIN_H__ #include #include #include #include #include "process.h" #include "plugin_desc.h" typedef struct _ladspa_holder ladspa_holder_t; typedef struct _plugin plugin_t; struct _ladspa_holder { LADSPA_Handle instance; lff_t * ui_control_fifos; LADSPA_Data * control_memory; jack_port_t ** aux_ports; }; struct _plugin { plugin_desc_t * desc; gint enabled; gint copies; ladspa_holder_t * holders; LADSPA_Data ** audio_input_memory; LADSPA_Data ** audio_output_memory; gboolean wet_dry_enabled; /* 1.0 = all wet, 0.0 = all dry, 0.5 = 50% wet/50% dry */ LADSPA_Data * wet_dry_values; lff_t * wet_dry_fifos; plugin_t * next; plugin_t * prev; const LADSPA_Descriptor * descriptor; void * dl_handle; struct _jack_rack * jack_rack; }; void process_add_plugin (process_info_t *, plugin_t *plugin); plugin_t * process_remove_plugin (process_info_t *, plugin_t *plugin); void process_ablise_plugin (process_info_t *, plugin_t *plugin, gboolean able); void process_ablise_plugin_wet_dry (process_info_t *, plugin_t *plugin, gboolean enable); void process_move_plugin (process_info_t *, plugin_t *plugin, gint up); plugin_t * process_change_plugin (process_info_t *, plugin_t *plugin, plugin_t * new_plugin); struct _jack_rack; struct _ui; plugin_t * plugin_new (plugin_desc_t * plugin_desc, struct _jack_rack * jack_rack); void plugin_destroy (plugin_t * plugin); void plugin_connect_input_ports (plugin_t * plugin, LADSPA_Data ** inputs); void plugin_connect_output_ports (plugin_t * plugin); #endif /* __JR_PLUGIN_H__ */ mlt-0.9.0/src/modules/jackrack/plugin_desc.c000066400000000000000000000273721215300731300207720ustar00rootroot00000000000000/* * JACK Rack * * Original: * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: * Copyright (C) 2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include "plugin_desc.h" #include "plugin.h" #define set_string_property(property, value) \ \ if (property) \ g_free (property); \ \ if (value) \ (property) = g_strdup (value); \ else \ (property) = NULL; void plugin_desc_set_ports (plugin_desc_t * pd, unsigned long port_count, const LADSPA_PortDescriptor * port_descriptors, const LADSPA_PortRangeHint * port_range_hints, const char * const * port_names); static void plugin_desc_init (plugin_desc_t * pd) { pd->object_file = NULL; pd->id = 0; pd->name = NULL; pd->maker = NULL; pd->properties = 0; pd->channels = 0; pd->port_count = 0; pd->port_descriptors = NULL; pd->port_range_hints = NULL; pd->audio_input_port_indicies = NULL; pd->audio_output_port_indicies = NULL; pd->audio_aux_port_indicies = NULL; pd->control_port_count = 0; pd->control_port_indicies = NULL; pd->aux_channels = 0; pd->aux_are_input = TRUE; pd->has_input = TRUE; } static void plugin_desc_free_ports (plugin_desc_t * pd) { if (pd->port_count) { g_free (pd->port_descriptors); g_free (pd->port_range_hints); pd->port_descriptors = NULL; pd->port_range_hints = NULL; pd->port_count = 0; } } static void plugin_desc_free (plugin_desc_t * pd) { plugin_desc_set_object_file (pd, NULL); plugin_desc_set_name (pd, NULL); plugin_desc_set_maker (pd, NULL); plugin_desc_free_ports (pd); } plugin_desc_t * plugin_desc_new () { plugin_desc_t * pd; pd = g_malloc (sizeof (plugin_desc_t)); plugin_desc_init (pd); return pd; } plugin_desc_t * plugin_desc_new_with_descriptor (const char * object_file, unsigned long index, const LADSPA_Descriptor * descriptor) { plugin_desc_t * pd; pd = plugin_desc_new (); plugin_desc_set_object_file (pd, object_file); plugin_desc_set_index (pd, index); plugin_desc_set_id (pd, descriptor->UniqueID); plugin_desc_set_name (pd, descriptor->Name); plugin_desc_set_maker (pd, descriptor->Maker); plugin_desc_set_properties (pd, descriptor->Properties); plugin_desc_set_ports (pd, descriptor->PortCount, descriptor->PortDescriptors, descriptor->PortRangeHints, descriptor->PortNames); pd->rt = LADSPA_IS_HARD_RT_CAPABLE(pd->properties) ? TRUE : FALSE; return pd; } void plugin_desc_destroy (plugin_desc_t * pd) { plugin_desc_free (pd); g_free (pd); } void plugin_desc_set_object_file (plugin_desc_t * pd, const char * object_file) { set_string_property (pd->object_file, object_file); } void plugin_desc_set_index (plugin_desc_t * pd, unsigned long index) { pd->index = index; } void plugin_desc_set_id (plugin_desc_t * pd, unsigned long id) { pd->id = id; } void plugin_desc_set_name (plugin_desc_t * pd, const char * name) { set_string_property (pd->name, name); } void plugin_desc_set_maker (plugin_desc_t * pd, const char * maker) { set_string_property (pd->maker, maker); } void plugin_desc_set_properties (plugin_desc_t * pd, LADSPA_Properties properties) { pd->properties = properties; } static void plugin_desc_add_audio_port_index (unsigned long ** indicies, unsigned long * current_port_count, unsigned long index) { (*current_port_count)++; if (*current_port_count == 0) *indicies = g_malloc (sizeof (unsigned long) * *current_port_count); else *indicies = g_realloc (*indicies, sizeof (unsigned long) * *current_port_count); (*indicies)[*current_port_count - 1] = index; } static void plugin_desc_set_port_counts (plugin_desc_t * pd) { unsigned long i; unsigned long icount = 0; unsigned long ocount = 0; for (i = 0; i < pd->port_count; i++) { if (LADSPA_IS_PORT_AUDIO (pd->port_descriptors[i])) { if (LADSPA_IS_PORT_INPUT (pd->port_descriptors[i])) plugin_desc_add_audio_port_index (&pd->audio_input_port_indicies, &icount, i); else plugin_desc_add_audio_port_index (&pd->audio_output_port_indicies, &ocount, i); } else { if (LADSPA_IS_PORT_OUTPUT (pd->port_descriptors[i])) continue; pd->control_port_count++; if (pd->control_port_count == 0) pd->control_port_indicies = g_malloc (sizeof (unsigned long) * pd->control_port_count); else pd->control_port_indicies = g_realloc (pd->control_port_indicies, sizeof (unsigned long) * pd->control_port_count); pd->control_port_indicies[pd->control_port_count - 1] = i; } } if (icount == ocount) pd->channels = icount; else if( icount == 0 ) { pd->channels = ocount; pd->has_input = FALSE; } else { /* deal with auxilliary ports */ unsigned long ** port_indicies; unsigned long port_count; unsigned long i, j; if (icount > ocount) { pd->channels = ocount; pd->aux_channels = icount - ocount; pd->aux_are_input = TRUE; port_indicies = &pd->audio_input_port_indicies; port_count = icount; } else { pd->channels = icount; pd->aux_channels = ocount - icount; pd->aux_are_input = FALSE; port_indicies = &pd->audio_output_port_indicies; port_count = ocount; } /* allocate indicies */ pd->audio_aux_port_indicies = g_malloc (sizeof (unsigned long) * pd->aux_channels); /* copy indicies */ for (i = pd->channels, j = 0; i < port_count; i++, j++) pd->audio_aux_port_indicies[j] = (*port_indicies)[i]; /* shrink the main indicies to only have channels indicies */ *port_indicies = g_realloc (*port_indicies, sizeof (unsigned long) * pd->channels); } } void plugin_desc_set_ports (plugin_desc_t * pd, unsigned long port_count, const LADSPA_PortDescriptor * port_descriptors, const LADSPA_PortRangeHint * port_range_hints, const char * const * port_names) { unsigned long i; plugin_desc_free_ports (pd); if (!port_count) return; pd->port_count = port_count; pd->port_descriptors = g_malloc (sizeof (LADSPA_PortDescriptor) * port_count); pd->port_range_hints = g_malloc (sizeof (LADSPA_PortRangeHint) * port_count); pd->port_names = g_malloc (sizeof (char *) * port_count); memcpy (pd->port_descriptors, port_descriptors, sizeof (LADSPA_PortDescriptor) * port_count); memcpy (pd->port_range_hints, port_range_hints, sizeof (LADSPA_PortRangeHint) * port_count); for (i = 0; i < port_count; i++) pd->port_names[i] = g_strdup (port_names[i]); plugin_desc_set_port_counts (pd); } LADSPA_Data plugin_desc_get_default_control_value (plugin_desc_t * pd, unsigned long port_index, guint32 sample_rate) { LADSPA_Data upper, lower; LADSPA_PortRangeHintDescriptor hint_descriptor; hint_descriptor = pd->port_range_hints[port_index].HintDescriptor; /* set upper and lower, possibly adjusted to the sample rate */ if (LADSPA_IS_HINT_SAMPLE_RATE(hint_descriptor)) { upper = pd->port_range_hints[port_index].UpperBound * (LADSPA_Data) sample_rate; lower = pd->port_range_hints[port_index].LowerBound * (LADSPA_Data) sample_rate; } else { upper = pd->port_range_hints[port_index].UpperBound; lower = pd->port_range_hints[port_index].LowerBound; } if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { if (lower < FLT_EPSILON) lower = FLT_EPSILON; } if (LADSPA_IS_HINT_HAS_DEFAULT(hint_descriptor)) { if (LADSPA_IS_HINT_DEFAULT_MINIMUM(hint_descriptor)) { return lower; } else if (LADSPA_IS_HINT_DEFAULT_LOW(hint_descriptor)) { if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { return exp(log(lower) * 0.75 + log(upper) * 0.25); } else { return lower * 0.75 + upper * 0.25; } } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hint_descriptor)) { if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { return exp(log(lower) * 0.5 + log(upper) * 0.5); } else { return lower * 0.5 + upper * 0.5; } } else if (LADSPA_IS_HINT_DEFAULT_HIGH(hint_descriptor)) { if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { return exp(log(lower) * 0.25 + log(upper) * 0.75); } else { return lower * 0.25 + upper * 0.75; } } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hint_descriptor)) { return upper; } else if (LADSPA_IS_HINT_DEFAULT_0(hint_descriptor)) { return 0.0; } else if (LADSPA_IS_HINT_DEFAULT_1(hint_descriptor)) { if (LADSPA_IS_HINT_SAMPLE_RATE(hint_descriptor)) { return (LADSPA_Data) sample_rate; } else { return 1.0; } } else if (LADSPA_IS_HINT_DEFAULT_100(hint_descriptor)) { if (LADSPA_IS_HINT_SAMPLE_RATE(hint_descriptor)) { return 100.0 * (LADSPA_Data) sample_rate; } else { return 100.0; } } else if (LADSPA_IS_HINT_DEFAULT_440(hint_descriptor)) { if (LADSPA_IS_HINT_SAMPLE_RATE(hint_descriptor)) { return 440.0 * (LADSPA_Data) sample_rate; } else { return 440.0; } } } else { /* try and find a reasonable default */ if (LADSPA_IS_HINT_BOUNDED_BELOW(hint_descriptor)) { return lower; } else if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint_descriptor)) { return upper; } } return 0.0; } LADSPA_Data plugin_desc_change_control_value (plugin_desc_t * pd, unsigned long control_index, LADSPA_Data value, guint32 old_sample_rate, guint32 new_sample_rate) { if (LADSPA_IS_HINT_SAMPLE_RATE (pd->port_range_hints[control_index].HintDescriptor)) { LADSPA_Data old_sr, new_sr; old_sr = (LADSPA_Data) old_sample_rate; new_sr = (LADSPA_Data) new_sample_rate; value /= old_sr; value *= new_sr; } return value; } gint plugin_desc_get_copies (plugin_desc_t * pd, unsigned long rack_channels) { gint copies = 1; if (pd->channels > rack_channels) return 0; while (pd->channels * copies < rack_channels) copies++; if (pd->channels * copies > rack_channels) return 0; return copies; } /* EOF */ mlt-0.9.0/src/modules/jackrack/plugin_desc.h000066400000000000000000000060771215300731300207760ustar00rootroot00000000000000/* * JACK Rack * * Original: * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: * Copyright (C) 2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __JR_PLUGIN_DESC_H__ #define __JR_PLUGIN_DESC_H__ #include #include typedef struct _plugin_desc plugin_desc_t; struct _plugin_desc { char * object_file; unsigned long index; unsigned long id; char * name; char * maker; LADSPA_Properties properties; gboolean rt; unsigned long channels; gboolean aux_are_input; unsigned long aux_channels; unsigned long port_count; LADSPA_PortDescriptor * port_descriptors; LADSPA_PortRangeHint * port_range_hints; char ** port_names; unsigned long * audio_input_port_indicies; unsigned long * audio_output_port_indicies; unsigned long * audio_aux_port_indicies; unsigned long control_port_count; unsigned long * control_port_indicies; gboolean has_input; }; plugin_desc_t * plugin_desc_new (); plugin_desc_t * plugin_desc_new_with_descriptor (const char * object_file, unsigned long index, const LADSPA_Descriptor * descriptor); void plugin_desc_destroy (plugin_desc_t * pd); void plugin_desc_set_object_file (plugin_desc_t * pd, const char * object_file); void plugin_desc_set_index (plugin_desc_t * pd, unsigned long index); void plugin_desc_set_id (plugin_desc_t * pd, unsigned long id); void plugin_desc_set_name (plugin_desc_t * pd, const char * name); void plugin_desc_set_maker (plugin_desc_t * pd, const char * maker); void plugin_desc_set_properties (plugin_desc_t * pd, LADSPA_Properties properties); struct _plugin * plugin_desc_instantiate (plugin_desc_t * pd); LADSPA_Data plugin_desc_get_default_control_value (plugin_desc_t * pd, unsigned long port_index, guint32 sample_rate); LADSPA_Data plugin_desc_change_control_value (plugin_desc_t *, unsigned long, LADSPA_Data, guint32, guint32); gint plugin_desc_get_copies (plugin_desc_t * pd, unsigned long rack_channels); #endif /* __JR_PLUGIN_DESC_H__ */ mlt-0.9.0/src/modules/jackrack/plugin_mgr.c000066400000000000000000000214771215300731300206410ustar00rootroot00000000000000/* * JACK Rack * * Original: * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: * Copyright (C) 2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "plugin_mgr.h" #include "plugin_desc.h" #include "framework/mlt_log.h" #include "framework/mlt_factory.h" static gboolean plugin_is_valid (const LADSPA_Descriptor * descriptor) { unsigned long i; unsigned long icount = 0; unsigned long ocount = 0; for (i = 0; i < descriptor->PortCount; i++) { if (!LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[i])) continue; if (LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[i])) icount++; else ocount++; } if (ocount == 0) return FALSE; return TRUE; } static void plugin_mgr_get_object_file_plugins (plugin_mgr_t * plugin_mgr, const char * filename) { const char * dlerr; void * dl_handle; LADSPA_Descriptor_Function get_descriptor; const LADSPA_Descriptor * descriptor; unsigned long plugin_index; plugin_desc_t * desc, * other_desc = NULL; GSList * list; gboolean exists; int err; /* open the object file */ dl_handle = dlopen (filename, RTLD_NOW); if (!dl_handle) { mlt_log_info( NULL, "%s: error opening shared object file '%s': %s\n", __FUNCTION__, filename, dlerror()); return; } /* get the get_descriptor function */ dlerror (); /* clear the error report */ get_descriptor = (LADSPA_Descriptor_Function) dlsym (dl_handle, "ladspa_descriptor"); dlerr = dlerror(); if (dlerr) { mlt_log_info( NULL, "%s: error finding ladspa_descriptor symbol in object file '%s': %s\n", __FUNCTION__, filename, dlerr); dlclose (dl_handle); return; } #ifdef __DARWIN__ if (!get_descriptor (0)) { void (*constructor)(void) = dlsym (dl_handle, "_init"); if (constructor) constructor(); } #endif plugin_index = 0; while ( (descriptor = get_descriptor (plugin_index)) ) { if (!plugin_is_valid (descriptor)) { plugin_index++; continue; } /* check it doesn't already exist */ exists = FALSE; for (list = plugin_mgr->all_plugins; list; list = g_slist_next (list)) { other_desc = (plugin_desc_t *) list->data; if (other_desc->id == descriptor->UniqueID) { exists = TRUE; break; } } if (exists) { mlt_log_info( NULL, "Plugin %ld exists in both '%s' and '%s'; using version in '%s'\n", descriptor->UniqueID, other_desc->object_file, filename, other_desc->object_file); plugin_index++; continue; } desc = plugin_desc_new_with_descriptor (filename, plugin_index, descriptor); plugin_mgr->all_plugins = g_slist_append (plugin_mgr->all_plugins, desc); plugin_index++; plugin_mgr->plugin_count++; /* print in the splash screen */ /* mlt_log_verbose( NULL, "Loaded plugin '%s'\n", desc->name); */ } err = dlclose (dl_handle); if (err) { mlt_log_warning( NULL, "%s: error closing object file '%s': %s\n", __FUNCTION__, filename, dlerror ()); } } static void plugin_mgr_get_dir_plugins (plugin_mgr_t * plugin_mgr, const char * dir) { DIR * dir_stream; struct dirent * dir_entry; char * file_name; int err; size_t dirlen; dir_stream = opendir (dir); if (!dir_stream) { /* mlt_log_warning( NULL, "%s: error opening directory '%s': %s\n", __FUNCTION__, dir, strerror (errno)); */ return; } dirlen = strlen (dir); while ( (dir_entry = readdir (dir_stream)) ) { struct stat info; if (strcmp (dir_entry->d_name, ".") == 0 || mlt_properties_get (plugin_mgr->blacklist, dir_entry->d_name) || strcmp (dir_entry->d_name, "..") == 0) continue; file_name = g_malloc (dirlen + 1 + strlen (dir_entry->d_name) + 1); strcpy (file_name, dir); if (file_name[dirlen - 1] == '/') strcpy (file_name + dirlen, dir_entry->d_name); else { file_name[dirlen] = '/'; strcpy (file_name + dirlen + 1, dir_entry->d_name); } stat (file_name, &info); if (S_ISDIR (info.st_mode)) plugin_mgr_get_dir_plugins (plugin_mgr, file_name); else plugin_mgr_get_object_file_plugins (plugin_mgr, file_name); g_free (file_name); } err = closedir (dir_stream); if (err) mlt_log_warning( NULL, "%s: error closing directory '%s': %s\n", __FUNCTION__, dir, strerror (errno)); } static void plugin_mgr_get_path_plugins (plugin_mgr_t * plugin_mgr) { char * ladspa_path, * dir; ladspa_path = g_strdup (getenv ("LADSPA_PATH")); #ifdef WIN32 if (!ladspa_path) { ladspa_path = malloc (strlen (mlt_environment("MLT_APPDIR")) + strlen ("\\lib\\ladspa") + 1); strcpy (ladspa_path, mlt_environment("MLT_APPDIR")); strcat (ladspa_path, "\\lib\\ladspa"); } #elif defined(__DARWIN__) && defined(RELOCATABLE) { ladspa_path = malloc( strlen (mlt_environment ("MLT_APPDIR")) + strlen ("/lib/ladspa") + 1 ); strcpy (ladspa_path, mlt_environment ("MLT_APPDIR")); strcat (ladspa_path, "/lib/ladspa" ); } #else if (!ladspa_path) ladspa_path = g_strdup ("/usr/local/lib/ladspa:/usr/lib/ladspa:/usr/lib64/ladspa"); #endif dir = strtok (ladspa_path, ":"); do plugin_mgr_get_dir_plugins (plugin_mgr, dir); while ((dir = strtok (NULL, ":"))); g_free (ladspa_path); } static gint plugin_mgr_sort (gconstpointer a, gconstpointer b) { const plugin_desc_t * da; const plugin_desc_t * db; da = (const plugin_desc_t *) a; db = (const plugin_desc_t *) b; return strcasecmp (da->name, db->name); } plugin_mgr_t * plugin_mgr_new () { plugin_mgr_t * pm; char dirname[PATH_MAX]; pm = g_malloc (sizeof (plugin_mgr_t)); pm->all_plugins = NULL; pm->plugins = NULL; pm->plugin_count = 0; snprintf (dirname, PATH_MAX, "%s/jackrack/blacklist.txt", mlt_environment ("MLT_DATA")); pm->blacklist = mlt_properties_load (dirname); plugin_mgr_get_path_plugins (pm); if (!pm->all_plugins) mlt_log_warning( NULL, "No LADSPA plugins were found!\n\nCheck your LADSPA_PATH environment variable.\n"); else pm->all_plugins = g_slist_sort (pm->all_plugins, plugin_mgr_sort); return pm; } void plugin_mgr_destroy (plugin_mgr_t * plugin_mgr) { GSList * list; for (list = plugin_mgr->all_plugins; list; list = g_slist_next (list)) plugin_desc_destroy ((plugin_desc_t *) list->data); g_slist_free (plugin_mgr->plugins); g_slist_free (plugin_mgr->all_plugins); free (plugin_mgr); } void plugin_mgr_set_plugins (plugin_mgr_t * plugin_mgr, unsigned long rack_channels) { GSList * list; plugin_desc_t * desc; /* clear the current plugins */ g_slist_free (plugin_mgr->plugins); plugin_mgr->plugins = NULL; for (list = plugin_mgr->all_plugins; list; list = g_slist_next (list)) { desc = (plugin_desc_t *) list->data; if (plugin_desc_get_copies (desc, rack_channels) != 0) plugin_mgr->plugins = g_slist_append (plugin_mgr->plugins, desc); } } static plugin_desc_t * plugin_mgr_find_desc (plugin_mgr_t * plugin_mgr, GSList * plugins, unsigned long id) { GSList * list; plugin_desc_t * desc; for (list = plugins; list; list = g_slist_next (list)) { desc = (plugin_desc_t *) list->data; if (desc->id == id) return desc; } return NULL; } plugin_desc_t * plugin_mgr_get_desc (plugin_mgr_t * plugin_mgr, unsigned long id) { return plugin_mgr_find_desc (plugin_mgr, plugin_mgr->plugins, id); } plugin_desc_t * plugin_mgr_get_any_desc (plugin_mgr_t * plugin_mgr, unsigned long id) { return plugin_mgr_find_desc (plugin_mgr, plugin_mgr->all_plugins, id); } /* EOF */ mlt-0.9.0/src/modules/jackrack/plugin_mgr.h000066400000000000000000000031611215300731300206340ustar00rootroot00000000000000/* * JACK Rack * * Original: * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: * Copyright (C) 2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __JR_PLUGIN_MANAGER_H__ #define __JR_PLUGIN_MANAGER_H__ #include #include "plugin_desc.h" #include "framework/mlt_properties.h" typedef struct _plugin_mgr plugin_mgr_t; struct _plugin_mgr { GSList * all_plugins; GSList * plugins; unsigned long plugin_count; mlt_properties blacklist; }; struct _ui; plugin_mgr_t * plugin_mgr_new (); void plugin_mgr_destroy (plugin_mgr_t * plugin_mgr); void plugin_mgr_set_plugins (plugin_mgr_t * plugin_mgr, unsigned long rack_channels); plugin_desc_t * plugin_mgr_get_desc (plugin_mgr_t * plugin_mgr, unsigned long id); plugin_desc_t * plugin_mgr_get_any_desc (plugin_mgr_t * plugin_mgr, unsigned long id); #endif /* __JR_PLUGIN_MANAGER_H__ */ mlt-0.9.0/src/modules/jackrack/plugin_settings.c000066400000000000000000000245231215300731300217070ustar00rootroot00000000000000/* * JACK Rack * * Original: * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: * Copyright (C) 2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include "plugin_settings.h" static void settings_set_to_default (settings_t * settings, guint32 sample_rate) { unsigned long control; guint copy; LADSPA_Data value; for (control = 0; control < settings->desc->control_port_count; control++) { value = plugin_desc_get_default_control_value (settings->desc, control, sample_rate); for (copy = 0; copy < settings->copies; copy++) { settings->control_values[copy][control] = value; } settings->locks[control] = TRUE; } } settings_t * settings_new (plugin_desc_t * desc, unsigned long channels, guint32 sample_rate) { settings_t * settings; unsigned long channel; guint copies; settings = g_malloc (sizeof (settings_t)); copies = plugin_desc_get_copies (desc, channels); settings->sample_rate = sample_rate; settings->desc = desc; settings->copies = copies; settings->channels = channels; settings->lock_all = TRUE; settings->enabled = FALSE; settings->locks = NULL; settings->control_values = NULL; settings->wet_dry_enabled = FALSE; settings->wet_dry_locked = TRUE; /* control settings */ if (desc->control_port_count > 0) { guint copy; settings->locks = g_malloc (sizeof (gboolean) * desc->control_port_count); settings->control_values = g_malloc (sizeof (LADSPA_Data *) * copies); for (copy = 0; copy < copies; copy++) { settings->control_values[copy] = g_malloc (sizeof (LADSPA_Data) * desc->control_port_count); } settings_set_to_default (settings, sample_rate); } /* wet/dry settings */ settings->wet_dry_values = g_malloc (sizeof (LADSPA_Data) * channels); for (channel = 0; channel < channels; channel++) settings->wet_dry_values[channel] = 1.0; return settings; } settings_t * settings_dup (settings_t * other) { settings_t * settings; plugin_desc_t * desc; unsigned long channel; settings = g_malloc (sizeof (settings_t)); settings->sample_rate = other->sample_rate; settings->desc = other->desc; settings->copies = settings_get_copies (other); settings->channels = settings_get_channels (other); settings->wet_dry_enabled = settings_get_wet_dry_enabled (other); settings->wet_dry_locked = settings_get_wet_dry_locked (other); settings->lock_all = settings_get_lock_all (other); settings->enabled = settings_get_enabled (other); settings->locks = NULL; settings->control_values = NULL; desc = other->desc; if (desc->control_port_count > 0) { guint copy; unsigned long control; settings->locks = g_malloc (sizeof (gboolean) * desc->control_port_count); for (control = 0; control < desc->control_port_count; control++) settings_set_lock (settings, control, settings_get_lock (other, control)); settings->control_values = g_malloc (sizeof (LADSPA_Data *) * settings->copies); for (copy = 0; copy < settings->copies; copy++) { settings->control_values[copy] = g_malloc (sizeof (LADSPA_Data) * desc->control_port_count); for (control = 0; control < desc->control_port_count; control++) { settings->control_values[copy][control] = settings_get_control_value (other, copy, control); } } } settings->wet_dry_values = g_malloc (sizeof (LADSPA_Data) * settings->channels); for (channel = 0; channel < settings->channels; channel++) settings->wet_dry_values[channel] = settings_get_wet_dry_value (other, channel); return settings; } void settings_destroy (settings_t * settings) { if (settings->desc->control_port_count > 0) { guint i; for (i = 0; i < settings->copies; i++) g_free (settings->control_values[i]); g_free (settings->control_values); g_free (settings->locks); } g_free (settings->wet_dry_values); g_free (settings); } static void settings_set_copies (settings_t * settings, guint copies) { guint copy; guint last_copy; unsigned long control; if (copies <= settings->copies) return; last_copy = settings->copies - 1; settings->control_values = g_realloc (settings->control_values, sizeof (LADSPA_Data *) * copies); /* copy over the last settings to the new copies */ for (copy = settings->copies; copy < copies; copy++) { for (control = 0; control < settings->desc->control_port_count; control++) { settings->control_values[copy][control] = settings->control_values[last_copy][control]; } } settings->copies = copies; } static void settings_set_channels (settings_t * settings, unsigned long channels) { unsigned long channel; LADSPA_Data last_value; if (channels <= settings->channels) return; settings->wet_dry_values = g_realloc (settings->wet_dry_values, sizeof (LADSPA_Data) * channels); last_value = settings->wet_dry_values[settings->channels - 1]; for (channel = settings->channels; channel < channels; channel++) settings->wet_dry_values[channel] = last_value; settings->channels = channels; } void settings_set_sample_rate (settings_t * settings, guint32 sample_rate) { LADSPA_Data old_sample_rate; LADSPA_Data new_sample_rate; g_return_if_fail (settings != NULL); if (settings->sample_rate == sample_rate) return; if (settings->desc->control_port_count > 0) { unsigned long control; guint copy; new_sample_rate = (LADSPA_Data) sample_rate; old_sample_rate = (LADSPA_Data) settings->sample_rate; for (control = 0; control < settings->desc->control_port_count; control++) { for (copy = 0; copy < settings->copies; copy++) { if (LADSPA_IS_HINT_SAMPLE_RATE (settings->desc->port_range_hints[control].HintDescriptor)) { settings->control_values[copy][control] = (settings->control_values[copy][control] / old_sample_rate) * new_sample_rate; } } } } settings->sample_rate = sample_rate; } void settings_set_control_value (settings_t * settings, guint copy, unsigned long control_index, LADSPA_Data value) { g_return_if_fail (settings != NULL); g_return_if_fail (control_index < settings->desc->control_port_count); if (copy >= settings->copies) settings_set_copies (settings, copy + 1); settings->control_values[copy][control_index] = value; } void settings_set_lock (settings_t * settings, unsigned long control_index, gboolean locked) { g_return_if_fail (settings != NULL); g_return_if_fail (control_index < settings->desc->control_port_count); settings->locks[control_index] = locked; } void settings_set_lock_all (settings_t * settings, gboolean lock_all) { g_return_if_fail (settings != NULL); settings->lock_all = lock_all; } void settings_set_enabled (settings_t * settings, gboolean enabled) { g_return_if_fail (settings != NULL); settings->enabled = enabled; } void settings_set_wet_dry_enabled (settings_t * settings, gboolean enabled) { g_return_if_fail (settings != NULL); settings->wet_dry_enabled = enabled; } void settings_set_wet_dry_locked (settings_t * settings, gboolean locked) { g_return_if_fail (settings != NULL); settings->wet_dry_locked = locked; } void settings_set_wet_dry_value (settings_t * settings, unsigned long channel, LADSPA_Data value) { g_return_if_fail (settings != NULL); if (channel >= settings->channels) settings_set_channels (settings, channel + 1); settings->wet_dry_values[channel] = value; } LADSPA_Data settings_get_control_value (settings_t * settings, guint copy, unsigned long control_index) { g_return_val_if_fail (settings != NULL, NAN); g_return_val_if_fail (control_index < settings->desc->control_port_count, NAN); if (copy >= settings->copies) settings_set_copies (settings, copy - 1); return settings->control_values[copy][control_index]; } gboolean settings_get_lock (const settings_t * settings, unsigned long control_index) { g_return_val_if_fail (settings != NULL, FALSE); return settings->locks[control_index]; } gboolean settings_get_lock_all (const settings_t * settings) { g_return_val_if_fail (settings != NULL, FALSE); return settings->lock_all; } gboolean settings_get_enabled (const settings_t * settings) { g_return_val_if_fail (settings != NULL, FALSE); return settings->enabled; } guint settings_get_copies (const settings_t * settings) { g_return_val_if_fail (settings != NULL, 0); return settings->copies; } unsigned long settings_get_channels (const settings_t * settings) { g_return_val_if_fail (settings != NULL, 0); return settings->channels; } gboolean settings_get_wet_dry_enabled (const settings_t * settings) { g_return_val_if_fail (settings != NULL, FALSE); return settings->wet_dry_enabled; } gboolean settings_get_wet_dry_locked (const settings_t * settings) { g_return_val_if_fail (settings != NULL, FALSE); return settings->wet_dry_locked; } LADSPA_Data settings_get_wet_dry_value (settings_t * settings, unsigned long channel) { g_return_val_if_fail (settings != NULL, NAN); if (channel >= settings->channels) settings_set_channels (settings, channel + 1); return settings->wet_dry_values[channel]; } /* EOF */ mlt-0.9.0/src/modules/jackrack/plugin_settings.h000066400000000000000000000061531215300731300217130ustar00rootroot00000000000000/* * JACK Rack * * Original: * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: * Copyright (C) 2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __JR_PLUGIN_SETTINGS_H__ #define __JR_PLUGIN_SETTINGS_H__ #include #include #include "plugin_mgr.h" #include "plugin_desc.h" typedef struct _settings settings_t; struct _settings { guint32 sample_rate; plugin_desc_t * desc; guint copies; LADSPA_Data ** control_values; gboolean * locks; gboolean lock_all; gboolean enabled; unsigned long channels; gboolean wet_dry_enabled; gboolean wet_dry_locked; LADSPA_Data * wet_dry_values; }; settings_t * settings_new (plugin_desc_t * desc, unsigned long channels, guint32 sample_rate); settings_t * settings_dup (settings_t * settings); void settings_destroy (settings_t * settings); void settings_set_control_value (settings_t * settings, guint copy, unsigned long control_index, LADSPA_Data value); void settings_set_lock (settings_t * settings, unsigned long control_index, gboolean locked); void settings_set_lock_all (settings_t * settings, gboolean lock_all); void settings_set_enabled (settings_t * settings, gboolean enabled); void settings_set_wet_dry_enabled (settings_t * settings, gboolean enabled); void settings_set_wet_dry_locked (settings_t * settings, gboolean locked); void settings_set_wet_dry_value (settings_t * settings, unsigned long channel, LADSPA_Data value); LADSPA_Data settings_get_control_value (settings_t * settings, guint copy, unsigned long control_index); gboolean settings_get_lock (const settings_t * settings, unsigned long control_index); gboolean settings_get_lock_all (const settings_t * settings); gboolean settings_get_enabled (const settings_t * settings); guint settings_get_copies (const settings_t * settings); unsigned long settings_get_channels (const settings_t * settings); gboolean settings_get_wet_dry_enabled (const settings_t * settings); gboolean settings_get_wet_dry_locked (const settings_t * settings); LADSPA_Data settings_get_wet_dry_value (settings_t * settings, unsigned long channel); void settings_set_sample_rate (settings_t * settings, guint32 sample_rate); #endif /* __JR_PLUGIN_SETTINGS_H__ */ mlt-0.9.0/src/modules/jackrack/process.c000066400000000000000000000446701215300731300201540ustar00rootroot00000000000000/* * JACK Rack * * Original: * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: * Copyright (C) 2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include "process.h" #include "lock_free_fifo.h" #include "plugin.h" #include "jack_rack.h" #include "framework/mlt_log.h" #ifndef _ #define _(x) x #endif extern pthread_mutex_t g_activate_mutex; #define USEC_PER_SEC 1000000 #define MSEC_PER_SEC 1000 #define TIME_RUN_SKIP_COUNT 5 #define MAX_BUFFER_SIZE 4096 jack_nframes_t sample_rate; jack_nframes_t buffer_size; static void jack_shutdown_cb (void * data) { process_info_t * procinfo = data; procinfo->quit = TRUE; } /** process messages for plugins' control ports */ void process_control_port_messages (process_info_t * procinfo) { plugin_t * plugin; unsigned long control; unsigned long channel; gint copy; if (!procinfo->chain) return; for (plugin = procinfo->chain; plugin; plugin = plugin->next) { if (plugin->desc->control_port_count > 0) for (control = 0; control < plugin->desc->control_port_count; control++) for (copy = 0; copy < plugin->copies; copy++) { while (lff_read (plugin->holders[copy].ui_control_fifos + control, plugin->holders[copy].control_memory + control) == 0); } if (plugin->wet_dry_enabled) for (channel = 0; channel < procinfo->channels; channel++) { while (lff_read (plugin->wet_dry_fifos + channel, plugin->wet_dry_values + channel) == 0); } } } int get_jack_buffers (process_info_t * procinfo, jack_nframes_t frames) { unsigned long channel; for (channel = 0; channel < procinfo->channels; channel++) { procinfo->jack_input_buffers[channel] = jack_port_get_buffer (procinfo->jack_input_ports[channel], frames); if (!procinfo->jack_input_buffers[channel]) { mlt_log_verbose( NULL, "%s: no jack buffer for input port %ld\n", __FUNCTION__, channel); return 1; } procinfo->jack_output_buffers[channel] = jack_port_get_buffer (procinfo->jack_output_ports[channel], frames); if (!procinfo->jack_output_buffers[channel]) { mlt_log_verbose( NULL, "%s: no jack buffer for output port %ld\n", __FUNCTION__, channel); return 1; } } return 0; } plugin_t * get_first_enabled_plugin (process_info_t * procinfo) { plugin_t * first_enabled; if (!procinfo->chain) return NULL; for (first_enabled = procinfo->chain; first_enabled; first_enabled = first_enabled->next) { if (first_enabled->enabled) return first_enabled; } return NULL; } plugin_t * get_last_enabled_plugin (process_info_t * procinfo) { plugin_t * last_enabled; if (!procinfo->chain) return NULL; for (last_enabled = procinfo->chain_end; last_enabled; last_enabled = last_enabled->prev) { if (last_enabled->enabled) return last_enabled; } return NULL; } void connect_chain (process_info_t * procinfo, jack_nframes_t frames) { plugin_t * first_enabled, * last_enabled, * plugin; gint copy; unsigned long channel; if (!procinfo->chain) return; first_enabled = get_first_enabled_plugin (procinfo); if (!first_enabled) return; last_enabled = get_last_enabled_plugin (procinfo); /* sort out the aux ports */ plugin = first_enabled; do { if (plugin->desc->aux_channels > 0 && plugin->enabled) { if (procinfo->jack_client) { for (copy = 0; copy < plugin->copies; copy++) for (channel = 0; channel < plugin->desc->aux_channels; channel++) plugin->descriptor-> connect_port (plugin->holders[copy].instance, plugin->desc->audio_aux_port_indicies[channel], jack_port_get_buffer (plugin->holders[copy].aux_ports[channel], frames)); } else { for (copy = 0; copy < frames; copy++) procinfo->silent_buffer[copy] = 0.0; for (copy = 0; copy < plugin->copies; copy++) for (channel = 0; channel < plugin->desc->aux_channels; channel++) plugin->descriptor-> connect_port (plugin->holders[copy].instance, plugin->desc->audio_aux_port_indicies[channel], procinfo->silent_buffer); } } } while ( (plugin != last_enabled) && (plugin = plugin->next) ); /* ensure that all the of the enabled plugins are connected to their memory */ plugin_connect_output_ports (first_enabled); if (first_enabled != last_enabled) { plugin_connect_input_ports (last_enabled, last_enabled->prev->audio_output_memory); for (plugin = first_enabled->next; plugin; plugin = plugin->next) { if (plugin->enabled) { plugin_connect_input_ports (plugin, plugin->prev->audio_output_memory); plugin_connect_output_ports (plugin); } } } /* input buffers for first plugin */ if( plugin->desc->has_input ) plugin_connect_input_ports (first_enabled, procinfo->jack_input_buffers); } void process_chain (process_info_t * procinfo, jack_nframes_t frames) { plugin_t * first_enabled; plugin_t * last_enabled = NULL; plugin_t * plugin; unsigned long channel; unsigned long i; if (procinfo->jack_client) { LADSPA_Data zero_signal[frames]; guint copy; /* set the zero signal to zero */ for (channel = 0; channel < frames; channel++) zero_signal[channel] = 0.0; /* possibly set aux output channels to zero if they're not enabled */ for (plugin = procinfo->chain; plugin; plugin = plugin->next) if (!plugin->enabled && plugin->desc->aux_channels > 0 && !plugin->desc->aux_are_input) for (copy = 0; copy < plugin->copies; copy++) for (channel = 0; channel < plugin->desc->aux_channels; channel++) memcpy (jack_port_get_buffer (plugin->holders[copy].aux_ports[channel], frames), zero_signal, sizeof (LADSPA_Data) * frames); } first_enabled = get_first_enabled_plugin (procinfo); /* no chain; just copy input to output */ if (!procinfo->chain || !first_enabled) { unsigned long channel; for (channel = 0; channel < procinfo->channels; channel++) { memcpy (procinfo->jack_output_buffers[channel], procinfo->jack_input_buffers[channel], sizeof(LADSPA_Data) * frames); } return; } /* all past here is guaranteed to have at least 1 enabled plugin */ last_enabled = get_last_enabled_plugin (procinfo); for (plugin = first_enabled; plugin; plugin = plugin->next) { if (plugin->enabled) { for (i = 0; i < plugin->copies; i++) plugin->descriptor->run (plugin->holders[i].instance, frames); if (plugin->wet_dry_enabled) for (channel = 0; channel < procinfo->channels; channel++) for (i = 0; i < frames; i++) { plugin->audio_output_memory[channel][i] *= plugin->wet_dry_values[channel]; plugin->audio_output_memory[channel][i] += plugin->audio_input_memory[channel][i] * (1.0 - plugin->wet_dry_values[channel]); } if (plugin == last_enabled) break; } else { /* copy the data through */ for (i = 0; i < procinfo->channels; i++) memcpy (plugin->audio_output_memory[i], plugin->prev->audio_output_memory[i], sizeof(LADSPA_Data) * frames); } } /* copy the last enabled data to the jack ports */ for (i = 0; i < procinfo->channels; i++) memcpy (procinfo->jack_output_buffers[i], last_enabled->audio_output_memory[i], sizeof(LADSPA_Data) * frames); } int process_ladspa (process_info_t * procinfo, jack_nframes_t frames, LADSPA_Data ** inputs, LADSPA_Data ** outputs) { unsigned long channel; if (!procinfo) { mlt_log_error( NULL, "%s: no process_info from jack!\n", __FUNCTION__); return 1; } if (procinfo->quit == TRUE) return 1; process_control_port_messages (procinfo); for (channel = 0; channel < procinfo->channels; channel++) { if(get_first_enabled_plugin (procinfo)->desc->has_input) { procinfo->jack_input_buffers[channel] = inputs[channel]; if (!procinfo->jack_input_buffers[channel]) { mlt_log_verbose( NULL, "%s: no jack buffer for input port %ld\n", __FUNCTION__, channel); return 1; } } procinfo->jack_output_buffers[channel] = outputs[channel]; if (!procinfo->jack_output_buffers[channel]) { mlt_log_verbose( NULL, "%s: no jack buffer for output port %ld\n", __FUNCTION__, channel); return 1; } } connect_chain (procinfo, frames); process_chain (procinfo, frames); return 0; } int process_jack (jack_nframes_t frames, void * data) { int err; process_info_t * procinfo; procinfo = (process_info_t *) data; if (!procinfo) { mlt_log_error( NULL, "%s: no process_info from jack!\n", __FUNCTION__); return 1; } if (procinfo->port_count == 0) return 0; if (procinfo->quit == TRUE) return 1; process_control_port_messages (procinfo); err = get_jack_buffers (procinfo, frames); if (err) { mlt_log_warning( NULL, "%s: failed to get jack ports, not processing\n", __FUNCTION__); return 0; } connect_chain (procinfo, frames); process_chain (procinfo, frames); return 0; } /******************************************* ************** non RT stuff *************** *******************************************/ static int process_info_connect_jack (process_info_t * procinfo) { mlt_log_info( NULL, _("Connecting to JACK server with client name '%s'\n"), procinfo->jack_client_name); procinfo->jack_client = jack_client_open (procinfo->jack_client_name, JackNullOption, NULL); if (!procinfo->jack_client) { mlt_log_warning( NULL, "%s: could not create jack client; is the jackd server running?\n", __FUNCTION__); return 1; } mlt_log_verbose( NULL, _("Connected to JACK server\n")); jack_set_process_callback (procinfo->jack_client, process_jack, procinfo); jack_on_shutdown (procinfo->jack_client, jack_shutdown_cb, procinfo); return 0; } static void process_info_connect_port (process_info_t * procinfo, gshort in, unsigned long port_index, const char * port_name) { const char ** jack_ports; unsigned long jack_port_index; int err; char * full_port_name; jack_ports = jack_get_ports (procinfo->jack_client, NULL, NULL, JackPortIsPhysical | (in ? JackPortIsOutput : JackPortIsInput)); if (!jack_ports) return; for (jack_port_index = 0; jack_ports[jack_port_index] && jack_port_index <= port_index; jack_port_index++) { if (jack_port_index != port_index) continue; full_port_name = g_strdup_printf ("%s:%s", procinfo->jack_client_name, port_name); mlt_log_debug( NULL, _("Connecting ports '%s' and '%s'\n"), full_port_name, jack_ports[jack_port_index]); err = jack_connect (procinfo->jack_client, in ? jack_ports[jack_port_index] : full_port_name, in ? full_port_name : jack_ports[jack_port_index]); if (err) mlt_log_warning( NULL, "%s: error connecting ports '%s' and '%s'\n", __FUNCTION__, full_port_name, jack_ports[jack_port_index]); else mlt_log_info( NULL, _("Connected ports '%s' and '%s'\n"), full_port_name, jack_ports[jack_port_index]); free (full_port_name); } free (jack_ports); } int process_info_set_port_count (process_info_t * procinfo, unsigned long port_count, gboolean connect_inputs, gboolean connect_outputs) { unsigned long i; char * port_name; jack_port_t ** port_ptr; gshort in; if (procinfo->port_count >= port_count) return -1; if (procinfo->port_count == 0) { procinfo->jack_input_ports = g_malloc (sizeof (jack_port_t *) * port_count); procinfo->jack_output_ports = g_malloc (sizeof (jack_port_t *) * port_count); procinfo->jack_input_buffers = g_malloc (sizeof (LADSPA_Data *) * port_count); procinfo->jack_output_buffers = g_malloc (sizeof (LADSPA_Data *) * port_count); } else { procinfo->jack_input_ports = g_realloc (procinfo->jack_input_ports, sizeof (jack_port_t *) * port_count); procinfo->jack_output_ports = g_realloc (procinfo->jack_output_ports, sizeof (jack_port_t *) * port_count); procinfo->jack_input_buffers = g_realloc (procinfo->jack_input_buffers, sizeof (LADSPA_Data *) * port_count); procinfo->jack_output_buffers = g_realloc (procinfo->jack_output_buffers, sizeof (LADSPA_Data *) * port_count); } for (i = procinfo->port_count; i < port_count; i++) { for (in = 0; in < 2; in++) { port_name = g_strdup_printf ("%s_%ld", in ? "in" : "out", i + 1); //mlt_log_debug( NULL, _("Creating %s port %s\n"), in ? "input" : "output", port_name); port_ptr = (in ? &procinfo->jack_input_ports[i] : &procinfo->jack_output_ports[i]); *port_ptr = jack_port_register (procinfo->jack_client, port_name, JACK_DEFAULT_AUDIO_TYPE, in ? JackPortIsInput : JackPortIsOutput, 0); if (!*port_ptr) { mlt_log_error( NULL, "%s: could not register port '%s'; aborting\n", __FUNCTION__, port_name); return 1; } //mlt_log_debug( NULL, _("Created %s port %s\n"), in ? "input" : "output", port_name); if ((in && connect_inputs) || (!in && connect_outputs)) process_info_connect_port (procinfo, in, i, port_name); g_free (port_name); } } procinfo->port_count = port_count; return 0; } void process_info_set_channels (process_info_t * procinfo, unsigned long channels, gboolean connect_inputs, gboolean connect_outputs) { process_info_set_port_count (procinfo, channels, connect_inputs, connect_outputs); procinfo->channels = channels; } process_info_t * process_info_new (const char * client_name, unsigned long rack_channels, gboolean connect_inputs, gboolean connect_outputs) { process_info_t * procinfo; char * jack_client_name; int err; procinfo = g_malloc (sizeof (process_info_t)); procinfo->chain = NULL; procinfo->chain_end = NULL; procinfo->jack_client = NULL; procinfo->port_count = 0; procinfo->jack_input_ports = NULL; procinfo->jack_output_ports = NULL; procinfo->channels = rack_channels; procinfo->quit = FALSE; if ( client_name == NULL ) { sample_rate = 48000; // should be set externally before calling process_ladspa buffer_size = MAX_BUFFER_SIZE; procinfo->silent_buffer = g_malloc (sizeof (LADSPA_Data) * buffer_size ); procinfo->jack_input_buffers = g_malloc (sizeof (LADSPA_Data *) * rack_channels); procinfo->jack_output_buffers = g_malloc (sizeof (LADSPA_Data *) * rack_channels); return procinfo; } /* sort out the client name */ procinfo->jack_client_name = jack_client_name = strdup (client_name); for (err = 0; jack_client_name[err] != '\0'; err++) { if (jack_client_name[err] == ' ') jack_client_name[err] = '_'; else if (!isalnum (jack_client_name[err])) { /* shift all the chars up one (to remove the non-alphanumeric char) */ int i; for (i = err; jack_client_name[i] != '\0'; i++) jack_client_name[i] = jack_client_name[i + 1]; } else if (isupper (jack_client_name[err])) jack_client_name[err] = tolower (jack_client_name[err]); } err = process_info_connect_jack (procinfo); if (err) { /* g_free (procinfo); */ return NULL; /* abort (); */ } sample_rate = jack_get_sample_rate (procinfo->jack_client); buffer_size = jack_get_sample_rate (procinfo->jack_client); jack_set_process_callback (procinfo->jack_client, process_jack, procinfo); pthread_mutex_lock( &g_activate_mutex ); jack_on_shutdown (procinfo->jack_client, jack_shutdown_cb, procinfo); pthread_mutex_unlock( &g_activate_mutex ); jack_activate (procinfo->jack_client); err = process_info_set_port_count (procinfo, rack_channels, connect_inputs, connect_outputs); if (err) return NULL; return procinfo; } void process_info_destroy (process_info_t * procinfo) { if (procinfo->jack_client) { jack_deactivate (procinfo->jack_client); jack_client_close (procinfo->jack_client); } g_free (procinfo->silent_buffer); g_free (procinfo->jack_input_ports); g_free (procinfo->jack_output_ports); g_free (procinfo->jack_input_buffers); g_free (procinfo->jack_output_buffers); g_free (procinfo); } void process_quit (process_info_t * procinfo) { procinfo->quit = TRUE; } mlt-0.9.0/src/modules/jackrack/process.h000066400000000000000000000044471215300731300201570ustar00rootroot00000000000000/* * JACK Rack * * Original: * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: * Copyright (C) 2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __JLH_PROCESS_H__ #define __JLH_PROCESS_H__ #include #include #include #include "lock_free_fifo.h" typedef struct _process_info process_info_t; /** this is what gets passed to the process() callback and contains all the data the process callback will need */ struct _process_info { /** the plugin instance chain */ struct _plugin * chain; struct _plugin * chain_end; jack_client_t * jack_client; unsigned long port_count; jack_port_t ** jack_input_ports; jack_port_t ** jack_output_ports; unsigned long channels; LADSPA_Data ** jack_input_buffers; LADSPA_Data ** jack_output_buffers; LADSPA_Data * silent_buffer; char * jack_client_name; int quit; }; extern jack_nframes_t sample_rate; extern jack_nframes_t buffer_size; process_info_t * process_info_new (const char * client_name, unsigned long rack_channels, gboolean connect_inputs, gboolean connect_outputs); void process_info_destroy (process_info_t * procinfo); void process_info_set_channels (process_info_t * procinfo, unsigned long channels, gboolean connect_inputs, gboolean connect_outputs); int process_ladspa (process_info_t * procinfo, jack_nframes_t frames, LADSPA_Data ** inputs, LADSPA_Data ** outputs); int process_jack (jack_nframes_t frames, void * data); void process_quit (process_info_t * procinfo); #endif /* __JLH_PROCESS_H__ */ mlt-0.9.0/src/modules/jackrack/producer_ladspa.c000066400000000000000000000134641215300731300216420ustar00rootroot00000000000000/* * producer_ladspa.c -- LADSPA plugin producer * Copyright (C) 2013 Ushodaya Enterprises Limited * Author: Brian Matherly * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include "jack_rack.h" #define BUFFER_LEN 10000 /** One-time initialization of jack rack. */ static jack_rack_t* initialise_jack_rack( mlt_properties properties, int channels ) { jack_rack_t *jackrack = NULL; unsigned long plugin_id = mlt_properties_get_int64( properties, "_pluginid" ); // Start JackRack if ( plugin_id ) { // Create JackRack without Jack client name so that it only uses LADSPA jackrack = jack_rack_new( NULL, channels ); mlt_properties_set_data( properties, "_jackrack", jackrack, 0, (mlt_destructor) jack_rack_destroy, NULL ); // Load one LADSPA plugin by its UniqueID plugin_desc_t *desc = plugin_mgr_get_any_desc( jackrack->plugin_mgr, plugin_id ); plugin_t *plugin; if ( desc && ( plugin = jack_rack_instantiate_plugin( jackrack, desc ) ) ) { LADSPA_Data value; int index, c; plugin->enabled = TRUE; plugin->wet_dry_enabled = FALSE; for ( index = 0; index < desc->control_port_count; index++ ) { // Apply the control port values char key[20]; value = plugin_desc_get_default_control_value( desc, index, sample_rate ); snprintf( key, sizeof(key), "%d", index ); if ( mlt_properties_get( properties, key ) ) value = mlt_properties_get_double( properties, key ); for ( c = 0; c < plugin->copies; c++ ) plugin->holders[c].control_memory[index] = value; } process_add_plugin( jackrack->procinfo, plugin ); } else { mlt_log_error( properties, "failed to load plugin %lu\n", plugin_id ); } } return jackrack; } static int producer_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the producer service mlt_producer producer = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "_producer_ladspa", NULL ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); int size = 0; LADSPA_Data** output_buffers = NULL; int i = 0; // Initialize LADSPA if needed jack_rack_t *jackrack = mlt_properties_get_data( producer_properties, "_jackrack", NULL ); if ( !jackrack ) { sample_rate = *frequency; // global inside jack_rack jackrack = initialise_jack_rack( producer_properties, *channels ); } if( jackrack ) { // Correct the returns if necessary *samples = *samples <= 0 ? 1920 : *samples; *channels = *channels <= 0 ? 2 : *channels; *frequency = *frequency <= 0 ? 48000 : *frequency; *format = mlt_audio_float; // Calculate the size of the buffer size = *samples * *channels * sizeof( float ); // Allocate the buffer *buffer = mlt_pool_alloc( size ); // Initialize the LADSPA output buffer. output_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * *channels ); for ( i = 0; i < *channels; i++ ) { output_buffers[i] = (LADSPA_Data*) *buffer + i * *samples; } // Do LADSPA processing process_ladspa( jackrack->procinfo, *samples, NULL, output_buffers ); mlt_pool_release( output_buffers ); // Set the buffer for destruction mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); } return 0; } static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); // Check that we created a frame and initialize it if ( *frame != NULL ) { // Obtain properties of frame mlt_properties frame_properties = MLT_FRAME_PROPERTIES( *frame ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Save the producer to be used in get_audio mlt_properties_set_data( frame_properties, "_producer_ladspa", producer, 0, NULL, NULL ); // Push the get_audio method mlt_frame_push_audio( *frame, producer_get_audio ); } // Calculate the next time code mlt_producer_prepare_next( producer ); return 0; } /** Destructor for the producer. */ static void producer_close( mlt_producer producer ) { producer->close = NULL; mlt_producer_close( producer ); free( producer ); } /** Constructor for the producer. */ mlt_producer producer_ladspa_init( mlt_profile profile, mlt_service_type type, const char* id, char* arg ) { // Create a new producer object mlt_producer producer = mlt_producer_new( profile ); if ( producer != NULL ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )producer_close; // Save the plugin ID. if ( !strncmp( id, "ladspa.", 7 ) ) { mlt_properties_set( properties, "_pluginid", id + 7 ); } // Make sure the plugin ID is valid. unsigned long plugin_id = mlt_properties_get_int64( properties, "_pluginid" ); if( plugin_id < 1000 || plugin_id > 0x00FFFFFF ) { producer_close( producer ); producer = NULL; } } return producer; } mlt-0.9.0/src/modules/jackrack/producer_ladspa.yml000066400000000000000000000005361215300731300222150ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: ladspa title: LADSPA version: 1 copyright: Copyright (C) 2013 Ushodaya Enterprises Limited license: GPLv2 language: en creator: Brian Matherly tags: - Audio description: Generate audio using LADSPA plugins. notes: > Automatically adapts to the number of channels and sampling rate of the consumer. mlt-0.9.0/src/modules/kdenlive/000077500000000000000000000000001215300731300163475ustar00rootroot00000000000000mlt-0.9.0/src/modules/kdenlive/Makefile000066400000000000000000000012671215300731300200150ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt include ../../../config.mak TARGET = ../libmltkdenlive$(LIBSUF) OBJS = factory.o \ filter_boxblur.o \ filter_freeze.o \ filter_wave.o \ producer_framebuffer.o LDFLAGS += -lm SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/kdenlive" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/kdenlive" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/kdenlive/factory.c000066400000000000000000000042431215300731300201650ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2007 Jean-Baptiste Mardelle * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include extern mlt_filter filter_boxblur_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_freeze_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_wave_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_framebuffer_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/kdenlive/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( filter_type, "boxblur", filter_boxblur_init ); MLT_REGISTER( filter_type, "freeze", filter_freeze_init ); MLT_REGISTER( filter_type, "wave", filter_wave_init ); MLT_REGISTER( producer_type, "framebuffer", producer_framebuffer_init ); MLT_REGISTER_METADATA( filter_type, "boxblur", metadata, "filter_boxblur.yml" ); MLT_REGISTER_METADATA( filter_type, "freeze", metadata, "filter_freeze.yml" ); MLT_REGISTER_METADATA( filter_type, "wave", metadata, "filter_wave.yml" ); MLT_REGISTER_METADATA( producer_type, "framebuffer", metadata, "producer_framebuffer.yml" ); } mlt-0.9.0/src/modules/kdenlive/filter_boxblur.c000066400000000000000000000124241215300731300215400ustar00rootroot00000000000000/* * filter_boxblur.c -- blur filter * Copyright (C) ?-2007 Leny Grisel * Copyright (C) 2007 Jean-Baptiste Mardelle * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include static void PreCompute(uint8_t *image, int32_t *rgb, int width, int height) { register int x, y, z; int32_t pts[3]; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { pts[0] = image[0]; pts[1] = image[1]; pts[2] = image[2]; for (z = 0; z < 3; z++) { if (x > 0) pts[z] += rgb[-3]; if (y > 0) pts[z] += rgb[width * -3]; if (x>0 && y>0) pts[z] -= rgb[(width + 1) * -3]; *rgb++ = pts[z]; } image += 3; } } } static int32_t GetRGB(int32_t *rgb, unsigned int w, unsigned int h, unsigned int x, int offsetx, unsigned int y, int offsety, unsigned int z) { int xtheo = x * 1 + offsetx; int ytheo = y + offsety; if (xtheo < 0) xtheo = 0; else if (xtheo >= w) xtheo = w - 1; if (ytheo < 0) ytheo = 0; else if (ytheo >= h) ytheo = h - 1; return rgb[3*(xtheo+ytheo*w)+z]; } static void DoBoxBlur(uint8_t *image, int32_t *rgb, unsigned int width, unsigned int height, unsigned int boxw, unsigned int boxh) { register int x, y; float mul = 1.f / ((boxw*2) * (boxh*2)); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { *image++ = (GetRGB(rgb, width, height, x, +boxw, y, +boxh, 0) + GetRGB(rgb, width, height, x, -boxw, y, -boxh, 0) - GetRGB(rgb, width, height, x, -boxw, y, +boxh, 0) - GetRGB(rgb, width, height, x, +boxw, y, -boxh, 0)) * mul; *image++ = (GetRGB(rgb, width, height, x, +boxw, y, +boxh, 1) + GetRGB(rgb, width, height, x, -boxw, y, -boxh, 1) - GetRGB(rgb, width, height, x, -boxw, y, +boxh, 1) - GetRGB(rgb, width, height, x, +boxw, y, -boxh, 1)) * mul; *image++ = (GetRGB(rgb, width, height, x, +boxw, y, +boxh, 2) + GetRGB(rgb, width, height, x, -boxw, y, -boxh, 2) - GetRGB(rgb, width, height, x, -boxw, y, +boxh, 2) - GetRGB(rgb, width, height, x, +boxw, y, -boxh, 2)) * mul; } } } static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the image *format = mlt_image_rgb24; int error = mlt_frame_get_image( this, image, format, width, height, 1 ); short hori = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "hori" ); short vert = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "vert" ); // Only process if we have no error and a valid colour space if ( error == 0 ) { double factor = mlt_properties_get_double( MLT_FRAME_PROPERTIES( this ), "boxblur" ); if ( factor != 0) { int h = *height + 1; int32_t *rgb = mlt_pool_alloc( 3 * *width * h * sizeof(int32_t) ); PreCompute( *image, rgb, *width, h ); DoBoxBlur( *image, rgb, *width, h, (int) factor * hori, (int) factor * vert ); mlt_pool_release( rgb ); } } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Get the starting blur level double blur = (double) mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "start" ); short hori = mlt_properties_get_int(MLT_FILTER_PROPERTIES( this ), "hori" ); short vert = mlt_properties_get_int(MLT_FILTER_PROPERTIES( this ), "vert" ); // If there is an end adjust gain to the range if ( mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "end" ) != NULL ) { // Determine the time position of this frame in the transition duration double end = (double) mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "end" ); blur += ( end - blur ) * mlt_filter_get_progress( this, frame ); } // Push the frame filter mlt_properties_set_double( MLT_FRAME_PROPERTIES( frame ), "boxblur", blur ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "hori", hori ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "vert", vert ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_boxblur_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "start", arg == NULL ? "2" : arg); mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "hori", arg == NULL ? "1" : arg); mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "vert", arg == NULL ? "1" : arg); } return this; } mlt-0.9.0/src/modules/kdenlive/filter_boxblur.yml000066400000000000000000000003331215300731300221130ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: boxblur title: Box Blur version: 1 copyright: Leny Grisel, Jean-Baptiste Mardelle creator: Leny Grisel, Jean-Baptiste Mardelle license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/kdenlive/filter_freeze.c000077500000000000000000000123061215300731300213450ustar00rootroot00000000000000/* * filter_freeze.c -- simple frame freezing filter * Copyright (C) 2007 Jean-Baptiste Mardelle * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the image mlt_filter filter = mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties props = MLT_FRAME_PROPERTIES( frame ); mlt_frame freeze_frame = NULL;; int freeze_before = mlt_properties_get_int( properties, "freeze_before" ); int freeze_after = mlt_properties_get_int( properties, "freeze_after" ); mlt_position pos = mlt_properties_get_position( properties, "frame" ) + mlt_producer_get_in( mlt_frame_get_original_producer( frame ) ); mlt_position currentpos = mlt_filter_get_position( filter, frame ); int do_freeze = 0; if (freeze_before == 0 && freeze_after == 0) { do_freeze = 1; } else if (freeze_before != 0 && pos > currentpos) { do_freeze = 1; } else if (freeze_after != 0 && pos < currentpos) { do_freeze = 1; } if (do_freeze == 1) { mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); freeze_frame = mlt_properties_get_data( properties, "freeze_frame", NULL ); if ( !freeze_frame || mlt_properties_get_position( properties, "_frame" ) != pos ) { // freeze_frame has not been fetched yet or is not useful, so fetch it and cache it. // get parent producer mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); mlt_producer_seek( producer, pos ); // Get the frame mlt_service_get_frame( mlt_producer_service(producer), &freeze_frame, 0 ); mlt_properties freeze_properties = MLT_FRAME_PROPERTIES( freeze_frame ); mlt_properties_set( freeze_properties, "rescale.interp", mlt_properties_get( props, "rescale.interp" ) ); mlt_properties_set_double( freeze_properties, "aspect_ratio", mlt_frame_get_aspect_ratio( frame ) ); mlt_properties_set_int( freeze_properties, "progressive", mlt_properties_get_int( props, "progressive" ) ); mlt_properties_set_int( freeze_properties, "consumer_deinterlace", mlt_properties_get_int( props, "consumer_deinterlace" ) || mlt_properties_get_int( properties, "deinterlace" ) ); mlt_properties_set_data( properties, "freeze_frame", freeze_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); mlt_properties_set_position( properties, "_frame", pos ); } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); // Get frozen image uint8_t *buffer = NULL; int error = mlt_frame_get_image( freeze_frame, &buffer, format, width, height, 1 ); // Copy it to current frame int size = mlt_image_format_size( *format, *width, *height, NULL ); uint8_t *image_copy = mlt_pool_alloc( size ); memcpy( image_copy, buffer, size ); *image = image_copy; mlt_frame_set_image( frame, *image, size, mlt_pool_release ); uint8_t *alpha_buffer = mlt_frame_get_alpha_mask( freeze_frame ); int alphasize = *width * *height; uint8_t *alpha_copy = mlt_pool_alloc( alphasize ); memcpy( alpha_copy, alpha_buffer, alphasize ); mlt_frame_set_alpha( frame, alpha_copy, alphasize, mlt_pool_release ); return error; } int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { // Push the filter on to the stack mlt_frame_push_service( frame, filter ); // Push the frame filter mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_freeze_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = mlt_filter_new( ); if ( filter != NULL ) { filter->process = filter_process; // Set the frame which will be chosen for freeze mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "frame", "0" ); // If freeze_after = 1, only frames after the "frame" value will be frozen mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "freeze_after", "0" ); // If freeze_before = 1, only frames before the "frame" value will be frozen mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "freeze_before", "0" ); } return filter; } mlt-0.9.0/src/modules/kdenlive/filter_freeze.yml000066400000000000000000000003041215300731300217140ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: freeze title: Freeze frame version: 1 copyright: Jean-Baptiste Mardelle creator: Jean-Baptiste Mardelle license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/kdenlive/filter_wave.c000066400000000000000000000120241215300731300210210ustar00rootroot00000000000000/* * wave.c -- wave filter * Copyright (C) ?-2007 Leny Grisel * Copyright (C) 2007 Jean-Baptiste Mardelle * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include // this is a utility function used by DoWave below static uint8_t getPoint(uint8_t *src, int w, int h, int x, int y, int z) { if (x<0) x+=-((-x)%w)+w; else if (x>=w) x=x%w; if (y<0) y+=-((-y)%h)+h; else if (y>=h) y=y%h; return src[(x+y*w)*4+z]; } // the main meat of the algorithm lies here static void DoWave(uint8_t *src, int src_w, int src_h, uint8_t *dst, mlt_position position, int speed, int factor, int deformX, int deformY) { register int x, y; int decalY, decalX, z; float amplitude, phase, pulsation; register int uneven = src_w % 2; int w = (src_w - uneven ) / 2; amplitude = factor; pulsation = 0.5 / factor; // smaller means bigger period phase = position * pulsation * speed / 10; // smaller means longer for (y=0;yprocess = filter_process; mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "start", arg == NULL ? "10" : arg); mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "speed", arg == NULL ? "5" : arg); mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "deformX", arg == NULL ? "1" : arg); mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "deformY", arg == NULL ? "1" : arg); } return filter; } mlt-0.9.0/src/modules/kdenlive/filter_wave.yml000066400000000000000000000003241215300731300214000ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: wave title: Wave version: 1 copyright: Leny Grisel, Jean-Baptiste Mardelle creator: Leny Grisel, Jean-Baptiste Mardelle license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/kdenlive/producer_framebuffer.c000066400000000000000000000312461215300731300227100ustar00rootroot00000000000000/* * producer_framebuffer.c -- create subspeed frames * Copyright (C) 2007 Jean-Baptiste Mardelle * Author: Jean-Baptiste Mardelle, based on the code of motion_est by Zachary Drew * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include // Forward references. static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ); /** Image stack(able) method */ static int framebuffer_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter object and properties mlt_producer producer = mlt_frame_pop_service( frame ); int index = mlt_frame_pop_service_int( frame ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); // Frame properties objects mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); mlt_frame first_frame = mlt_properties_get_data( properties, "first_frame", NULL ); // Get producer parameters int strobe = mlt_properties_get_int( properties, "strobe" ); int freeze = mlt_properties_get_int( properties, "freeze" ); int freeze_after = mlt_properties_get_int( properties, "freeze_after" ); int freeze_before = mlt_properties_get_int( properties, "freeze_before" ); int in = mlt_properties_get_position( properties, "in" ); // Determine the position mlt_position first_position = (first_frame != NULL) ? mlt_frame_get_position( first_frame ) : -1; mlt_position need_first = freeze; if ( !freeze || freeze_after || freeze_before ) { double prod_speed = mlt_properties_get_double( properties, "_speed" ); double actual_position = in + prod_speed * (double) mlt_producer_position( producer ); if ( mlt_properties_get_int( properties, "reverse" ) ) actual_position = mlt_producer_get_playtime( producer ) - actual_position; if ( strobe < 2 ) { need_first = floor( actual_position ); } else { // Strobe effect wanted, calculate frame position need_first = floor( actual_position ); need_first -= MLT_POSITION_MOD(need_first, strobe); } if ( freeze ) { if ( freeze_after && need_first > freeze ) need_first = freeze; else if ( freeze_before && need_first < freeze ) need_first = freeze; } } // Determine output buffer size *width = mlt_properties_get_int( frame_properties, "width" ); *height = mlt_properties_get_int( frame_properties, "height" ); int size = mlt_image_format_size( *format, *width, *height, NULL ); // Get output buffer int buffersize = 0; int alphasize = *width * *height; uint8_t *output = mlt_properties_get_data( properties, "output_buffer", &buffersize ); uint8_t *output_alpha = mlt_properties_get_data( properties, "output_alpha", NULL ); if( buffersize == 0 || buffersize != size ) { // invalidate cached frame first_position = -1; } if ( need_first != first_position ) { // invalidate cached frame first_position = -1; // Bust the cached frame mlt_properties_set_data( properties, "first_frame", NULL, 0, NULL, NULL ); first_frame = NULL; } if ( output && first_position != -1 ) { // Using the cached frame uint8_t *image_copy = mlt_pool_alloc( size ); memcpy( image_copy, output, size ); uint8_t *alpha_copy = mlt_pool_alloc( alphasize ); memcpy( alpha_copy, output_alpha, alphasize ); // Set the output image *image = image_copy; mlt_frame_set_image( frame, image_copy, size, mlt_pool_release ); mlt_frame_set_alpha( frame, alpha_copy, alphasize, mlt_pool_release ); *width = mlt_properties_get_int( properties, "_output_width" ); *height = mlt_properties_get_int( properties, "_output_height" ); *format = mlt_properties_get_int( properties, "_output_format" ); mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); return 0; } // Get the cached frame if ( first_frame == NULL ) { // Get the frame to cache from the real producer mlt_producer real_producer = mlt_properties_get_data( properties, "producer", NULL ); // Seek the producer to the correct place mlt_producer_seek( real_producer, need_first ); // Get the frame mlt_service_get_frame( MLT_PRODUCER_SERVICE( real_producer ), &first_frame, index ); // Cache the frame mlt_properties_set_data( properties, "first_frame", first_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); } mlt_properties first_frame_properties = MLT_FRAME_PROPERTIES( first_frame ); // Which frames are buffered? uint8_t *first_image = mlt_properties_get_data( first_frame_properties, "image", NULL ); uint8_t *first_alpha = mlt_properties_get_data( first_frame_properties, "alpha", NULL ); if ( !first_image ) { mlt_properties_set( first_frame_properties, "rescale.interp", mlt_properties_get( frame_properties, "rescale.interp" ) ); int error = mlt_frame_get_image( first_frame, &first_image, format, width, height, writable ); if ( error != 0 ) { mlt_log_warning( MLT_PRODUCER_SERVICE( producer ), "first_image == NULL get image died\n" ); mlt_properties_set_data( properties, "first_frame", NULL, 0, NULL, NULL ); mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); return error; } output = mlt_pool_alloc( size ); memcpy( output, first_image, size ); // Let someone else clean up mlt_properties_set_data( properties, "output_buffer", output, size, mlt_pool_release, NULL ); mlt_properties_set_int( properties, "_output_width", *width ); mlt_properties_set_int( properties, "_output_height", *height ); mlt_properties_set_int( properties, "_output_format", *format ); } if ( !first_alpha ) { alphasize = *width * *height; first_alpha = mlt_frame_get_alpha_mask( first_frame ); output_alpha = mlt_pool_alloc( alphasize ); memcpy( output_alpha, first_alpha, alphasize ); mlt_properties_set_data( properties, "output_alpha", output_alpha, alphasize, mlt_pool_release, NULL ); } mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); // Create a copy uint8_t *image_copy = mlt_pool_alloc( size ); memcpy( image_copy, first_image, size ); uint8_t *alpha_copy = mlt_pool_alloc( alphasize ); memcpy( alpha_copy, first_alpha, alphasize ); // Set the output image *image = image_copy; mlt_frame_set_image( frame, *image, size, mlt_pool_release ); mlt_frame_set_alpha( frame, alpha_copy, alphasize, mlt_pool_release ); return 0; } static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { if ( frame ) { // Construct a new frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); // Stack the producer and producer's get image mlt_frame_push_service_int( *frame, index ); mlt_frame_push_service( *frame, producer ); mlt_frame_push_service( *frame, framebuffer_get_image ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_properties frame_properties = MLT_FRAME_PROPERTIES(*frame); // Get frame from the real producer mlt_frame first_frame = mlt_properties_get_data( properties, "first_frame", NULL ); if ( first_frame == NULL ) { // Get the frame to cache from the real producer mlt_producer real_producer = mlt_properties_get_data( properties, "producer", NULL ); // Seek the producer to the correct place mlt_producer_seek( real_producer, mlt_producer_position( producer ) ); // Get the frame mlt_service_get_frame( MLT_PRODUCER_SERVICE( real_producer ), &first_frame, index ); // Cache the frame mlt_properties_set_data( properties, "first_frame", first_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); } mlt_properties_inherit( frame_properties, MLT_FRAME_PROPERTIES(first_frame) ); double force_aspect_ratio = mlt_properties_get_double( properties, "force_aspect_ratio" ); if ( force_aspect_ratio <= 0.0 ) force_aspect_ratio = mlt_properties_get_double( properties, "aspect_ratio" ); mlt_properties_set_double( frame_properties, "aspect_ratio", force_aspect_ratio ); // Give the returned frame temporal identity mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); mlt_properties_set_int( frame_properties, "meta.media.width", mlt_properties_get_int( properties, "width" ) ); mlt_properties_set_int( frame_properties, "meta.media.height", mlt_properties_get_int( properties, "height" ) ); mlt_properties_pass_list( frame_properties, properties, "width, height" ); } return 0; } mlt_producer producer_framebuffer_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { if ( !arg ) return NULL; mlt_producer producer = NULL; producer = calloc( 1, sizeof( struct mlt_producer_s ) ); if ( !producer ) return NULL; if ( mlt_producer_init( producer, NULL ) ) { free( producer ); return NULL; } // Wrap loader mlt_producer real_producer; // Check if a speed was specified. /** * Speed must be appended to the filename with '?'. To play your video at 50%: melt framebuffer:my_video.mpg?0.5 * Stroboscope effect can be obtained by adding a stobe=x parameter, where x is the number of frames that will be ignored. * You can play the movie backwards by adding reverse=1 * You can freeze the clip at a determined position by adding freeze=frame_pos add freeze_after=1 to freeze only paste position or freeze_before to freeze before it **/ double speed = 0.0; char *props = strdup( arg ); char *ptr = strrchr( props, '?' ); if ( ptr ) { speed = atof( ptr + 1 ); if ( speed != 0.0 ) // If speed was valid, then strip it and the delimiter. // Otherwise, an invalid speed probably means this '?' was not a delimiter. *ptr = '\0'; } real_producer = mlt_factory_producer( profile, "abnormal", props ); free( props ); if (speed == 0.0) speed = 1.0; if ( producer != NULL && real_producer != NULL) { // Get the properties of this producer mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_properties_set( properties, "resource", arg); // Store the producer and fitler mlt_properties_set_data( properties, "producer", real_producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); // Grab some stuff from the real_producer mlt_properties_pass_list( properties, MLT_PRODUCER_PROPERTIES( real_producer ), "length, width, height, aspect_ratio" ); if ( speed < 0 ) { speed = -speed; mlt_properties_set_int( properties, "reverse", 1 ); } if ( speed != 1.0 ) { double real_length = ( (double) mlt_producer_get_length( real_producer ) ) / speed; mlt_properties_set_position( properties, "length", real_length ); mlt_properties real_properties = MLT_PRODUCER_PROPERTIES( real_producer ); const char* service = mlt_properties_get( real_properties, "mlt_service" ); if ( service && !strcmp( service, "avformat" ) ) { int n = mlt_properties_count( real_properties ); int i; for ( i = 0; i < n; i++ ) { if ( strstr( mlt_properties_get_name( real_properties, i ), "stream.frame_rate" ) ) { double source_fps = mlt_properties_get_double( real_properties, mlt_properties_get_name( real_properties, i ) ); if ( source_fps > mlt_profile_fps( profile ) ) { mlt_properties_set_double( real_properties, "force_fps", source_fps * speed ); mlt_properties_set_position( real_properties, "length", real_length ); mlt_properties_set_position( real_properties, "out", real_length - 1 ); speed = 1.0; } break; } } } } mlt_properties_set_position( properties, "out", mlt_producer_get_length( producer ) - 1 ); // Since we control the seeking, prevent it from seeking on its own mlt_producer_set_speed( real_producer, 0 ); mlt_producer_set_speed( producer, speed ); // Override the get_frame method producer->get_frame = producer_get_frame; } else { if ( producer ) mlt_producer_close( producer ); if ( real_producer ) mlt_producer_close( real_producer ); producer = NULL; } return producer; } mlt-0.9.0/src/modules/kdenlive/producer_framebuffer.yml000066400000000000000000000003041215300731300232560ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: framebuffer title: Speed version: 1 copyright: Jean-Baptiste Mardelle creator: Jean-Baptiste Mardelle license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/kino/000077500000000000000000000000001215300731300155065ustar00rootroot00000000000000mlt-0.9.0/src/modules/kino/Makefile000066400000000000000000000017151215300731300171520ustar00rootroot00000000000000CFLAGS += -I../../ CXXFLAGS += $(CFLAGS) -Wno-deprecated LDFLAGS += -L../../framework -lmlt -lpthread include ../../../config.mak include config.mak TARGET = ../libmltkino.so OBJS = factory.o producer_kino.o CPPOBJS = kino_wrapper.o avi.o error.o filehandler.o riff.o LDFLAGS += -lstdc++ ifdef HAVE_LIBQUICKTIME CFLAGS += `pkg-config --cflags libquicktime` CXXFLAGS += `pkg-config --cflags libquicktime` LDFLAGS += `pkg-config --libs libquicktime` endif ifdef HAVE_LIBDV CFLAGS += `pkg-config --cflags libdv` LDFLAGS += `pkg-config --libs libdv` endif SRCS := $(OBJS:.o=.c) $(CPPOBJS:.o=.cc) all: $(TARGET) $(TARGET): $(OBJS) $(CPPOBJS) $(CXX) -shared -o $@ $(OBJS) $(CPPOBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend config.h config.mak clean: rm -f $(OBJS) $(TARGET) $(CPPOBJS) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/kino/avi.cc000066400000000000000000001517211215300731300166030ustar00rootroot00000000000000/* * avi.cc library for AVI file format i/o * Copyright (C) 2000 - 2002 Arne Schirmacher * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" // C++ includes #include #include #include using std::cout; using std::hex; using std::dec; using std::setw; using std::setfill; using std::endl; // C includes #include #include #include #include #include // local includes #include "error.h" #include "riff.h" #include "avi.h" #define PADDING_SIZE (512) #define PADDING_1GB (0x40000000) #define IX00_INDEX_SIZE (4028) #define AVIF_HASINDEX 0x00000010 #define AVIF_MUSTUSEINDEX 0x00000020 #define AVIF_TRUSTCKTYPE 0x00000800 #define AVIF_ISINTERLEAVED 0x00000100 #define AVIF_WASCAPTUREFILE 0x00010000 #define AVIF_COPYRIGHTED 0x00020000 //static char g_zeroes[ PADDING_SIZE ]; /** The constructor \todo mainHdr not initialized \todo add checking for NULL pointers */ AVIFile::AVIFile() : RIFFFile(), idx1( NULL ), file_list( -1 ), riff_list( -1 ), hdrl_list( -1 ), avih_chunk( -1 ), movi_list( -1 ), junk_chunk( -1 ), idx1_chunk( -1 ), index_type( -1 ), current_ix00( -1 ), odml_list( -1 ), dmlh_chunk( -1 ), isUpdateIdx1( true ) { // cerr << "0x" << hex << (long)this << dec << " AVIFile::AVIFile() : RIFFFile(), ..." << endl; for ( int i = 0; i < 2; ++i ) { indx[ i ] = new AVISuperIndex; memset( indx[ i ], 0, sizeof( AVISuperIndex ) ); ix[ i ] = new AVIStdIndex; memset( ix[ i ], 0, sizeof( AVIStdIndex ) ); indx_chunk[ i ] = -1; ix_chunk[ i ] = -1; strl_list[ i ] = -1; strh_chunk[ i ] = -1; strf_chunk[ i ] = -1; } idx1 = new AVISimpleIndex; memset( idx1, 0, sizeof( AVISimpleIndex ) ); memset( dmlh, 0, sizeof( dmlh ) ); memset( &mainHdr, 0, sizeof( mainHdr ) ); memset( &streamHdr, 0, sizeof( streamHdr ) ); } /** The copy constructor \todo add checking for NULL pointers */ AVIFile::AVIFile( const AVIFile& avi ) : RIFFFile( avi ) { // cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile::AVIFile(const AVIFile& avi) : RIFFFile(avi)" << endl; mainHdr = avi.mainHdr; idx1 = new AVISimpleIndex; *idx1 = *avi.idx1; file_list = avi.file_list; riff_list = avi.riff_list; hdrl_list = avi.hdrl_list; avih_chunk = avi.avih_chunk; movi_list = avi.movi_list; junk_chunk = avi.junk_chunk; idx1_chunk = avi.idx1_chunk; for ( int i = 0; i < 2; ++i ) { indx[ i ] = new AVISuperIndex; *indx[ i ] = *avi.indx[ i ]; ix[ i ] = new AVIStdIndex; *ix[ i ] = *avi.ix[ i ]; indx_chunk[ i ] = avi.indx_chunk[ i ]; ix_chunk[ i ] = avi.ix_chunk[ i ]; strl_list[ i ] = avi.strl_list[ i ]; strh_chunk[ i ] = avi.strh_chunk[ i ]; strf_chunk[ i ] = avi.strf_chunk[ i ]; } index_type = avi.index_type; current_ix00 = avi.current_ix00; for ( int i = 0; i < 62; ++i ) dmlh[ i ] = avi.dmlh[ i ]; isUpdateIdx1 = avi.isUpdateIdx1; odml_list = 0; dmlh_chunk = 0; memset( &streamHdr, 0, sizeof( streamHdr ) ); } /** The assignment operator */ AVIFile& AVIFile::operator=( const AVIFile& avi ) { // cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile& AVIFile::operator=(const AVIFile& avi)" << endl; if ( this != &avi ) { RIFFFile::operator=( avi ); mainHdr = avi.mainHdr; *idx1 = *avi.idx1; file_list = avi.file_list; riff_list = avi.riff_list; hdrl_list = avi.hdrl_list; avih_chunk = avi.avih_chunk; movi_list = avi.movi_list; junk_chunk = avi.junk_chunk; idx1_chunk = avi.idx1_chunk; for ( int i = 0; i < 2; ++i ) { *indx[ i ] = *avi.indx[ i ]; *ix[ i ] = *avi.ix[ i ]; indx_chunk[ i ] = avi.indx_chunk[ i ]; ix_chunk[ i ] = avi.ix_chunk[ i ]; strl_list[ i ] = avi.strl_list[ i ]; strh_chunk[ i ] = avi.strh_chunk[ i ]; strf_chunk[ i ] = avi.strf_chunk[ i ]; } index_type = avi.index_type; current_ix00 = avi.current_ix00; for ( int i = 0; i < 62; ++i ) dmlh[ i ] = avi.dmlh[ i ]; isUpdateIdx1 = avi.isUpdateIdx1; } return *this; } /** The destructor */ AVIFile::~AVIFile() { // cerr << "0x" << hex << (long)this << dec << " AVIFile::~AVIFile()" << endl; for ( int i = 0; i < 2; ++i ) { delete ix[ i ]; delete indx[ i ]; } delete idx1; } /** Initialize the AVI structure to its initial state, either for PAL or NTSC format Initialize the AVIFile attributes: mainHdr, indx, ix00, idx1 \todo consolidate AVIFile::Init, AVI1File::Init, AVI2File::Init. They are somewhat redundant. \param format pass AVI_PAL or AVI_NTSC \param sampleFrequency the sample frequency of the audio content \param indexType pass AVI_SMALL_INDEX or AVI_LARGE_INDEX */ void AVIFile::Init( int format, int sampleFrequency, int indexType ) { int i, j; assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) ); index_type = indexType; switch ( format ) { case AVI_PAL: mainHdr.dwMicroSecPerFrame = 40000; mainHdr.dwSuggestedBufferSize = 144008; break; case AVI_NTSC: mainHdr.dwMicroSecPerFrame = 33366; mainHdr.dwSuggestedBufferSize = 120008; break; default: /* no default allowed */ assert( 0 ); break; } /* Initialize the 'avih' chunk */ mainHdr.dwMaxBytesPerSec = 3600000 + sampleFrequency * 4; mainHdr.dwPaddingGranularity = PADDING_SIZE; mainHdr.dwFlags = AVIF_TRUSTCKTYPE; if ( indexType & AVI_SMALL_INDEX ) mainHdr.dwFlags |= AVIF_HASINDEX; mainHdr.dwTotalFrames = 0; mainHdr.dwInitialFrames = 0; mainHdr.dwStreams = 1; mainHdr.dwWidth = 0; mainHdr.dwHeight = 0; mainHdr.dwReserved[ 0 ] = 0; mainHdr.dwReserved[ 1 ] = 0; mainHdr.dwReserved[ 2 ] = 0; mainHdr.dwReserved[ 3 ] = 0; /* Initialize the 'idx1' chunk */ for ( int i = 0; i < 8000; ++i ) { idx1->aIndex[ i ].dwChunkId = 0; idx1->aIndex[ i ].dwFlags = 0; idx1->aIndex[ i ].dwOffset = 0; idx1->aIndex[ i ].dwSize = 0; } idx1->nEntriesInUse = 0; /* Initialize the 'indx' chunk */ for ( i = 0; i < 2; ++i ) { indx[ i ] ->wLongsPerEntry = 4; indx[ i ] ->bIndexSubType = 0; indx[ i ] ->bIndexType = KINO_AVI_INDEX_OF_INDEXES; indx[ i ] ->nEntriesInUse = 0; indx[ i ] ->dwReserved[ 0 ] = 0; indx[ i ] ->dwReserved[ 1 ] = 0; indx[ i ] ->dwReserved[ 2 ] = 0; for ( j = 0; j < 2014; ++j ) { indx[ i ] ->aIndex[ j ].qwOffset = 0; indx[ i ] ->aIndex[ j ].dwSize = 0; indx[ i ] ->aIndex[ j ].dwDuration = 0; } } /* The ix00 and ix01 chunk will be added dynamically in avi_write_frame as needed */ /* Initialize the 'dmlh' chunk. I have no clue what this means though */ for ( i = 0; i < 62; ++i ) dmlh[ i ] = 0; //dmlh[0] = -1; /* frame count + 1? */ } /** Find position and size of a given frame in the file Depending on which index is available, search one of them to find position and frame size \todo the size parameter is redundant. All frames have the same size, which is also in the mainHdr. \todo all index related operations should be isolated \param offset the file offset to the start of the frame \param size the size of the frame \param frameNum the number of the frame we wish to find \return 0 if the frame could be found, -1 otherwise */ int AVIFile::GetDVFrameInfo( off_t &offset, int &size, int frameNum ) { switch ( index_type ) { case AVI_LARGE_INDEX: /* find relevant index in indx0 */ int i; for ( i = 0; frameNum >= indx[ 0 ] ->aIndex[ i ].dwDuration; frameNum -= indx[ 0 ] ->aIndex[ i ].dwDuration, ++i ) ; if ( i != current_ix00 ) { fail_if( lseek( fd, indx[ 0 ] ->aIndex[ i ].qwOffset + RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 ); fail_neg( read( fd, ix[ 0 ], indx[ 0 ] ->aIndex[ i ].dwSize - RIFF_HEADERSIZE ) ); current_ix00 = i; } if ( frameNum < ix[ 0 ] ->nEntriesInUse ) { offset = ix[ 0 ] ->qwBaseOffset + ix[ 0 ] ->aIndex[ frameNum ].dwOffset; size = ix[ 0 ] ->aIndex[ frameNum ].dwSize; return 0; } else return -1; break; case AVI_SMALL_INDEX: int index = -1; int frameNumIndex = 0; for ( int i = 0; i < idx1->nEntriesInUse; ++i ) { FOURCC chunkID1 = make_fourcc( "00dc" ); FOURCC chunkID2 = make_fourcc( "00db" ); if ( idx1->aIndex[ i ].dwChunkId == chunkID1 || idx1->aIndex[ i ].dwChunkId == chunkID2 ) { if ( frameNumIndex == frameNum ) { index = i; break; } ++frameNumIndex; } } if ( index != -1 ) { // compatibility check for broken dvgrab dv2 format if ( idx1->aIndex[ 0 ].dwOffset > GetDirectoryEntry( movi_list ).offset ) { offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE; } else { // new, correct dv2 format offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE + GetDirectoryEntry( movi_list ).offset; } size = idx1->aIndex[ index ].dwSize; return 0; } else return -1; break; } return -1; } /** Find position and size of a given frame in the file Depending on which index is available, search one of them to find position and frame size \todo the size parameter is redundant. All frames have the same size, which is also in the mainHdr. \todo all index related operations should be isolated \param offset the file offset to the start of the frame \param size the size of the frame \param frameNum the number of the frame we wish to find \param chunkID the ID of the type of chunk we want \return 0 if the frame could be found, -1 otherwise */ int AVIFile::GetFrameInfo( off_t &offset, int &size, int frameNum, FOURCC chunkID ) { if ( index_type & AVI_LARGE_INDEX ) { int i; for ( i = 0; frameNum >= indx[ 0 ] ->aIndex[ i ].dwDuration; frameNum -= indx[ 0 ] ->aIndex[ i ].dwDuration, ++i ) ; if ( i != current_ix00 ) { fail_if( lseek( fd, indx[ 0 ] ->aIndex[ i ].qwOffset + RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 ); fail_neg( read( fd, ix[ 0 ], indx[ 0 ] ->aIndex[ i ].dwSize - RIFF_HEADERSIZE ) ); current_ix00 = i; } if ( frameNum < ix[ 0 ] ->nEntriesInUse ) { if ( ( FOURCC ) ix[ 0 ] ->dwChunkId == chunkID ) { offset = ix[ 0 ] ->qwBaseOffset + ix[ 0 ] ->aIndex[ frameNum ].dwOffset; size = ix[ 0 ] ->aIndex[ frameNum ].dwSize; return 0; } } } if ( index_type & AVI_SMALL_INDEX ) { int index = -1; int frameNumIndex = 0; for ( int i = 0; i < idx1->nEntriesInUse; ++i ) { if ( idx1->aIndex[ i ].dwChunkId == chunkID ) { if ( frameNumIndex == frameNum ) { index = i; break; } ++frameNumIndex; } } if ( index != -1 ) { // compatibility check for broken dvgrab dv2 format if ( idx1->aIndex[ 0 ].dwOffset > GetDirectoryEntry( movi_list ).offset ) { offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE; } else { // new, correct dv2 format offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE + GetDirectoryEntry( movi_list ).offset; } size = idx1->aIndex[ index ].dwSize; return 0; } } return -1; } /** Read in a frame \todo we actually don't need the frame here, we could use just a void pointer \param frame a reference to the frame object that will receive the frame data \param frameNum the frame number to read \return 0 if the frame could be read, -1 otherwise */ int AVIFile::GetDVFrame( uint8_t *data, int frameNum ) { off_t offset; int size; if ( GetDVFrameInfo( offset, size, frameNum ) != 0 || size < 0 ) return -1; pthread_mutex_lock( &file_mutex ); fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 ); fail_neg( read( fd, data, size ) ); pthread_mutex_unlock( &file_mutex ); return 0; } /** Read in a frame \param data a pointer to the audio buffer \param frameNum the frame number to read \param chunkID the ID of the type of chunk we want \return the size the of the frame data, 0 if could not be read */ int AVIFile::getFrame( void *data, int frameNum, FOURCC chunkID ) { off_t offset; int size; if ( GetFrameInfo( offset, size, frameNum, chunkID ) != 0 ) return 0; fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 ); fail_neg( read( fd, data, size ) ); return size; } int AVIFile::GetTotalFrames() const { return mainHdr.dwTotalFrames; } /** prints out a directory entry in text form Every subclass of RIFFFile is supposed to override this function and to implement it for the entry types it knows about. For all other entry types it should call its parent::PrintDirectoryData. \todo use 64 bit routines \param entry the entry to print */ void AVIFile::PrintDirectoryEntryData( const RIFFDirEntry &entry ) const { static FOURCC lastStreamType = make_fourcc( " " ); if ( entry.type == make_fourcc( "avih" ) ) { int i; MainAVIHeader main_avi_header; fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); fail_neg( read( fd, &main_avi_header, sizeof( MainAVIHeader ) ) ); cout << " dwMicroSecPerFrame: " << ( int ) main_avi_header.dwMicroSecPerFrame << endl << " dwMaxBytesPerSec: " << ( int ) main_avi_header.dwMaxBytesPerSec << endl << " dwPaddingGranularity: " << ( int ) main_avi_header.dwPaddingGranularity << endl << " dwFlags: " << ( int ) main_avi_header.dwFlags << endl << " dwTotalFrames: " << ( int ) main_avi_header.dwTotalFrames << endl << " dwInitialFrames: " << ( int ) main_avi_header.dwInitialFrames << endl << " dwStreams: " << ( int ) main_avi_header.dwStreams << endl << " dwSuggestedBufferSize: " << ( int ) main_avi_header.dwSuggestedBufferSize << endl << " dwWidth: " << ( int ) main_avi_header.dwWidth << endl << " dwHeight: " << ( int ) main_avi_header.dwHeight << endl; for ( i = 0; i < 4; ++i ) cout << " dwReserved[" << i << "]: " << ( int ) main_avi_header.dwReserved[ i ] << endl; } else if ( entry.type == make_fourcc( "strh" ) ) { AVIStreamHeader avi_stream_header; fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); fail_neg( read( fd, &avi_stream_header, sizeof( AVIStreamHeader ) ) ); lastStreamType = avi_stream_header.fccType; cout << " fccType: '" << ((char *)&avi_stream_header.fccType)[0] << ((char *)&avi_stream_header.fccType)[1] << ((char *)&avi_stream_header.fccType)[2] << ((char *)&avi_stream_header.fccType)[3] << '\'' << endl << " fccHandler: '" << ((char *)&avi_stream_header.fccHandler)[0] << ((char *)&avi_stream_header.fccHandler)[1] << ((char *)&avi_stream_header.fccHandler)[2] << ((char *)&avi_stream_header.fccHandler)[3] << '\'' << endl << " dwFlags: " << ( int ) avi_stream_header.dwFlags << endl << " wPriority: " << ( int ) avi_stream_header.wPriority << endl << " wLanguage: " << ( int ) avi_stream_header.wLanguage << endl << " dwInitialFrames: " << ( int ) avi_stream_header.dwInitialFrames << endl << " dwScale: " << ( int ) avi_stream_header.dwScale << endl << " dwRate: " << ( int ) avi_stream_header.dwRate << endl << " dwLength: " << ( int ) avi_stream_header.dwLength << endl << " dwQuality: " << ( int ) avi_stream_header.dwQuality << endl << " dwSampleSize: " << ( int ) avi_stream_header.dwSampleSize << endl; } else if ( entry.type == make_fourcc( "indx" ) ) { int i; AVISuperIndex avi_super_index; fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); fail_neg( read( fd, &avi_super_index, sizeof( AVISuperIndex ) ) ); cout << " wLongsPerEntry: " << ( int ) avi_super_index.wLongsPerEntry << endl << " bIndexSubType: " << ( int ) avi_super_index.bIndexSubType << endl << " bIndexType: " << ( int ) avi_super_index.bIndexType << endl << " nEntriesInUse: " << ( int ) avi_super_index.nEntriesInUse << endl << " dwChunkId: '" << ((char *)&avi_super_index.dwChunkId)[0] << ((char *)&avi_super_index.dwChunkId)[1] << ((char *)&avi_super_index.dwChunkId)[2] << ((char *)&avi_super_index.dwChunkId)[3] << '\'' << endl << " dwReserved[0]: " << ( int ) avi_super_index.dwReserved[ 0 ] << endl << " dwReserved[1]: " << ( int ) avi_super_index.dwReserved[ 1 ] << endl << " dwReserved[2]: " << ( int ) avi_super_index.dwReserved[ 2 ] << endl; for ( i = 0; i < avi_super_index.nEntriesInUse; ++i ) { cout << ' ' << setw( 4 ) << setfill( ' ' ) << i << ": qwOffset : 0x" << setw( 12 ) << setfill( '0' ) << hex << avi_super_index.aIndex[ i ].qwOffset << endl << " dwSize : 0x" << setw( 8 ) << avi_super_index.aIndex[ i ].dwSize << endl << " dwDuration : " << dec << avi_super_index.aIndex[ i ].dwDuration << endl; } } else if ( entry.type == make_fourcc( "strf" ) ) { if ( lastStreamType == make_fourcc( "auds" ) ) { WAVEFORMATEX waveformatex; fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); fail_neg( read( fd, &waveformatex, sizeof( WAVEFORMATEX ) ) ); cout << " waveformatex.wFormatTag : " << waveformatex.wFormatTag << endl; cout << " waveformatex.nChannels : " << waveformatex.nChannels << endl; cout << " waveformatex.nSamplesPerSec : " << waveformatex.nSamplesPerSec << endl; cout << " waveformatex.nAvgBytesPerSec: " << waveformatex.nAvgBytesPerSec << endl; cout << " waveformatex.nBlockAlign : " << waveformatex.nBlockAlign << endl; cout << " waveformatex.wBitsPerSample : " << waveformatex.wBitsPerSample << endl; cout << " waveformatex.cbSize : " << waveformatex.cbSize << endl; } else if ( lastStreamType == make_fourcc( "vids" ) ) { BITMAPINFOHEADER bitmapinfo; fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); fail_neg( read( fd, &bitmapinfo, sizeof( BITMAPINFOHEADER ) ) ); cout << " bitmapinfo.biSize : " << bitmapinfo.biSize << endl; cout << " bitmapinfo.biWidth : " << bitmapinfo.biWidth << endl; cout << " bitmapinfo.biHeight : " << bitmapinfo.biHeight << endl; cout << " bitmapinfo.biPlanes : " << bitmapinfo.biPlanes << endl; cout << " bitmapinfo.biBitCount : " << bitmapinfo.biBitCount << endl; cout << " bitmapinfo.biCompression : " << bitmapinfo.biCompression << endl; cout << " bitmapinfo.biSizeImage : " << bitmapinfo.biSizeImage << endl; cout << " bitmapinfo.biXPelsPerMeter: " << bitmapinfo.biXPelsPerMeter << endl; cout << " bitmapinfo.biYPelsPerMeter: " << bitmapinfo.biYPelsPerMeter << endl; cout << " bitmapinfo.biClrUsed : " << bitmapinfo.biClrUsed << endl; cout << " bitmapinfo.biClrImportant : " << bitmapinfo.biClrImportant << endl; } else if ( lastStreamType == make_fourcc( "iavs" ) ) { DVINFO dvinfo; fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); fail_neg( read( fd, &dvinfo, sizeof( DVINFO ) ) ); cout << " dvinfo.dwDVAAuxSrc : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxSrc << endl; cout << " dvinfo.dwDVAAuxCtl : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxCtl << endl; cout << " dvinfo.dwDVAAuxSrc1: 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxSrc1 << endl; cout << " dvinfo.dwDVAAuxCtl1: 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxCtl1 << endl; cout << " dvinfo.dwDVVAuxSrc : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVVAuxSrc << endl; cout << " dvinfo.dwDVVAuxCtl : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVVAuxCtl << endl; } } /* This is the Standard Index. It is an array of offsets and sizes relative to some start offset. */ else if ( ( entry.type == make_fourcc( "ix00" ) ) || ( entry.type == make_fourcc( "ix01" ) ) ) { int i; AVIStdIndex avi_std_index; fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); fail_neg( read( fd, &avi_std_index, sizeof( AVIStdIndex ) ) ); cout << " wLongsPerEntry: " << ( int ) avi_std_index.wLongsPerEntry << endl << " bIndexSubType: " << ( int ) avi_std_index.bIndexSubType << endl << " bIndexType: " << ( int ) avi_std_index.bIndexType << endl << " nEntriesInUse: " << ( int ) avi_std_index.nEntriesInUse << endl << " dwChunkId: '" << ((char *)&avi_std_index.dwChunkId)[0] << ((char *)&avi_std_index.dwChunkId)[1] << ((char *)&avi_std_index.dwChunkId)[2] << ((char *)&avi_std_index.dwChunkId)[3] << '\'' << endl << " qwBaseOffset: 0x" << setw( 12 ) << hex << avi_std_index.qwBaseOffset << endl << " dwReserved: " << dec << ( int ) avi_std_index.dwReserved << endl; for ( i = 0; i < avi_std_index.nEntriesInUse; ++i ) { cout << ' ' << setw( 4 ) << setfill( ' ' ) << i << ": dwOffset : 0x" << setw( 8 ) << setfill( '0' ) << hex << avi_std_index.aIndex[ i ].dwOffset << " (0x" << setw( 12 ) << avi_std_index.qwBaseOffset + avi_std_index.aIndex[ i ].dwOffset << ')' << endl << " dwSize : 0x" << setw( 8 ) << avi_std_index.aIndex[ i ].dwSize << dec << endl; } } else if ( entry.type == make_fourcc( "idx1" ) ) { int i; int numEntries = entry.length / sizeof( int ) / 4; DWORD *idx1 = new DWORD[ numEntries * 4 ]; // FOURCC movi_list = FindDirectoryEntry(make_fourcc("movi")); fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); fail_neg( read( fd, idx1, entry.length ) ); for ( i = 0; i < numEntries; ++i ) { cout << ' ' << setw( 4 ) << setfill( ' ' ) << i << setfill( '0' ) << ": dwChunkId : '" << ((char *)&idx1[ i * 4 + 0 ])[0] << ((char *)&idx1[ i * 4 + 0 ])[1] << ((char *)&idx1[ i * 4 + 0 ])[2] << ((char *)&idx1[ i * 4 + 0 ])[3] << '\'' << endl << " dwType : 0x" << setw( 8 ) << hex << idx1[ i * 4 + 1 ] << endl << " dwOffset : 0x" << setw( 8 ) << idx1[ i * 4 + 2 ] << endl // << " (0x" << setw(8) << idx1[i * 4 + 2] + GetDirectoryEntry(movi_list).offset << ')' << endl << " dwSize : 0x" << setw( 8 ) << idx1[ i * 4 + 3 ] << dec << endl; } delete[] idx1; } else if ( entry.type == make_fourcc( "dmlh" ) ) { int i; int numEntries = entry.length / sizeof( int ); DWORD *dmlh = new DWORD[ numEntries ]; fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); fail_neg( read( fd, dmlh, entry.length ) ); for ( i = 0; i < numEntries; ++i ) { cout << ' ' << setw( 4 ) << setfill( ' ' ) << i << setfill( '0' ) << ": " << " dwTotalFrames: 0x" << setw( 8 ) << hex << dmlh[ i ] << " (" << dec << dmlh[ i ] << ")" << endl; } delete[] dmlh; } } /** If this is not a movi list, read its contents */ void AVIFile::ParseList( int parent ) { FOURCC type; FOURCC name; DWORD length; int list; off_t pos; off_t listEnd; /* Read in the chunk header (type and length). */ fail_neg( read( fd, &type, sizeof( type ) ) ); fail_neg( read( fd, &length, sizeof( length ) ) ); if ( length & 1 ) length++; /* The contents of the list starts here. Obtain its offset. The list name (4 bytes) is already part of the contents). */ pos = lseek( fd, 0, SEEK_CUR ); fail_if( pos == ( off_t ) - 1 ); fail_neg( read( fd, &name, sizeof( name ) ) ); /* if we encounter a movi list, do not read it. It takes too much time and we don't need it anyway. */ if ( name != make_fourcc( "movi" ) ) { // if (1) { /* Add an entry for this list. */ list = AddDirectoryEntry( type, name, sizeof( name ), parent ); /* Read in any chunks contained in this list. This list is the parent for all chunks it contains. */ listEnd = pos + length; while ( pos < listEnd ) { ParseChunk( list ); pos = lseek( fd, 0, SEEK_CUR ); fail_if( pos == ( off_t ) - 1 ); } } else { /* Add an entry for this list. */ movi_list = AddDirectoryEntry( type, name, length, parent ); pos = lseek( fd, length - 4, SEEK_CUR ); fail_if( pos == ( off_t ) - 1 ); } } void AVIFile::ParseRIFF() { RIFFFile::ParseRIFF(); avih_chunk = FindDirectoryEntry( make_fourcc( "avih" ) ); if ( avih_chunk != -1 ) ReadChunk( avih_chunk, ( void* ) & mainHdr, sizeof( MainAVIHeader ) ); } void AVIFile::ReadIndex() { indx_chunk[ 0 ] = FindDirectoryEntry( make_fourcc( "indx" ) ); if ( indx_chunk[ 0 ] != -1 ) { ReadChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ], sizeof( AVISuperIndex ) ); index_type = AVI_LARGE_INDEX; /* recalc number of frames from each index */ mainHdr.dwTotalFrames = 0; for ( int i = 0; i < indx[ 0 ] ->nEntriesInUse; mainHdr.dwTotalFrames += indx[ 0 ] ->aIndex[ i++ ].dwDuration ) ; return ; } idx1_chunk = FindDirectoryEntry( make_fourcc( "idx1" ) ); if ( idx1_chunk != -1 ) { ReadChunk( idx1_chunk, ( void* ) idx1, sizeof( AVISuperIndex ) ); idx1->nEntriesInUse = GetDirectoryEntry( idx1_chunk ).length / 16; index_type = AVI_SMALL_INDEX; /* recalc number of frames from the simple index */ int frameNumIndex = 0; FOURCC chunkID1 = make_fourcc( "00dc" ); FOURCC chunkID2 = make_fourcc( "00db" ); for ( int i = 0; i < idx1->nEntriesInUse; ++i ) { if ( idx1->aIndex[ i ].dwChunkId == chunkID1 || idx1->aIndex[ i ].dwChunkId == chunkID2 ) { ++frameNumIndex; } } mainHdr.dwTotalFrames = frameNumIndex; return ; } } void AVIFile::FlushIndx( int stream ) { FOURCC type; FOURCC name; off_t length; off_t offset; int parent; int i; /* Write out the previous index. When this function is entered for the first time, there is no index to write. Note: this may be an expensive operation because of a time consuming seek to the former file position. */ if ( ix_chunk[ stream ] != -1 ) WriteChunk( ix_chunk[ stream ], ix[ stream ] ); /* make a new ix chunk. */ if ( stream == 0 ) type = make_fourcc( "ix00" ); else type = make_fourcc( "ix01" ); ix_chunk[ stream ] = AddDirectoryEntry( type, 0, sizeof( AVIStdIndex ), movi_list ); GetDirectoryEntry( ix_chunk[ stream ], type, name, length, offset, parent ); /* fill out all required fields. The offsets in the array are relative to qwBaseOffset, so fill in the offset to the next free location in the file there. */ ix[ stream ] ->wLongsPerEntry = 2; ix[ stream ] ->bIndexSubType = 0; ix[ stream ] ->bIndexType = KINO_AVI_INDEX_OF_CHUNKS; ix[ stream ] ->nEntriesInUse = 0; ix[ stream ] ->dwChunkId = indx[ stream ] ->dwChunkId; ix[ stream ] ->qwBaseOffset = offset + length; ix[ stream ] ->dwReserved = 0; for ( i = 0; i < IX00_INDEX_SIZE; ++i ) { ix[ stream ] ->aIndex[ i ].dwOffset = 0; ix[ stream ] ->aIndex[ i ].dwSize = 0; } /* add a reference to this new index in our super index. */ i = indx[ stream ] ->nEntriesInUse++; indx[ stream ] ->aIndex[ i ].qwOffset = offset - RIFF_HEADERSIZE; indx[ stream ] ->aIndex[ i ].dwSize = length + RIFF_HEADERSIZE; indx[ stream ] ->aIndex[ i ].dwDuration = 0; } void AVIFile::UpdateIndx( int stream, int chunk, int duration ) { FOURCC type; FOURCC name; off_t length; off_t offset; int parent; int i; /* update the appropiate entry in the super index. It reflects the number of frames in the referenced index. */ i = indx[ stream ] ->nEntriesInUse - 1; indx[ stream ] ->aIndex[ i ].dwDuration += duration; /* update the standard index. Calculate the file position of the new frame. */ GetDirectoryEntry( chunk, type, name, length, offset, parent ); indx[ stream ] ->dwChunkId = type; i = ix[ stream ] ->nEntriesInUse++; ix[ stream ] ->aIndex[ i ].dwOffset = offset - ix[ stream ] ->qwBaseOffset; ix[ stream ] ->aIndex[ i ].dwSize = length; } void AVIFile::UpdateIdx1( int chunk, int flags ) { if ( idx1->nEntriesInUse < 20000 ) { FOURCC type; FOURCC name; off_t length; off_t offset; int parent; GetDirectoryEntry( chunk, type, name, length, offset, parent ); idx1->aIndex[ idx1->nEntriesInUse ].dwChunkId = type; idx1->aIndex[ idx1->nEntriesInUse ].dwFlags = flags; idx1->aIndex[ idx1->nEntriesInUse ].dwOffset = offset - GetDirectoryEntry( movi_list ).offset - RIFF_HEADERSIZE; idx1->aIndex[ idx1->nEntriesInUse ].dwSize = length; idx1->nEntriesInUse++; } } bool AVIFile::verifyStreamFormat( FOURCC type ) { int i, j = 0; AVIStreamHeader avi_stream_header; BITMAPINFOHEADER bih; FOURCC strh = make_fourcc( "strh" ); FOURCC strf = make_fourcc( "strf" ); while ( ( i = FindDirectoryEntry( strh, j++ ) ) != -1 ) { ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) ); if ( avi_stream_header.fccHandler == type ) return true; } j = 0; while ( ( i = FindDirectoryEntry( strf, j++ ) ) != -1 ) { ReadChunk( i, ( void* ) & bih, sizeof( BITMAPINFOHEADER ) ); if ( ( FOURCC ) bih.biCompression == type ) return true; } return false; } bool AVIFile::verifyStream( FOURCC type ) { int i, j = 0; AVIStreamHeader avi_stream_header; FOURCC strh = make_fourcc( "strh" ); while ( ( i = FindDirectoryEntry( strh, j++ ) ) != -1 ) { ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) ); if ( avi_stream_header.fccType == type ) return true; } return false; } bool AVIFile::isOpenDML( void ) { int i, j = 0; FOURCC dmlh = make_fourcc( "dmlh" ); while ( ( i = FindDirectoryEntry( dmlh, j++ ) ) != -1 ) { return true; } return false; } AVI1File::AVI1File() : AVIFile() { memset( &dvinfo, 0, sizeof( dvinfo ) ); } AVI1File::~AVI1File() {} /* Initialize the AVI structure to its initial state, either for PAL or NTSC format */ void AVI1File::Init( int format, int sampleFrequency, int indexType ) { int num_blocks; FOURCC type; FOURCC name; off_t length; off_t offset; int parent; assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) ); AVIFile::Init( format, sampleFrequency, indexType ); switch ( format ) { case AVI_PAL: mainHdr.dwWidth = 720; mainHdr.dwHeight = 576; streamHdr[ 0 ].dwScale = 1; streamHdr[ 0 ].dwRate = 25; streamHdr[ 0 ].dwSuggestedBufferSize = 144008; /* initialize the 'strf' chunk */ /* Meaning of the DV stream format chunk per Microsoft dwDVAAuxSrc Specifies the Audio Auxiliary Data Source Pack for the first audio block (first 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of a frame. A DIF sequence is a data block that contains 150 DIF blocks. A DIF block consists of 80 bytes. The Audio Auxiliary Data Source Pack is defined in section D.7.1 of Part 2, Annex D, "The Pack Header Table and Contents of Packs" of the Specification of Consumer-use Digital VCRs. dwDVAAuxCtl Specifies the Audio Auxiliary Data Source Control Pack for the first audio block of a frame. The Audio Auxiliary Data Control Pack is defined in section D.7.2 of Part 2, Annex D, "The Pack Header Table and Contents of Packs" of the Specification of Consumer-use Digital VCRs. dwDVAAuxSrc1 Specifies the Audio Auxiliary Data Source Pack for the second audio block (second 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of a frame. dwDVAAuxCtl1 Specifies the Audio Auxiliary Data Source Control Pack for the second audio block of a frame. dwDVVAuxSrc Specifies the Video Auxiliary Data Source Pack as defined in section D.8.1 of Part 2, Annex D, "The Pack Header Table and Contents of Packs" of the Specification of Consumer-use Digital VCRs. dwDVVAuxCtl Specifies the Video Auxiliary Data Source Control Pack as defined in section D.8.2 of Part 2, Annex D, "The Pack Header Table and Contents of Packs" of the Specification of Consumer-use Digital VCRs. dwDVReserved[2] Reserved. Set this array to zero. */ dvinfo.dwDVAAuxSrc = 0xd1e030d0; dvinfo.dwDVAAuxCtl = 0xffa0cf3f; dvinfo.dwDVAAuxSrc1 = 0xd1e03fd0; dvinfo.dwDVAAuxCtl1 = 0xffa0cf3f; dvinfo.dwDVVAuxSrc = 0xff20ffff; dvinfo.dwDVVAuxCtl = 0xfffdc83f; dvinfo.dwDVReserved[ 0 ] = 0; dvinfo.dwDVReserved[ 1 ] = 0; break; case AVI_NTSC: mainHdr.dwWidth = 720; mainHdr.dwHeight = 480; streamHdr[ 0 ].dwScale = 1001; streamHdr[ 0 ].dwRate = 30000; streamHdr[ 0 ].dwSuggestedBufferSize = 120008; /* initialize the 'strf' chunk */ dvinfo.dwDVAAuxSrc = 0xc0c000c0; dvinfo.dwDVAAuxCtl = 0xffa0cf3f; dvinfo.dwDVAAuxSrc1 = 0xc0c001c0; dvinfo.dwDVAAuxCtl1 = 0xffa0cf3f; dvinfo.dwDVVAuxSrc = 0xff80ffff; dvinfo.dwDVVAuxCtl = 0xfffcc83f; dvinfo.dwDVReserved[ 0 ] = 0; dvinfo.dwDVReserved[ 1 ] = 0; break; default: /* no default allowed */ assert( 0 ); break; } indx[ 0 ] ->dwChunkId = make_fourcc( "00__" ); /* Initialize the 'strh' chunk */ streamHdr[ 0 ].fccType = make_fourcc( "iavs" ); streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" ); streamHdr[ 0 ].dwFlags = 0; streamHdr[ 0 ].wPriority = 0; streamHdr[ 0 ].wLanguage = 0; streamHdr[ 0 ].dwInitialFrames = 0; streamHdr[ 0 ].dwStart = 0; streamHdr[ 0 ].dwLength = 0; streamHdr[ 0 ].dwQuality = 0; streamHdr[ 0 ].dwSampleSize = 0; streamHdr[ 0 ].rcFrame.top = 0; streamHdr[ 0 ].rcFrame.bottom = 0; streamHdr[ 0 ].rcFrame.left = 0; streamHdr[ 0 ].rcFrame.right = 0; /* This is a simple directory structure setup. For details see the "OpenDML AVI File Format Extensions" document. An AVI file contains basically two types of objects, a "chunk" and a "list" object. The list object contains any number of chunks. Since a list is also a chunk, it is possible to create a hierarchical "list of lists" structure. Every AVI file starts with a "RIFF" object, which is a list of several other required objects. The actual DV data is contained in a "movi" list, each frame is in its own chunk. Old AVI files (pre OpenDML V. 1.02) contain only one RIFF chunk of less than 1 GByte size per file. The current format which allow for almost arbitrary sizes can contain several RIFF chunks of less than 1 GByte size. Old software however would only deal with the first RIFF chunk. Note that the first entry (FILE) isn�t actually part of the AVI file. I use this (pseudo-) directory entry to keep track of the RIFF chunks and their positions in the AVI file. */ /* Create the container directory entry */ file_list = AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT ); /* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */ riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVI " ), RIFF_LISTSIZE, file_list ); hdrl_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "hdrl" ), RIFF_LISTSIZE, riff_list ); avih_chunk = AddDirectoryEntry( make_fourcc( "avih" ), 0, sizeof( MainAVIHeader ), hdrl_list ); strl_list[ 0 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list ); strh_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 0 ] ); strf_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( dvinfo ), strl_list[ 0 ] ); if ( index_type & AVI_LARGE_INDEX ) indx_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 0 ] ); odml_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "odml" ), RIFF_LISTSIZE, hdrl_list ); dmlh_chunk = AddDirectoryEntry( make_fourcc( "dmlh" ), 0, 0x00f8, odml_list ); /* align movi list to block */ GetDirectoryEntry( hdrl_list, type, name, length, offset, parent ); num_blocks = length / PADDING_SIZE + 1; length = num_blocks * PADDING_SIZE - length - 5 * RIFF_HEADERSIZE; // why 5? junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list ); movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list ); /* The ix00 chunk will be added dynamically to the movi_list in avi_write_frame as needed */ ix_chunk[ 0 ] = -1; } /* Write a DV video frame. This is somewhat complex... */ #if 0 bool AVI1File::WriteFrame( const Frame &frame ) { int frame_chunk; int junk_chunk; int num_blocks; FOURCC type; FOURCC name; off_t length; off_t offset; int parent; /* exit if no large index and 1GB reached */ if ( !( index_type & AVI_LARGE_INDEX ) && isUpdateIdx1 == false ) return false; /* Check if we need a new ix00 Standard Index. It has a capacity of IX00_INDEX_SIZE frames. Whenever we exceed that number, we need a new index. The new ix00 chunk is also part of the movi list. */ if ( ( index_type & AVI_LARGE_INDEX ) && ( ( ( streamHdr[ 0 ].dwLength - 0 ) % IX00_INDEX_SIZE ) == 0 ) ) FlushIndx( 0 ); /* Write the DV frame data. Make a new 00__ chunk for the new frame, write out the frame. */ frame_chunk = AddDirectoryEntry( make_fourcc( "00__" ), 0, frame.GetFrameSize(), movi_list ); if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 ) { GetDirectoryEntry( frame_chunk, type, name, length, offset, parent ); ix[ 0 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE; } WriteChunk( frame_chunk, frame.data ); // num_blocks = (frame.GetFrameSize() + RIFF_HEADERSIZE) / PADDING_SIZE + 1; // length = num_blocks * PADDING_SIZE - frame.GetFrameSize() - 2 * RIFF_HEADERSIZE; // junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list); // WriteChunk(junk_chunk, g_zeroes); if ( index_type & AVI_LARGE_INDEX ) UpdateIndx( 0, frame_chunk, 1 ); if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 ) UpdateIdx1( frame_chunk, 0x10 ); /* update some variables with the new frame count. */ if ( isUpdateIdx1 ) ++mainHdr.dwTotalFrames; ++streamHdr[ 0 ].dwLength; ++dmlh[ 0 ]; /* Find out if the current riff list is close to 1 GByte in size. If so, start a new (extended) RIFF. The only allowed item in the new RIFF chunk is a movi list (with video frames and indexes as usual). */ GetDirectoryEntry( riff_list, type, name, length, offset, parent ); if ( length > 0x3f000000 ) { /* write idx1 only once and before end of first GB */ if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 ) { int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list ); WriteChunk( idx1_chunk, ( void* ) idx1 ); } isUpdateIdx1 = false; if ( index_type & AVI_LARGE_INDEX ) { /* pad out to 1GB */ //GetDirectoryEntry(riff_list, type, name, length, offset, parent); //junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, PADDING_1GB - length - 5 * RIFF_HEADERSIZE, riff_list); //WriteChunk(junk_chunk, g_zeroes); /* padding for alignment */ GetDirectoryEntry( riff_list, type, name, length, offset, parent ); num_blocks = ( length + 4 * RIFF_HEADERSIZE ) / PADDING_SIZE + 1; length = ( num_blocks * PADDING_SIZE ) - length - 4 * RIFF_HEADERSIZE - 2 * RIFF_LISTSIZE; if ( length > 0 ) { junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list ); WriteChunk( junk_chunk, g_zeroes ); } riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVIX" ), RIFF_LISTSIZE, file_list ); movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list ); } } return true; } #endif void AVI1File::WriteRIFF() { WriteChunk( avih_chunk, ( void* ) & mainHdr ); WriteChunk( strh_chunk[ 0 ], ( void* ) & streamHdr[ 0 ] ); WriteChunk( strf_chunk[ 0 ], ( void* ) & dvinfo ); WriteChunk( dmlh_chunk, ( void* ) & dmlh ); if ( index_type & AVI_LARGE_INDEX ) { WriteChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ] ); WriteChunk( ix_chunk[ 0 ], ( void* ) ix[ 0 ] ); } if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 ) { int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list ); WriteChunk( idx1_chunk, ( void* ) idx1 ); } RIFFFile::WriteRIFF(); } AVI2File::AVI2File() : AVIFile() {} AVI2File::~AVI2File() {} /* Initialize the AVI structure to its initial state, either for PAL or NTSC format */ void AVI2File::Init( int format, int sampleFrequency, int indexType ) { int num_blocks; FOURCC type; FOURCC name; off_t length; off_t offset; int parent; assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) ); AVIFile::Init( format, sampleFrequency, indexType ); switch ( format ) { case AVI_PAL: mainHdr.dwStreams = 2; mainHdr.dwWidth = 720; mainHdr.dwHeight = 576; /* Initialize the 'strh' chunk */ streamHdr[ 0 ].fccType = make_fourcc( "vids" ); streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" ); streamHdr[ 0 ].dwFlags = 0; streamHdr[ 0 ].wPriority = 0; streamHdr[ 0 ].wLanguage = 0; streamHdr[ 0 ].dwInitialFrames = 0; streamHdr[ 0 ].dwScale = 1; streamHdr[ 0 ].dwRate = 25; streamHdr[ 0 ].dwStart = 0; streamHdr[ 0 ].dwLength = 0; streamHdr[ 0 ].dwSuggestedBufferSize = 144008; streamHdr[ 0 ].dwQuality = -1; streamHdr[ 0 ].dwSampleSize = 0; streamHdr[ 0 ].rcFrame.top = 0; streamHdr[ 0 ].rcFrame.bottom = 0; streamHdr[ 0 ].rcFrame.left = 0; streamHdr[ 0 ].rcFrame.right = 0; bitmapinfo.biSize = sizeof( bitmapinfo ); bitmapinfo.biWidth = 720; bitmapinfo.biHeight = 576; bitmapinfo.biPlanes = 1; bitmapinfo.biBitCount = 24; bitmapinfo.biCompression = make_fourcc( "dvsd" ); bitmapinfo.biSizeImage = 144000; bitmapinfo.biXPelsPerMeter = 0; bitmapinfo.biYPelsPerMeter = 0; bitmapinfo.biClrUsed = 0; bitmapinfo.biClrImportant = 0; streamHdr[ 1 ].fccType = make_fourcc( "auds" ); streamHdr[ 1 ].fccHandler = 0; streamHdr[ 1 ].dwFlags = 0; streamHdr[ 1 ].wPriority = 0; streamHdr[ 1 ].wLanguage = 0; streamHdr[ 1 ].dwInitialFrames = 0; streamHdr[ 1 ].dwScale = 2 * 2; streamHdr[ 1 ].dwRate = sampleFrequency * 2 * 2; streamHdr[ 1 ].dwStart = 0; streamHdr[ 1 ].dwLength = 0; streamHdr[ 1 ].dwSuggestedBufferSize = 8192; streamHdr[ 1 ].dwQuality = -1; streamHdr[ 1 ].dwSampleSize = 2 * 2; streamHdr[ 1 ].rcFrame.top = 0; streamHdr[ 1 ].rcFrame.bottom = 0; streamHdr[ 1 ].rcFrame.left = 0; streamHdr[ 1 ].rcFrame.right = 0; break; case AVI_NTSC: mainHdr.dwTotalFrames = 0; mainHdr.dwStreams = 2; mainHdr.dwWidth = 720; mainHdr.dwHeight = 480; /* Initialize the 'strh' chunk */ streamHdr[ 0 ].fccType = make_fourcc( "vids" ); streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" ); streamHdr[ 0 ].dwFlags = 0; streamHdr[ 0 ].wPriority = 0; streamHdr[ 0 ].wLanguage = 0; streamHdr[ 0 ].dwInitialFrames = 0; streamHdr[ 0 ].dwScale = 1001; streamHdr[ 0 ].dwRate = 30000; streamHdr[ 0 ].dwStart = 0; streamHdr[ 0 ].dwLength = 0; streamHdr[ 0 ].dwSuggestedBufferSize = 120008; streamHdr[ 0 ].dwQuality = -1; streamHdr[ 0 ].dwSampleSize = 0; streamHdr[ 0 ].rcFrame.top = 0; streamHdr[ 0 ].rcFrame.bottom = 0; streamHdr[ 0 ].rcFrame.left = 0; streamHdr[ 0 ].rcFrame.right = 0; bitmapinfo.biSize = sizeof( bitmapinfo ); bitmapinfo.biWidth = 720; bitmapinfo.biHeight = 480; bitmapinfo.biPlanes = 1; bitmapinfo.biBitCount = 24; bitmapinfo.biCompression = make_fourcc( "dvsd" ); bitmapinfo.biSizeImage = 120000; bitmapinfo.biXPelsPerMeter = 0; bitmapinfo.biYPelsPerMeter = 0; bitmapinfo.biClrUsed = 0; bitmapinfo.biClrImportant = 0; streamHdr[ 1 ].fccType = make_fourcc( "auds" ); streamHdr[ 1 ].fccHandler = 0; streamHdr[ 1 ].dwFlags = 0; streamHdr[ 1 ].wPriority = 0; streamHdr[ 1 ].wLanguage = 0; streamHdr[ 1 ].dwInitialFrames = 1; streamHdr[ 1 ].dwScale = 2 * 2; streamHdr[ 1 ].dwRate = sampleFrequency * 2 * 2; streamHdr[ 1 ].dwStart = 0; streamHdr[ 1 ].dwLength = 0; streamHdr[ 1 ].dwSuggestedBufferSize = 8192; streamHdr[ 1 ].dwQuality = 0; streamHdr[ 1 ].dwSampleSize = 2 * 2; streamHdr[ 1 ].rcFrame.top = 0; streamHdr[ 1 ].rcFrame.bottom = 0; streamHdr[ 1 ].rcFrame.left = 0; streamHdr[ 1 ].rcFrame.right = 0; break; } waveformatex.wFormatTag = 1; waveformatex.nChannels = 2; waveformatex.nSamplesPerSec = sampleFrequency; waveformatex.nAvgBytesPerSec = sampleFrequency * 2 * 2; waveformatex.nBlockAlign = 4; waveformatex.wBitsPerSample = 16; waveformatex.cbSize = 0; file_list = AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT ); /* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */ riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVI " ), RIFF_LISTSIZE, file_list ); hdrl_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "hdrl" ), RIFF_LISTSIZE, riff_list ); avih_chunk = AddDirectoryEntry( make_fourcc( "avih" ), 0, sizeof( MainAVIHeader ), hdrl_list ); strl_list[ 0 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list ); strh_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 0 ] ); strf_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( BITMAPINFOHEADER ), strl_list[ 0 ] ); if ( index_type & AVI_LARGE_INDEX ) { indx_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 0 ] ); ix_chunk[ 0 ] = -1; indx[ 0 ] ->dwChunkId = make_fourcc( "00dc" ); } strl_list[ 1 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list ); strh_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 1 ] ); strf_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( WAVEFORMATEX ) - 2, strl_list[ 1 ] ); junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, 2, strl_list[ 1 ] ); if ( index_type & AVI_LARGE_INDEX ) { indx_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 1 ] ); ix_chunk[ 1 ] = -1; indx[ 1 ] ->dwChunkId = make_fourcc( "01wb" ); odml_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "odml" ), RIFF_LISTSIZE, hdrl_list ); dmlh_chunk = AddDirectoryEntry( make_fourcc( "dmlh" ), 0, 0x00f8, odml_list ); } /* align movi list to block */ GetDirectoryEntry( hdrl_list, type, name, length, offset, parent ); num_blocks = length / PADDING_SIZE + 1; length = num_blocks * PADDING_SIZE - length - 5 * RIFF_HEADERSIZE; // why 5 headers? junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list ); movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list ); idx1->aIndex[ idx1->nEntriesInUse ].dwChunkId = make_fourcc( "7Fxx" ); idx1->aIndex[ idx1->nEntriesInUse ].dwFlags = 0; idx1->aIndex[ idx1->nEntriesInUse ].dwOffset = 0; idx1->aIndex[ idx1->nEntriesInUse ].dwSize = 0; idx1->nEntriesInUse++; } void AVI2File::WriteRIFF() { WriteChunk( avih_chunk, ( void* ) & mainHdr ); WriteChunk( strh_chunk[ 0 ], ( void* ) & streamHdr[ 0 ] ); WriteChunk( strf_chunk[ 0 ], ( void* ) & bitmapinfo ); if ( index_type & AVI_LARGE_INDEX ) { WriteChunk( dmlh_chunk, ( void* ) & dmlh ); WriteChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ] ); WriteChunk( ix_chunk[ 0 ], ( void* ) ix[ 0 ] ); } WriteChunk( strh_chunk[ 1 ], ( void* ) & streamHdr[ 1 ] ); WriteChunk( strf_chunk[ 1 ], ( void* ) & waveformatex ); if ( index_type & AVI_LARGE_INDEX ) { WriteChunk( indx_chunk[ 1 ], ( void* ) indx[ 1 ] ); WriteChunk( ix_chunk[ 1 ], ( void* ) ix[ 1 ] ); } if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 ) { int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list ); WriteChunk( idx1_chunk, ( void* ) idx1 ); } RIFFFile::WriteRIFF(); } /** Write a DV video frame \param frame the frame to write */ #if 0 bool AVI2File::WriteFrame( const Frame &frame ) { int audio_chunk; int frame_chunk; int junk_chunk; char soundbuf[ 20000 ]; int audio_size; int num_blocks; FOURCC type; FOURCC name; off_t length; off_t offset; int parent; /* exit if no large index and 1GB reached */ if ( !( index_type & AVI_LARGE_INDEX ) && isUpdateIdx1 == false ) return false; /* Check if we need a new ix00 Standard Index. It has a capacity of IX00_INDEX_SIZE frames. Whenever we exceed that number, we need a new index. The new ix00 chunk is also part of the movi list. */ if ( ( index_type & AVI_LARGE_INDEX ) && ( ( ( streamHdr[ 0 ].dwLength - 0 ) % IX00_INDEX_SIZE ) == 0 ) ) { FlushIndx( 0 ); FlushIndx( 1 ); } /* Write audio data if we have it */ audio_size = frame.ExtractAudio( soundbuf ); if ( audio_size > 0 ) { audio_chunk = AddDirectoryEntry( make_fourcc( "01wb" ), 0, audio_size, movi_list ); if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 ) { GetDirectoryEntry( audio_chunk, type, name, length, offset, parent ); ix[ 1 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE; } WriteChunk( audio_chunk, soundbuf ); // num_blocks = (audio_size + RIFF_HEADERSIZE) / PADDING_SIZE + 1; // length = num_blocks * PADDING_SIZE - audio_size - 2 * RIFF_HEADERSIZE; // junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list); // WriteChunk(junk_chunk, g_zeroes); if ( index_type & AVI_LARGE_INDEX ) UpdateIndx( 1, audio_chunk, audio_size / waveformatex.nChannels / 2 ); if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 ) UpdateIdx1( audio_chunk, 0x00 ); streamHdr[ 1 ].dwLength += audio_size / waveformatex.nChannels / 2; } /* Write video data */ frame_chunk = AddDirectoryEntry( make_fourcc( "00dc" ), 0, frame.GetFrameSize(), movi_list ); if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 ) { GetDirectoryEntry( frame_chunk, type, name, length, offset, parent ); ix[ 0 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE; } WriteChunk( frame_chunk, frame.data ); // num_blocks = (frame.GetFrameSize() + RIFF_HEADERSIZE) / PADDING_SIZE + 1; // length = num_blocks * PADDING_SIZE - frame.GetFrameSize() - 2 * RIFF_HEADERSIZE; // junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list); // WriteChunk(junk_chunk, g_zeroes); if ( index_type & AVI_LARGE_INDEX ) UpdateIndx( 0, frame_chunk, 1 ); if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 ) UpdateIdx1( frame_chunk, 0x10 ); /* update some variables with the new frame count. */ if ( isUpdateIdx1 ) ++mainHdr.dwTotalFrames; ++streamHdr[ 0 ].dwLength; ++dmlh[ 0 ]; /* Find out if the current riff list is close to 1 GByte in size. If so, start a new (extended) RIFF. The only allowed item in the new RIFF chunk is a movi list (with video frames and indexes as usual). */ GetDirectoryEntry( riff_list, type, name, length, offset, parent ); if ( length > 0x3f000000 ) { /* write idx1 only once and before end of first GB */ if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 ) { int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list ); WriteChunk( idx1_chunk, ( void* ) idx1 ); } isUpdateIdx1 = false; if ( index_type & AVI_LARGE_INDEX ) { /* padding for alignment */ GetDirectoryEntry( riff_list, type, name, length, offset, parent ); num_blocks = ( length + 4 * RIFF_HEADERSIZE ) / PADDING_SIZE + 1; length = ( num_blocks * PADDING_SIZE ) - length - 4 * RIFF_HEADERSIZE - 2 * RIFF_LISTSIZE; if ( length > 0 ) { junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list ); WriteChunk( junk_chunk, g_zeroes ); } riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVIX" ), RIFF_LISTSIZE, file_list ); movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list ); } } return true; } #endif void AVI1File::setDVINFO( DVINFO &info ) { // do not do this until debugged audio against DirectShow return ; dvinfo.dwDVAAuxSrc = info.dwDVAAuxSrc; dvinfo.dwDVAAuxCtl = info.dwDVAAuxCtl; dvinfo.dwDVAAuxSrc1 = info.dwDVAAuxSrc1; dvinfo.dwDVAAuxCtl1 = info.dwDVAAuxCtl1; dvinfo.dwDVVAuxSrc = info.dwDVVAuxSrc; dvinfo.dwDVVAuxCtl = info.dwDVVAuxCtl; } void AVI2File::setDVINFO( DVINFO &info ) {} void AVIFile::setFccHandler( FOURCC type, FOURCC handler ) { for ( int i = 0; i < mainHdr.dwStreams; i++ ) { if ( streamHdr[ i ].fccType == type ) { int k, j = 0; FOURCC strf = make_fourcc( "strf" ); BITMAPINFOHEADER bih; streamHdr[ i ].fccHandler = handler; while ( ( k = FindDirectoryEntry( strf, j++ ) ) != -1 ) { ReadChunk( k, ( void* ) & bih, sizeof( BITMAPINFOHEADER ) ); bih.biCompression = handler; } } } } bool AVIFile::getStreamFormat( void* data, FOURCC type ) { int i, j = 0; FOURCC strh = make_fourcc( "strh" ); FOURCC strf = make_fourcc( "strf" ); AVIStreamHeader avi_stream_header; bool result = false; while ( ( result == false ) && ( i = FindDirectoryEntry( strh, j++ ) ) != -1 ) { ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) ); if ( avi_stream_header.fccType == type ) { FOURCC chunkID; int size; pthread_mutex_lock( &file_mutex ); fail_neg( read( fd, &chunkID, sizeof( FOURCC ) ) ); if ( chunkID == strf ) { fail_neg( read( fd, &size, sizeof( int ) ) ); fail_neg( read( fd, data, size ) ); result = true; } pthread_mutex_unlock( &file_mutex ); } } return result; } mlt-0.9.0/src/modules/kino/avi.h000066400000000000000000000163501215300731300164430ustar00rootroot00000000000000/* * avi.h library for AVI file format i/o * Copyright (C) 2000 - 2002 Arne Schirmacher * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** Common AVI declarations Some of this comes from the public domain AVI specification, which explains the microsoft-style definitions. \file avi.h */ #ifndef _AVI_H #define _AVI_H 1 #include #include "riff.h" #define PACKED(x) __attribute__((packed)) x #define AVI_SMALL_INDEX (0x01) #define AVI_LARGE_INDEX (0x02) #define KINO_AVI_INDEX_OF_INDEXES (0x00) #define KINO_AVI_INDEX_OF_CHUNKS (0x01) #define AVI_INDEX_2FIELD (0x01) enum { AVI_PAL, AVI_NTSC, AVI_AUDIO_48KHZ, AVI_AUDIO_44KHZ, AVI_AUDIO_32KHZ }; /** Declarations of the main AVI file header The contents of this struct goes into the 'avih' chunk. */ typedef struct { /// frame display rate (or 0L) DWORD dwMicroSecPerFrame; /// max. transfer rate DWORD dwMaxBytesPerSec; /// pad to multiples of this size, normally 2K DWORD dwPaddingGranularity; /// the ever-present flags DWORD dwFlags; /// # frames in file DWORD dwTotalFrames; DWORD dwInitialFrames; DWORD dwStreams; DWORD dwSuggestedBufferSize; DWORD dwWidth; DWORD dwHeight; DWORD dwReserved[ 4 ]; } PACKED(MainAVIHeader); typedef struct { WORD top, bottom, left, right; } PACKED(RECT); /** Declaration of a stream header The contents of this struct goes into the 'strh' header. */ typedef struct { FOURCC fccType; FOURCC fccHandler; DWORD dwFlags; /* Contains AVITF_* flags */ WORD wPriority; WORD wLanguage; DWORD dwInitialFrames; DWORD dwScale; DWORD dwRate; /* dwRate / dwScale == samples/second */ DWORD dwStart; DWORD dwLength; /* In units above... */ DWORD dwSuggestedBufferSize; DWORD dwQuality; DWORD dwSampleSize; RECT rcFrame; } PACKED(AVIStreamHeader); typedef struct { DWORD dwDVAAuxSrc; DWORD dwDVAAuxCtl; DWORD dwDVAAuxSrc1; DWORD dwDVAAuxCtl1; DWORD dwDVVAuxSrc; DWORD dwDVVAuxCtl; DWORD dwDVReserved[ 2 ]; } PACKED(DVINFO); typedef struct { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; char dummy[ 1040 ]; } PACKED(BITMAPINFOHEADER); typedef struct { WORD wFormatTag; WORD nChannels; DWORD nSamplesPerSec; DWORD nAvgBytesPerSec; WORD nBlockAlign; WORD wBitsPerSample; WORD cbSize; WORD dummy; } PACKED(WAVEFORMATEX); typedef struct { WORD wLongsPerEntry; BYTE bIndexSubType; BYTE bIndexType; DWORD nEntriesInUse; FOURCC dwChunkId; DWORD dwReserved[ 3 ]; struct avisuperindex_entry { QUADWORD qwOffset; DWORD dwSize; DWORD dwDuration; } aIndex[ 3198 ]; } PACKED(AVISuperIndex); typedef struct { WORD wLongsPerEntry; BYTE bIndexSubType; BYTE bIndexType; DWORD nEntriesInUse; FOURCC dwChunkId; QUADWORD qwBaseOffset; DWORD dwReserved; struct avifieldindex_entry { DWORD dwOffset; DWORD dwSize; } aIndex[ 17895 ]; } PACKED(AVIStdIndex); typedef struct { struct avisimpleindex_entry { FOURCC dwChunkId; DWORD dwFlags; DWORD dwOffset; DWORD dwSize; } aIndex[ 20000 ]; DWORD nEntriesInUse; } PACKED(AVISimpleIndex); typedef struct { DWORD dirEntryType; DWORD dirEntryName; DWORD dirEntryLength; size_t dirEntryOffset; int dirEntryWrittenFlag; int dirEntryParentList; } AviDirEntry; /** base class for all AVI type files It contains methods and members which are the same in all AVI type files regardless of the particular compression, number of streams etc. The AVIFile class also contains methods for handling several indexes to the video frame content. */ class AVIFile : public RIFFFile { public: AVIFile(); AVIFile( const AVIFile& ); virtual ~AVIFile(); virtual AVIFile& operator=( const AVIFile& ); virtual void Init( int format, int sampleFrequency, int indexType ); virtual int GetDVFrameInfo( off_t &offset, int &size, int frameNum ); virtual int GetFrameInfo( off_t &offset, int &size, int frameNum, FOURCC chunkID ); virtual int GetDVFrame( uint8_t *data, int frameNum ); virtual int getFrame( void *data, int frameNum, FOURCC chunkID ); virtual int GetTotalFrames() const; virtual void PrintDirectoryEntryData( const RIFFDirEntry &entry ) const; //virtual bool WriteFrame( const Frame &frame ) { return false; } virtual void ParseList( int parent ); virtual void ParseRIFF( void ); virtual void ReadIndex( void ); virtual void WriteRIFF( void ) { } virtual void FlushIndx( int stream ); virtual void UpdateIndx( int stream, int chunk, int duration ); virtual void UpdateIdx1( int chunk, int flags ); virtual bool verifyStreamFormat( FOURCC type ); virtual bool verifyStream( FOURCC type ); virtual bool isOpenDML( void ); virtual void setDVINFO( DVINFO& ) { } virtual void setFccHandler( FOURCC type, FOURCC handler ); virtual bool getStreamFormat( void* data, FOURCC type ); protected: MainAVIHeader mainHdr; AVISimpleIndex *idx1; int file_list; int riff_list; int hdrl_list; int avih_chunk; int movi_list; int junk_chunk; int idx1_chunk; AVIStreamHeader streamHdr[ 2 ]; AVISuperIndex *indx[ 2 ]; AVIStdIndex *ix[ 2 ]; int indx_chunk[ 2 ]; int ix_chunk[ 2 ]; int strl_list[ 2 ]; int strh_chunk[ 2 ]; int strf_chunk[ 2 ]; int index_type; int current_ix00; DWORD dmlh[ 62 ]; int odml_list; int dmlh_chunk; bool isUpdateIdx1; }; /** writing Type 1 DV AVIs */ class AVI1File : public AVIFile { public: AVI1File(); virtual ~AVI1File(); virtual void Init( int format, int sampleFrequency, int indexType ); //virtual bool WriteFrame( const Frame &frame ); virtual void WriteRIFF( void ); virtual void setDVINFO( DVINFO& ); private: DVINFO dvinfo; AVI1File( const AVI1File& ); AVI1File& operator=( const AVI1File& ); }; /** writing Type 2 (separate audio data) DV AVIs This file type contains both audio and video tracks. It is therefore more compatible to certain Windows programs, which expect any AVI having both audio and video tracks. The video tracks contain the raw DV data (as in type 1) and the extracted audio tracks. Note that because the DV data contains audio information anyway, this means duplication of data and a slight increase of file size. */ class AVI2File : public AVIFile { public: AVI2File(); virtual ~AVI2File(); virtual void Init( int format, int sampleFrequency, int indexType ); //virtual bool WriteFrame( const Frame &frame ); virtual void WriteRIFF( void ); virtual void setDVINFO( DVINFO& ); private: BITMAPINFOHEADER bitmapinfo; WAVEFORMATEX waveformatex; AVI2File( const AVI2File& ); AVI2File& operator=( const AVI2File& ); }; #endif mlt-0.9.0/src/modules/kino/configure000077500000000000000000000015411215300731300174160ustar00rootroot00000000000000#!/bin/sh if [ "$help" != "1" ] then if [ "$targetos" = "Darwin" ] || [ "$targetos" = "MinGW" ] then echo "- does not build on OS X or Windows: disabling" touch ../disable-kino exit 0 fi # Entirely optional... pkg-config libquicktime 2> /dev/null lqt_disabled=$? pkg-config libdv 2> /dev/null libdv_disabled=$? echo > config.h [ "$lqt_disabled" = "0" ] && echo "#define HAVE_LIBQUICKTIME" >> config.h [ "$libdv_disabled" = "0" ] && echo "#define HAVE_LIBDV" >> config.h echo > config.mak [ "$lqt_disabled" = "0" ] && echo "HAVE_LIBQUICKTIME=1" >> config.mak [ "$libdv_disabled" = "0" ] && echo "HAVE_LIBDV=1" >> config.mak [ "$lqt_disabled" != "0" ] && echo "- libquicktime not found: only enabling dv avi support" [ "$libdv_disabled" != "0" -a "$lqt_disabled" = "0" ] && echo "- libdv not found: mov dv may not have audio" exit 0 fi mlt-0.9.0/src/modules/kino/endian_types.h000066400000000000000000000137741215300731300203550ustar00rootroot00000000000000/* * * Quick hack to handle endianness and word length issues. * Defines _le, _be, and _ne variants to standard ISO types * like int32_t, that are stored in little-endian, big-endian, * and native-endian byteorder in memory, respectively. * Caveat: int32_le_t and friends cannot be used in vararg * functions like printf() without an explicit cast. * * Copyright (c) 2003-2005 Daniel Kobras * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ENDIAN_TYPES_H #define _ENDIAN_TYPES_H /* Needed for BYTE_ORDER and BIG/LITTLE_ENDIAN macros. */ #if !defined(__FreeBSD__) && !defined(__NetBSD__) #ifndef _BSD_SOURCE # define _BSD_SOURCE # include # undef _BSD_SOURCE #else # include #endif #else # include #endif /* !defined(__FreeBSD__) && !defined(__NetBSD__) */ #include #if !defined(__FreeBSD__) && !defined(__NetBSD__) #include #else #define bswap_16(x) bswap16(x) #define bswap_32(x) bswap32(x) #define bswap_64(x) bswap64(x) #endif /* !defined(__FreeBSD__) && !defined(__NetBSD__) */ static inline int8_t bswap(const int8_t& x) { return x; } static inline u_int8_t bswap(const u_int8_t& x) { return x; } static inline int16_t bswap(const int16_t& x) { return bswap_16(x); } static inline u_int16_t bswap(const u_int16_t& x) { return bswap_16(x); } static inline int32_t bswap(const int32_t& x) { return bswap_32(x); } static inline u_int32_t bswap(const u_int32_t& x) { return bswap_32(x); } static inline int64_t bswap(const int64_t& x) { return bswap_64(x); } static inline u_int64_t bswap(const u_int64_t& x) { return bswap_64(x); } #define le_to_cpu cpu_to_le #define be_to_cpu cpu_to_be template static inline T cpu_to_le(const T& x) { #if BYTE_ORDER == LITTLE_ENDIAN return x; #else return bswap(x); #endif } template static inline T cpu_to_be(const T& x) { #if BYTE_ORDER == LITTLE_ENDIAN return bswap(x); #else return x; #endif } template class le_t { T m; T read() const { return le_to_cpu(m); }; void write(const T& n) { m = cpu_to_le(n); }; public: le_t(void) { m = 0; }; le_t(const T& o) { write(o); }; operator T() const { return read(); }; le_t operator++() { write(read() + 1); return *this; }; le_t operator++(int) { write(read() + 1); return *this; }; le_t operator--() { write(read() - 1); return *this; }; le_t operator--(int) { write(read() - 1); return *this; }; le_t& operator+=(const T& t) { write(read() + t); return *this; }; le_t& operator-=(const T& t) { write(read() - t); return *this; }; le_t& operator&=(const le_t& t) { m &= t.m; return *this; }; le_t& operator|=(const le_t& t) { m |= t.m; return *this; }; } __attribute__((packed)); /* Just copy-and-pasted from le_t. Too lazy to do it right. */ template class be_t { T m; T read() const { return be_to_cpu(m); }; void write(const T& n) { m = cpu_to_be(n); }; public: be_t(void) { m = 0; }; be_t(const T& o) { write(o); }; operator T() const { return read(); }; be_t operator++() { write(read() + 1); return *this; }; be_t operator++(int) { write(read() + 1); return *this; }; be_t operator--() { write(read() - 1); return *this; }; be_t operator--(int) { write(read() - 1); return *this; }; be_t& operator+=(const T& t) { write(read() + t); return *this; }; be_t& operator-=(const T& t) { write(read() - t); return *this; }; be_t& operator&=(const be_t& t) { m &= t.m; return *this; }; be_t& operator|=(const be_t& t) { m |= t.m; return *this; }; } __attribute__((packed)); /* Define types of native endianness similar to the little and big endian * versions below. Not really necessary but useful occasionally to emphasize * endianness of data. */ typedef int8_t int8_ne_t; typedef int16_t int16_ne_t; typedef int32_t int32_ne_t; typedef int64_t int64_ne_t; typedef u_int8_t u_int8_ne_t; typedef u_int16_t u_int16_ne_t; typedef u_int32_t u_int32_ne_t; typedef u_int64_t u_int64_ne_t; /* The classes work on their native endianness as well, but obviously * introduce some overhead. Use the faster typedefs to native types * therefore, unless you're debugging. */ #if BYTE_ORDER == LITTLE_ENDIAN typedef int8_ne_t int8_le_t; typedef int16_ne_t int16_le_t; typedef int32_ne_t int32_le_t; typedef int64_ne_t int64_le_t; typedef u_int8_ne_t u_int8_le_t; typedef u_int16_ne_t u_int16_le_t; typedef u_int32_ne_t u_int32_le_t; typedef u_int64_ne_t u_int64_le_t; typedef int8_t int8_be_t; typedef be_t int16_be_t; typedef be_t int32_be_t; typedef be_t int64_be_t; typedef u_int8_t u_int8_be_t; typedef be_t u_int16_be_t; typedef be_t u_int32_be_t; typedef be_t u_int64_be_t; #else typedef int8_ne_t int8_be_t; typedef int16_ne_t int16_be_t; typedef int32_ne_t int32_be_t; typedef int64_ne_t int64_be_t; typedef u_int8_ne_t u_int8_be_t; typedef u_int16_ne_t u_int16_be_t; typedef u_int32_ne_t u_int32_be_t; typedef u_int64_ne_t u_int64_be_t; typedef int8_t int8_le_t; typedef le_t int16_le_t; typedef le_t int32_le_t; typedef le_t int64_le_t; typedef u_int8_t u_int8_le_t; typedef le_t u_int16_le_t; typedef le_t u_int32_le_t; typedef le_t u_int64_le_t; #endif #endif mlt-0.9.0/src/modules/kino/error.cc000066400000000000000000000050141215300731300171460ustar00rootroot00000000000000/* * error.cc Error handling * Copyright (C) 2000 Arne Schirmacher * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif // C++ includes #include #include #include #include using std::ostringstream; using std::string; using std::endl; using std::ends; using std::cerr; // C includes #include #include // local includes #include "error.h" void real_fail_neg( int eval, const char *eval_str, const char *func, const char *file, int line ) { if ( eval < 0 ) { string exc; ostringstream sb; sb << file << ":" << line << ": In function \"" << func << "\": \"" << eval_str << "\" evaluated to " << eval; if ( errno != 0 ) sb << endl << file << ":" << line << ": errno: " << errno << " (" << strerror( errno ) << ")"; sb << ends; exc = sb.str(); cerr << exc << endl; throw exc; } } /** error handler for NULL result codes Whenever this is called with a NULL argument, it will throw an exception. Typically used with functions like malloc() and new(). */ void real_fail_null( const void *eval, const char *eval_str, const char *func, const char *file, int line ) { if ( eval == NULL ) { string exc; ostringstream sb; sb << file << ":" << line << ": In function \"" << func << "\": " << eval_str << " is NULL" << ends; exc = sb.str(); cerr << exc << endl; throw exc; } } void real_fail_if( bool eval, const char *eval_str, const char *func, const char *file, int line ) { if ( eval == true ) { string exc; ostringstream sb; sb << file << ":" << line << ": In function \"" << func << "\": condition \"" << eval_str << "\" is true"; if ( errno != 0 ) sb << endl << file << ":" << line << ": errno: " << errno << " (" << strerror( errno ) << ")"; sb << ends; exc = sb.str(); cerr << exc << endl; throw exc; } } mlt-0.9.0/src/modules/kino/error.h000066400000000000000000000033021215300731300170060ustar00rootroot00000000000000/* * error.h Error handling * Copyright (C) 2000 Arne Schirmacher * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ERROR_H #define _ERROR_H 1 #ifdef __cplusplus extern "C" { #endif /* * Should check for gcc/g++ and version > 2.6 I suppose */ #ifndef __ASSERT_FUNCTION # define __ASSERT_FUNCTION __PRETTY_FUNCTION__ #endif #define fail_neg(eval) real_fail_neg (eval, #eval, __ASSERT_FUNCTION, __FILE__, __LINE__) #define fail_null(eval) real_fail_null (eval, #eval, __ASSERT_FUNCTION, __FILE__, __LINE__) #define fail_if(eval) real_fail_if (eval, #eval, __ASSERT_FUNCTION, __FILE__, __LINE__) void real_fail_neg ( int eval, const char * eval_str, const char * func, const char * file, int line ); void real_fail_null ( const void * eval, const char * eval_str, const char * func, const char * file, int line ); void real_fail_if ( bool eval, const char * eval_str, const char * func, const char * file, int line ); extern void sigpipe_clear( ); extern int sigpipe_get( ); #ifdef __cplusplus } #endif #endif mlt-0.9.0/src/modules/kino/factory.c000066400000000000000000000021331215300731300173200ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2005 Ushodaya Enterprises Limited * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include extern mlt_producer producer_kino_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); MLT_REPOSITORY { MLT_REGISTER( producer_type, "kino", producer_kino_init ); } mlt-0.9.0/src/modules/kino/filehandler.cc000066400000000000000000000470651215300731300203060ustar00rootroot00000000000000/* * filehandler.cc -- saving DV data into different file formats * Copyright (C) 2000 Arne Schirmacher * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" extern "C" { #include } #include #include #include #include using std::cerr; using std::endl; using std::ostringstream; using std::setw; using std::setfill; #include #include #include #include #include #include #include #include #include // libdv header files #ifdef HAVE_LIBDV #include #endif #include "filehandler.h" #include "error.h" #include "riff.h" #include "avi.h" FileTracker *FileTracker::instance = NULL; FileTracker::FileTracker( ) : mode( CAPTURE_MOVIE_APPEND ) { cerr << ">> Constructing File Capture tracker" << endl; } FileTracker::~FileTracker( ) { cerr << ">> Destroying File Capture tracker" << endl; } FileTracker &FileTracker::GetInstance( ) { if ( instance == NULL ) instance = new FileTracker(); return *instance; } void FileTracker::SetMode( FileCaptureMode mode ) { this->mode = mode; } FileCaptureMode FileTracker::GetMode( ) { return this->mode; } char *FileTracker::Get( int index ) { return list[ index ]; } void FileTracker::Add( const char *file ) { if ( this->mode != CAPTURE_IGNORE ) { cerr << ">>>> Registering " << file << " with the tracker" << endl; list.push_back( strdup( file ) ); } } unsigned int FileTracker::Size( ) { return list.size(); } void FileTracker::Clear( ) { while ( Size() > 0 ) { free( list[ Size() - 1 ] ); list.pop_back( ); } this->mode = CAPTURE_MOVIE_APPEND; } FileHandler::FileHandler() : done( false ), autoSplit( false ), maxFrameCount( 999999 ), framesWritten( 0 ), filename( "" ) { /* empty body */ timeStamp = 0; everyNthFrame = 0; framesToSkip = 0; maxFileSize = 0; } FileHandler::~FileHandler() { /* empty body */ } bool FileHandler::GetAutoSplit() const { return autoSplit; } bool FileHandler::GetTimeStamp() const { return timeStamp; } string FileHandler::GetBaseName() const { return base; } string FileHandler::GetExtension() const { return extension; } int FileHandler::GetMaxFrameCount() const { return maxFrameCount; } off_t FileHandler::GetMaxFileSize() const { return maxFileSize; } string FileHandler::GetFilename() const { return filename; } void FileHandler::SetAutoSplit( bool flag ) { autoSplit = flag; } void FileHandler::SetTimeStamp( bool flag ) { timeStamp = flag; } void FileHandler::SetBaseName( const string& s ) { base = s; } void FileHandler::SetMaxFrameCount( int count ) { assert( count >= 0 ); maxFrameCount = count; } void FileHandler::SetEveryNthFrame( int every ) { assert ( every > 0 ); everyNthFrame = every; } void FileHandler::SetMaxFileSize( off_t size ) { assert ( size >= 0 ); maxFileSize = size; } #if 0 void FileHandler::SetSampleFrame( const Frame& sample ) { /* empty body */ } #endif bool FileHandler::Done() { return done; } #if 0 bool FileHandler::WriteFrame( const Frame& frame ) { static TimeCode prevTimeCode; TimeCode timeCode; /* If the user wants autosplit, start a new file if a new recording is detected. */ prevTimeCode.sec = -1; frame.GetTimeCode( timeCode ); int time_diff = timeCode.sec - prevTimeCode.sec; bool discontinuity = prevTimeCode.sec != -1 && ( time_diff > 1 || ( time_diff < 0 && time_diff > -59 ) ); if ( FileIsOpen() && GetAutoSplit() == true && ( frame.IsNewRecording() || discontinuity ) ) { Close(); } if ( FileIsOpen() == false ) { string filename; static int counter = 0; if ( GetTimeStamp() == true ) { ostringstream sb, sb2; struct tm date; string recDate; if ( ! frame.GetRecordingDate( date ) ) { struct timeval tv; struct timezone tz; gettimeofday( &tv, &tz ); localtime_r( static_cast< const time_t * >( &tv.tv_sec ), &date ); } sb << setfill( '0' ) << setw( 4 ) << date.tm_year + 1900 << '.' << setw( 2 ) << date.tm_mon + 1 << '.' << setw( 2 ) << date.tm_mday << '_' << setw( 2 ) << date.tm_hour << '-' << setw( 2 ) << date.tm_min << '-' << setw( 2 ) << date.tm_sec; recDate = sb.str(); sb2 << GetBaseName() << recDate << GetExtension(); filename = sb2.str(); cerr << ">>> Trying " << filename << endl; } else { struct stat stats; do { ostringstream sb; sb << GetBaseName() << setfill( '0' ) << setw( 3 ) << ++ counter << GetExtension(); filename = sb.str(); cerr << ">>> Trying " << filename << endl; } while ( stat( filename.c_str(), &stats ) == 0 ); } SetSampleFrame( frame ); if ( Create( filename ) == false ) { cerr << ">>> Error creating file!" << endl; return false; } framesWritten = 0; framesToSkip = 0; } /* write frame */ if ( framesToSkip == 0 ) { if ( 0 > Write( frame ) ) { cerr << ">>> Error writing frame!" << endl; return false; } framesToSkip = everyNthFrame; ++framesWritten; } framesToSkip--; /* If the frame count is exceeded, close the current file. If the autosplit flag is set, a new file will be created in the next iteration. If the flag is not set, we are done. */ if ( ( GetMaxFrameCount() > 0 ) && ( framesWritten >= GetMaxFrameCount() ) ) { Close(); done = !GetAutoSplit(); } /* If the file size could be exceeded by another frame, close the current file. If the autosplit flag is set, a new file will be created on the next iteration. If the flag is not set, we are done. */ /* not exact, but should be good enough to prevent going over. */ if ( FileIsOpen() ) { AudioInfo info; frame.GetAudioInfo( info ); if ( ( GetFileSize() > 0 ) && ( GetMaxFileSize() > 0 ) && ( GetFileSize() + frame.GetFrameSize() + info.samples * 4 + 12 ) >= GetMaxFileSize() ) { // 12 = sizeof chunk metadata Close(); done = !GetAutoSplit(); } } prevTimeCode.sec = timeCode.sec; return true; } #endif RawHandler::RawHandler() : fd( -1 ) { extension = ".dv"; numBlocks = 0; } RawHandler::~RawHandler() { Close(); } bool RawHandler::FileIsOpen() { return fd != -1; } bool RawHandler::Create( const string& filename ) { fd = open( filename.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_NONBLOCK, 0644 ); if ( fd != -1 ) { FileTracker::GetInstance().Add( filename.c_str() ); this->filename = filename; } return ( fd != -1 ); } #if 0 int RawHandler::Write( const Frame& frame ) { int result = write( fd, frame.data, frame.GetFrameSize() ); return result; } #endif int RawHandler::Close() { if ( fd != -1 ) { close( fd ); fd = -1; } return 0; } off_t RawHandler::GetFileSize() { struct stat file_status; fstat( fd, &file_status ); return file_status.st_size; } int RawHandler::GetTotalFrames() { return GetFileSize() / ( 480 * numBlocks ); } bool RawHandler::Open( const char *s ) { unsigned char data[ 4 ]; assert( fd == -1 ); fd = open( s, O_RDONLY | O_NONBLOCK ); if ( fd < 0 ) return false; if ( read( fd, data, 4 ) < 0 ) return false; if ( lseek( fd, 0, SEEK_SET ) < 0 ) return false; numBlocks = ( ( data[ 3 ] & 0x80 ) == 0 ) ? 250 : 300; filename = s; return true; } int RawHandler::GetFrame( uint8_t *data, int frameNum ) { assert( fd != -1 ); int size = 480 * numBlocks; if ( frameNum < 0 ) return -1; off_t offset = ( ( off_t ) frameNum * ( off_t ) size ); fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 ); if ( read( fd, data, size ) > 0 ) return 0; else return -1; } /***************************************************************************/ AVIHandler::AVIHandler( int format ) : avi( NULL ), aviFormat( format ), isOpenDML( false ), fccHandler( make_fourcc( "dvsd" ) ), channels( 2 ), isFullyInitialized( false ), audioBuffer( NULL ) { extension = ".avi"; for ( int c = 0; c < 4; c++ ) audioChannels[ c ] = NULL; memset( &dvinfo, 0, sizeof( dvinfo ) ); } AVIHandler::~AVIHandler() { if ( audioBuffer != NULL ) { delete audioBuffer; audioBuffer = NULL; } for ( int c = 0; c < 4; c++ ) { if ( audioChannels[ c ] != NULL ) { delete audioChannels[ c ]; audioChannels[ c ] = NULL; } } delete avi; } #if 0 void AVIHandler::SetSampleFrame( const Frame& sample ) { Pack pack; sample.GetAudioInfo( audioInfo ); sample.GetVideoInfo( videoInfo ); sample.GetAAUXPack( 0x50, pack ); dvinfo.dwDVAAuxSrc = *( DWORD* ) ( pack.data + 1 ); sample.GetAAUXPack( 0x51, pack ); dvinfo.dwDVAAuxCtl = *( DWORD* ) ( pack.data + 1 ); sample.GetAAUXPack( 0x52, pack ); dvinfo.dwDVAAuxSrc1 = *( DWORD* ) ( pack.data + 1 ); sample.GetAAUXPack( 0x53, pack ); dvinfo.dwDVAAuxCtl1 = *( DWORD* ) ( pack.data + 1 ); sample.GetVAUXPack( 0x60, pack ); dvinfo.dwDVVAuxSrc = *( DWORD* ) ( pack.data + 1 ); sample.GetVAUXPack( 0x61, pack ); dvinfo.dwDVVAuxCtl = *( DWORD* ) ( pack.data + 1 ); #ifdef WITH_LIBDV if ( sample.decoder->std == e_dv_std_smpte_314m ) fccHandler = make_fourcc( "dv25" ); #endif } #endif bool AVIHandler::FileIsOpen() { return avi != NULL; } bool AVIHandler::Create( const string& filename ) { assert( avi == NULL ); switch ( aviFormat ) { case AVI_DV1_FORMAT: fail_null( avi = new AVI1File ); if ( !avi || avi->Create( filename.c_str() ) == false ) return false; //avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency, AVI_LARGE_INDEX ); break; case AVI_DV2_FORMAT: fail_null( avi = new AVI2File ); if ( !avi || avi->Create( filename.c_str() ) == false ) return false; //if ( GetOpenDML() ) //avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency, //( AVI_SMALL_INDEX | AVI_LARGE_INDEX ) ); //else //avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency, //( AVI_SMALL_INDEX ) ); break; default: assert( aviFormat == AVI_DV1_FORMAT || aviFormat == AVI_DV2_FORMAT ); } avi->setDVINFO( dvinfo ); avi->setFccHandler( make_fourcc( "iavs" ), fccHandler ); avi->setFccHandler( make_fourcc( "vids" ), fccHandler ); this->filename = filename; FileTracker::GetInstance().Add( filename.c_str() ); return ( avi != NULL ); } #if 0 int AVIHandler::Write( const Frame& frame ) { assert( avi != NULL ); try { return avi->WriteFrame( frame ) ? 0 : -1; } catch (...) { return -1; } } #endif int AVIHandler::Close() { if ( avi != NULL ) { avi->WriteRIFF(); delete avi; avi = NULL; } if ( audioBuffer != NULL ) { delete audioBuffer; audioBuffer = NULL; } for ( int c = 0; c < 4; c++ ) { if ( audioChannels[ c ] != NULL ) { delete audioChannels[ c ]; audioChannels[ c ] = NULL; } } isFullyInitialized = false; return 0; } off_t AVIHandler::GetFileSize() { return avi->GetFileSize(); } int AVIHandler::GetTotalFrames() { return avi->GetTotalFrames(); } bool AVIHandler::Open( const char *s ) { assert( avi == NULL ); fail_null( avi = new AVI1File ); if ( avi->Open( s ) ) { avi->ParseRIFF(); if ( ! ( avi->verifyStreamFormat( make_fourcc( "dvsd" ) ) || avi->verifyStreamFormat( make_fourcc( "DVSD" ) ) || avi->verifyStreamFormat( make_fourcc( "dvcs" ) ) || avi->verifyStreamFormat( make_fourcc( "DVCS" ) ) || avi->verifyStreamFormat( make_fourcc( "dvcp" ) ) || avi->verifyStreamFormat( make_fourcc( "DVCP" ) ) || avi->verifyStreamFormat( make_fourcc( "CDVC" ) ) || avi->verifyStreamFormat( make_fourcc( "cdvc" ) ) || avi->verifyStreamFormat( make_fourcc( "DV25" ) ) || avi->verifyStreamFormat( make_fourcc( "dv25" ) ) ) ) return false; avi->ReadIndex(); if ( avi->verifyStream( make_fourcc( "auds" ) ) ) aviFormat = AVI_DV2_FORMAT; else aviFormat = AVI_DV1_FORMAT; isOpenDML = avi->isOpenDML(); filename = s; return true; } else return false; } int AVIHandler::GetFrame( uint8_t *data, int frameNum ) { int result = avi->GetDVFrame( data, frameNum ); #if 0 if ( result == 0 ) { /* get the audio from the audio stream, if available */ if ( aviFormat == AVI_DV2_FORMAT ) { WAVEFORMATEX wav; if ( ! isFullyInitialized && avi->getStreamFormat( ( void* ) &wav, make_fourcc( "auds" ) ) ) { if ( channels > 0 && channels < 5 ) { // Allocate interleaved audio buffer audioBuffer = new int16_t[ 2 * DV_AUDIO_MAX_SAMPLES * channels ]; // Allocate non-interleaved audio buffers for ( int c = 0; c < channels; c++ ) audioChannels[ c ] = new int16_t[ 2 * DV_AUDIO_MAX_SAMPLES ]; // Get the audio parameters from AVI for subsequent calls to method audioInfo.channels = wav.nChannels; audioInfo.frequency = wav.nSamplesPerSec; // Skip initialization on subsequent calls to method isFullyInitialized = true; cerr << ">>> using audio from separate AVI audio stream" << endl; } } // Get the frame from AVI int n = avi->getFrame( audioBuffer, frameNum, make_fourcc( "01wb" ) ); if ( n > 0 ) { // Temporary pointer to audio scratch buffer int16_t * s = audioBuffer; // Determine samples in this frame audioInfo.samples = n / audioInfo.channels / sizeof( int16_t ); // Convert interleaved audio into non-interleaved for ( int n = 0; n < audioInfo.samples; ++n ) for ( int i = 0; i < audioInfo.channels; i++ ) audioChannels[ i ][ n ] = *s++; // Write interleaved audio into frame frame.EncodeAudio( audioInfo, audioChannels ); } } // Parse important metadata in DV bitstream frame.ExtractHeader(); } #endif return result; } void AVIHandler::SetOpenDML( bool flag ) { isOpenDML = flag; } bool AVIHandler::GetOpenDML() const { return isOpenDML; } /***************************************************************************/ #ifdef HAVE_LIBQUICKTIME #ifndef HAVE_LIBDV #define DV_AUDIO_MAX_SAMPLES 1944 #endif // Missing fourcc's in libquicktime (allows compilation) #ifndef QUICKTIME_DV_AVID #define QUICKTIME_DV_AVID "AVdv" #endif #ifndef QUICKTIME_DV_AVID_A #define QUICKTIME_DV_AVID_A "dvcp" #endif #ifndef QUICKTIME_DVCPRO #define QUICKTIME_DVCPRO "dvpp" #endif QtHandler::QtHandler() : fd( NULL ) { extension = ".mov"; Init(); } QtHandler::~QtHandler() { Close(); } void QtHandler::Init() { if ( fd != NULL ) Close(); fd = NULL; samplingRate = 0; samplesPerBuffer = 0; channels = 2; audioBuffer = NULL; audioChannelBuffer = NULL; isFullyInitialized = false; } bool QtHandler::FileIsOpen() { return fd != NULL; } bool QtHandler::Create( const string& filename ) { Init(); if ( open( filename.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_NONBLOCK, 0644 ) != -1 ) { fd = quicktime_open( const_cast( filename.c_str() ), 0, 1 ); if ( fd != NULL ) FileTracker::GetInstance().Add( filename.c_str() ); } else return false; this->filename = filename; return true; } void QtHandler::AllocateAudioBuffers() { if ( channels > 0 && channels < 5 ) { audioBufferSize = DV_AUDIO_MAX_SAMPLES * 2; audioBuffer = new int16_t[ audioBufferSize * channels ]; audioChannelBuffer = new short int * [ channels ]; for ( int c = 0; c < channels; c++ ) audioChannelBuffer[ c ] = new short int[ audioBufferSize ]; isFullyInitialized = true; } } inline void QtHandler::DeinterlaceStereo16( void* pInput, int iBytes, void* pLOutput, void* pROutput ) { short int * piSampleInput = ( short int* ) pInput; short int* piSampleLOutput = ( short int* ) pLOutput; short int* piSampleROutput = ( short int* ) pROutput; while ( ( char* ) piSampleInput < ( ( char* ) pInput + iBytes ) ) { *piSampleLOutput++ = *piSampleInput++; *piSampleROutput++ = *piSampleInput++; } } #if 0 int QtHandler::Write( const Frame& frame ) { if ( ! isFullyInitialized ) { AudioInfo audio; if ( frame.GetAudioInfo( audio ) ) { channels = 2; quicktime_set_audio( fd, channels, audio.frequency, 16, QUICKTIME_TWOS ); } else { channels = 0; } quicktime_set_video( fd, 1, 720, frame.IsPAL() ? 576 : 480, frame.GetFrameRate(), QUICKTIME_DV ); AllocateAudioBuffers(); } int result = quicktime_write_frame( fd, const_cast( frame.data ), frame.GetFrameSize(), 0 ); if ( channels > 0 ) { AudioInfo audio; if ( frame.GetAudioInfo( audio ) && ( unsigned int ) audio.samples < audioBufferSize ) { long bytesRead = frame.ExtractAudio( audioBuffer ); DeinterlaceStereo16( audioBuffer, bytesRead, audioChannelBuffer[ 0 ], audioChannelBuffer[ 1 ] ); quicktime_encode_audio( fd, audioChannelBuffer, NULL, audio.samples ); } } return result; } #endif int QtHandler::Close() { if ( fd != NULL ) { quicktime_close( fd ); fd = NULL; } if ( audioBuffer != NULL ) { delete audioBuffer; audioBuffer = NULL; } if ( audioChannelBuffer != NULL ) { for ( int c = 0; c < channels; c++ ) delete audioChannelBuffer[ c ]; delete audioChannelBuffer; audioChannelBuffer = NULL; } return 0; } off_t QtHandler::GetFileSize() { struct stat file_status; stat( filename.c_str(), &file_status ); return file_status.st_size; } int QtHandler::GetTotalFrames() { return ( int ) quicktime_video_length( fd, 0 ); } bool QtHandler::Open( const char *s ) { Init(); fd = quicktime_open( s, 1, 0 ); if ( fd == NULL ) { fprintf( stderr, "Error opening: %s\n", s ); return false; } if ( quicktime_has_video( fd ) <= 0 ) { fprintf( stderr, "There must be at least one video track in the input file (%s).\n", s ); Close(); return false; } char * fcc = quicktime_video_compressor( fd, 0 ); if ( strncmp( fcc, QUICKTIME_DV, 4 ) != 0 && strncmp( fcc, QUICKTIME_DV_AVID, 4 ) != 0 && strncmp( fcc, QUICKTIME_DV_AVID_A, 4 ) != 0 && strncmp( fcc, QUICKTIME_DVCPRO, 4 ) != 0 ) { Close(); return false; } if ( quicktime_has_audio( fd ) ) channels = quicktime_track_channels( fd, 0 ); filename = s; return true; } int QtHandler::GetFrame( uint8_t *data, int frameNum ) { assert( fd != NULL ); quicktime_set_video_position( fd, frameNum, 0 ); quicktime_read_frame( fd, data, 0 ); #ifdef HAVE_LIBDV if ( quicktime_has_audio( fd ) ) { if ( ! isFullyInitialized ) AllocateAudioBuffers(); // Fetch the frequency of the audio track and calc number of samples needed int frequency = quicktime_sample_rate( fd, 0 ); float fps = ( data[ 3 ] & 0x80 ) ? 25.0f : 29.97f; int samples = mlt_sample_calculator( fps, frequency, frameNum ); int64_t seek = mlt_sample_calculator_to_now( fps, frequency, frameNum ); // Obtain a dv encoder and initialise it with minimal info dv_encoder_t *encoder = dv_encoder_new( 0, 0, 0 ); encoder->isPAL = ( data[ 3 ] & 0x80 ); encoder->samples_this_frame = samples; // Seek to the calculated position and decode quicktime_set_audio_position( fd, seek, 0 ); lqt_decode_audio( fd, audioChannelBuffer, NULL, (long) samples ); // Encode the audio on the frame and done dv_encode_full_audio( encoder, audioChannelBuffer, channels, frequency, data ); dv_encoder_free( encoder ); } #endif return 0; } #endif mlt-0.9.0/src/modules/kino/filehandler.h000066400000000000000000000117001215300731300201330ustar00rootroot00000000000000/* * filehandler.h * Copyright (C) 2000 Arne Schirmacher * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _FILEHANDLER_H #define _FILEHANDLER_H // enum { PAL_FORMAT, NTSC_FORMAT, AVI_DV1_FORMAT, AVI_DV2_FORMAT, QT_FORMAT, RAW_FORMAT, TEST_FORMAT, UNDEFINED }; #include using std::vector; #include using std::string; #include "riff.h" #include "avi.h" #include #include enum { AVI, PLAYLIST, RAW_DV, QT, UNKNOWN_FORMAT }; enum { PAL_FORMAT, NTSC_FORMAT, AVI_DV1_FORMAT, AVI_DV2_FORMAT, QT_FORMAT, RAW_FORMAT, TEST_FORMAT, UNDEFINED }; enum { DISPLAY_XX, DISPLAY_GDKRGB, DISPLAY_GDKRGB32, DISPLAY_XV, DISPLAY_SDL }; enum { NORM_UNSPECIFIED=0, NORM_PAL=1, NORM_NTSC=2 }; enum { AUDIO_32KHZ=0, AUDIO_44KHZ=1, AUDIO_48KHZ=2 }; enum { ASPECT_43=0, ASPECT_169=1 }; enum FileCaptureMode { CAPTURE_IGNORE, CAPTURE_FRAME_APPEND, CAPTURE_FRAME_INSERT, CAPTURE_MOVIE_APPEND }; class FileTracker { protected: FileTracker(); ~FileTracker(); public: static FileTracker &GetInstance( ); void SetMode( FileCaptureMode ); FileCaptureMode GetMode( ); unsigned int Size(); char *Get( int ); void Add( const char * ); void Clear( ); private: static FileTracker *instance; vector list; FileCaptureMode mode; }; class FileHandler { public: FileHandler(); virtual ~FileHandler(); virtual bool GetAutoSplit() const; virtual bool GetTimeStamp() const; virtual string GetBaseName() const; virtual string GetExtension() const; virtual int GetMaxFrameCount() const; virtual off_t GetMaxFileSize() const; virtual off_t GetFileSize() = 0; virtual int GetTotalFrames() = 0; virtual string GetFilename() const; virtual void SetAutoSplit( bool ); virtual void SetTimeStamp( bool ); virtual void SetBaseName( const string& base ); virtual void SetMaxFrameCount( int ); virtual void SetEveryNthFrame( int ); virtual void SetMaxFileSize( off_t ); //virtual void SetSampleFrame( const Frame& sample ); //virtual bool WriteFrame( const Frame& frame ); virtual bool FileIsOpen() = 0; virtual bool Create( const string& filename ) = 0; //virtual int Write( const Frame& frame ) = 0; virtual int Close() = 0; virtual bool Done( void ); virtual bool Open( const char *s ) = 0; virtual int GetFrame( uint8_t *data, int frameNum ) = 0; int GetFramesWritten() const { return framesWritten; } protected: bool done; bool autoSplit; bool timeStamp; int maxFrameCount; int framesWritten; int everyNthFrame; int framesToSkip; off_t maxFileSize; string base; string extension; string filename; }; class RawHandler: public FileHandler { public: int fd; RawHandler(); ~RawHandler(); bool FileIsOpen(); bool Create( const string& filename ); //int Write( const Frame& frame ); int Close(); off_t GetFileSize(); int GetTotalFrames(); bool Open( const char *s ); int GetFrame( uint8_t *data, int frameNum ); private: int numBlocks; }; class AVIHandler: public FileHandler { public: AVIHandler( int format = AVI_DV1_FORMAT ); ~AVIHandler(); //void SetSampleFrame( const Frame& sample ); bool FileIsOpen(); bool Create( const string& filename ); //int Write( const Frame& frame ); int Close(); off_t GetFileSize(); int GetTotalFrames(); bool Open( const char *s ); int GetFrame( uint8_t *data, int frameNum ); bool GetOpenDML() const; void SetOpenDML( bool ); int GetFormat() const { return aviFormat; } protected: AVIFile *avi; int aviFormat; //AudioInfo audioInfo; //VideoInfo videoInfo; bool isOpenDML; DVINFO dvinfo; FOURCC fccHandler; int channels; bool isFullyInitialized; int16_t *audioBuffer; int16_t *audioChannels[ 4 ]; }; #ifdef HAVE_LIBQUICKTIME #include class QtHandler: public FileHandler { public: QtHandler(); ~QtHandler(); bool FileIsOpen(); bool Create( const string& filename ); //int Write( const Frame& frame ); int Close(); off_t GetFileSize(); int GetTotalFrames(); bool Open( const char *s ); int GetFrame( uint8_t *data, int frameNum ); void AllocateAudioBuffers(); private: quicktime_t *fd; long samplingRate; int samplesPerBuffer; int channels; bool isFullyInitialized; unsigned int audioBufferSize; int16_t *audioBuffer; short int** audioChannelBuffer; void Init(); inline void DeinterlaceStereo16( void* pInput, int iBytes, void* pLOutput, void* pROutput ); }; #endif #endif mlt-0.9.0/src/modules/kino/gpl000066400000000000000000000000001215300731300162010ustar00rootroot00000000000000mlt-0.9.0/src/modules/kino/kino_wrapper.cc000066400000000000000000000055531215300731300205250ustar00rootroot00000000000000/* * kino_wrapper.cc -- c wrapper for kino file handler * Copyright (C) 2005 Ushodaya Enterprises Limited * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include #include #include "kino_wrapper.h" #include "filehandler.h" extern "C" { #include struct kino_wrapper_s { FileHandler *handler; int is_pal; }; kino_wrapper kino_wrapper_init( ) { kino_wrapper self = ( kino_wrapper )malloc( sizeof( kino_wrapper_s ) ); if ( self != NULL ) self->handler = NULL; return self; } int kino_wrapper_open( kino_wrapper self, char *src ) { if ( self != NULL ) { // Rough file determination based on file type if ( strncasecmp( strrchr( src, '.' ), ".avi", 4 ) == 0 ) self->handler = new AVIHandler( ); else if ( strncasecmp( strrchr( src, '.' ), ".dv", 3 ) == 0 || strncasecmp( strrchr( src, '.' ), ".dif", 4 ) == 0 ) self->handler = new RawHandler( ); #ifdef HAVE_LIBQUICKTIME else if ( strncasecmp( strrchr( src, '.' ), ".mov", 4 ) == 0 ) self->handler = new QtHandler( ); #endif // Open the file if we have a handler if ( self->handler != NULL ) if ( !self->handler->Open( src ) ) self = NULL; // Check the first frame to see if it's PAL or NTSC if ( self != NULL && self->handler != NULL ) { uint8_t *data = ( uint8_t * )mlt_pool_alloc( 144000 ); if ( self->handler->GetFrame( data, 0 ) == 0 ) self->is_pal = data[3] & 0x80; else self = NULL; mlt_pool_release( data ); } } return kino_wrapper_is_open( self ); } int kino_wrapper_get_frame_count( kino_wrapper self ) { return self != NULL && self->handler != NULL ? self->handler->GetTotalFrames( ) : 0; } int kino_wrapper_is_open( kino_wrapper self ) { return self != NULL && self->handler != NULL ? self->handler->FileIsOpen( ) : 0; } int kino_wrapper_is_pal( kino_wrapper self ) { return self != NULL ? self->is_pal : 0; } int kino_wrapper_get_frame( kino_wrapper self, uint8_t *data, int index ) { return self != NULL && self->handler != NULL ? !self->handler->GetFrame( data, index ) : 0; } void kino_wrapper_close( kino_wrapper self ) { if ( self ) delete self->handler; free( self ); } } mlt-0.9.0/src/modules/kino/kino_wrapper.h000066400000000000000000000026711215300731300203650ustar00rootroot00000000000000/* * kino_wrapper.h -- c wrapper for kino file handler * Copyright (C) 2005 Ushodaya Enterprises Limited * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef MLT_PRODUCER_KINO_WRAPPER_H_ #define MLT_PRODUCER_KINO_WRAPPER_H_ #include #ifdef __cplusplus extern "C" { #endif typedef struct kino_wrapper_s *kino_wrapper; extern kino_wrapper kino_wrapper_init( ); extern int kino_wrapper_open( kino_wrapper, char * ); extern int kino_wrapper_is_open( kino_wrapper ); extern int kino_wrapper_is_pal( kino_wrapper ); extern int kino_wrapper_get_frame_count( kino_wrapper ); extern int kino_wrapper_get_frame( kino_wrapper, uint8_t *, int ); extern void kino_wrapper_close( kino_wrapper ); #ifdef __cplusplus } #endif #endif mlt-0.9.0/src/modules/kino/producer_kino.c000066400000000000000000000106061215300731300205200ustar00rootroot00000000000000/* * producer_kino.c -- a DV file format parser * Copyright (C) 2005 Ushodaya Enterprises Limited * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include "kino_wrapper.h" /* NB: This is an abstract producer - it provides no codec support whatsoever. */ #define FRAME_SIZE_525_60 10 * 150 * 80 #define FRAME_SIZE_625_50 12 * 150 * 80 typedef struct producer_kino_s *producer_kino; struct producer_kino_s { struct mlt_producer_s parent; kino_wrapper wrapper; }; static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ); static void producer_close( mlt_producer parent ); mlt_producer producer_kino_init( mlt_profile profile, mlt_service_type type, const char *id, char *filename ) { kino_wrapper wrapper = kino_wrapper_init( ); if ( kino_wrapper_open( wrapper, filename ) ) { producer_kino this = calloc( 1, sizeof( struct producer_kino_s ) ); if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 ) { mlt_producer producer = &this->parent; mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); double fps = kino_wrapper_is_pal( wrapper ) ? 25 : 30000.0 / 1001.0; // Assign the wrapper this->wrapper = wrapper; // Pass wrapper properties (frame rate, count etc) mlt_properties_set_position( properties, "length", kino_wrapper_get_frame_count( wrapper ) ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", kino_wrapper_get_frame_count( wrapper ) - 1 ); mlt_properties_set_double( properties, "real_fps", fps ); mlt_properties_set( properties, "resource", filename ); // Register transport implementation with the producer producer->close = ( mlt_destructor )producer_close; // Register our get_frame implementation with the producer producer->get_frame = producer_get_frame; // Return the producer return producer; } free( this ); } kino_wrapper_close( wrapper ); return NULL; } static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { producer_kino this = producer->child; uint8_t *data = mlt_pool_alloc( FRAME_SIZE_625_50 ); // Obtain the current frame number uint64_t position = mlt_producer_frame( producer ); // Create an empty frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); // Seek and fetch if ( kino_wrapper_get_frame( this->wrapper, data, position ) ) { // Get the frames properties mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Determine if we're PAL or NTSC int is_pal = kino_wrapper_is_pal( this->wrapper ); // Pass the dv data mlt_properties_set_data( properties, "dv_data", data, FRAME_SIZE_625_50, ( mlt_destructor )mlt_pool_release, NULL ); // Update other info on the frame mlt_properties_set_int( properties, "width", 720 ); mlt_properties_set_int( properties, "height", is_pal ? 576 : 480 ); mlt_properties_set_int( properties, "top_field_first", is_pal ? 0 : ( data[ 5 ] & 0x07 ) == 0 ? 0 : 1 ); } else { mlt_pool_release( data ); } // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; } static void producer_close( mlt_producer parent ) { if ( parent != NULL ) { // Obtain this producer_kino this = parent->child; // Close the file if ( this != NULL ) kino_wrapper_close( this->wrapper ); // Close the parent parent->close = NULL; mlt_producer_close( parent ); // Free the memory free( this ); } } mlt-0.9.0/src/modules/kino/riff.cc000066400000000000000000000362331215300731300167520ustar00rootroot00000000000000/* * riff.cc library for RIFF file format i/o * Copyright (C) 2000 - 2002 Arne Schirmacher * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" // C++ includes #include //#include #include #include using std::cout; using std::hex; using std::dec; using std::setw; using std::setfill; using std::endl; // C includes #include #include #include // local includes #include "error.h" #include "riff.h" /** make a 32 bit "string-id" \param s a pointer to 4 chars \return the 32 bit "string id" \bugs It is not checked whether we really have 4 characters Some compilers understand constants like int id = 'ABCD'; but I could not get it working on the gcc compiler so I had to use this workaround. We can now use id = make_fourcc("ABCD") instead. */ FOURCC make_fourcc( const char *s ) { if ( s[ 0 ] == 0 ) return 0; else return *( ( FOURCC* ) s ); } RIFFDirEntry::RIFFDirEntry() { type = 0; name = 0; length = 0; offset = 0; parent = 0; written = 0; } RIFFDirEntry::RIFFDirEntry ( FOURCC t, FOURCC n, int l, int o, int p ) : type( t ), name( n ), length( l ), offset( o ), parent( p ), written( 0 ) {} /** Creates the object without an output file. */ RIFFFile::RIFFFile() : fd( -1 ) { pthread_mutex_init( &file_mutex, NULL ); } /* Copy constructor Duplicate the file descriptor */ RIFFFile::RIFFFile( const RIFFFile& riff ) : fd( -1 ) { if ( riff.fd != -1 ) { fd = dup( riff.fd ); } directory = riff.directory; } /** Destroys the object. If it has an associated opened file, close it. */ RIFFFile::~RIFFFile() { Close(); pthread_mutex_destroy( &file_mutex ); } RIFFFile& RIFFFile::operator=( const RIFFFile& riff ) { if ( fd != riff.fd ) { Close(); if ( riff.fd != -1 ) { fd = dup( riff.fd ); } directory = riff.directory; } return *this; } /** Creates or truncates the file. \param s the filename */ bool RIFFFile::Create( const char *s ) { fd = open( s, O_RDWR | O_NONBLOCK | O_CREAT | O_TRUNC, 00644 ); if ( fd == -1 ) return false; else return true; } /** Opens the file read only. \param s the filename */ bool RIFFFile::Open( const char *s ) { fd = open( s, O_RDONLY | O_NONBLOCK ); if ( fd == -1 ) return false; else return true; } /** Destroys the object. If it has an associated opened file, close it. */ void RIFFFile::Close() { if ( fd != -1 ) { close( fd ); fd = -1; } } /** Adds an entry to the list of containers. \param type the type of this entry \param name the name \param length the length of the data in the container \param list the container in which this object is contained. \return the ID of the newly created entry The topmost object is not contained in any other container. Use the special ID RIFF_NO_PARENT to create the topmost object. */ int RIFFFile::AddDirectoryEntry( FOURCC type, FOURCC name, off_t length, int list ) { /* Put all parameters in an RIFFDirEntry object. The offset is currently unknown. */ RIFFDirEntry entry( type, name, length, 0 /* offset */, list ); /* If the new chunk is in a list, then get the offset and size of that list. The offset of this chunk is the end of the list (parent_offset + parent_length) plus the size of the chunk header. */ if ( list != RIFF_NO_PARENT ) { RIFFDirEntry parent = GetDirectoryEntry( list ); entry.offset = parent.offset + parent.length + RIFF_HEADERSIZE; } /* The list which this new chunk is a member of has now increased in size. Get that directory entry and bump up its length by the size of the chunk. Since that list may also be contained in another list, walk up to the top of the tree. */ while ( list != RIFF_NO_PARENT ) { RIFFDirEntry parent = GetDirectoryEntry( list ); parent.length += RIFF_HEADERSIZE + length; SetDirectoryEntry( list, parent ); list = parent.parent; } directory.insert( directory.end(), entry ); return directory.size() - 1; } /** Modifies an entry. \param i the ID of the entry which is to modify \param type the type of this entry \param name the name \param length the length of the data in the container \param list the container in which this object is contained. \note Do not change length, offset, or the parent container. \note Do not change an empty name ("") to a name and vice versa */ void RIFFFile::SetDirectoryEntry( int i, FOURCC type, FOURCC name, off_t length, off_t offset, int list ) { RIFFDirEntry entry( type, name, length, offset, list ); assert( i >= 0 && i < ( int ) directory.size() ); directory[ i ] = entry; } /** Modifies an entry. The entry.written flag is set to false because the contents has been modified \param i the ID of the entry which is to modify \param entry the new entry \note Do not change length, offset, or the parent container. \note Do not change an empty name ("") to a name and vice versa */ void RIFFFile::SetDirectoryEntry( int i, RIFFDirEntry &entry ) { assert( i >= 0 && i < ( int ) directory.size() ); entry.written = false; directory[ i ] = entry; } /** Retrieves an entry. Gets the most important member variables. \param i the ID of the entry to retrieve \param type \param name \param length \param offset \param list */ void RIFFFile::GetDirectoryEntry( int i, FOURCC &type, FOURCC &name, off_t &length, off_t &offset, int &list ) const { RIFFDirEntry entry; assert( i >= 0 && i < ( int ) directory.size() ); entry = directory[ i ]; type = entry.type; name = entry.name; length = entry.length; offset = entry.offset; list = entry.parent; } /** Retrieves an entry. Gets the whole RIFFDirEntry object. \param i the ID of the entry to retrieve \return the entry */ RIFFDirEntry RIFFFile::GetDirectoryEntry( int i ) const { assert( i >= 0 && i < ( int ) directory.size() ); return directory[ i ]; } /** Calculates the total size of the file \return the size the file in bytes */ off_t RIFFFile::GetFileSize( void ) const { /* If we have at least one entry, return the length field of the FILE entry, which is the length of its contents, which is the actual size of whatever is currently in the AVI directory structure. Note that the first entry does not belong to the AVI file. If we don't have any entry, the file size is zero. */ if ( directory.size() > 0 ) return directory[ 0 ].length; else return 0; } /** prints the attributes of the entry \param i the ID of the entry to print */ void RIFFFile::PrintDirectoryEntry ( int i ) const { RIFFDirEntry entry; RIFFDirEntry parent; FOURCC entry_name; FOURCC list_name; /* Get all attributes of the chunk object. If it is contained in a list, get the name of the list too (otherwise the name of the list is blank). If the chunk object doesn´t have a name (only LISTs and RIFFs have a name), the name is blank. */ entry = GetDirectoryEntry( i ); if ( entry.parent != RIFF_NO_PARENT ) { parent = GetDirectoryEntry( entry.parent ); list_name = parent.name; } else { list_name = make_fourcc( " " ); } if ( entry.name != 0 ) { entry_name = entry.name; } else { entry_name = make_fourcc( " " ); } /* Print out the ascii representation of type and name, as well as length and file offset. */ cout << hex << setfill( '0' ) << "type: " << ((char *)&entry.type)[0] << ((char *)&entry.type)[1] << ((char *)&entry.type)[2] << ((char *)&entry.type)[3] << " name: " << ((char *)&entry_name)[0] << ((char *)&entry_name)[1] << ((char *)&entry_name)[2] << ((char *)&entry_name)[3] << " length: 0x" << setw( 12 ) << entry.length << " offset: 0x" << setw( 12 ) << entry.offset << " list: " << ((char *)&list_name)[0] << ((char *)&list_name)[1] << ((char *)&list_name)[2] << ((char *)&list_name)[3] << dec << endl; /* print the content itself */ PrintDirectoryEntryData( entry ); } /** prints the contents of the entry Prints a readable representation of the contents of an index. Override this to print out any objects you store in the RIFF file. \param entry the entry to print */ void RIFFFile::PrintDirectoryEntryData( const RIFFDirEntry &entry ) const {} /** prints the contents of the whole directory Prints a readable representation of the contents of an index. Override this to print out any objects you store in the RIFF file. \param entry the entry to print */ void RIFFFile::PrintDirectory() const { int i; int count = directory.size(); for ( i = 0; i < count; ++i ) PrintDirectoryEntry( i ); } /** finds the index finds the index of a given directory entry type \todo inefficient if the directory has lots of items \param type the type of the entry to find \param n the zero-based instance of type to locate \return the index of the found object in the directory, or -1 if not found */ int RIFFFile::FindDirectoryEntry ( FOURCC type, int n ) const { int i, j = 0; int count = directory.size(); for ( i = 0; i < count; ++i ) if ( directory[ i ].type == type ) { if ( j == n ) return i; j++; } return -1; } /** Reads all items that are contained in one list Read in one chunk and add it to the directory. If the chunk happens to be of type LIST, then call ParseList recursively for it. \param parent The id of the item to process */ void RIFFFile::ParseChunk( int parent ) { FOURCC type; DWORD length; int typesize; /* Check whether it is a LIST. If so, let ParseList deal with it */ fail_if( read( fd, &type, sizeof( type ) ) != sizeof( type )); if ( type == make_fourcc( "LIST" ) ) { typesize = (int) -sizeof( type ); fail_if( lseek( fd, typesize, SEEK_CUR ) == ( off_t ) - 1 ); ParseList( parent ); } /* it is a normal chunk, create a new directory entry for it */ else { fail_neg( read( fd, &length, sizeof( length ) ) ); if ( length & 1 ) length++; AddDirectoryEntry( type, 0, length, parent ); fail_if( lseek( fd, length, SEEK_CUR ) == ( off_t ) - 1 ); } } /** Reads all items that are contained in one list \param parent The id of the list to process */ void RIFFFile::ParseList( int parent ) { FOURCC type; FOURCC name; int list; DWORD length; off_t pos; off_t listEnd; /* Read in the chunk header (type and length). */ fail_neg( read( fd, &type, sizeof( type ) ) ); fail_neg( read( fd, &length, sizeof( length ) ) ); if ( length & 1 ) length++; /* The contents of the list starts here. Obtain its offset. The list name (4 bytes) is already part of the contents). */ pos = lseek( fd, 0, SEEK_CUR ); fail_if( pos == ( off_t ) - 1 ); fail_neg( read( fd, &name, sizeof( name ) ) ); /* Add an entry for this list. */ list = AddDirectoryEntry( type, name, sizeof( name ), parent ); /* Read in any chunks contained in this list. This list is the parent for all chunks it contains. */ listEnd = pos + length; while ( pos < listEnd ) { ParseChunk( list ); pos = lseek( fd, 0, SEEK_CUR ); fail_if( pos == ( off_t ) - 1 ); } } /** Reads the directory structure of the whole RIFF file */ void RIFFFile::ParseRIFF( void ) { FOURCC type; DWORD length; off_t filesize = 0; off_t pos; int container = AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT ); pos = lseek( fd, 0, SEEK_SET ); fail_if( pos == -1 ); /* calculate file size from RIFF header instead from physical file. */ while ( ( read( fd, &type, sizeof( type ) ) > 0 ) && ( read( fd, &length, sizeof( length ) ) > 0 ) && ( type == make_fourcc( "RIFF" ) ) ) { filesize += length + RIFF_HEADERSIZE; fail_if( lseek( fd, pos, SEEK_SET ) == ( off_t ) - 1 ); ParseList( container ); pos = lseek( fd, 0, SEEK_CUR ); fail_if( pos == ( off_t ) - 1 ); } } /** Reads one item including its contents from the RIFF file \param chunk_index The index of the item to write \param data A pointer to the data */ void RIFFFile::ReadChunk( int chunk_index, void *data, off_t data_len ) { RIFFDirEntry entry; entry = GetDirectoryEntry( chunk_index ); pthread_mutex_lock( &file_mutex ); fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); fail_neg( read( fd, data, entry.length > data_len ? data_len : entry.length ) ); pthread_mutex_unlock( &file_mutex ); } /** Writes one item including its contents to the RIFF file \param chunk_index The index of the item to write \param data A pointer to the data */ void RIFFFile::WriteChunk( int chunk_index, const void *data ) { RIFFDirEntry entry; entry = GetDirectoryEntry( chunk_index ); pthread_mutex_lock( &file_mutex ); fail_if( lseek( fd, entry.offset - RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 ); fail_neg( write( fd, &entry.type, sizeof( entry.type ) ) ); DWORD length = entry.length; fail_neg( write( fd, &length, sizeof( length ) ) ); fail_neg( write( fd, data, entry.length ) ); pthread_mutex_unlock( &file_mutex ); /* Remember that this entry already has been written. */ directory[ chunk_index ].written = true; } /** Writes out the directory structure For all items in the directory list that have not been written yet, it seeks to the file position where that item should be stored and writes the type and length field. If the item has a name, it will also write the name field. \note It does not write the contents of any item. Use WriteChunk to do that. */ void RIFFFile::WriteRIFF( void ) { int i; RIFFDirEntry entry; int count = directory.size(); /* Start at the second entry (RIFF), since the first entry (FILE) is needed only for internal purposes and is not written to the file. */ for ( i = 1; i < count; ++i ) { /* Only deal with entries that haven´t been written */ entry = GetDirectoryEntry( i ); if ( entry.written == false ) { /* A chunk entry consist of its type and length, a list entry has an additional name. Look up the entry, seek to the start of the header, which is at the offset of the data start minus the header size and write out the items. */ fail_if( lseek( fd, entry.offset - RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 ) ; fail_neg( write( fd, &entry.type, sizeof( entry.type ) ) ); DWORD length = entry.length; fail_neg( write( fd, &length, sizeof( length ) ) ); /* If it has a name, it is a list. Write out the extra name field. */ if ( entry.name != 0 ) { fail_neg( write( fd, &entry.name, sizeof( entry.name ) ) ); } /* Remember that this entry already has been written. */ directory[ i ].written = true; } } } mlt-0.9.0/src/modules/kino/riff.h000066400000000000000000000100161215300731300166030ustar00rootroot00000000000000/* * riff.h library for RIFF file format i/o * Copyright (C) 2000 - 2002 Arne Schirmacher * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Tag: $Name$ * * Change log: * * $Log$ * Revision 1.2 2005/07/25 07:21:39 lilo_booter * + fixes for opendml dv avi * * Revision 1.1 2005/04/15 14:28:26 lilo_booter * Initial version * * Revision 1.14 2005/04/01 23:43:10 ddennedy * apply endian fixes from Daniel Kobras * * Revision 1.13 2004/10/11 01:37:11 ddennedy * mutex safety locks in RIFF and AVI classes, type 2 AVI optimization, mencoder export script * * Revision 1.12 2004/01/06 22:53:42 ddennedy * metadata editing tweaks and bugfixes, new ui elements in preparation for publish functions * * Revision 1.11 2003/11/25 23:01:25 ddennedy * cleanup and a few bugfixes * * Revision 1.10 2003/10/21 16:34:34 ddennedy * GNOME2 port phase 1: initial checkin * * Revision 1.8.4.1 2002/11/25 04:48:31 ddennedy * bugfix to report errors when loading files * * Revision 1.8 2002/04/21 06:36:40 ddennedy * kindler avc and 1394 bus reset support in catpure page, honor max file size * * Revision 1.7 2002/04/09 06:53:42 ddennedy * cleanup, new libdv 0.9.5, large AVI, dnd storyboard * * Revision 1.3 2002/03/25 21:34:25 arne * Support for large (64 bit) files mostly completed * * Revision 1.2 2002/03/04 19:22:43 arne * updated to latest Kino avi code * * Revision 1.1.1.1 2002/03/03 19:08:08 arne * import of version 1.01 * */ #ifndef _RIFF_H #define _RIFF_H 1 #include using std::vector; #include #include "endian_types.h" #define QUADWORD int64_le_t #define DWORD int32_le_t #define LONG u_int32_le_t #define WORD int16_le_t #define BYTE u_int8_le_t #define FOURCC u_int32_t // No endian conversion needed. #define RIFF_NO_PARENT (-1) #define RIFF_LISTSIZE (4) #define RIFF_HEADERSIZE (8) #ifdef __cplusplus extern "C" { FOURCC make_fourcc( const char * s ); } #endif class RIFFDirEntry { public: FOURCC type; FOURCC name; off_t length; off_t offset; int parent; int written; RIFFDirEntry(); RIFFDirEntry( FOURCC t, FOURCC n, int l, int o, int p ); }; class RIFFFile { public: RIFFFile(); RIFFFile( const RIFFFile& ); virtual ~RIFFFile(); RIFFFile& operator=( const RIFFFile& ); virtual bool Open( const char *s ); virtual bool Create( const char *s ); virtual void Close(); virtual int AddDirectoryEntry( FOURCC type, FOURCC name, off_t length, int list ); virtual void SetDirectoryEntry( int i, FOURCC type, FOURCC name, off_t length, off_t offset, int list ); virtual void SetDirectoryEntry( int i, RIFFDirEntry &entry ); virtual void GetDirectoryEntry( int i, FOURCC &type, FOURCC &name, off_t &length, off_t &offset, int &list ) const; virtual RIFFDirEntry GetDirectoryEntry( int i ) const; virtual off_t GetFileSize( void ) const; virtual void PrintDirectoryEntry( int i ) const; virtual void PrintDirectoryEntryData( const RIFFDirEntry &entry ) const; virtual void PrintDirectory( void ) const; virtual int FindDirectoryEntry( FOURCC type, int n = 0 ) const; virtual void ParseChunk( int parent ); virtual void ParseList( int parent ); virtual void ParseRIFF( void ); virtual void ReadChunk( int chunk_index, void *data, off_t data_len ); virtual void WriteChunk( int chunk_index, const void *data ); virtual void WriteRIFF( void ); protected: int fd; pthread_mutex_t file_mutex; private: vector directory; }; #endif mlt-0.9.0/src/modules/linsys/000077500000000000000000000000001215300731300160675ustar00rootroot00000000000000mlt-0.9.0/src/modules/linsys/20-linsys.rules000066400000000000000000000007111215300731300207020ustar00rootroot00000000000000# udev rules for linsys cards to give members of the video group permissions KERNEL=="sdi*[rt]x[0-9]*", MODE="0660", GROUP="video", \ RUN+="/usr/bin/find /sys/$env{DEVPATH}/ -type f -execdir /bin/chmod 0660 {} + -execdir /bin/chgrp video {} +", OPTIONS="last_rule" KERNEL=="asi*[rt]x[0-9]*", MODE="0660", GROUP="video", \ RUN+="/usr/bin/find /sys/$env{DEVPATH}/ -type f -execdir /bin/chmod 0660 {} + -execdir /bin/chgrp video {} +", OPTIONS="last_rule" mlt-0.9.0/src/modules/linsys/Makefile000077500000000000000000000012701215300731300175320ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lpthread include ../../../config.mak include config.mak TARGET = ../libmltlinsys$(LIBSUF) OBJS = factory.o \ consumer_SDIstream.o ifdef WITH_JPEG CFLAGS += -DWITH_JPEG LDFLAGS += -ljpeg endif SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/linsys" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/linsys" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/linsys/configure000077500000000000000000000007131215300731300177770ustar00rootroot00000000000000#!/bin/sh if [ "$help" = "1" ] then cat << EOF Linsys options: --linsys-with-jpeg - Enable the option to export JPEGs (disabled by default) EOF else if [ "$targetos" = "Darwin" ] || [ "$targetos" = "MinGW" ] then echo "- does not build on OS X or Windows: disabling" touch ../disable-linsys exit 0 fi touch config.mak for i in "$@" do case $i in --linsys-with-jpeg ) echo "WITH_JPEG=1" > config.mak ;; esac done exit 0 fi mlt-0.9.0/src/modules/linsys/consumer_SDIstream.c000066400000000000000000000572751215300731300220210ustar00rootroot00000000000000/** * * MLT SDI Consumer: * request video and audio data from MLT and generate an SDI stream * * Copyright (C) Broadcasting Center Europe S.A. http://www.bce.lu * an RTL Group Company http://www.rtlgroup.com * All rights reserved. * * E-mail: support_plasec@bce.lu * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * DESCRIPTION: * This software act as interface between the MLT Frameworkas as * MLT Consumer and the Linear Systems Ltd. SMPTE 292M and SMPTE 259M-C boards. * * Linear Systems can be contacted at http://www.linsys.ca * ********************************************************************************** * System : INTeL I686 64Bit * OS : Linux SuSE Kernel 2.6.27.39-0.2-default * Compiler: gcc 4.3.2 (c++) ********************************************************************************** * Project : MLT SDI Consumer for SD and HD * Started by : Thomas Kurpick, Dipl.Inf. (FH) ********************************************************************************** * Supported and tested boards for SD-SDI or HD-SDI Output: * PCI SDI Master™ (model 107) * PCIe SDI Master™ (model 159) * PCIe LP SDI Master™ FD (model 145) * PCIe LP SDI Master™ Quad/o (model 180) * PCIe LP HD-SDI Master™ O (model 193) * * Note: PCIe LP HD-SDI Master™ O (model 193) is an VidPort model and supports an * seperate video and audio interface. Device file: * /dev/sdivideotx[] for active video data * /dev/sdiaudiotx[] for pcm audio data * * This mlt consumer use the following device files: * /dev/sditx[] (SD-PAL) up to 8 x AES (8 x stereo / 16 audio channels) * /dev/sdivideotx[] (HD) * /dev/sdiaudiotx[] (HD) up to 4 x AES (4 x stereo / 8 audio channels) * * ********************************************************************************** * Last modified by: * Thomas Kurpick 08.Jan.2010 * and * Dan Dennedy 10.Feb.2010 * Ver. 2.0 * See also Git commit log. * ********************************************************************************** * * Consumer properties: * 'dev_video' * 'dev_audio' * 'blanking' * Only to monitor the SDI output a beta version of jpeg-writer is implemented. * 'jpeg_files' a number for output interval * 'save_jpegs' path for image * * EXAMPLE: * * SDI boards with full frame stream (with blanking): * melt video.dv -consumer sdi:/dev/sditx0 * melt video.dv -consumer sdi:/dev/sditx0 blanking=true * melt video.dv -consumer sdi dev_video=/dev/sditx0 blanking=true * melt video.dv audio_index=all -consumer sdi dev_video=/dev/sditx0 blanking=true * * SDI boards without full frame stream (without blanking): * melt -profile atsc_1080i_50 video.mpeg audio_index=1 -consumer sdi dev_video=/dev/sdivideotx0 dev_audio=/dev/sdiaudiotx0 blanking=false * melt -profile atsc_1080i_50 video.mpeg audio_index=all -consumer sdi dev_video=/dev/sdivideotx0 dev_audio=/dev/sdiaudiotx0 blanking=false * melt -profile atsc_1080i_50 video.mpeg audio_index=all -consumer sdi dev_video=/dev/sdivideotx0 dev_audio=/dev/sdiaudiotx0 blanking=false jpeg_files=25 save_jpegs=channel_04.jpg * * * SDI output formats and MLT profiles: * ##################################################################################################################################################### * ########## SMPTE 274M 1920 x 1080 Image Sample Structure ############################################################################################ * ##################################################################################################################################################### * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model) * 4 1920 x 1080/60/I interlaced 30 HZ 4 x AES (8 channels) atsc_1080i_60 193 * 5 1920 x 1080/59.94/I interlaced 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_1080i_5994 193 * 6 1920 x 1080/50/I interlaced 25 HZ 4 x AES (8 channels) atsc_1080i_50 193 * 7 1920 x 1080/30/P progressive 30 HZ 4 x AES (8 channels) atsc_1080p_30 193 * 8 1920 x 1080/29.97/P progressive 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_1080p_2997 193 * 9 1920 x 1080/25/P progressive 25 HZ 4 x AES (8 channels) atsc_1080p_25 193 * 10 1920 x 1080/24/P progressive 24 HZ 4 x AES (8 channels) atsc_1080p_24 193 * 11 1920 x 1080/23.98/P progressive 24000/1001 ~ 23.98 HZ 4 x AES (8 channels) atsc_1080p_2398 193 * * ##################################################################################################################################################### * ########## SMPTE 296M 1280 × 720 Progressive Image Sample Structure ################################################################################# * ##################################################################################################################################################### * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model) * 1 1280 × 720/60 progressive 60 HZ 4 x AES (8 channels) atsc_720p_60 193 * 2 1280 × 720/59.94 progressive 60000/1001 ~ 59.97 HZ 4 x AES (8 channels) atsc_720p_5994 193 * 3 1280 × 720/50 progressive 50 HZ 4 x AES (8 channels) atsc_720p_50 193 * 4 1280 × 720/30 progressive 30 HZ 4 x AES (8 channels) atsc_720p_30 193 * 5 1280 × 720/29.97 progressive 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_720p_2997 193 * 6 1280 × 720/25 progressive 25 HZ 4 x AES (8 channels) atsc_720p_25 193 * 7 1280 × 720/24 progressive 24 HZ 4 x AES (8 channels) atsc_720p_24 193 * 8 1280 × 720/23.98 progressive 24000/1001 ~ 23.98 HZ 4 x AES (8 channels) atsc_720p_2398 193 * * ##################################################################################################################################################### * ########## SMPTE 125M 486i 29.97Hz & BT.656 576i 25Hz ############################################################################################### * ##################################################################################################################################################### * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model) * SD PAL 720 × 576/50/I interlaced 25 HZ 8 x AES (16 channels) dv_pal 180,145,159,107 * SD PAL 720 × 576/50/I interlaced 25 HZ 4 x AES (8 channels) dv_pal 193 * SD NTSC 720 × 486/59.94/I interlaced 30000/1001 ~ 29.97 HZ 8 x AES (16 channels) sdi_486i_5994 TODO:180,145,159,107 * SD NTSC 720 × 486/59.94/I interlaced 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) sdi_486i_5994 193 * **/ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef WITH_JPEG // for JPEG output #include #endif #include "sdi_generator.c" // alias for "struct consumer_SDIstream_s *" , now we can write "consumer_SDIstream". Makes it more readable... typedef struct consumer_SDIstream_s *consumer_SDIstream; struct consumer_SDIstream_s { // Most of these values are set to their defaults by the parent consumer struct mlt_consumer_s parent; // This is the basic Consumer from which we fetch our data mlt_image_format pix_fmt; // Must be mlt_image_yuv422 for SDI int width; int height; struct audio_format audio_format; /** * device file: * /dev/sditx0 * /dev/sdivideotx0 * /dev/sdiaudiotx0 **/ char *device_file_video; // Path for SDI output char *device_file_audio; // Path for exlusive SDI audio output /** * write own HANC (ancillary data) is available for: * SDI board ASSY 193 HD 'blanking=false' * SDI board ASSY 180 SD quad 'blanking=true' * SDI board ASSY 145 SD single 'blanking=true' * * 0=false, 1=true * **/ uint8_t blanking; // our audio channel pair for this frame int16_t audio_buffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES]; // The SDI audio channel pairs for this frame char *video_fmt_name; // 1080i25, 1080p25, 576i50, 486i2997, ... }; /** * Forward references to static functions. **/ static int consumer_start(mlt_consumer this); static int consumer_stop(mlt_consumer this); static int consumer_is_stopped(mlt_consumer this); static void consumer_close(mlt_consumer parent); static void *consumer_thread(void *); static void consumer_write_JPEG(char * path, uint8_t **vBuffer, mlt_profile myProfile); int convertYCBCRtoRGB(int y1, int cb, int cr, int y2, uint8_t * target_rgb); /***************************************************************************************************** ****************************************** SDI Master Consumer ************************************** *****************************************************************************************************/ /** This is what will be called by the factory * @param profile: profile name for consumer * @param type: unused * @param *id: unused * @param *arg: pointer to output path **/ mlt_consumer consumer_SDIstream_init(mlt_profile profile, mlt_service_type type, const char *id, char *arg) { // Create the consumer object consumer_SDIstream this = calloc( 1, sizeof(struct consumer_SDIstream_s) ); // If malloc and consumer init ok if (this != NULL && mlt_consumer_init(&this->parent, this, profile) == 0) { // Get the parent consumer object mlt_consumer parent = &this->parent; // We have stuff to clean up, so override the close method parent->close = consumer_close; // Set output path for SDI, default is "/dev/sditx0" if (arg == NULL) { this->device_file_video = strdup("/dev/sditx0"); } else { this->device_file_video = strdup(arg); } // Set up start/stop/terminated callbacks parent->start = consumer_start; parent->stop = consumer_stop; parent->is_stopped = consumer_is_stopped; // Set explicit to zero or other value int i, j; for (i = 0; i < MAX_AUDIO_STREAMS; i++) { for (j = 0; j < MAX_AUDIO_SAMPLES; j++) { this->audio_buffer[i][j] = j; } } mlt_events_register( MLT_CONSUMER_PROPERTIES(parent), "consumer-fatal-error", NULL ); // Return the consumer produced return parent; } // malloc or consumer init failed free(this); // Indicate failure return NULL; } /** * Start the consumer. **/ static int consumer_start(mlt_consumer parent) { // Get the properties mlt_properties properties = mlt_consumer_properties(parent); // Get the actual object consumer_SDIstream this = parent->child; // Check that we're not already running if (!mlt_properties_get_int(properties, "running")) { // Allocate threads pthread_t *consumer_pthread = calloc(1, sizeof(pthread_t)); // Assign the thread to properties mlt_properties_set_data(properties, "consumer_pthread", consumer_pthread, sizeof(pthread_t), free, NULL); // Set the running state mlt_properties_set_int(properties, "running", 1); // Create the the threads pthread_create(consumer_pthread, NULL, consumer_thread, this); } return 0; } /** * Stop the consumer **/ static int consumer_stop(mlt_consumer parent) { // Get the properties mlt_properties properties = mlt_consumer_properties(parent); // Check that we're running if (mlt_properties_get_int(properties, "running")) { // Get the threads pthread_t *consumer_pthread = mlt_properties_get_data(properties, "consumer_pthread", NULL); // Stop the threads mlt_properties_set_int(properties, "running", 0); // Wait for termination pthread_join(*consumer_pthread, NULL); } return 0; } /** * Determine if the consumer is stopped **/ static int consumer_is_stopped(mlt_consumer this) { // Get the properties mlt_properties properties = mlt_consumer_properties(this); return !mlt_properties_get_int(properties, "running"); } /** * Threaded wrapper for pipe. **/ static void *consumer_thread(void *arg) { // Identify the arg consumer_SDIstream this = arg; // Get the consumer mlt_consumer consumer = &this->parent; // Convenience functionality (this is to stop melt/inigo after the end of a playout) int terminate_on_pause = mlt_properties_get_int(MLT_CONSUMER_PROPERTIES( consumer ), "terminate_on_pause"); int terminated = 0; // save ony status int save_jpegs = mlt_properties_get_int(MLT_CONSUMER_PROPERTIES( consumer ), "save_jpegs"); char * jpeg_folder = mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "jpeg_file"); // If no folder is specified, skip jpeg export if (jpeg_folder == NULL) { save_jpegs = 0; } if (save_jpegs > 0) mlt_log_info(MLT_CONSUMER_SERVICE(consumer), "Saving a JPEG every %i frame.\n", save_jpegs); int counter = 0; // each second we save a Jpeg // set properties (path) for device files if (mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "dev_video") != NULL) { this->device_file_video = strdup(mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "dev_video")); } if (mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "dev_audio") != NULL) { if (this->blanking == 0) { this->device_file_audio = strdup(mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "dev_audio")); } else { // if we write HANC we do not write further audio data mlt_log_info(MLT_CONSUMER_SERVICE(consumer), "Audio device file is set but will not be used.\n"); } } // Set additional device file defaults struct stat st; int fd = -1; if (this->device_file_video) fd = stat(this->device_file_video, &st); if (fd == -1) { if (this->device_file_video) free(this->device_file_video); this->device_file_video = strdup("/dev/sdivideotx0"); } else { close(fd); } if (this->device_file_audio) { fd = stat(this->device_file_audio, &st); if (fd == -1) { if (this->device_file_audio) free(this->device_file_audio); this->device_file_audio = strdup("/dev/sdiaudiotx0"); } else { close(fd); } } else if (this->device_file_video && strstr(this->device_file_video, "sdivideotx")) { if (this->device_file_audio) free(this->device_file_audio); this->device_file_audio = strdup("/dev/sdiaudiotx0"); } // set blanking flag; is not nessary we write no own blanking(HANC) for HD board ASSY 193 if (mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "blanking")) { // set value if (!strcmp( mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "blanking"), "false")) { this->blanking = 0; } else if (!strcmp( mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "blanking"), "true")) { this->blanking = 1; } else { this->blanking = mlt_properties_get_int(MLT_CONSUMER_PROPERTIES( consumer ), "blanking"); } } else if (this->device_file_video && strstr(this->device_file_video, "sdivideotx")) { this->blanking = 0; } else { // set default value without HD board, also with blanking this->blanking = 1; } // Define a frame pointer mlt_frame frame; // set Datablock number for SDI encoding int my_dbn = 1; double fps = mlt_properties_get_double(MLT_CONSUMER_PROPERTIES(consumer), "fps"); unsigned int count = 0; // Tell the framework how we want our audio and video int frequency = this->audio_format.sample_rate; int channels = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES(consumer), "channels" ); int samples; // set number of audio channels, linsys vidport model 193 is limited to 8 channels (4AES frames) this->audio_format.channels = 8; /* 0,2,4,6,8 */ this->audio_format.aformat = mlt_audio_s16; /* 16, 24, 32 */ this->audio_format.sample_rate = 48000; this->pix_fmt = mlt_image_yuv422; if (this->device_file_video && this->device_file_audio && !sdi_init(this->device_file_video, this->device_file_audio, this->blanking, mlt_service_profile((mlt_service) consumer), &this->audio_format)) { mlt_log_fatal( MLT_CONSUMER_SERVICE(consumer), "failed to initialize\n" ); mlt_events_fire( MLT_CONSUMER_PROPERTIES(consumer), "consumer-fatal-error", NULL ); } uint8_t *video_buffer; int16_t *audio_buffer_tmp; // the upstream audio buffer // Loop until told not to while (!consumer_is_stopped(consumer) && terminated == 0) { // // Get a frame from the service if ((frame = mlt_consumer_rt_frame(consumer)) != NULL) { // Check for termination if (terminate_on_pause && frame != NULL) { terminated = mlt_properties_get_double(MLT_FRAME_PROPERTIES( frame ), "_speed") == 0.0; if (terminated == 1) { mlt_log_verbose(MLT_CONSUMER_SERVICE(consumer), "\nEnd of playout reached, terminating\n"); consumer_stop(consumer); } } // True if mlt_consumer_rt_frame(...) successful if (mlt_properties_get_int(mlt_frame_properties(frame), "rendered") == 1) { // Get the video from this frame and save it to our video_buffer mlt_frame_get_image(frame, &video_buffer, &this->pix_fmt, &this->width, &this->height, 1); // Get the audio from this frame and save it to our audio_buffer samples = mlt_sample_calculator(fps, frequency, count++); mlt_frame_get_audio(frame, (void**) &audio_buffer_tmp, &this->audio_format.aformat, &frequency, &channels, &samples); this->audio_format.sample_rate = frequency; this->audio_format.samples = samples; /* TODO: Audio is currently hard coded to 8 channels because write 8 channels to the sdi board. The Linys SDI board has to be configured with the same number of channels! this->audio_format.channels = channels; // take given number of channels */ /* Tell the sdi_generator.c to playout our frame * 8 AES (8 x stereo channels are possible, max. 16 channels) Linsys SD board model: 107, 159, 145, 180 * 4 AES (4 x stereo channels are possible, max. 8 channels) Linsys HD board model: 193 */ if (video_buffer) { // provide mapping of audio channels int i, j = 0; int map_channels, map_start; for (i = 0; i < MAX_AUDIO_STREAMS && j < channels; i++) { char key[27]; int c; sprintf(key, "meta.map.audio.%d.channels", i); map_channels = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), key); sprintf(key, "meta.map.audio.%d.start", i); map_start = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), key); if (!map_channels) map_channels = channels - j; for (c = 0; c < map_channels && j < channels; c++, j++) { int16_t *src = audio_buffer_tmp + j; int16_t *dest = this->audio_buffer[(map_start + c) / 2] + (map_start + c) % 2; int s = samples + 1; while (--s) { *dest = *src; dest += 2; src += channels; } } } // generate SDI frame and playout my_dbn = sdi_playout(video_buffer, this->audio_buffer, &this->audio_format, (channels + 1) / 2, my_dbn); // write a JPEG of every X-th frame if (save_jpegs > 0 && counter >= save_jpegs) { consumer_write_JPEG(jpeg_folder, &video_buffer, mlt_service_profile((mlt_service) consumer)); counter = 0; } else if (save_jpegs > 0) { counter++; } mlt_events_fire(MLT_CONSUMER_PROPERTIES( consumer ), "consumer-frame-show", frame, NULL ); } else { mlt_log_warning(MLT_CONSUMER_SERVICE(consumer), "Videobuffer was NULL, skipping playout!\n"); } } else { mlt_log_warning(MLT_CONSUMER_SERVICE(consumer), "WARNING the requested frame is not yet rendered! This will cause image disturbance!\n"); if (video_buffer) { my_dbn = sdi_playout(video_buffer, this->audio_buffer, &this->audio_format, (channels + 1) / 2, my_dbn); } else { mlt_log_warning(MLT_CONSUMER_SERVICE(consumer), "Videobuffer was NULL, skipping playout!\n"); } } if (frame != NULL) mlt_frame_close(frame); } } return NULL; } /** * Callback to allow override of the close method. **/ static void consumer_close(mlt_consumer parent) { // Get the actual object consumer_SDIstream this = parent->child; free(this->device_file_video); free(this->device_file_audio); // Now clean up the rest (the close = NULL is a bit nasty but needed for now) parent->close = NULL; mlt_consumer_close(parent); // Invoke the close function of the sdi_generator to close opened files used for output sdimaster_close(); // Finally clean up this free(this); } /** * Write videobuffer as JPEG to path * @param path **/ static void consumer_write_JPEG(char * filename, uint8_t **vBuffer, mlt_profile myProfile) { #ifdef WITH_JPEG int bytes_per_pixel = 3; // or 1 for GRACYSCALE images int color_space = JCS_RGB; // or JCS_GRAYSCALE for grayscale images uint8_t * buffer_position = *vBuffer; uint8_t image_rgb[myProfile->width * myProfile->height * bytes_per_pixel]; //convert vBuffer to RGB int i; for (i = 0; i < sizeof(image_rgb) / 6; i++) { int y1 = *(buffer_position++); int cb = *(buffer_position++); int y2 = *(buffer_position++); int cr = *(buffer_position++); convertYCBCRtoRGB(y1, cb, cr, y2, &image_rgb[i * 6]); } struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; // this is a pointer to one row of image data JSAMPROW row_pointer[1]; FILE *outfile = fopen(filename, "wb"); if (!outfile) { mlt_log_error(NULL, "%s: Error opening output jpeg file %s\n!", __FILE__, filename); return; } cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, outfile); // Setting the parameters of the output file here cinfo.image_width = myProfile->width; cinfo.image_height = myProfile->height; cinfo.input_components = bytes_per_pixel; cinfo.in_color_space = (J_COLOR_SPACE) color_space; // default compression parameters, we shouldn't be worried about these jpeg_set_defaults(&cinfo); // Now do the compression jpeg_start_compress(&cinfo, TRUE); // like reading a file, this time write one row at a time while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = &image_rgb[cinfo.next_scanline * cinfo.image_width * cinfo.input_components]; jpeg_write_scanlines(&cinfo, row_pointer, 1); } // similar to read file, clean up after we're done compressing jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); fclose(outfile); #endif } /** * converts YCbCr samples to two 32-bit RGB values * @param y1 cb cr and y2 values * @param target pointer * @return 0 upon success **/ int convertYCBCRtoRGB(int y1, int cb, int cr, int y2, uint8_t * target_rgb) { #ifdef WITH_JPEG if(y1 > 235) y1 = 235; if(y1 < 16) y1 = 16; if(y2 > 235) y2 = 235; if(y2 < 16) y2 = 16; if(cr > 240) cr = 240; if(cr < 16) cr = 16; if(cb > 240) cb = 240; if(cb < 16) cb = 16; uint8_t r1, g1, b1, r2, g2, b2; //pointer to current output buffer position uint8_t * target_pointer = target_rgb; r1 = y1 + 1.402 * (cr - 128); g1 = y1 - 0.34414 * (cb - 128) - 0.71414 * (cr - 128); b1 = y1 + 1.772 * (cb - 128); r2 = y2 + 1.402 * (cr - 128); g2 = y2 - 0.34414 * (cb - 128) - 0.71414 *(cr - 128); b2 = y2 + 1.772 * (cb - 128); *target_pointer++ = r1; *target_pointer++ = g1; *target_pointer++ = b1; *target_pointer++ = r2; *target_pointer++ = g2; *target_pointer++ = b2; return 0; #endif return 1; } mlt-0.9.0/src/modules/linsys/consumer_sdi.yml000066400000000000000000000003211215300731300213000ustar00rootroot00000000000000schema_version: 0.1 type: consumer identifier: sdi title: Linear Systems SDI version: 1 copyright: Broadcasting Center Europe S.A. creator: Thomas Kurpick license: GPLv2 language: en tags: - Audio - Video mlt-0.9.0/src/modules/linsys/factory.c000066400000000000000000000011761215300731300177070ustar00rootroot00000000000000/* * factory.c for Linsys SDI consumer */ #include #include #include extern mlt_consumer consumer_SDIstream_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/linsys/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( consumer_type, "sdi", consumer_SDIstream_init ); MLT_REGISTER_METADATA( consumer_type, "sdi", metadata, "consumer_sdi.yml" ); } mlt-0.9.0/src/modules/linsys/gpl000066400000000000000000000000001215300731300165620ustar00rootroot00000000000000mlt-0.9.0/src/modules/linsys/sdi_generator.c000066400000000000000000002361521215300731300210710ustar00rootroot00000000000000/** * * MLT SDI Consumer: * request video and audio data from MLT and generate an SDI stream * * Copyright (C) Broadcasting Center Europe S.A. http://www.bce.lu * an RTL Group Company http://www.rtlgroup.com * All rights reserved. * * E-mail: support_plasec@bce.lu * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * DESCRIPTION: * This software act as interface between the MLT Frameworkas as * MLT Consumer and the Linear Systems Ltd. SMPTE 292M and SMPTE 259M-C boards. * * Linear Systems can be contacted at http://www.linsys.ca * ********************************************************************************** * System : INTeL I686 64Bit * OS : Linux SuSE Kernel 2.6.27.39-0.2-default * Compiler: gcc 4.3.2 (c++) ********************************************************************************** * Project : MLT SDI Consumer for SD and HD * Started by : Thomas Kurpick, Dipl.Inf. (FH) ********************************************************************************** * Supported and tested boards for SD-SDI or HD-SDI Output: * PCI SDI Master™ (model 107) * PCIe SDI Master™ (model 159) * PCIe LP SDI Master™ FD (model 145) * PCIe LP SDI Master™ Quad/o (model 180) * PCIe LP HD-SDI Master™ O (model 193) * * Note: PCIe LP HD-SDI Master™ O (model 193) is an VidPort model and supports an * seperate video and audio interface. Device file: * /dev/sdivideotx[] for active video data * /dev/sdiaudiotx[] for pcm audio data * * This mlt consumer use the following device files: * /dev/sditx[] (SD-PAL) up to 8 x AES (8 x stereo / 16 audio channels) * /dev/sdivideotx[] (HD) * /dev/sdiaudiotx[] (HD) up to 4 x AES (4 x stereo / 8 audio channels) * * ********************************************************************************** * Last modified by: * Thomas Kurpick 08.Jan.2010 * Ver. 2.0 * ********************************************************************************** * * Consumer properties: * 'dev_video' * 'dev_audio' * 'blanking' * Only to monitor the SDI output a beta version of jpeg-writer is implemented. * 'jpeg_files' a number for output interval * 'save_jpegs' path for image * * EXAMPLE: * * SDI boards with full frame stream (with blanking): * melt video.dv -consumer sdi:/dev/sditx0 buffer=0; * melt video.dv -consumer sdi:/dev/sditx0 buffer=0 blanking=true; * melt video.dv -consumer sdi dev_video=/dev/sditx0 buffer=0 blanking=true; * melt video.dv audio_index=all -consumer sdi dev_video=/dev/sditx0 buffer=0 blanking=true; * * SDI boards without full frame stream (without blanking): * melt -profile atsc_1080i_50 video.mpeg audio_index=1 -consumer sdi dev_video=/dev/sdivideotx0 dev_sdiaudio=/dev/sdiaudiotx0 blanking=false * melt -profile atsc_1080i_50 video.mpeg audio_index=all -consumer sdi dev_video=/dev/sdivideotx0 dev_sdiaudio=/dev/sdiaudiotx0 blanking=false * melt -profile atsc_1080i_50 video.mpeg audio_index=all -consumer sdi dev_video=/dev/sdivideotx0 dev_sdiaudio=/dev/sdiaudiotx0 blanking=false jpeg_files=25 save_jpegs=channel_04.jpg * * * SDI output formats and MLT profiles: * ##################################################################################################################################################### * ########## SMPTE 274M 1920 x 1080 Image Sample Structure ############################################################################################ * ##################################################################################################################################################### * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model) * 4 1920 x 1080/60/I interlaced 30 HZ 4 x AES (8 channels) atsc_1080i_60 193 * 5 1920 x 1080/59.94/I interlaced 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_1080i_5994 193 * 6 1920 x 1080/50/I interlaced 25 HZ 4 x AES (8 channels) atsc_1080i_50 193 * 7 1920 x 1080/30/P progressive 30 HZ 4 x AES (8 channels) atsc_1080p_30 193 * 8 1920 x 1080/29.97/P progressive 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_1080p_2997 193 * 9 1920 x 1080/25/P progressive 25 HZ 4 x AES (8 channels) atsc_1080p_25 193 * 10 1920 x 1080/24/P progressive 24 HZ 4 x AES (8 channels) atsc_1080p_24 193 * 11 1920 x 1080/23.98/P progressive 24000/1001 ~ 23.98 HZ 4 x AES (8 channels) atsc_1080p_2398 193 * * ##################################################################################################################################################### * ########## SMPTE 296M 1280 × 720 Progressive Image Sample Structure ################################################################################# * ##################################################################################################################################################### * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model) * 1 1280 × 720/60 progressive 60 HZ 4 x AES (8 channels) atsc_720p_60 193 * 2 1280 × 720/59.94 progressive 60000/1001 ~ 59.97 HZ 4 x AES (8 channels) atsc_720p_5994 193 * 3 1280 × 720/50 progressive 50 HZ 4 x AES (8 channels) atsc_720p_50 193 * 4 1280 × 720/30 progressive 30 HZ 4 x AES (8 channels) atsc_720p_30 193 * 5 1280 × 720/29.97 progressive 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_720p_2997 193 * 6 1280 × 720/25 progressive 25 HZ 4 x AES (8 channels) atsc_720p_25 193 * 7 1280 × 720/24 progressive 24 HZ 4 x AES (8 channels) atsc_720p_24 193 * 8 1280 × 720/23.98 progressive 24000/1001 ~ 23.98 HZ 4 x AES (8 channels) atsc_720p_2398 193 * * ##################################################################################################################################################### * ########## SMPTE 125M 486i 29.97Hz & BT.656 576i 25Hz ############################################################################################### * ##################################################################################################################################################### * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model) * SD PAL 720 × 576/50/I interlaced 25 HZ 8 x AES (16 channels) dv_pal 180,145,159,107 * SD PAL 720 × 576/50/I interlaced 25 HZ 4 x AES (8 channels) dv_pal 193 * SD NTSC 720 × 486/59.94/I interlaced 30000/1001 ~ 29.97 HZ 8 x AES (16 channels) sdi_486i_5994 TODO:180,145,159,107 * SD NTSC 720 × 486/59.94/I interlaced 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) sdi_486i_5994 193 * **/ #include "sdi_generator.h" /*!/brief initialization of the file handlers for the playout * @param *device_video: file or SDITX device or SDIVIDEOTX device * @param *device_audio: file or SDIAUDIOTX device * @param blanking: true or false (if false the consumer write only active video data without any VANH or HANC) */ static int sdi_init(char *device_video, char *device_audio, uint8_t blanking, mlt_profile myProfile, const struct audio_format * audio_format) { // set device file device_file_video = device_video; device_file_audio = device_audio; // set flag for using of blanking with ancillary data info.blanking = blanking; // set pack method for SDI word conversion pack = pack8; //pack = pack10; //pack = pack_v210; // check format if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1 && myProfile->progressive == 0) { info.fmt = &FMT_1080i60; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080I_60HZ; } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001 && myProfile->progressive == 0) { info.fmt = &FMT_1080i5994; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080I_59_94HZ; } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1 && myProfile->progressive == 0) { info.fmt = &FMT_1080i50; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080I_50HZ; } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1 && myProfile->progressive == 1) { info.fmt = &FMT_1080p30; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_30HZ; } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001 && myProfile->progressive == 1) { info.fmt = &FMT_1080p2997; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_29_97HZ; } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1 && myProfile->progressive == 1) { info.fmt = &FMT_1080p25; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_25HZ; } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 24 && myProfile->frame_rate_den == 1 && myProfile->progressive == 1) { info.fmt = &FMT_1080p24; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_24HZ; } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 24000 && myProfile->frame_rate_den == 1001 && myProfile->progressive == 1) { info.fmt = &FMT_1080p2398; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_23_98HZ; } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 60 && myProfile->frame_rate_den == 1 && myProfile->progressive == 1) { info.fmt = &FMT_720p60; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_60HZ; } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 60000 && myProfile->frame_rate_den == 1001 && myProfile->progressive == 1) { info.fmt = &FMT_720p5994; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_59_94HZ; } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 50 && myProfile->frame_rate_den == 1 && myProfile->progressive == 1) { info.fmt = &FMT_720p50; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_50HZ; } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1 && myProfile->progressive == 1) { info.fmt = &FMT_720p30; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_30HZ; } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001 && myProfile->progressive == 1) { info.fmt = &FMT_720p2997; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_29_97HZ; } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1 && myProfile->progressive == 1) { info.fmt = &FMT_720p25; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_25HZ; } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 24 && myProfile->frame_rate_den == 1 && myProfile->progressive == 1) { info.fmt = &FMT_720p24; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_24HZ; } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 24000 && myProfile->frame_rate_den == 1001 && myProfile->progressive == 1) { info.fmt = &FMT_720p2398; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_23_98HZ; } else if (myProfile->width == 720 && myProfile->height == 576 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1 && myProfile->progressive == 0) { info.fmt = &FMT_576i50; sdi_frame_mode = SDIVIDEO_CTL_BT_601_576I_50HZ; } else if (myProfile->width == 720 && myProfile->height == 486 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001 && myProfile->progressive == 0) { info.fmt = &FMT_486i5994; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_125M_486I_59_94HZ; } else if (myProfile->width == 720 && myProfile->height == 480 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den == 1001 && myProfile->progressive == 0) { info.fmt = &FMT_480i5994; sdi_frame_mode = SDIVIDEO_CTL_SMPTE_125M_486I_59_94HZ; } else { printf("Consumer got unknown format: %s", myProfile->description); info.fmt = &FMT_576i50; sdi_frame_mode = SDIVIDEO_CTL_BT_601_576I_50HZ; } printf("Consumer use format: %s\nProfile: %i %i %i %i %i\n", myProfile->description, myProfile->width, myProfile->height, myProfile->frame_rate_num, myProfile->frame_rate_den, myProfile->progressive); // Check if the format supports own blanking (note: model 193 supports currently only active video at the video device file) if (info.blanking && info.fmt != &FMT_576i50) { printf("SDI consumer doesn't support blanking(HANC) for the configured SD board and SDI format. Try argument: blanking=false\n"); return EXIT_FAILURE; } // if we write our own HANC we need an AES channel status bit array if (info.blanking) { // small description // http://www.sencore.com/newsletter/Nov05/DigAudioChannelStatusBits.htm // or // http://www.sencore.com/uploads/files/DigAudioChannelStatusBits.pdf // create empty AESChannelStatusBitArray int i = 0; for (i = 0; i < sizeof(AESChannelStatusBitArray) / sizeof(AESChannelStatusBitArray[0]); i++) AESChannelStatusBitArray[i] = 0; /** * Professional Format - Channel Status Bits **/ ////// Byte 0 ////// AESChannelStatusBitArray[0] = 1; // professional format AESChannelStatusBitArray[1] = 0; // PCM Format AESChannelStatusBitArray[2] = 1; // Emphasis: [100] No Emphasis AESChannelStatusBitArray[3] = 0; // ^ AESChannelStatusBitArray[4] = 0; // ^ AESChannelStatusBitArray[5] = 0; // locked AESChannelStatusBitArray[6] = 0; // sample frequency Fs: [01]48kHz, [10]44kHz, [11]32kHz AESChannelStatusBitArray[7] = 1; // ^ ////// Byte 1 ////// AESChannelStatusBitArray[8] = 0; // channel mode: [0000] not indicated, [0001]2channels, [0010]1channel mono, ... AESChannelStatusBitArray[9] = 0; // ^ AESChannelStatusBitArray[10] = 0; // ^ AESChannelStatusBitArray[11] = 1; // ^ ////// Byte 2 ////// AESChannelStatusBitArray[19] = 0; // Encoded sample word length [100]20bits, AESChannelStatusBitArray[20] = 0; // AESChannelStatusBitArray[21] = 0; // ////// Byte 3 ////// AESChannelStatusBitArray[24] = 0; // AESChannelStatusBitArray[25] = 0; // AESChannelStatusBitArray[26] = 0; // AESChannelStatusBitArray[27] = 0; // AESChannelStatusBitArray[28] = 0; // AESChannelStatusBitArray[29] = 0; // AESChannelStatusBitArray[30] = 0; // AESChannelStatusBitArray[31] = 0; // Multi Channel Mode ////// Byte 4-21 ////// //AESChannelStatusBitArray[32-179]= 0; ////// Byte 22 ////// AESChannelStatusBitArray[180] = 0; // Reliability Flags AESChannelStatusBitArray[181] = 1; // ^ AESChannelStatusBitArray[182] = 1; // ^ AESChannelStatusBitArray[183] = 1; // ^ ////// Byte 23 ////// AESChannelStatusBitArray[184] = 0; // Cyclic Redundancy Check AESChannelStatusBitArray[185] = 1; // ^ AESChannelStatusBitArray[186] = 0; // ^ AESChannelStatusBitArray[187] = 0; // ^ AESChannelStatusBitArray[188] = 1; // ^ AESChannelStatusBitArray[189] = 0; // ^ AESChannelStatusBitArray[190] = 1; // ^ AESChannelStatusBitArray[191] = 1; // ^ } // set buffer for one line of active video samples line_buffer = (uint16_t*) calloc(info.fmt->samples_per_line, sizeof(uint16_t)); // calculate and set buffer for the complete SDI frame if (info.fmt != &FMT_576i50 && info.fmt != &FMT_486i5994) { if (info.blanking) { if (pack == pack_v210) { samples = (info.fmt->samples_per_line / 96 * 48) + ((info.fmt->samples_per_line % 96) ? 48 : 0); sdi_frame_size = samples * info.fmt->lines_per_frame * 8 / 3; } else { sdi_frame_size = info.fmt->samples_per_line * info.fmt->lines_per_frame; } } else { if (pack == pack_v210) { samples = (info.fmt->active_samples_per_line / 96 * 48) + ((info.fmt->active_samples_per_line % 96) ? 48 : 0); sdi_frame_size = samples * info.fmt->active_lines_per_frame * 8 / 3; } else { sdi_frame_size = info.fmt->active_samples_per_line * info.fmt->active_lines_per_frame; } } } else { if (info.blanking) { if (pack == pack_v210) { sdi_frame_size = info.fmt->samples_per_line * 4 / 3 * info.fmt->lines_per_frame; } else if (pack == pack8) { sdi_frame_size = info.fmt->samples_per_line * info.fmt->lines_per_frame; } else { sdi_frame_size = info.fmt->samples_per_line * 10 / 8 * info.fmt->lines_per_frame; } } else { if (pack == pack_v210) { sdi_frame_size = info.fmt->active_samples_per_line * 4 / 3 * info.fmt->active_lines_per_frame; } else if (pack == pack8) { sdi_frame_size = info.fmt->active_samples_per_line * info.fmt->active_lines_per_frame; } else { sdi_frame_size = info.fmt->active_samples_per_line * 10 / 8 * info.fmt->active_lines_per_frame; } } } // (*10/8 because we store (TOTAL_SAMPLES*TOTAL_LINES) words with 10 bit in this 8 bit array) ) if (info.fmt == &FMT_576i50 && info.blanking) { sdi_frame_size = info.fmt->samples_per_line * 10 / 8 * info.fmt->lines_per_frame; } if (info.blanking) { printf("SDI frame size: %"PRIu64"\n", sdi_frame_size); } else { printf("Frame size for active video: %"PRIu64"\n", sdi_frame_size); } /** * Setup HD-SDI Master device (vidport): * * if device_file_video available then * if vidport available * 1. setup * end * 1. open device file handler * * if device_file_audio available then * 1. setup * 2. open device file handler * end * end **/ if (device_file_video != NULL) { // If we use a Linsys HD board with active video (without blanking) setup the board for the used mode if (strstr(device_file_video, "sdivideotx") != NULL && !info.blanking) { char * value; // Buffer size value = itoa(sdi_frame_size); setSDIVideoProperties(SETTING_BUFFER_SIZE_VIDEO, value, device_video); free(value); // Frame Mode value = itoa(sdi_frame_mode); setSDIVideoProperties(SETTING_FRAME_MODE, value, device_video); free(value); // Data Mode if (pack == pack8) setSDIVideoProperties(SETTING_DATA_MODE, "0", device_video); else if (pack == pack_v210) setSDIVideoProperties(SETTING_DATA_MODE, "1", device_video); } // open file handle for SDI(video) output if ((fh_sdi_video = open(device_file_video, O_WRONLY)) == -1) { perror(NULL); printf("\ncould not open video output destination: %s\n", device_file_video); return EXIT_FAILURE; } printf("SDI consumer uses video device file: %s\n", device_file_video); // Check if we have to use a separate device file for audio if (device_file_audio != NULL) { // set settings for audio device file if (strstr(device_file_audio, "sdiaudiotx") != NULL && !info.blanking) { char * value; /** * prepare sample size * MLT suports: 16bit, 32bit * LINSYS SDI boards supports: 16bit, 24bit, 32bit * we set 16bit as default **/ uint8_t sample_size = audio_format->aformat == mlt_audio_s32 ? 32 : 16; // Buffer size // audio buffer per frame (Bytes) = sample rate / frame rate * ( sample size / 1Byte ) x channels value = itoa( (uint64_t) audio_format->sample_rate / ( (uint64_t) myProfile->frame_rate_num / (uint64_t) myProfile->frame_rate_den) * (uint64_t) sample_size / 8 * (uint64_t) audio_format->channels); setSDIAudioProperties(SETTING_BUFFER_SIZE_AUDIO, value, device_audio); free(value); // channels value = itoa(audio_format->channels); setSDIAudioProperties(SETTING_CHANNELS, value, device_audio); free(value); // sample rate value = itoa(audio_format->sample_rate); setSDIAudioProperties(SETTING_SAMPEL_RATE, value, device_audio); free(value); // sample size value = itoa(sample_size); setSDIAudioProperties(SETTING_SAMPLE_SIZE, value, device_audio); free(value); } // open file handle for audio output if ((fh_sdi_audio = open(device_file_audio, O_WRONLY)) == -1) { perror(NULL); printf("\nCould not open audio output destination: %s\n", device_file_audio); return EXIT_FAILURE; } printf("SDI consumer uses audio device file: %s\n", device_file_audio); } } // set buffer for the complete SDI frame data = (uint8_t*) calloc(sdi_frame_size, sizeof(uint8_t)); return 1; } /** * Writes video and audio to specified files in SDI format * @param *vBuffer: Pointer to a video Buffer * @param aBuffer[][] * @param *audio_format: mlt audio_format * @param audio_streams: number of audio streams which have content in aBuffer (available 0-8) * @return current DBN (data block number of SDI frame) **/ static int sdi_playout(uint8_t *vBuffer, int16_t aBuffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES], const struct audio_format * audio_format, int audio_streams, int my_DBN) { // Pointer to the start of data. This is used to fill data line by line uint8_t *p = data; //******************************************************************************************* //**************** Build the SDI frame line by line **************************************** //******************************************************************************************* /* * if SDI FMT_576i50 for card ASSY 145 or ASSY 159, with access to whole SDI frame buffer * and device_file_audio must be NULL * than we write own audio data, * else * than HD for card ASSY 193 */ //if (info.fmt == &FMT_576i50 && device_file_audio == NULL && !strcmp(device_file_video, "/dev/sdivideotx0")) { if (info.fmt == &FMT_576i50 && info.blanking) { //counter for the lines int i = 0; int16_t AudioGroupCounter = 0; /*#####################################################*/ /*######## FIELD 1 #######################*/ /*#####################################################*/ info.xyz = &FIELD_1_VERT_BLANKING; // line 1-22 VERTICAL_BLANKING:23 lines SAV 0x2ac EAV 0x2d8 for (i = 1; i <= 5; i++) { create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); AudioGroupCounter += getNumberOfAudioGroups2Write(i); p = pack10(p, line_buffer, info.fmt->samples_per_line); } for (i = 6; i <= 8; i++) { create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); AudioGroupCounter += getNumberOfAudioGroups2Write(i); p = pack10(p, line_buffer, info.fmt->samples_per_line); } for (i = 9; i <= 22; i++) { create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); AudioGroupCounter += getNumberOfAudioGroups2Write(i); p = pack10(p, line_buffer, info.fmt->samples_per_line); } // line 23-310 ACTIVE: 287 lines SAV 0x200 EAV 0x274 info.xyz = &FIELD_1_ACTIVE; int f1counter = 1; // only odd lines for (i = 23; i <= 310; i++) { create_SD_SDI_Line(line_buffer, &info, FIELD_1, ACTIVE_VIDEO, vBuffer, aBuffer, i, f1counter, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); AudioGroupCounter += getNumberOfAudioGroups2Write(i); p = pack10(p, line_buffer, info.fmt->samples_per_line); f1counter += 2; } i = 311; // line 311-312 VERTICAL_BLANKING: 2 lines SAV 0x2ac EAV 0x2d8 info.xyz = &FIELD_1_VERT_BLANKING; create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); AudioGroupCounter += getNumberOfAudioGroups2Write(i++); p = pack10(p, line_buffer, info.fmt->samples_per_line); create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); AudioGroupCounter += getNumberOfAudioGroups2Write(i++); p = pack10(p, line_buffer, info.fmt->samples_per_line); /*#####################################################*/ /*######## FIELD 2 ########################*/ /*#####################################################*/ info.xyz = &FIELD_2_VERT_BLANKING; // line 313-336 VERTICAL_BLANKING: 23 lines SAV 0x3b0 EAV 0x3c4 create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); AudioGroupCounter += getNumberOfAudioGroups2Write(i++); p = pack10(p, line_buffer, info.fmt->samples_per_line); create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); AudioGroupCounter += getNumberOfAudioGroups2Write(i++); p = pack10(p, line_buffer, info.fmt->samples_per_line); create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); AudioGroupCounter += getNumberOfAudioGroups2Write(i++); p = pack10(p, line_buffer, info.fmt->samples_per_line); create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); AudioGroupCounter += getNumberOfAudioGroups2Write(i++); p = pack10(p, line_buffer, info.fmt->samples_per_line); create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); AudioGroupCounter += getNumberOfAudioGroups2Write(i++); p = pack10(p, line_buffer, info.fmt->samples_per_line); create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); AudioGroupCounter += getNumberOfAudioGroups2Write(i++); p = pack10(p, line_buffer, info.fmt->samples_per_line); // `getAudioGroups2Write()`=0 for (i = 319; i <= 321; i++) { create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); AudioGroupCounter += getNumberOfAudioGroups2Write(i); p = pack10(p, line_buffer, info.fmt->samples_per_line); } for (i = 322; i <= 335; i++) { create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); AudioGroupCounter += getNumberOfAudioGroups2Write(i); p = pack10(p, line_buffer, info.fmt->samples_per_line); } // line 336-623 ACTIVE: 288 lines SAV 0x31c EAV 0x368 info.xyz = &FIELD_2_ACTIVE; int f2counter = 2; // only even Lines for (i = 336; i <= 623; i++) { create_SD_SDI_Line(line_buffer, &info, FIELD_2, ACTIVE_VIDEO, vBuffer, aBuffer, i, f2counter, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); AudioGroupCounter += getNumberOfAudioGroups2Write(i); p = pack10(p, line_buffer, info.fmt->samples_per_line); f2counter += 2; } // line 624-625 VERTICAL_BLANKING: 2 lines SAV 0x3b0 EAV 0x3c4 info.xyz = &FIELD_2_VERT_BLANKING; for (i = 624; i <= 625; i++) { create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); AudioGroupCounter += getNumberOfAudioGroups2Write(i); p = pack10(p, line_buffer, info.fmt->samples_per_line); } } else { // use HD board without blanking // start with first even line active_video_line = 1; /* ***************************************** * *********** LINE DISTRIBUTION *********** * ***************************************** * * << decide form of scanning (interlaced || progressive) >> * if (interlaced) * << decide lines per frame (1125 || 625 || 525) >> * if(1125) 1080x1920 HD * than create lines * else if(625) 576x720 PAL * than create lines * else (525) 486x720 NTSC * than create lines * else (progressive) * << decide resolution (1125 || 750) >> * if(1125) 1080x1920 HD * than create lines * else(750) 720x1280 HD * than create lines * **/ // Generate a frame if (info.fmt->interlaced) { /**************************************** * INTERLACED ****************************************/ if (info.fmt->lines_per_frame == 1125) { if (info.blanking) { elements = info.fmt->samples_per_line; info.xyz = &FIELD_1_VERT_BLANKING; for (info.ln = 1; info.ln <= 20; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } } else { elements = info.fmt->active_samples_per_line; } info.xyz = &FIELD_1_ACTIVE; for (info.ln = 21; info.ln <= 560; info.ln++) { create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer); p = pack(p, line_buffer, elements); active_video_line += 2; } if (info.blanking) { info.xyz = &FIELD_1_VERT_BLANKING; for (info.ln = 561; info.ln <= 563; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } info.xyz = &FIELD_2_VERT_BLANKING; for (info.ln = 564; info.ln <= 583; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } } // start with first odd line active_video_line = 2; info.xyz = &FIELD_2_ACTIVE; for (info.ln = 584; info.ln <= 1123; info.ln++) { create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer); p = pack(p, line_buffer, elements); active_video_line += 2; } if (info.blanking) { info.xyz = &FIELD_2_VERT_BLANKING; for (info.ln = 1124; info.ln <= 1125; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } } } else if (info.fmt->lines_per_frame == 625) { elements = info.fmt->active_samples_per_line; // start with first even line active_video_line = 1; /** * Generate an SDI PAL frame **/ if (info.blanking) { info.xyz = &FIELD_1_VERT_BLANKING; for (info.ln = 1; info.ln <= 22; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } } info.xyz = &FIELD_1_ACTIVE; for (info.ln = 23; info.ln <= 310; info.ln++) { create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer); p = pack(p, line_buffer, elements); active_video_line += 2; } if (info.blanking) { info.xyz = &FIELD_1_VERT_BLANKING; for (info.ln = 311; info.ln <= 312; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } info.xyz = &FIELD_2_VERT_BLANKING; for (info.ln = 313; info.ln <= 335; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } } // start with first odd line active_video_line = 2; info.xyz = &FIELD_2_ACTIVE; for (info.ln = 336; info.ln <= 623; info.ln++) { create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer); p = pack(p, line_buffer, elements); active_video_line += 2; } if (info.blanking) { info.xyz = &FIELD_2_VERT_BLANKING; for (info.ln = 624; info.ln <= 625; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } } } else if (info.fmt->lines_per_frame == 525) { /** * Generate an SDI NTSC frame * * * 16 lines VERT_BLANKING FIELD_1_VERT_BLANKING * 1 lines VERT_BLANKING FIELD_1_ACTIVE * 3 lines ACTIVE_VIDEO FIELD_1_ACTIVE (opt. video data) * 240 lines ACTIVE_VIDEO FIELD_1_ACTIVE * 2 lines VERT_BLANKING FIELD_1_VERT_BLANKING * * 8 lines VERT_BLANKING FIELD_2_VERT_BLANKING * 9 lines VERT_BLANKING FIELD_2_VERT_BLANKING * 3 lines ACTIVE_VIDEO FIELD_2_ACTIVE (opt. video data) * 240 lines ACTIVE_VIDEO FIELD_2_ACTIVE * 4 lines VERT_BLANKING FIELD_2_VERT_BLANKING * **/ elements = info.fmt->active_samples_per_line; active_video_line = 1; if (info.blanking) { info.xyz = &FIELD_1_VERT_BLANKING; for (info.ln = 1; info.ln <= 15; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } for (info.ln = 16; info.ln <= 16; info.ln++) { info.xyz = &FIELD_1_ACTIVE; mkline(line_buffer, &info, VERT_BLANKING); p = pack(p, line_buffer, elements); } } info.xyz = &FIELD_1_ACTIVE; // 480 or 486 lines if (info.fmt == &FMT_480i5994) { // 3 lines opt. video data for (info.ln = 17; info.ln <= 19; info.ln++) { mkline(line_buffer, &info, BLACK); p = pack(p, line_buffer, elements); } // 240 lines for (info.ln = 20; info.ln <= 259; info.ln++) { create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer); p = pack(p, line_buffer, elements); active_video_line += 2; } } else { // 243 lines for (info.ln = 17; info.ln <= 259; info.ln++) { create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer); p = pack(p, line_buffer, elements); active_video_line += 2; } } if (info.blanking) { // 2 lines vertical data info.xyz = &FIELD_1_VERT_BLANKING; for (info.ln = 260; info.ln <= 261; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } // 8 lines vertical data info.xyz = &FIELD_2_VERT_BLANKING; for (info.ln = 262; info.ln <= 269; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } // 9 lines for (info.ln = 270; info.ln <= 278; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } } active_video_line = 0; // 480 or 486 lines if (info.fmt == &FMT_480i5994) { // 3 lines opt. video data info.xyz = &FIELD_2_ACTIVE; for (info.ln = 279; info.ln <= 281; info.ln++) { mkline(line_buffer, &info, BLACK); p = pack(p, line_buffer, elements); } // 240 lines for (info.ln = 282; info.ln <= 521; info.ln++) { create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer); p = pack(p, line_buffer, elements); active_video_line += 2; } } else { // 243 lines for (info.ln = 279; info.ln <= 521; info.ln++) { create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer); p = pack(p, line_buffer, elements); active_video_line += 2; } } // 4 lines vertical data if (info.blanking) { info.xyz = &FIELD_2_VERT_BLANKING; for (info.ln = 522; info.ln <= 525; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } } } } else { /**************************************** * PROGRESSIVE ****************************************/ // start with first line numerber active_video_line = 0; if (info.fmt->lines_per_frame == 1125) { if (info.blanking) { elements = info.fmt->samples_per_line; info.xyz = &FIELD_1_VERT_BLANKING; for (info.ln = 1; info.ln <= 41; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } } else { elements = info.fmt->active_samples_per_line; } info.xyz = &FIELD_1_ACTIVE; for (info.ln = 42; info.ln <= 1121; info.ln++) { create_HD_SDI_Line(line_buffer, &info, active_video_line++, ACTIVE_VIDEO, vBuffer); p = pack(p, line_buffer, elements); } if (info.blanking) { info.xyz = &FIELD_1_VERT_BLANKING; for (info.ln = 1122; info.ln <= 1125; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } } } else { if (info.blanking) { elements = info.fmt->samples_per_line; info.xyz = &FIELD_1_VERT_BLANKING; for (info.ln = 1; info.ln <= 25; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } } else { elements = info.fmt->active_samples_per_line; } info.xyz = &FIELD_1_ACTIVE; for (info.ln = 26; info.ln <= 745; info.ln++) { create_HD_SDI_Line(line_buffer, &info, active_video_line++, ACTIVE_VIDEO, vBuffer); p = pack(p, line_buffer, elements); } if (info.blanking) { info.xyz = &FIELD_1_VERT_BLANKING; for (info.ln = 746; info.ln <= 750; info.ln++) { create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); p = pack(p, line_buffer, elements); } } } } } // sum of bytes that have already been written to file int bytes = 0; // store actual written bytes per 'write() int written_bytes = 0; /** * WRITE BUFFER TO FILEHANDLE **/ // Write the complete frame to output // The "while" is necessary because the sdi device file does not take the complete frame at once written_bytes = 0; while (bytes < sdi_frame_size) { if ((written_bytes = write(fh_sdi_video, data + bytes, sdi_frame_size - bytes)) < 0) { fprintf(stderr, "\nunable to write SDI video.\n"); return -1; } bytes += written_bytes; } // Check for events of the SDI board unsigned int val; if (ioctl(fh_sdi_video, SDI_IOC_TXGETEVENTS, &val) < 0) { // Maybe this is not an SDI device... //fprintf(stderr, "SDI VIDEO output:"); //perror("unable to get the transmitter event flags"); } else if (val) { if (val & SDI_EVENT_TX_BUFFER) { printf("SDI VIDEO driver transmit buffer queue underrun " "detected.\n"); fflush(stdout); } if (val & SDI_EVENT_TX_FIFO) { printf("SDI VIDEO onboard transmit FIFO underrun detected.\n"); fflush(stdout); } if (val & SDI_EVENT_TX_DATA) { printf("SDI VIDEO transmit data change detected.\n"); fflush(stdout); } } // if available write audio data if (fh_sdi_audio) { // count writen bytes written_bytes = 0; // set number of samples and cut by 1600 if NTSC (handle problem of real time encoding of NTSC frequencies) size_t samples_total_per_track = audio_format->samples; uint16_t sample_number = 0; size_t channels_per_track_total = 2; uint8_t stream_number = 0; //printf("samples_total_per_track:%li\n", samples_total_per_track); // to write blockwise 2 samples of one track we must claculate the number of bytes we want to write per write-session // 2samples = 2x16Bit = 32Bit = 4Byte // 2samples = 2x32Bit = 64Bit = 8Byte // set total bytes per session size_t bytes_total = 0; bytes_total = audio_format->aformat == mlt_audio_s16 ? channels_per_track_total * sizeof(int16_t) : bytes_total; bytes_total = audio_format->aformat == mlt_audio_s32 ? channels_per_track_total * sizeof(int32_t) : bytes_total; // write all samples of all streams interleaved /** * aBuffer[track0]+sample1 * aBuffer[track0]+sample2 * aBuffer[track1]+sample1 * aBuffer[track1]+sample2 * aBuffer[track.]+sample1 * aBuffer[track.]+sample2 * * aBuffer[track0]+sample3 * aBuffer[track0]+sample4 * aBuffer[track1]+sample3 * aBuffer[track1]+sample4 * aBuffer[track.]+sample3 * aBuffer[track.]+sample4 * * aBuffer[track0]+sample5 * aBuffer[track0]+sample6 * aBuffer[track1]+sample5 * aBuffer[track1]+sample6 * aBuffer[track.]+sample5 * aBuffer[track.]+sample6 **/ int sum_written_bytes = 0; int sum_written_bytes_a = 0; int sum_written_bytes_b = 0; // write all samples per track while (sample_number < samples_total_per_track) { stream_number = 0; /** * Because we have and write a fix number of audio streams to SDI board: * we have a actual number of real audio tracks and a rest number of pseudo tracks **/ // write all streams while (stream_number < audio_streams) { // write for every stream n samples // n = number of channels per stream written_bytes = 0; while (written_bytes < bytes_total) { written_bytes += write(fh_sdi_audio, (uint8_t *) aBuffer[stream_number] + sample_number * bytes_total + written_bytes, bytes_total - written_bytes); } sum_written_bytes += written_bytes; sum_written_bytes_a += written_bytes; stream_number++; } // write pseudo tracks // now fill rest of audio tracks(AES frames) with NULL or copy of first track while (stream_number < audio_format->channels / 2) { // write for every stream n samples // n = number of channels per stream written_bytes = 0; while (written_bytes < bytes_total) { written_bytes += write(fh_sdi_audio, (uint8_t *) aBuffer[0] + sample_number * bytes_total + written_bytes, bytes_total - written_bytes); } sum_written_bytes += written_bytes; sum_written_bytes_b += written_bytes; stream_number++; } sample_number++; // Check for events of the SDI audio device unsigned int val; if (ioctl(fh_sdi_audio, SDIAUDIO_IOC_TXGETEVENTS, &val) < 0) { //Maybe this is not an SDI device... // fprintf(stderr, "SDI AUDIO output:"); // perror("unable to get the transmitter event flags"); } else if (val) { if (val & SDIAUDIO_EVENT_TX_BUFFER) { printf("SDI AUDIO driver transmit buffer queue underrun " "detected.\n"); } if (val & SDIAUDIO_EVENT_TX_FIFO) { printf("SDI AUDIO onboard transmit FIFO underrun detected.\n"); } if (val & SDIAUDIO_EVENT_TX_DATA) { printf("SDI AUDIO transmit data change detected.\n"); } } } } return getDBN(my_DBN); } // end sdimaster_playout() //**************************************************************************************** //*************************** Create Line ********************************************** //**************************************************************************************** /** generate one SDI line * @param *buf: buffer to hold the line * @param field: size of the video Buffer * @param active: v-blank or active-video * @param *video_buffer: video buffer * @param *audio_buffer2: 1.audio buffer ch1-ch2 * @param *audio_buffer1: 2.audio buffer ch2-ch3 * @param line: linenumber * @param AudioGroupCounter: count written AudioGroup * @param AudioGroups2Write: number of samples to write * @param audio_streams: number of audio streams to integrate */ static inline int create_SD_SDI_Line(uint16_t *buf, const struct line_info *info, int field, int active, uint8_t *video_buffer, int16_t audio_buffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES], int linenumber_sdiframe, int active_video_line, int my_DBN, int16_t AudioGroupCounter, int16_t AudioGroups2Write, int audio_streams) { // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2) // ************************************************************************* // 625 lines: | EAV | ANC | SAV | [CbY1CrY2] | // ************************************************************************* // 1728 SDI-words: | 4 | 280 | 4 | 720+360+360=1440 | // ************************************************************************* // points to current position in line uint16_t *p = buf; //######################################################################################### /* TRS Timing Reference Signal for EAV * [3ff] * [000] * [000] * [XYZ-Wort] * */ *p++ = 0x3ff; *p++ = 0x000; *p++ = 0x000; *p++ = info->xyz->eav; //######################################################################################### /* ANC Ancillary Data with AES * * [ADF][ADF][ADF][DID][DBN][DC][UDW]...[UDW][CS] * * */ // write ANC Data and get number of samples are written // step with `p` += to the number of written samples //printf("audio_streams:%i\n",audio_streams); // 1 stream, Audio Group 1 with AES Frame 1 - 2 if (audio_streams == 1) { p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[0], AudioGroupCounter, AudioGroups2Write); } // 2 streams, Audio Group 1 with AES Frame 1 - 2 if (audio_streams == 2) { p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write); } // 3 streams, Audio Group 2 with AES Frame 1 - 4 if (audio_streams == 3) { p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write); p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[2], AudioGroupCounter, AudioGroups2Write); } // 4 streams, Audio Group 2 with AES Frame 1 - 4 if (audio_streams == 4) { p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write); p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write); } // 5 streams, Audio Group 3 with AES Frame 1 - 6 if (audio_streams == 5) { p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write); p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write); p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[4], AudioGroupCounter, AudioGroups2Write); } // 6 streams, Audio Group 3 with AES Frame 1 - 6 if (audio_streams == 6) { p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write); p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write); p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write); } // 7 streams, Audio Group 4 with AES Frame 1 - 7 if (audio_streams == 7) { p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write); p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write); p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write); p += writeANC(p, linenumber_sdiframe, 0x2F9, my_DBN, audio_buffer[6], audio_buffer[6], AudioGroupCounter, AudioGroups2Write); } // 8 streams, Audio Group 4 with AES Frame 1 - 7 if (audio_streams == 8) { p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write); p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write); p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write); p += writeANC(p, linenumber_sdiframe, 0x2F9, my_DBN, audio_buffer[6], audio_buffer[7], AudioGroupCounter, AudioGroups2Write); } // Fill ANC data in until the end (position(p) to `ANCILLARY_DATA_SAMPLES`) while (p < (buf + ANCILLARY_DATA_SAMPLES + 4)) { // video color: black *p++ = 0x200; *p++ = 0x040; } //######################################################################################### // TRS Timing Reference Signal for SAV *p++ = 0x3ff; *p++ = 0x000; *p++ = 0x000; *p++ = info->xyz->sav; //######################################################################################### // Because we skip the first line of video, it can happen that we read too far in the buffer if (active_video_line >= info->fmt->active_lines_per_frame) { active_video_line = info->fmt->active_lines_per_frame - 1; // in SD PAL was set 575 } //Index of the start of the current line in the video_buffer int start_of_current_line = active_video_line * info->fmt->active_samples_per_line; // If VBlank then fill the line with 0x200 and 0x040 (total black) switch (active) { default: case VERT_BLANKING: while (p < (buf + info->fmt->samples_per_line)) { *p++ = 0x200; *p++ = 0x040; } break; case ACTIVE_VIDEO: // Insert the video into the line while (p < (buf + info->fmt->samples_per_line)) { // fill the rest of the line with active video // shift "<< 2" because 8 bit data in 10 bit word *p = video_buffer[start_of_current_line + ((p - 288) - buf) + 1] << 2; // Cb p++; if (*(p - 1) < 0x040) *(p - 1) = 0x040; // check values if (*(p - 1) > 0x3c0) *(p - 1) = 0x3c0; *p = video_buffer[start_of_current_line + ((p - 288) - buf) - 1] << 2; // Y1 p++; if (*(p - 1) < 0x040) *(p - 1) = 0x040; if (*(p - 1) > 0x3ac) *(p - 1) = 0x3ac; *p = video_buffer[start_of_current_line + ((p - 288) - buf) + 1] << 2; // Cr p++; if (*(p - 1) < 0x040) *(p - 1) = 0x040; if (*(p - 1) > 0x3c0) *(p - 1) = 0x3c0; *p = video_buffer[start_of_current_line + ((p - 288) - buf) - 1] << 2; // Y2 p++; if (*(p - 1) < 0x040) *(p - 1) = 0x040; if (*(p - 1) > 0x3ac) *(p - 1) = 0x3ac; } break; } return 0; } /** * create_HD_SDI_Line - generate one line * @buf: pointer to a buffer * @info: pointer to a line information structure * @active_video_line * @active: * @video_buffer: pattern * * Returns a negative error code on failure and zero on success. **/ static inline int create_HD_SDI_Line(uint16_t *buf, const struct line_info *info, uint16_t active_video_line, unsigned int active, uint8_t *video_buffer) { uint16_t *p = buf, *endp, ln; uint16_t samples = info->blanking ? info->fmt->samples_per_line : info->fmt->active_samples_per_line; if (active_video_line >= info->fmt->active_lines_per_frame) { active_video_line = info->fmt->active_lines_per_frame - 1; } int start_of_current_line = active_video_line * info->fmt->active_samples_per_line; if (info->blanking) { // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2) // Example SD PAL: // ************************************************************************* // 625 lines: | EAV | ANC | SAV | [CbY1CrY2] | // ************************************************************************* // 1728 SDI-words: | 4 | 280 | 4 | 720+360+360=1440 | // ************************************************************************* // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2) // Example HD 1080i: // ************************************************************************* // 1125 lines: | EAV | LN | CRC | ANC | SAV | [CbY1CrY2] | // ************************************************************************* // 5280 SDI-words: | 6 | 4 | 4 | 280 | 6 | 1920+720+720=3840 | // ************************************************************************* if (info->fmt == &FMT_576i50) { /* EAV */ *p++ = 0x3ff; *p++ = 0x000; *p++ = 0x000; *p++ = info->xyz->eav; } else { /* EAV */ *p++ = 1023; *p++ = 1023; *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 0; *p++ = info->xyz->eav; *p++ = info->xyz->eav; /* LN */ ln = ((info->ln & 0x07f) << 2) | (~info->ln & 0x040) << 3; *p++ = ln; *p++ = ln; ln = ((info->ln & 0x780) >> 5) | 0x200; *p++ = ln; *p++ = ln; /* CRC, added by serializer */ *p++ = 512; *p++ = 64; *p++ = 512; *p++ = 64; } /* Horizontal blanking */ while (p < (buf + info->fmt->samples_per_line - info->fmt->active_samples_per_line - 4)) { *p++ = 512; *p++ = 64; *p++ = 512; *p++ = 64; } if (info->fmt == &FMT_576i50) { /* SAV */ *p++ = 0x3ff; *p++ = 0x000; *p++ = 0x000; *p++ = info->xyz->sav; } else { /* SAV */ *p++ = 1023; *p++ = 1023; *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 0; *p++ = info->xyz->sav; *p++ = info->xyz->sav; } } /* Active region */ endp = p; switch (active) { default: case VERT_BLANKING: while (p < (buf + samples)) { *p++ = 512; *p++ = 64; *p++ = 512; *p++ = 64; } break; case ACTIVE_VIDEO: { while (p < (buf + samples)) { *p = video_buffer[start_of_current_line + (p - buf) + 1] << 2; // Cb p++; //check values, this needs a lot of resources // if (*(p - 1) < 0x040) // *(p - 1) = 0x040; // if (*(p - 1) > 0x3c0) // *(p - 1) = 0x3c0; // *p = video_buffer[start_of_current_line + (p - buf) - 1] << 2; // Y1 p++; // if (*(p - 1) < 0x040) // *(p - 1) = 0x040; // if (*(p - 1) > 0x3ac) // *(p - 1) = 0x3ac; // *p = video_buffer[start_of_current_line + (p - buf) + 1] << 2; // Cr p++; // if (*(p - 1) < 0x040) // *(p - 1) = 0x040; // if (*(p - 1) > 0x3c0) // *(p - 1) = 0x3c0; // *p = video_buffer[start_of_current_line + (p - buf) - 1] << 2; // Y2 p++; // if (*(p - 1) < 0x040) // *(p - 1) = 0x040; // if (*(p - 1) > 0x3ac) // *(p - 1) = 0x3ac; } } break; } return 0; } static int writeANC(uint16_t *p, int videoline_sdiframe, uint16_t DID, int my_DBN, int16_t *audio_buffer_A, int16_t *audio_buffer_B, int16_t AudioGroupCounter, int16_t AudioGroups2Write) { /** * ANC Ancillary Data (vgl. SMPTE 291-M page 6 ) * [ADF][ADF][ADF][DID][DBN][DC][UDW]...[UDW][CS] * **/ // save only current position for return value uint16_t *pp = p; // 16bit buffer to write temporarily 10bit word uint16_t buffer = 0; // set all explicit to zero, special the bit9 for parity // parity_counter int8_t parity_counter = 0; if (AudioGroups2Write > 0) { // 3 ADF (Ancillary Data Flag) *p++ = 0x000; *p++ = 0x3FF; *p++ = 0x3FF; // 1 DID (Data Identification) // save DID for checker() uint16_t *DID_pointer = p; *p++ = DID;// (AES Audio Data, Group // *p++ = 0x2FF; // (AES Audio Data, Group1=0x2FF) // *p++ = 0x1FD; // (AES Audio Data, Group2=0x1FD) // *p++ = 0x1FB; // (AES Audio Data, Group3=0x1FB) // *p++ = 0x2F9; // (AES Audio Data, Group4=0x2F9) // 1 DBN (Data Block Number) inactiv: 1000000000 b9,b8,b7-b0 ; SMPTE 272-M chapter15.1 // *p++ = 0x200; // 1 DBN (dynamic version0.1-beta ), should start with previus DBN of SDI-Frame // -need "previus DBN" or "current framenumber" // SDI-LINE: DBN: // [1] [1] << start sdi frame // [2] [2] // [.] [.] // [255] [255] // [256] [1] // [257] [2] // [.] [.] // [510] [255] // [511] [1] // [512] [2] // [.] [.] // [625] [115] << end sdi frame // [1] [116] << start sdi frame // Accuracy of videoline_sdiframe(1 up to 625) to 8bit (1-255) //buffer = ((videoline_sdiframe-1) % 255)+1; buffer = my_DBN; parity_counter = 0; // count binary ones for parity int i = 0; for (i = 0; i < 8; i++) { if (buffer & (1 << i)) parity_counter++; } if ((parity_counter % 2) == 0) { //else leave the 0 buffer += 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8 } else { buffer += 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8 } *p++ = buffer; // 1 DC (Data Counter) // number of UDW = AudioGroups2Write x 2AESFrames x 2channesl x 3words(X,X+1,X+2) buffer = AudioGroups2Write * 2 * 2 * 3; parity_counter = 0; // count binary ones for parity for (i = 0; i < 8; i++) { if (buffer & (1 << i)) parity_counter++; } if ((parity_counter % 2) == 0) { //else leave the 0 buffer += 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8 } else { buffer += 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8 } *p++ = buffer; int16_t sample_number = 0; int16_t counter = 0; // write subframes: // = n x 1 AudioGroup // = n x 2 x 1AESFrame // = n x 2 x 2samples // = 4 samples // = 4 x 3words while (counter < AudioGroups2Write * 2) { /* 4:3 */ // write one Audio Group with 4 x AES subframes // ( samples for ch01,ch02,ch03,ch04 or ch05,ch06,ch07,ch08 or ch09,ch10,ch11,ch12 or ch13,ch14,ch15,ch16) // and use audio_buffer_A(stereo) and audio_buffer_B(stereo) // `pack_AES_subframe()` write 3 ANC words (3*10bit), also 1 sample sample_number = (AudioGroupCounter * 2) + counter; pack_AES_subframe(p, getChannelStatusBit(sample_number / 2, 1), getZBit(sample_number / 2), 0, &audio_buffer_A[sample_number]); // left p += 3; // step 3 words sample_number = (AudioGroupCounter * 2) + counter + 1; pack_AES_subframe(p, getChannelStatusBit(sample_number / 2, 2), getZBit(sample_number / 2), 1, &audio_buffer_A[sample_number]); // right p += 3; sample_number = (AudioGroupCounter * 2) + counter; pack_AES_subframe(p, getChannelStatusBit(sample_number / 2, 3), getZBit(sample_number / 2), 2, &audio_buffer_B[sample_number]); // left p += 3; sample_number = (AudioGroupCounter * 2) + counter + 1; pack_AES_subframe(p, getChannelStatusBit(sample_number / 2, 4), getZBit(sample_number / 2), 3, &audio_buffer_B[sample_number]); // right p += 3; counter += 2; } // 1 CS (Checksum from DID - UDW) *p++ = checker(DID_pointer); // fill ANC with one dummy for videocolor black // rest until end of `ANCILLARY_DATA_SAMPLES` will be fill in a loop after call this function *p++ = 0x040; } return p - pp; } // calculate checksumm of ANC (SMPTE 272-M 15.3 Checksum (CS)) static uint16_t checker(uint16_t *DID_pointer) { // Checksumm uint16_t cs = 0x00; // DID - Datablock Identification cs += (*DID_pointer++) & 0x1FF; // 9 x LSB // DBN - Datablock Number cs += (*DID_pointer++) & 0x1FF; // 9 x LSB // DC - DataCounter cs += (*DID_pointer) & 0x1FF; // 9 x LSB // store address of DC an ad to the real value of DC // DataCounter store // ´ende´ point to DataCounter uint16_t *ende = DID_pointer; // ´ende´ point to last field ende += (*DID_pointer) & 0xFF; // without parity-Bit and ¬9-Bit DID_pointer++; // while DID_pointer point to smaller addres like 'ende' while (DID_pointer <= ende) { cs += (*DID_pointer++) & 0x1FF; // 9 x LSB } // limit to 9Bit, because of overflow of sum cs = cs & 0x1FF; // set bit10 NOT bit9: // - cs invert // - & with bitmask '01 0000 0000' // - shift rest (1xbit)to left // - add to cs cs += ((~cs) & 0x100) << 1; return cs; } // end checker /** * pack 16bit in AES subframe with 3 words (30 bit) and write in ´*p´ * 10bit-words --> [X],[X+1], [X+2] implements 20bit for audio * * BIT 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 * ##### ### ### ### ### ### ### ### ### ### * [X] : [ !bit8, a5, a4, a3, a2, a1, a0, ch0, ch1, z ], * [X+1] : [ !bit8, a14, a13, a12, a11, a10, a9, a8, a7 , a6 ], * [X+2] : [ !bit8, P, C, U, V, a19, a18, a17, a16, a15 ] * * @param *p: Pointer to SDI frame buffer * @param c: value of AES subframe Channel Status Bit * @param z: value of AES subframe * @param ch: channel od AES subframe (value:0,1,2,3) * @param *audio_samplex: pointer to the audio buffer **/ static int pack_AES_subframe(uint16_t *p, int8_t c, int8_t z, int8_t ch, int16_t *audio_samplex) { /** * NOTE: WE JUST SUPPORT ONLY 16BIT SAMPLE SIZE **/ // push 16bit up to 20bit(32bit) int32_t audio_sample = *audio_samplex; audio_sample = audio_sample << 4; // Shift by 4 (louder) // parity_counter int8_t parity_counter = 0; // 16bit buffer to write 10bit of [X]word,[X+1]word,[X+2]word, uint16_t buffer = 0; //######################################################### //### WORD X ############################################ //######################################################### // word X: !bit8, a5, a4, a3, a2, a1, a0, ch1, ch0, z // SMPTE 272M s.7 buffer = z; // z bit every 192bit = 1 buffer += ch << 1; // ch1 - ch0 buffer += (audio_sample & 0x3f) << 3; // a5 - a0 buffer += ((~buffer) & 0x100) << 1; // !bit8 // write word ´X´ *p++ = buffer; // count ones int i = 0; for (i = 0; i < 9; i++) { if (buffer & 1 << i) parity_counter++; } //######################################################### //### WORD X+1 ############################################ //######################################################### // word X+1: !bit8, a14, a13, a12, a11, a10, a9, a8, a7, a6 // SMPTE 272M s.7 buffer = 0; buffer += (audio_sample >> 6) & 0x1ff; // a14 - a6 buffer += ((~buffer) & 0x100) << 1; // !bit8 // write word ´X+1´ *p++ = buffer; // count ones (zähle Einsen) i = 0; for (i = 0; i < 9; i++) { if (buffer & 1 << i) parity_counter++; } //######################################################### //### WORD X+2 ############################################ //######################################################### // word X+2: !bit8, P, C, U, V, a19, a18, a17, a16, a15 // SMPTE 272M s.7 buffer = 0; buffer += (audio_sample >> 15) & 0x01F; // a15 - a19 // default of [V][U][C] bits = `0` //buffer += 1<<5; // V (AES sample validity bit) //buffer += 1<<6; // U (AES user bit) //buffer += 1<<7; // C (AES audio channel status bit) buffer += c << 7; // C (AES audio channel status bit) // count ones (zähle Einsen) for (i = 0; i < 8; i++) { if (buffer & 1 << i) parity_counter++; } // if (!parity_counter%2) //else leave the 0 // buffer+= 1 << 8; // P (AES even parity bit) // // buffer += ((~buffer) & 0x100 )<<1; // !bit8 if ((parity_counter % 2) == 0) { //else leave the 0 buffer += 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8 } else { buffer += 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8 } *p++ = buffer; // write word ´X+2´ *p++ = buffer; return 1; } static uint8_t getZBit(int sample_number) { // start in SDI line 6 also 18samples later //sample_number+=192-18; if (sample_number % 192 == 0) { //printf("1 %i\n", sample_number); return 1; } else { //printf("0"); return 0; } } static uint8_t getChannelStatusBit(uint16_t sample_number, uint8_t ch) { // return value uint8_t AESChannelStatusBit = 0; // start in SDI line 6 also 18samples later //AESChannelStatusBit=((sample_number+192-18)%192); // interval in 192bit AESChannelStatusBit = sample_number % 192; // when mulichannelmode is true if (AESChannelStatusBitArray[31] == 1) { // set bits for channel if (AESChannelStatusBit == 30 && ch == 2) return 1; if (AESChannelStatusBit == 30 && ch == 4) return 1; if (AESChannelStatusBit == 29 && (ch == 4)) return 1; if (AESChannelStatusBit == 29 && (ch == 3)) return 1; } return AESChannelStatusBitArray[AESChannelStatusBit]; } static int16_t getNumberOfAudioGroups2Write(int linenumber) { // `4:3_VTR`-distribution if (linenumber >= 11 && linenumber <= 95) { if ((linenumber - 11) % 14 == 0) { return 4; } else { return 3; } } else if (linenumber >= 108 && linenumber <= 220) { if ((linenumber - 10) % 14 == 0) { return 4; } else { return 3; } } else if (linenumber >= 233 && linenumber <= 345) { if ((linenumber - 9) % 14 == 0) { return 4; } else { return 3; } } else if (linenumber >= 358 && linenumber <= 470) { if ((linenumber - 8) % 14 == 0) { return 4; } else { return 3; } } else if (linenumber >= 483 && linenumber <= 595) { if ((linenumber - 7) % 14 == 0) { return 4; } else { return 3; } } else if (linenumber >= 608 && linenumber <= 622) { if ((linenumber - 6) % 14 == 0) { return 4; } else { return 3; } } else { return 3; } // // `4:3`-distribution // if(linenumber<=315){ // if(linenumber>=6 && linenumber<=8){ // return 0; // } // if((linenumber+5)%10==0){ // return 4; // }else{ // return 3; // } // }else{ // if(linenumber>=319 && linenumber<=321){ // return 0; // } // if((linenumber-8)%10==0){ // return 4; // }else{ // return 3; // } // } // // full-distribution // if(linenumber<=45){ // return 4; // }else{ // return 3; // } // // fullhalf-distribution // if (linenumber==625) // return 4; // // if (linenumber%14==0) { // return 4; // } else { // return 3; // } } static uint8_t getDBN(int my_DBN) { return ((my_DBN - 1) % 255) + 1; } /** * pack8 - pack a line of 8-bit data * @outbuf: pointer to the output buffer * @inbuf: pointer to the input buffer * @count: number of elements in the buffer * * Returns a pointer to the next output location. **/ static inline uint8_t * pack8(uint8_t *outbuf, uint16_t *inbuf, size_t count) { uint16_t *inp = inbuf; uint8_t *outp = outbuf; while (inp < (inbuf + count)) { *outp++ = *inp++ >> 2; } return outp; } /** * pack10 - pack a line of 10-bit data * @outbuf: pointer to the output buffer * @inbuf: pointer to the input buffer * @count: number of elements in the buffer * * Returns a pointer to the next output location. **/ static inline uint8_t * pack10(uint8_t *outbuf, uint16_t *inbuf, size_t count) { uint16_t *inp = inbuf; uint8_t *outp = outbuf; while (inp < (inbuf + count)) { *outp++ = *inp & 0xff; *outp = *inp++ >> 8; *outp++ += (*inp << 2) & 0xfc; *outp = *inp++ >> 6; *outp++ += (*inp << 4) & 0xf0; *outp = *inp++ >> 4; *outp++ += (*inp << 6) & 0xc0; *outp++ = *inp++ >> 2; } return outp; } /** * pack_v210 - pack a line of v210 data * @outbuf: pointer to the output buffer * @inbuf: pointer to the input buffer * @count: number of elements in the buffer * * Returns a pointer to the next output location. **/ static inline uint8_t * pack_v210(uint8_t *outbuf, uint16_t *inbuf, size_t count) { uint16_t *inp = inbuf; uint8_t *outp = outbuf; count = (count / 96) * 96 + ((count % 96) ? 96 : 0); while (inp < (inbuf + count)) { *outp++ = *inp & 0xff; *outp = *inp++ >> 8; *outp++ += (*inp << 2) & 0xfc; *outp = *inp++ >> 6; *outp++ += (*inp << 4) & 0xf0; *outp++ = *inp++ >> 4; } return outp; } // Clean up static int sdimaster_close() { free(line_buffer); free(data); if (fh_sdi_audio) close(fh_sdi_audio); if (fh_sdi_video) close(fh_sdi_video); return 1; } /** * mkline - generate one line * @buf: pointer to a buffer * @info: pointer to a line information structure * @pattern: pattern * * Returns a negative error code on failure and zero on success. **/ static int mkline(unsigned short int *buf, const struct line_info *info, unsigned int pattern) { const unsigned int b = 205; unsigned short int *p = buf, *endp; unsigned int samples = info->blanking ? info->fmt->samples_per_line : info->fmt->active_samples_per_line; if (info->blanking) { /* EAV */ *p++ = 0x3ff; *p++ = 0x000; *p++ = 0x000; *p++ = info->xyz->eav; /* Horizontal blanking */ while (p < (buf + 272)) { *p++ = 0x200; *p++ = 0x040; *p++ = 0x200; *p++ = 0x040; } /* SAV */ *p++ = 0x3ff; *p++ = 0x000; *p++ = 0x000; *p++ = info->xyz->sav; } /* Active region */ endp = p; switch (pattern) { default: case VERT_BLANKING: while (p < (buf + samples)) { *p++ = 0x200; *p++ = 0x040; *p++ = 0x200; *p++ = 0x040; } break; case BLACK: /* black line (filler for FMT_480i5994 ) */ while (p < (buf + samples)) { *p++ = 0x200; *p++ = 0x040; *p++ = 0x200; *p++ = 0x040; } break; case GREEN: /* green line for test purpose */ while (p < (buf + samples)) { *p++ = 289; *p++ = 450; *p++ = 231; *p++ = 450; } break; case MAIN_SET: /* 75% gray */ endp += b + 1; while (p < endp) { *p++ = 512; *p++ = 721; *p++ = 512; *p++ = 721; } /* 75% yellow */ endp += b + 1; while (p < endp) { *p++ = 176; *p++ = 646; *p++ = 567; *p++ = 646; } /* 75% cyan */ endp += b + 1; while (p < endp) { *p++ = 625; *p++ = 525; *p++ = 176; *p++ = 525; } /* 75% green */ endp += b - 1; while (p < endp) { *p++ = 289; *p++ = 450; *p++ = 231; *p++ = 450; } /* 75% magenta */ endp += b + 1; while (p < endp) { *p++ = 735; *p++ = 335; *p++ = 793; *p++ = 335; } /* 75% red */ endp += b + 1; while (p < endp) { *p++ = 399; *p++ = 260; *p++ = 848; *p++ = 260; } /* 75% blue */ while (p < (buf + samples)) { *p++ = 848; *p++ = 139; *p++ = 457; *p++ = 139; } break; case CHROMA_SET: /* 75% blue */ endp += b + 1; while (p < endp) { *p++ = 848; *p++ = 139; *p++ = 457; *p++ = 139; } /* black */ endp += b + 1; while (p < endp) { *p++ = 0x200; *p++ = 0x040; *p++ = 0x200; *p++ = 0x040; } /* 75% magenta */ endp += b + 1; while (p < endp) { *p++ = 735; *p++ = 335; *p++ = 793; *p++ = 335; } /* black */ endp += b - 1; while (p < endp) { *p++ = 0x200; *p++ = 0x040; *p++ = 0x200; *p++ = 0x040; } /* 75% cyan */ endp += b + 1; while (p < endp) { *p++ = 625; *p++ = 525; *p++ = 176; *p++ = 525; } /* black */ endp += b + 1; while (p < endp) { *p++ = 0x200; *p++ = 0x040; *p++ = 0x200; *p++ = 0x040; } /* 75% gray */ while (p < (buf + samples)) { *p++ = 512; *p++ = 721; *p++ = 512; *p++ = 721; } break; case BLACK_SET: /* -I */ endp += 257; while (p < endp) { *p++ = 624; *p++ = 231; *p++ = 390; *p++ = 231; } /* white */ endp += 257; while (p < endp) { *p++ = 0x200; *p++ = 940; *p++ = 0x200; *p++ = 940; } /* +Q */ endp += 257; while (p < endp) { *p++ = 684; *p++ = 177; *p++ = 591; *p++ = 177; } /* black */ endp += 257; while (p < endp) { *p++ = 0x200; *p++ = 0x040; *p++ = 0x200; *p++ = 0x040; } /* blacker than black */ endp += 68; while (p < endp) { *p++ = 0x200; *p++ = 29; *p++ = 0x200; *p++ = 29; } /* black */ endp += 68 + 2; while (p < endp) { *p++ = 0x200; *p++ = 0x040; *p++ = 0x200; *p++ = 0x040; } /* whiter than black */ endp += 68; while (p < endp) { *p++ = 0x200; *p++ = 99; *p++ = 0x200; *p++ = 99; } /* black */ while (p < (buf + samples)) { *p++ = 0x200; *p++ = 0x040; *p++ = 0x200; *p++ = 0x040; } break; } return 0; } static int setSDIVideoProperties(enum sdi_setting_video_e setting, char * value, char * device) { const char fmt[] = "/sys/class/sdivideo/sdivideo%cx%i/%s"; struct stat buf; int num; char type, name[256], data[256]; char *endptr; /* Get the sysfs info */ memset(&buf, 0, sizeof(buf)); /** * Stat the file, fills the structure with info about the file * Get the major number from device node **/ if (stat(device, &buf) < 0) { fprintf(stderr, "%s: ", device); perror("unable to get the file status"); return -1; } /* Check if it is a character device or not */ if (!S_ISCHR (buf.st_mode)) { fprintf(stderr, "%s: not a character device\n", device); return -1; } /* Check the minor number to determine if it is a receive or transmit device */ type = (buf.st_rdev & 0x0080) ? 'r' : 't'; /* Get the receiver or transmitter number */ num = buf.st_rdev & 0x007f; /* Build the path to sysfs file */ snprintf(name, sizeof(name), fmt, type, num, "dev"); memset(data, 0, sizeof(data)); /* Read sysfs file (dev) */ if (util_read(name, data, sizeof(data)) < 0) { fprintf(stderr, "%s: ", device); perror("unable to get the device number"); return -1; } /* Compare the major number taken from sysfs file to the one taken from device node */ if (strtoul(data, &endptr, 0) != (buf.st_rdev >> 8)) { fprintf(stderr, "%s: not a SMPTE 292M/SMPTE 259M-C device\n", device); return -1; } if (*endptr != ':') { fprintf(stderr, "%s: error reading %s\n", device, name); return -1; } // Which setting do we write if (setting == SETTING_BUFFER_NUMBER_VIDEO) { snprintf(name, sizeof(name), fmt, type, num, "buffers"); snprintf(data, sizeof(data), "%s\n", value); if (util_write(name, data, sizeof(data)) < 0) { fprintf(stderr, "%s: ", device); perror("unable to set the number of buffers"); return -1; } printf("\tSet number of buffers = %s\n", value); } else if (setting == SETTING_BUFFER_SIZE_VIDEO) { snprintf(name, sizeof(name), fmt, type, num, "bufsize"); snprintf(data, sizeof(data), "%s\n", value); if (util_write(name, data, sizeof(data)) < 0) { fprintf(stderr, "%s: ", device); perror("unable to set the buffer size"); return -1; } printf("\tSet buffer size = %s Bytes\n", value); } else if (setting == SETTING_CLOCK_SOURCE) { snprintf(name, sizeof(name), fmt, type, num, "clock_source"); snprintf(data, sizeof(data), "%s\n", value); if (util_write(name, data, sizeof(data)) < 0) { fprintf(stderr, "%s: ", device); perror("unable to set the clock source"); return -1; } printf("\tSet clock source = %s\n", value); } else if (setting == SETTING_DATA_MODE) { snprintf(name, sizeof(name), fmt, type, num, "mode"); snprintf(data, sizeof(data), "%s\n", value); if (util_write(name, data, sizeof(data)) < 0) { fprintf(stderr, "%s: ", device); perror("unable to set the interface operating mode"); return -1; } printf("\tSet data mode = %s\n", value); } else if (setting == SETTING_FRAME_MODE) { snprintf(name, sizeof(name), fmt, type, num, "frame_mode"); snprintf(data, sizeof(data), "%s\n", value); if (util_write(name, data, sizeof(data)) < 0) { fprintf(stderr, "%s: ", device); perror("unable to set the interface frame mode"); return -1; } printf("\tSet frame mode = %s\n", value); } return 0; } static int setSDIAudioProperties(enum sdi_setting_audio_e setting, char * value, char * device) { const char fmt[] = "/sys/class/sdiaudio/sdiaudio%cx%i/%s"; struct stat buf; int num; char type, name[256], data[256]; char *endptr; /* Get the sysfs info */ memset(&buf, 0, sizeof(buf)); if (stat(device, &buf) < 0) { fprintf(stderr, "%s: ", device); perror("unable to get the file status"); return -1; } if (!S_ISCHR (buf.st_mode)) { fprintf(stderr, "%s: not a character device\n", device); return -1; } type = (buf.st_rdev & 0x0080) ? 'r' : 't'; num = buf.st_rdev & 0x007f; snprintf(name, sizeof(name), fmt, type, num, "dev"); memset(data, 0, sizeof(data)); if (util_read(name, data, sizeof(data)) < 0) { fprintf(stderr, "%s: ", device); perror("unable to get the device number"); return -1; } if (strtoul(data, &endptr, 0) != (buf.st_rdev >> 8)) { fprintf(stderr, "%s: not an audio device\n", device); return -1; } if (*endptr != ':') { fprintf(stderr, "%s: error reading %s\n", device, name); return -1; } if (setting == SETTING_BUFFER_NUMBER_AUDIO) { snprintf(name, sizeof(name), fmt, type, num, "buffers"); snprintf(data, sizeof(data), "%s\n", value); if (util_write(name, data, sizeof(data)) < 0) { fprintf(stderr, "%s: ", device); perror("unable to set the number of buffers"); return -1; } printf("\tSet number of buffers = %s\n", value); } else if (setting == SETTING_BUFFER_SIZE_AUDIO) { snprintf(name, sizeof(name), fmt, type, num, "bufsize"); snprintf(data, sizeof(data), "%s\n", value); if (util_write(name, data, sizeof(data)) < 0) { fprintf(stderr, "%s: ", device); perror("unable to set the buffer size"); return -1; } printf("\tSet buffer size = %s Bytes\n", value); } else if (setting == SETTING_SAMPLE_SIZE) { snprintf(name, sizeof(name), fmt, type, num, "sample_size"); snprintf(data, sizeof(data), "%s\n", value); if (util_write(name, data, sizeof(data)) < 0) { fprintf(stderr, "%s: ", device); perror("unable to set the interface audio sample size"); return -1; } switch (atol(value)) { case SDIAUDIO_CTL_AUDSAMP_SZ_16: printf("\tAssuming 16-bit audio.\n"); break; case SDIAUDIO_CTL_AUDSAMP_SZ_24: printf("\tAssuming 24-bit audio.\n"); break; case SDIAUDIO_CTL_AUDSAMP_SZ_32: printf("\tAssuming 32-bit audio.\n"); break; default: printf("\tSet audio sample size = %lu.\n", atol(value)); break; } } else if (setting == SETTING_SAMPEL_RATE) { snprintf(name, sizeof(name), fmt, type, num, "sample_rate"); snprintf(data, sizeof(data), "%lu\n", atol(value)); if (util_write(name, data, sizeof(data)) < 0) { fprintf(stderr, "%s: ", device); perror("unable to set the interface audio sample rate"); return -1; } switch (atoi(value)) { case 32000: printf("\tAssuming 32 kHz audio.\n"); break; case 44100: printf("\tAssuming 44.1 kHz audio.\n"); break; case 48000: printf("\tAssuming 48 kHz audio.\n"); break; default: printf("\tSet audio sample rate = %lu.\n", atol(value)); break; } } else if (setting == SETTING_CHANNELS) { snprintf(name, sizeof(name), fmt, type, num, "channels"); snprintf(data, sizeof(data), "%lu\n", atol(value)); if (util_write(name, data, sizeof(data)) < 0) { fprintf(stderr, "%s: ", device); perror("unable to set " "the interface audio channel enable"); return -1; } switch (atol(value)) { case SDIAUDIO_CTL_AUDCH_EN_0: printf("\tDisabling audio.\n"); break; case SDIAUDIO_CTL_AUDCH_EN_2: printf("\tAssuming 2 channels of audio.\n"); break; case SDIAUDIO_CTL_AUDCH_EN_4: printf("\tAssuming 4 channels of audio.\n"); break; case SDIAUDIO_CTL_AUDCH_EN_6: printf("\tAssuming 6 channels of audio.\n"); break; case SDIAUDIO_CTL_AUDCH_EN_8: printf("\tAssuming 8 channels of audio.\n"); break; default: printf("\tSet audio channel enable = %lu.\n", atol(value)); break; } } else if (setting == SETTING_NON_AUDIO) { snprintf(name, sizeof(name), fmt, type, num, "non_audio"); snprintf(data, sizeof(data), "0x%04lX\n", atol(value)); if (util_write(name, data, sizeof(data)) < 0) { fprintf(stderr, "%s: ", device); perror("unable to set " "the interface non-audio"); return -1; } switch (atol(value)) { case 0x0000: printf("\tPassing PCM audio.\n"); break; case 0x00ff: printf("\tPassing non-audio.\n"); break; default: printf("\tSet non-audio = 0x%04lX.\n", atol(value)); break; } } return 0; } static ssize_t util_read(const char *name, char *buf, size_t count) { ssize_t fd, ret; if ((fd = open(name, O_RDONLY)) < 0) { return fd; } ret = read(fd, buf, count); close(fd); return ret; } static ssize_t util_write(const char *name, const char *buf, size_t count) { ssize_t fd, ret; if ((fd = open(name, O_WRONLY)) < 0) { return fd; } ret = write(fd, buf, count); close(fd); return ret; } static char * itoa(uint64_t i) { if (i == 0) return strdup("0"); char * mystring = (char *) malloc(50); sprintf(mystring, "%"PRIu64, i); return mystring; } mlt-0.9.0/src/modules/linsys/sdi_generator.h000066400000000000000000000310111215300731300210610ustar00rootroot00000000000000/** * sdi_generator.h **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef SDI_GENERATOR_H_ #define SDI_GENERATOR_H_ // definitions are only for SD NTSC (mkline funktion for test pattern) #define VERT_BLANKING 0 #define MAIN_SET 1 #define CHROMA_SET 2 #define BLACK_SET 3 #define BLACK 4 #define GREEN 5 // defines for SD SDI with blanking #define ANCILLARY_DATA_SAMPLES 280 #define FIELD_1 1 #define FIELD_2 2 #define VERT_BLANKING 0 #define ACTIVE_VIDEO 1 // Master SDI device #define SDI_IOC_MAGIC '=' #define SDI_IOC_TXGETEVENTS _IOR(SDI_IOC_MAGIC, 2, unsigned int) // Transmitter event flag bit locations #define SDI_EVENT_TX_BUFFER_ORDER 0 #define SDI_EVENT_TX_BUFFER (1 << SDI_EVENT_TX_BUFFER_ORDER) #define SDI_EVENT_TX_FIFO_ORDER 1 #define SDI_EVENT_TX_FIFO (1 << SDI_EVENT_TX_FIFO_ORDER) #define SDI_EVENT_TX_DATA_ORDER 2 #define SDI_EVENT_TX_DATA (1 << SDI_EVENT_TX_DATA_ORDER) // part of the linsys sdiaudio.h #define SDIAUDIO_IOC_TXGETCAP _IOR(SDIAUDIO_IOC_MAGIC, 1, unsigned int) #define SDIAUDIO_IOC_TXGETEVENTS _IOR(SDIAUDIO_IOC_MAGIC, 2, unsigned int) #define SDIAUDIO_IOC_TXGETBUFLEVEL _IOR(SDIAUDIO_IOC_MAGIC, 3, unsigned int) #define SDIAUDIO_IOC_TXGETTXD _IOR(SDIAUDIO_IOC_MAGIC, 4, int) #define SDIAUDIO_IOC_MAGIC '~' /* This ioctl magic number is currently free. See * /usr/src/linux/Documentation/ioctl-number.txt */ /* Transmitter event flag bit locations */ #define SDIAUDIO_EVENT_TX_BUFFER_ORDER 0 #define SDIAUDIO_EVENT_TX_BUFFER (1 << SDIAUDIO_EVENT_TX_BUFFER_ORDER) #define SDIAUDIO_EVENT_TX_FIFO_ORDER 1 #define SDIAUDIO_EVENT_TX_FIFO (1 << SDIAUDIO_EVENT_TX_FIFO_ORDER) #define SDIAUDIO_EVENT_TX_DATA_ORDER 2 #define SDIAUDIO_EVENT_TX_DATA (1 << SDIAUDIO_EVENT_TX_DATA_ORDER) // Filehandler for sdi output static int fh_sdi_video; static int fh_sdi_audio; #define MAX_SAMPLES_PER_LINE (2*2750) #define MAX_LINES_PER_FRAME 1125 #define MAX_AUDIO_STREAMS (8) // max. audio samples per frame #define MAX_AUDIO_SAMPLES (2002*2) /** * 23.98Hz = fix:{2002} * 24Hz = fix:{2000} * 25Hz = fix:{1920} * 29.97Hz = varies:{1601,1602,1602} * 30Hz = fix:{1600} **/ #define MAX_SDI_HEIGHT 1125 // HD-SDI #define MAX_SDI_WIDTH 2750 // HD-SDI (FMT_1080p24 has up to 2750) #define MAX_SDI_FRAMESIZE (MAX_SDI_HEIGHT*MAX_SDI_WIDTH*2) // SDI frame size, (2 Pixels are represented by 4 bytes, yuyv422) struct source_format { unsigned int lines_per_frame; unsigned int active_lines_per_frame; unsigned int samples_per_line; unsigned int active_samples_per_line; unsigned int interlaced; }; struct audio_format { mlt_audio_format aformat; // default: mlt_audio_pcm uint16_t samples; // default 2*1920 uint16_t sample_rate; // default 48000 /** * 0 channels = audio disabled, transmit only * 2 channels (stereo) * 4 channels * 6 channels * 8 channels **/ int channels; // default 2 (stereo) }; /** * SDI DEVICE FILE SETTINGS AND MODES **/ enum sdi_setting_video_e { SETTING_BUFFER_NUMBER_VIDEO = 0, SETTING_BUFFER_SIZE_VIDEO = 1, SETTING_CLOCK_SOURCE = 2, SETTING_DATA_MODE = 3, SETTING_FRAME_MODE = 4 }; enum sdi_setting_audio_e { SETTING_BUFFER_NUMBER_AUDIO = 0, SETTING_BUFFER_SIZE_AUDIO = 1, SETTING_SAMPLE_SIZE = 2, SETTING_CHANNELS = 3, SETTING_SAMPEL_RATE = 4, SETTING_NON_AUDIO = 5 }; static int sdi_frame_mode = 0; /* Frame mode settings */ #define SDIVIDEO_CTL_UNLOCKED 0 #define SDIVIDEO_CTL_SMPTE_125M_486I_59_94HZ 1 #define SDIVIDEO_CTL_BT_601_576I_50HZ 2 #define SDIVIDEO_CTL_SMPTE_260M_1035I_60HZ 5 #define SDIVIDEO_CTL_SMPTE_260M_1035I_59_94HZ 6 #define SDIVIDEO_CTL_SMPTE_295M_1080I_50HZ 7 #define SDIVIDEO_CTL_SMPTE_274M_1080I_60HZ 8 #define SDIVIDEO_CTL_SMPTE_274M_1080PSF_30HZ 9 #define SDIVIDEO_CTL_SMPTE_274M_1080I_59_94HZ 10 #define SDIVIDEO_CTL_SMPTE_274M_1080PSF_29_97HZ 11 #define SDIVIDEO_CTL_SMPTE_274M_1080I_50HZ 12 #define SDIVIDEO_CTL_SMPTE_274M_1080PSF_25HZ 13 #define SDIVIDEO_CTL_SMPTE_274M_1080PSF_24HZ 14 #define SDIVIDEO_CTL_SMPTE_274M_1080PSF_23_98HZ 15 #define SDIVIDEO_CTL_SMPTE_274M_1080P_30HZ 16 #define SDIVIDEO_CTL_SMPTE_274M_1080P_29_97HZ 17 #define SDIVIDEO_CTL_SMPTE_274M_1080P_25HZ 18 #define SDIVIDEO_CTL_SMPTE_274M_1080P_24HZ 19 #define SDIVIDEO_CTL_SMPTE_274M_1080P_23_98HZ 20 #define SDIVIDEO_CTL_SMPTE_296M_720P_60HZ 21 #define SDIVIDEO_CTL_SMPTE_296M_720P_59_94HZ 22 #define SDIVIDEO_CTL_SMPTE_296M_720P_50HZ 23 #define SDIVIDEO_CTL_SMPTE_296M_720P_30HZ 24 #define SDIVIDEO_CTL_SMPTE_296M_720P_29_97HZ 25 #define SDIVIDEO_CTL_SMPTE_296M_720P_25HZ 26 #define SDIVIDEO_CTL_SMPTE_296M_720P_24HZ 27 #define SDIVIDEO_CTL_SMPTE_296M_720P_23_98HZ 28 /* Audio sample size */ #define SDIAUDIO_CTL_AUDSAMP_SZ_16 16 /* 16 bit */ #define SDIAUDIO_CTL_AUDSAMP_SZ_24 24 /* 24 bit */ #define SDIAUDIO_CTL_AUDSAMP_SZ_32 32 /* 32 bit */ /* Audio channel enable */ #define SDIAUDIO_CTL_AUDCH_EN_0 0 /* 0 channel/disable audio */ #define SDIAUDIO_CTL_AUDCH_EN_2 2 /* 2 channel */ #define SDIAUDIO_CTL_AUDCH_EN_4 4 /* 4 channel */ #define SDIAUDIO_CTL_AUDCH_EN_6 6 /* 6 channel */ #define SDIAUDIO_CTL_AUDCH_EN_8 8 /* 8 channel */ static char * itoa(uint64_t i); static ssize_t util_read(const char *name, char *buf, size_t count); static ssize_t util_write(const char *name, const char *buf, size_t count); static int setSDIVideoProperties(enum sdi_setting_video_e setting, char * value, char * device); static int setSDIAudioProperties(enum sdi_setting_audio_e setting, char * value, char * device); // HD static const struct source_format FMT_1080i60 = { .lines_per_frame = 1125, .active_lines_per_frame = 1080, .samples_per_line = 2*2200, .active_samples_per_line = 2*1920, .interlaced = 1 }; static const struct source_format FMT_1080i5994 = { .lines_per_frame = 1125, .active_lines_per_frame = 1080, .samples_per_line = 2*2200, .active_samples_per_line = 2*1920, .interlaced = 1 }; static const struct source_format FMT_1080i50 = { .lines_per_frame = 1125, .active_lines_per_frame = 1080, .samples_per_line = 2*2640, .active_samples_per_line = 2*1920, .interlaced = 1 }; static const struct source_format FMT_1080p30 = { .lines_per_frame = 1125, .active_lines_per_frame = 1080, .samples_per_line = 2*2200, .active_samples_per_line = 2*1920, .interlaced = 0 }; static const struct source_format FMT_1080p2997 = { .lines_per_frame = 1125, .active_lines_per_frame = 1080, .samples_per_line = 2*2200, .active_samples_per_line = 2*1920, .interlaced = 0 }; static const struct source_format FMT_1080p25 = { .lines_per_frame = 1125, .active_lines_per_frame = 1080, .samples_per_line = 2*2640, .active_samples_per_line = 2*1920, .interlaced = 0 }; static const struct source_format FMT_1080p24 = { .lines_per_frame = 1125, .active_lines_per_frame = 1080, .samples_per_line = 2*2750, .active_samples_per_line = 2*1920, .interlaced = 0 }; static const struct source_format FMT_1080p2398 = { .lines_per_frame = 1125, .active_lines_per_frame = 1080, .samples_per_line = 2*2750, .active_samples_per_line = 2*1920, .interlaced = 0 }; static const struct source_format FMT_720p60 = { .lines_per_frame = 750, .active_lines_per_frame = 720, .samples_per_line = 2*1650, .active_samples_per_line = 2*1280, .interlaced = 0 }; static const struct source_format FMT_720p5994 = { .lines_per_frame = 750, .active_lines_per_frame = 720, .samples_per_line = 2*1650, .active_samples_per_line = 2*1280, .interlaced = 0 }; static const struct source_format FMT_720p50 = { .lines_per_frame = 750, .active_lines_per_frame = 720, .samples_per_line = 2*1980, .active_samples_per_line = 2*1280, .interlaced = 0 }; static const struct source_format FMT_720p30 = { .lines_per_frame = 750, .active_lines_per_frame = 720, .samples_per_line = 2*3300, .active_samples_per_line = 2*1280, .interlaced = 0 }; static const struct source_format FMT_720p2997 = { .lines_per_frame = 750, .active_lines_per_frame = 720, .samples_per_line = 2*3300, .active_samples_per_line = 2*1280, .interlaced = 0 }; static const struct source_format FMT_720p25 = { .lines_per_frame = 750, .active_lines_per_frame = 720, .samples_per_line = 2*3960, .active_samples_per_line = 2*1280, .interlaced = 0 }; static const struct source_format FMT_720p24 = { .lines_per_frame = 750, .active_lines_per_frame = 720, .samples_per_line = 2*4125, .active_samples_per_line = 2*1280, .interlaced = 0 }; static const struct source_format FMT_720p2398 = { .lines_per_frame = 750, .active_lines_per_frame = 720, .samples_per_line = 2*4125, .active_samples_per_line = 2*1280, .interlaced = 0 }; // SD PAL static const struct source_format FMT_576i50 = { .lines_per_frame = 625, .active_lines_per_frame = 576, .samples_per_line = 2*864 /*1728*/, .active_samples_per_line = 2*720 /* 720xY, 360xCb, 360xCr */, .interlaced = 1 }; // SD NTSC; 486 video lines static const struct source_format FMT_486i5994 = { .lines_per_frame = 525, .active_lines_per_frame = 486, .samples_per_line = 2*858 /*1716*/, .active_samples_per_line = 2*720 /* 720xY, 360xCb, 360xCr */, .interlaced = 1 }; // SD NTSC; 480 video lines, 6 lines opt. video data /** * sames as FMT_486i5994 but the first 6 lines will be filled with SDI-BLACK * or can be used for opt. video data (s.SMPTE) */ static const struct source_format FMT_480i5994 = { .lines_per_frame = 525, .active_lines_per_frame = 486, .samples_per_line = 2*858 /*1716*/, .active_samples_per_line = 2*720 /* 720xY, 360xCb, 360xCr */, .interlaced = 1 }; struct trs { unsigned short int sav; unsigned short int eav; }; static const struct trs FIELD_1_ACTIVE = { .sav = 0x200, .eav = 0x274 }; static const struct trs FIELD_1_VERT_BLANKING = { .sav = 0x2ac, .eav = 0x2d8 }; static const struct trs FIELD_2_ACTIVE = { .sav = 0x31c, .eav = 0x368 }; static const struct trs FIELD_2_VERT_BLANKING = { .sav = 0x3b0, .eav = 0x3c4 }; struct line_info { const struct source_format *fmt; unsigned int ln; const struct trs *xyz; uint8_t blanking; }; struct SDI_atr { int status; int *fh; uint8_t *data; size_t framesize; } SDI_atr; // 192bit for AESChannelStatusBits uint8_t AESChannelStatusBitArray[192]; // beta array //uint8_t AESChannelStatusBitArray[24]; // TODO better way for 24x8bit !!! // buffer for one sdi line uint16_t * line_buffer; // counter for active line number uint16_t active_video_line; // buffer for sdi frame size uint64_t sdi_frame_size; // buffer for the complete SDI frame uint8_t * data; static char * device_file_video; static char * device_file_audio; static struct line_info info; static uint8_t *(*pack)(uint8_t *outbuf, unsigned short int *inbuf, size_t count); static size_t elements; static unsigned int samples; // functions static int sdi_init(char *device_video, char *device_audio, uint8_t blanking, mlt_profile myProfile, const struct audio_format * audio_format); static int sdimaster_close(); static int sdi_playout(uint8_t *vBuffer, int16_t aBuffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES], const struct audio_format * audio_format, int audio_streams, int my_DBN); static int mkline(unsigned short int *buf, const struct line_info *info, unsigned int pattern); static inline int create_HD_SDI_Line(uint16_t *buf, const struct line_info *info, uint16_t active_video_line, unsigned int active, uint8_t *video_buffer); static inline int create_SD_SDI_Line(uint16_t *buf, const struct line_info *info, int field, int active, uint8_t *video_buffer, int16_t audio_buffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES], int linenumber_sdiframe, int active_video_line, int my_DBN, int16_t AudioGroupCounter, int16_t AudioGroups2Write, int audio_streams); static int writeANC(uint16_t *p, int linenumber_sdiframe, uint16_t DID, int my_DBN, int16_t *audio_buffer_A, int16_t *audio_buffer_B, int16_t AudioDataPacketCounter, int16_t AudioGroups2Write); static uint16_t checker(uint16_t *DID_pointer); static uint8_t getZBit(int sample_number); static uint8_t getChannelStatusBit(uint16_t sample_number, uint8_t ch); static int16_t getNumberOfAudioGroups2Write(int linenuber); static uint8_t getDBN(int my_DBN); static inline uint8_t *pack8(uint8_t *outbuf, uint16_t *inbuf, size_t count); // alias 'pack_uyvy()' static inline uint8_t *pack10(uint8_t *outbuf, uint16_t *inbuf, size_t count); static inline uint8_t *pack_v210(uint8_t *outbuf, uint16_t *inbuf, size_t count); static int pack_AES_subframe(uint16_t *p, int8_t c, int8_t z, int8_t ch, int16_t *audio_sample); #endif /* SDI_GENERATOR_H_ */ mlt-0.9.0/src/modules/lumas/000077500000000000000000000000001215300731300156675ustar00rootroot00000000000000mlt-0.9.0/src/modules/lumas/Makefile000066400000000000000000000006121215300731300173260ustar00rootroot00000000000000include ../../../config.mak LDFLAGS= all: luma create_lumas @./create_lumas luma: luma.c create_lumas: depend: distclean: rm -rf PAL NTSC luma clean: rm -f luma install: all install -d $(DESTDIR)$(mltdatadir)/lumas/PAL install -d $(DESTDIR)$(mltdatadir)/lumas/NTSC install -m 644 PAL/* $(DESTDIR)$(mltdatadir)/lumas/PAL install -m 644 NTSC/* $(DESTDIR)$(mltdatadir)/lumas/NTSC mlt-0.9.0/src/modules/lumas/configure000077500000000000000000000005611215300731300176000ustar00rootroot00000000000000#!/bin/sh if [ "$help" = "1" ] then cat << EOF Luma options: --luma-compress - Produce compressed (png) lumas --luma-8bpp - Produce 8 bit pgm lumas (defaut is 16 bit) EOF else rm -f .8bit .compress .executed for i in "$@" do case $i in --luma-compress ) touch .compress .8bit ;; --luma-8bit ) touch .8bit ;; esac done fi mlt-0.9.0/src/modules/lumas/create_lumas000077500000000000000000000032531215300731300202640ustar00rootroot00000000000000#!/bin/sh [ \( -d PAL \) -a \( ! $0 -nt .executed \) ] && exit 0 bpp=16 [ -f .8bit ] && bpp=8 for i in PAL NTSC do mkdir -p $i rm -f $i/*.pgm $i/*.png [ "$i" = "PAL" ] && h=576 || h=480 ./luma -h $h -bpp $bpp > $i/luma01.pgm ./luma -h $h -bpp $bpp -bands $h > $i/luma02.pgm ./luma -h $h -bpp $bpp -hmirror 1 > $i/luma03.pgm ./luma -h $h -bpp $bpp -bands $h -vmirror 1 > $i/luma04.pgm ./luma -h $h -bpp $bpp -offset 32768 -dmirror 1 > $i/luma05.pgm ./luma -h $h -bpp $bpp -offset 32768 -dmirror 1 -flip 1 > $i/luma06.pgm ./luma -h $h -bpp $bpp -offset 32768 -dmirror 1 -quart 1 > $i/luma07.pgm ./luma -h $h -bpp $bpp -offset 32768 -dmirror 1 -quart 1 -flip 1 > $i/luma08.pgm ./luma -h $h -bpp $bpp -bands 12 -rband 0 > $i/luma09.pgm ./luma -h $h -bpp $bpp -bands 12 -rband 0 -rotate 1 -flop 1 > $i/luma10.pgm ./luma -h $h -bpp $bpp -bands 12 -rband 1 > $i/luma11.pgm ./luma -h $h -bpp $bpp -bands 12 -rband 1 -vmirror 1 > $i/luma12.pgm ./luma -h $h -bpp $bpp -bands 12 -rband 1 -rotate 1 -flop 1 > $i/luma13.pgm ./luma -h $h -bpp $bpp -bands 12 -rband 1 -rotate 1 -vmirror 1 > $i/luma14.pgm ./luma -h $h -bpp $bpp -offset 32768 -dmirror 1 -hmirror 1 > $i/luma15.pgm ./luma -h $h -bpp $bpp -type 1 > $i/luma16.pgm ./luma -h $h -bpp $bpp -type 1 -bands 2 -rband 1 > $i/luma17.pgm ./luma -h $h -bpp $bpp -type 2 > $i/luma18.pgm ./luma -h $h -bpp $bpp -type 2 -quart 1 > $i/luma19.pgm ./luma -h $h -bpp $bpp -type 2 -quart 1 -flip 1 > $i/luma20.pgm ./luma -h $h -bpp $bpp -type 2 -quart 1 -bands 2 > $i/luma21.pgm ./luma -h $h -bpp $bpp -type 3 > $i/luma22.pgm if [ -f .compress ] then for f in $i/*.pgm do convert $f $f.png rm -f $f done fi done touch .executed mlt-0.9.0/src/modules/lumas/luma.c000066400000000000000000000222101215300731300167660ustar00rootroot00000000000000/* * luma.c -- image generator for transition_luma * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include typedef struct { int type; int w; int h; int bands; int rband; int vmirror; int hmirror; int dmirror; int invert; int offset; int flip; int flop; int pflip; int pflop; int quart; int rotate; } luma; void luma_init( luma *this ) { memset( this, 0, sizeof( luma ) ); this->type = 0; this->w = 720; this->h = 576; this->bands = 1; this->rband = 0; this->vmirror = 0; this->hmirror = 0; this->dmirror = 0; this->invert = 0; this->offset = 0; this->flip = 0; this->flop = 0; this->quart = 0; this->pflop = 0; this->pflip = 0; } static inline int sqrti( int n ) { int p = 0; int q = 1; int r = n; int h = 0; while( q <= n ) q = 4 * q; while( q != 1 ) { q = q / 4; h = p + q; p = p / 2; if ( r >= h ) { p = p + q; r = r - h; } } return p; } uint16_t *luma_render( luma *this ) { int i = 0; int j = 0; int k = 0; if ( this->quart ) { this->w *= 2; this->h *= 2; } if ( this->rotate ) { int t = this->w; this->w = this->h; this->h = t; } int max = ( 1 << 16 ) - 1; uint16_t *image = malloc( this->w * this->h * sizeof( uint16_t ) ); uint16_t *end = image + this->w * this->h; uint16_t *p = image; uint16_t *r = image; int lower = 0; int lpb = this->h / this->bands; int rpb = max / this->bands; int direction = 1; int half_w = this->w / 2; int half_h = this->h / 2; if ( !this->dmirror && ( this->hmirror || this->vmirror ) ) rpb *= 2; for ( i = 0; i < this->bands; i ++ ) { lower = i * rpb; direction = 1; if ( this->rband && i % 2 == 1 ) { direction = -1; lower += rpb; } switch( this->type ) { case 1: { int length = sqrti( half_w * half_w + lpb * lpb / 4 ); int value; int x = 0; int y = 0; for ( j = 0; j < lpb; j ++ ) { y = j - lpb / 2; for ( k = 0; k < this->w; k ++ ) { x = k - half_w; value = sqrti( x * x + y * y ); *p ++ = lower + ( direction * rpb * ( ( max * value ) / length ) / max ) + ( j * this->offset * 2 / lpb ) + ( j * this->offset / lpb ); } } } break; case 2: { for ( j = 0; j < lpb; j ++ ) { int value = ( ( j * this->w ) / lpb ) - half_w; if ( value > 0 ) value = - value; for ( k = - half_w; k < value; k ++ ) *p ++ = lower + ( direction * rpb * ( ( max * abs( k ) ) / half_w ) / max ); for ( k = value; k < abs( value ); k ++ ) *p ++ = lower + ( direction * rpb * ( ( max * abs( value ) ) / half_w ) / max ) + ( j * this->offset * 2 / lpb ) + ( j * this->offset / lpb ); for ( k = abs( value ); k < half_w; k ++ ) *p ++ = lower + ( direction * rpb * ( ( max * abs( k ) ) / half_w ) / max ); } } break; case 3: { int length; for ( j = -half_h; j < half_h; j ++ ) { if ( j < 0 ) { for ( k = - half_w; k < half_w; k ++ ) { length = sqrti( k * k + j * j ); *p ++ = ( max / 4 * k ) / ( length + 1 ); } } else { for ( k = half_w; k > - half_w; k -- ) { length = sqrti( k * k + j * j ); *p ++ = ( max / 2 ) + ( max / 4 * k ) / ( length + 1 ); } } } } break; default: for ( j = 0; j < lpb; j ++ ) for ( k = 0; k < this->w; k ++ ) *p ++ = lower + ( direction * ( rpb * ( ( k * max ) / this->w ) / max ) ) + ( j * this->offset * 2 / lpb ); break; } } if ( this->quart ) { this->w /= 2; this->h /= 2; for ( i = 1; i < this->h; i ++ ) { p = image + i * this->w; r = image + i * 2 * this->w; j = this->w; while ( j -- > 0 ) *p ++ = *r ++; } } if ( this->dmirror ) { for ( i = 0; i < this->h; i ++ ) { p = image + i * this->w; r = end - i * this->w; j = ( this->w * ( this->h - i ) ) / this->h; while ( j -- ) *( -- r ) = *p ++; } } if ( this->flip ) { uint16_t t; for ( i = 0; i < this->h; i ++ ) { p = image + i * this->w; r = p + this->w; while( p != r ) { t = *p; *p ++ = *( -- r ); *r = t; } } } if ( this->flop ) { uint16_t t; r = end; for ( i = 1; i < this->h / 2; i ++ ) { p = image + i * this->w; j = this->w; while( j -- ) { t = *( -- p ); *p = *( -- r ); *r = t; } } } if ( this->hmirror ) { p = image; while ( p < end ) { r = p + this->w; while ( p != r ) *( -- r ) = *p ++; p += this->w / 2; } } if ( this->vmirror ) { p = image; r = end; while ( p != r ) *( -- r ) = *p ++; } if ( this->invert ) { p = image; r = image; while ( p < end ) *p ++ = max - *r ++; } if ( this->pflip ) { uint16_t t; for ( i = 0; i < this->h; i ++ ) { p = image + i * this->w; r = p + this->w; while( p != r ) { t = *p; *p ++ = *( -- r ); *r = t; } } } if ( this->pflop ) { uint16_t t; end = image + this->w * this->h; r = end; for ( i = 1; i < this->h / 2; i ++ ) { p = image + i * this->w; j = this->w; while( j -- ) { t = *( -- p ); *p = *( -- r ); *r = t; } } } if ( this->rotate ) { uint16_t *image2 = malloc( this->w * this->h * sizeof( uint16_t ) ); for ( i = 0; i < this->h; i ++ ) { p = image + i * this->w; r = image2 + this->h - i - 1; for ( j = 0; j < this->w; j ++ ) { *r = *( p ++ ); r += this->h; } } i = this->w; this->w = this->h; this->h = i; free( image ); image = image2; } return image; } int main( int argc, char **argv ) { int arg = 1; int bpp = 8; luma this; uint16_t *image = NULL; luma_init( &this ); for ( arg = 1; arg < argc - 1; arg ++ ) { if ( !strcmp( argv[ arg ], "-bpp" ) ) bpp = atoi( argv[ ++ arg ] ); else if ( !strcmp( argv[ arg ], "-type" ) ) this.type = atoi( argv[ ++ arg ] ); else if ( !strcmp( argv[ arg ], "-w" ) ) { int tmp = atoi( argv[ ++ arg ] ); // TODO: is there an upper bound? if ( tmp ) this.w = tmp; else return 1; } else if ( !strcmp( argv[ arg ], "-h" ) ) { int tmp = atoi( argv[ ++ arg ] ); // TODO: is there an upper bound? if ( tmp ) this.h = tmp; else return 1; } else if ( !strcmp( argv[ arg ], "-bands" ) ) { int tmp = atoi( argv[ ++ arg ] ); // TODO: is there an upper bound? if ( tmp >= 0 ) this.bands = tmp; else return 1; } else if ( !strcmp( argv[ arg ], "-rband" ) ) this.rband = atoi( argv[ ++ arg ] ); else if ( !strcmp( argv[ arg ], "-hmirror" ) ) this.hmirror = atoi( argv[ ++ arg ] ); else if ( !strcmp( argv[ arg ], "-vmirror" ) ) this.vmirror = atoi( argv[ ++ arg ] ); else if ( !strcmp( argv[ arg ], "-dmirror" ) ) this.dmirror = atoi( argv[ ++ arg ] ); else if ( !strcmp( argv[ arg ], "-offset" ) ) this.offset = atoi( argv[ ++ arg ] ); else if ( !strcmp( argv[ arg ], "-invert" ) ) this.invert = atoi( argv[ ++ arg ] ); else if ( !strcmp( argv[ arg ], "-flip" ) ) this.flip = atoi( argv[ ++ arg ] ); else if ( !strcmp( argv[ arg ], "-flop" ) ) this.flop = atoi( argv[ ++ arg ] ); else if ( !strcmp( argv[ arg ], "-pflip" ) ) this.pflip = atoi( argv[ ++ arg ] ); else if ( !strcmp( argv[ arg ], "-pflop" ) ) this.pflop = atoi( argv[ ++ arg ] ); else if ( !strcmp( argv[ arg ], "-quart" ) ) this.quart = atoi( argv[ ++ arg ] ); else if ( !strcmp( argv[ arg ], "-rotate" ) ) this.rotate = atoi( argv[ ++ arg ] ); else fprintf( stderr, "ignoring %s\n", argv[ arg ] ); } if ( bpp != 8 && bpp != 16 ) { fprintf( stderr, "Invalid bpp %d\n", bpp ); return 1; } image = luma_render( &this ); if ( bpp == 16 ) { uint16_t *end = image + this.w * this.h; uint16_t *p = image; uint8_t *q = ( uint8_t * )image; while ( p < end ) { *p ++ = ( *q << 8 ) + *( q + 1 ); q += 2; } printf( "P5\n" ); printf( "%d %d\n", this.w, this.h ); printf( "65535\n" ); fwrite( image, this.w * this.h * sizeof( uint16_t ), 1, stdout ); } else { uint16_t *end = image + this.w * this.h; uint16_t *p = image; uint8_t *q = ( uint8_t * )image; while ( p < end ) *q ++ = ( uint8_t )( *p ++ >> 8 ); printf( "P5\n" ); printf( "%d %d\n", this.w, this.h ); printf( "255\n" ); fwrite( image, this.w * this.h, 1, stdout ); } return 0; } mlt-0.9.0/src/modules/motion_est/000077500000000000000000000000001215300731300167265ustar00rootroot00000000000000mlt-0.9.0/src/modules/motion_est/Makefile000066400000000000000000000036271215300731300203760ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lm include ../../../config.mak TARGET = ../libmltmotion_est$(LIBSUF) OBJS = factory.o \ filter_motion_est.o \ filter_crop_detect.o \ filter_autotrack_rectangle.o \ arrow_code.o \ filter_vismv.o \ producer_slowmotion.o SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/motion_est" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/motion_est" test: $(TARGET) ~/mlt-devel/mlt/src/melt/melt -filter motion_est -filter vismv -filter benchmark -consumer sdl rescale=none real_time=0 audio_off=1 silent=1 /media/cdrecorder/BBC.The.Private.Life.Of.Plants.Pt5.Living.Together.DivX505.AC3.www.MVGroup.org.uk.avi in=50000 hist: $(TARGET) ~/mlt-devel/mlt/src/melt/melt -filter motion_est -filter histogram -consumer sdl rescale=none real_time=0 audio_off=1 silent=1 /media/cdrecorder/BBC.The.Private.Life.Of.Plants.Pt5.Living.Together.DivX505.AC3.www.MVGroup.org.uk.avi in=40000 test2: $(TARGET) melt colour:black -filter watermark:"+mello.txt" composite.geometry="0/0:10%x10%;99=90%/90%" composite.out=99 -filter crop_detect -filter motion_est -filter vismv realtime: $(TARGET) ~/mlt-devel/mlt/src/melt/melt -filter motion_est -filter vismv -consumer sdl rescale=none /media/cdrecorder/BBC.The.Private.Life.Of.Plants.Pt5.Living.Together.DivX505.AC3.www.MVGroup.org.uk.avi in=30000 testhist: $(TARGET) ~/mlt-devel/mlt/src/melt/melt -consumer sdl rescale=none silent=1 -filter motion_est -filter histogram -filter vismv /media/cdrecorder/BBC.The.Private.Life.Of.Plants.Pt5.Living.Together.DivX505.AC3.www.MVGroup.org.uk.avi in=10000 ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/motion_est/README000066400000000000000000000064121215300731300176110ustar00rootroot00000000000000INTRO: This module is designed to provide application agnostic motion estimation. I wrote it from scratch because I found the other Open Source code to be limited by their difficulty of reuse. COMPILE: To compile this module, you must supply these options to the root configure script: --enable-gpl --enable-motion-est EXAMPLES: Estimate the motion: > melt -filter motion_est To display the motion vectors as pretty arrows: > melt -filter motion_est -filter vismv If your using a movie file that contains a crop, you will get better results with this: > melt -filter crop_detect -filter motion_est -filter vismv If your computer is unable to do the above examples in real time, try this: > melt -filter motion_est -filter vismv -consumer melt real_time=0 If you'd like to see the motion vectors without the median denoising function, do this: > melt -filter motion_est denoise=0 -filter vismv To reconstruct each frame by applying the motion to the previous frame: > melt -filter motion_est show_reconstruction=1 To compare the reconstructed frame and the real frame (while paused): > melt -filter motion_est show_reconstruction=1 toggle_when_paused=1 To show the difference (residual) between the reconstructed frame the real frame: > melt -filter motion_est show_residual=1 To automatically track an object in the frame, try this: > melt -filter autotrack_rectangle:X,Y:WxH debug=1 (Where X,Y is the origin of the rectangle indexed from upper left and WxH is the dimensions of the rectangle.) To obscure that same object in the frame, try this: > melt -filter autotrack_rectangle:X,Y:WxH obscure=1 There is now a slow motion producer that does interpolation based on the motion vectors: > melt slowmotion: _speed=0.1 method=1 debug=1 NOTES (and deficiencies): 1. Ignore shot change detection when your using the autotrack_rectangle filter. 2. Don't assume motion vectors displayed while stepping backwards and forward are that same vectors that would be calculated while playing the footage from start to finish, nonstop. Stepping forward should be fine after a few frames, however. 3. SSE instructions are lazily assumed. MMX, Altivec, and SIMD-less would be good too. 4. Motion estimation is only performed in the luma color space. 5. Motion vectors should have sub-pixel accuracy. 6. Motion vectors are not serializable yet. 7. A diligent test suite is needed. (show_reconstruction & show_residual are a start) 8. Multithreaded code will see HUGE benefits on multi-CPU systems. Donations of a multi-core cpu or a multi-cpu system to the author will encourage development. 9. Macroblock sizes are not dynamic (Though settable at runtime.) 10. Notes (5), (7), and (9) would go a long ways to making this code suitable for a modern video encoder. 11. Shot change works well but arbitrarily chosen thresholds need to be tuned. 12. Given the documentation of other motion estimation code bases, I will GLADLY clarify and document any piece of code upon request. 13. Considerable effort has been put into the speed. I usually experience 10ms or less per frame for PAL on 2.8GHZ p4. Zachary Drew drew0054@tc.umn.edu mlt-0.9.0/src/modules/motion_est/arrow_code.c000066400000000000000000000102031215300731300212120ustar00rootroot00000000000000/* * /brief Draw arrows * /author Zachary Drew, Copyright 2004 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "arrow_code.h" #include #include #include #include #define MIN(a,b) ((a) > (b) ? (b) : (a)) #define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) #define ABS(a) ((a) >= 0 ? (a) : (-(a))) static int w; static int h; static int xstride; static int ystride; static mlt_image_format format; int init_arrows( mlt_image_format *image_format, int width, int height ) { w = width; h = height; format = *image_format; switch( *image_format ) { case mlt_image_yuv422: xstride = 2; ystride = xstride * w; break; default: // I don't know return 0; } return 1; } // ffmpeg borrowed static inline int clip(int a, int amin, int amax) { if (a < amin) return amin; else if (a > amax) return amax; else return a; } /** * draws an line from (ex, ey) -> (sx, sy). * Credits: modified from ffmpeg project * @param ystride stride/linesize of the image * @param xstride stride/element size of the image * @param color color of the arrow */ void draw_line(uint8_t *buf, int sx, int sy, int ex, int ey, int color) { int t, x, y, fr, f; sx= clip(sx, 0, w-1); sy= clip(sy, 0, h-1); ex= clip(ex, 0, w-1); ey= clip(ey, 0, h-1); buf[sy*ystride + sx*xstride]+= color; if(ABS(ex - sx) > ABS(ey - sy)){ if(sx > ex){ t=sx; sx=ex; ex=t; t=sy; sy=ey; ey=t; } buf+= sx*xstride + sy*ystride; ex-= sx; f= ((ey-sy)<<16)/ex; for(x= 0; x <= ex; x++){ y = (x*f)>>16; fr= (x*f)&0xFFFF; buf[ y *ystride + x*xstride]+= (color*(0x10000-fr))>>16; buf[(y+1)*ystride + x*xstride]+= (color* fr )>>16; } }else{ if(sy > ey){ t=sx; sx=ex; ex=t; t=sy; sy=ey; ey=t; } buf+= sx*xstride + sy*ystride; ey-= sy; if(ey) f= ((ex-sx)<<16)/ey; else f= 0; for(y= 0; y <= ey; y++){ x = (y*f)>>16; fr= (y*f)&0xFFFF; buf[y*ystride + x *xstride]+= (color*(0x10000-fr))>>16;; buf[y*ystride + (x+1)*xstride]+= (color* fr )>>16;; } } } void draw_rectangle_fill(uint8_t *buf, int x, int y, int w, int h, int color) { int i,j; for ( i = 0; i < w; i++ ) for ( j = 0; j < h; j++ ) buf[ (y+j)*ystride + (x+i)*xstride] = color; } void draw_rectangle_outline(uint8_t *buf, int x, int y, int w, int h, int color) { int i,j; for ( i = 0; i < w; i++ ) { buf[ y*ystride + (x+i)*xstride ] += color; buf[ (y+h)*ystride + (x+i)*xstride ] += color; } for ( j = 1; j < h+1; j++ ) { buf[ (y+j)*ystride + x*xstride ] += color; buf[ (y+j)*ystride + (x+w)*xstride ] += color; } } /** * draws an arrow from (ex, ey) -> (sx, sy). * Credits: modified from ffmpeg project * @param stride stride/linesize of the image * @param color color of the arrow */ void draw_arrow(uint8_t *buf, int sx, int sy, int ex, int ey, int color){ int dx,dy; dx= ex - sx; dy= ey - sy; if(dx*dx + dy*dy > 3*3){ int rx= dx + dy; int ry= -dx + dy; int length= sqrt((rx*rx + ry*ry)<<8); rx= ROUNDED_DIV(rx*3<<4, length); ry= ROUNDED_DIV(ry*3<<4, length); draw_line(buf, sx, sy, sx + rx, sy + ry, color); draw_line(buf, sx, sy, sx - ry, sy + rx, color); } draw_line(buf, sx, sy, ex, ey, color); } mlt-0.9.0/src/modules/motion_est/arrow_code.h000066400000000000000000000023401215300731300212220ustar00rootroot00000000000000/** * file: arrow_code.h * * /brief Misc functions to draw arrows * /author Zachary Drew, Copyright 2004 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ extern int init_arrows( mlt_image_format *image_format, int width, int height ); extern void draw_line(uint8_t *buf, int sx, int sy, int ex, int ey, int color); extern void draw_arrow(uint8_t *buf, int sx, int sy, int ex, int ey, int color); extern void draw_rectangle_fill(uint8_t *buf, int x, int y, int w, int h, int color); extern void draw_rectangle_outline(uint8_t *buf, int x, int y, int w, int h, int color); mlt-0.9.0/src/modules/motion_est/factory.c000066400000000000000000000046251215300731300205500ustar00rootroot00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include extern mlt_filter filter_motion_est_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_vismv_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_crop_detect_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_autotrack_rectangle_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_slowmotion_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/motion_est/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( filter_type, "motion_est", filter_motion_est_init ); MLT_REGISTER( filter_type, "vismv", filter_vismv_init ); MLT_REGISTER( filter_type, "crop_detect", filter_crop_detect_init ); MLT_REGISTER( filter_type, "autotrack_rectangle", filter_autotrack_rectangle_init ); MLT_REGISTER( producer_type, "slowmotion", producer_slowmotion_init ); MLT_REGISTER_METADATA( filter_type, "motion_est", metadata, "filter_motion_est.yml" ); MLT_REGISTER_METADATA( filter_type, "vismv", metadata, "filter_vismv.yml" ); MLT_REGISTER_METADATA( filter_type, "crop_detect", metadata, "filter_crop_detect.yml" ); MLT_REGISTER_METADATA( filter_type, "autotrack_rectangle", metadata, "filter_autotrack_rectangle.yml" ); MLT_REGISTER_METADATA( producer_type, "slowmotion", metadata, "producer_slowmotion.yml" ); } mlt-0.9.0/src/modules/motion_est/filter_autotrack_rectangle.c000066400000000000000000000277741215300731300245010ustar00rootroot00000000000000/* * filter_autotrack_rectangle.c * * /brief * /author Zachary Drew, Copyright 2005 * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "filter_motion_est.h" #include "arrow_code.h" #include #include #include #include #include #define MIN(a,b) ((a) > (b) ? (b) : (a)) #define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) #define ABS(a) ((a) >= 0 ? (a) : (-(a))) void caculate_motion( struct motion_vector_s *vectors, mlt_geometry_item boundry, int macroblock_width, int macroblock_height, int mv_buffer_width, int method, int width, int height ) { // translate pixel units (from bounds) to macroblock units // make sure whole macroblock stay within bounds int left_mb = ( boundry->x + macroblock_width - 1 ) / macroblock_width; int top_mb = ( boundry->y + macroblock_height - 1 ) / macroblock_height; int right_mb = ( boundry->x + boundry->w ) / macroblock_width - 1; int bottom_mb = ( boundry->y + boundry->h ) / macroblock_height - 1; int i, j, n = 0; int average_x = 0, average_y = 0; #define CURRENT ( vectors + j*mv_buffer_width + i ) for( i = left_mb; i <= right_mb; i++ ){ for( j = top_mb; j <= bottom_mb; j++ ) { n++; average_x += CURRENT->dx; average_y += CURRENT->dy; } } if ( n == 0 ) return; average_x /= n; average_y /= n; n = 0; int average2_x = 0, average2_y = 0; for( i = left_mb; i <= right_mb; i++ ){ for( j = top_mb; j <= bottom_mb; j++ ){ if( ABS(CURRENT->dx - average_x) < 3 && ABS(CURRENT->dy - average_y) < 3 ) { n++; average2_x += CURRENT->dx; average2_y += CURRENT->dy; } } } if ( n == 0 ) return; boundry->x -= (double)average2_x / (double)n; boundry->y -= (double)average2_y / (double)n; if ( boundry->x < 0 ) boundry->x = 0; if ( boundry->y < 0 ) boundry->y = 0; if ( boundry->x + boundry->w > width ) boundry->x = width - boundry->w; if ( boundry->y + boundry->h > height ) boundry->y = height - boundry->h; } // Image stack(able) method static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter object mlt_filter filter = mlt_frame_pop_service( frame ); // Get the filter's property object mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter); // Get the frame properties mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame); // Get the frame position mlt_position position = mlt_filter_get_position( filter, frame ); // Get the new image int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); if( error != 0 ) mlt_properties_debug( frame_properties, "error after mlt_frame_get_image() in autotrack_rectangle", stderr ); mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); // Get the geometry object mlt_geometry geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL); // Get the current geometry item struct mlt_geometry_item_s boundry; mlt_geometry_fetch(geometry, &boundry, position); // Get the motion vectors struct motion_vector_s *vectors = mlt_properties_get_data( frame_properties, "motion_est.vectors", NULL ); // Cleanse the geometry item boundry.w = boundry.x < 0 ? boundry.w + boundry.x : boundry.w; boundry.h = boundry.y < 0 ? boundry.h + boundry.y : boundry.h; boundry.x = boundry.x < 0 ? 0 : boundry.x; boundry.y = boundry.y < 0 ? 0 : boundry.y; boundry.w = boundry.w < 0 ? 0 : boundry.w; boundry.h = boundry.h < 0 ? 0 : boundry.h; // How did the rectangle move? if( vectors != NULL && boundry.key != 1 ) // Paused? { int method = mlt_properties_get_int( filter_properties, "method" ); // Get the size of macroblocks in pixel units int macroblock_height = mlt_properties_get_int( frame_properties, "motion_est.macroblock_height" ); int macroblock_width = mlt_properties_get_int( frame_properties, "motion_est.macroblock_width" ); int mv_buffer_width = *width / macroblock_width; caculate_motion( vectors, &boundry, macroblock_width, macroblock_height, mv_buffer_width, method, *width, *height ); // Make the geometry object a real boy boundry.key = 1; boundry.f[0] = 1; boundry.f[1] = 1; boundry.f[2] = 1; boundry.f[3] = 1; boundry.f[4] = 1; mlt_geometry_insert(geometry, &boundry); mlt_geometry_interpolate(geometry); } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); if( mlt_properties_get_int( filter_properties, "debug" ) == 1 ) { init_arrows( format, *width, *height ); draw_rectangle_outline(*image, boundry.x, boundry.y, boundry.w, boundry.h, 100); } if( mlt_properties_get_int( filter_properties, "_serialize" ) == 1 ) { // Add the vector change to the list mlt_geometry key_frames = mlt_properties_get_data( filter_properties, "motion_vector_list", NULL ); if ( !key_frames ) { key_frames = mlt_geometry_init(); mlt_properties_set_data( filter_properties, "motion_vector_list", key_frames, 0, (mlt_destructor) mlt_geometry_close, (mlt_serialiser) mlt_geometry_serialise ); if ( key_frames ) mlt_geometry_set_length( key_frames, mlt_filter_get_length2( filter, frame ) ); } if ( key_frames ) { struct mlt_geometry_item_s item; item.frame = (int) mlt_frame_get_position( frame ); item.key = 1; item.x = boundry.x; item.y = boundry.y; item.w = boundry.w; item.h = boundry.h; item.mix = 0; item.f[0] = item.f[1] = item.f[2] = item.f[3] = 1; item.f[4] = 0; mlt_geometry_insert( key_frames, &item ); } } if( mlt_properties_get_int( filter_properties, "obscure" ) == 1 ) { mlt_filter obscure = mlt_properties_get_data( filter_properties, "_obscure", NULL ); mlt_properties_pass_list( MLT_FILTER_PROPERTIES(obscure), filter_properties, "in, out"); // Because filter_obscure needs to be rewritten to use mlt_geometry char geom[100]; sprintf( geom, "%d/%d:%dx%d", (int)boundry.x, (int)boundry.y, (int)boundry.w, (int)boundry.h ); mlt_properties_set( MLT_FILTER_PROPERTIES( obscure ), "start", geom ); mlt_properties_set( MLT_FILTER_PROPERTIES( obscure ), "end", geom ); } if( mlt_properties_get_int( filter_properties, "collect" ) == 1 ) { fprintf( stderr, "%d,%d,%d,%d\n", (int)boundry.x, (int)boundry.y, (int)boundry.w, (int)boundry.h ); fflush( stdout ); } return error; } static int attach_boundry_to_frame( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter object mlt_filter filter = mlt_frame_pop_service( frame ); // Get the filter's property object mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter); // Get the frame properties mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame); // Get the frame position mlt_position position = mlt_filter_get_position( filter, frame ); mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); // Get the geometry object mlt_geometry geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL); if (geometry == NULL) { mlt_geometry geom = mlt_geometry_init(); char *arg = mlt_properties_get(filter_properties, "geometry"); // Initialize with the supplied geometry struct mlt_geometry_item_s item; mlt_geometry_parse_item( geom, &item, arg ); item.frame = 0; item.key = 1; item.mix = 100; mlt_geometry_insert( geom, &item ); mlt_geometry_interpolate( geom ); mlt_properties_set_data( filter_properties, "filter_geometry", geom, 0, (mlt_destructor)mlt_geometry_close, (mlt_serialiser)mlt_geometry_serialise ); geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL); } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); // Get the current geometry item mlt_geometry_item geometry_item = mlt_pool_alloc( sizeof( struct mlt_geometry_item_s ) ); mlt_geometry_fetch(geometry, geometry_item, position); // Cleanse the geometry item geometry_item->w = geometry_item->x < 0 ? geometry_item->w + geometry_item->x : geometry_item->w; geometry_item->h = geometry_item->y < 0 ? geometry_item->h + geometry_item->y : geometry_item->h; geometry_item->x = geometry_item->x < 0 ? 0 : geometry_item->x; geometry_item->y = geometry_item->y < 0 ? 0 : geometry_item->y; geometry_item->w = geometry_item->w < 0 ? 0 : geometry_item->w; geometry_item->h = geometry_item->h < 0 ? 0 : geometry_item->h; mlt_properties_set_data( frame_properties, "bounds", geometry_item, sizeof( struct mlt_geometry_item_s ), mlt_pool_release, NULL ); // Get the new image int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); if( error != 0 ) mlt_properties_debug( frame_properties, "error after mlt_frame_get_image() in autotrack_rectangle attach_boundry_to_frame", stderr ); return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { /* modify the frame with the current geometry */ mlt_frame_push_service( frame, this); mlt_frame_push_get_image( frame, attach_boundry_to_frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( this ); /* apply the motion estimation filter */ mlt_filter motion_est = mlt_properties_get_data( properties, "_motion_est", NULL ); /* Pass motion_est properties */ mlt_properties_pass( MLT_FILTER_PROPERTIES( motion_est ), properties, "motion_est." ); mlt_filter_process( motion_est, frame); /* calculate the new geometry based on the motion */ mlt_frame_push_service( frame, this); mlt_frame_push_get_image( frame, filter_get_image ); /* visualize the motion vectors */ if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(this), "debug" ) == 1 ) { mlt_filter vismv = mlt_properties_get_data( properties, "_vismv", NULL ); if( vismv == NULL ) { mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) ); vismv = mlt_factory_filter( profile, "vismv", NULL ); mlt_properties_set_data( properties, "_vismv", vismv, 0, (mlt_destructor)mlt_filter_close, NULL ); } mlt_filter_process( vismv, frame ); } if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(this), "obscure" ) == 1 ) { mlt_filter obscure = mlt_properties_get_data( properties, "_obscure", NULL ); if( obscure == NULL ) { mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) ); obscure = mlt_factory_filter( profile, "obscure", NULL ); mlt_properties_set_data( properties, "_obscure", obscure, 0, (mlt_destructor)mlt_filter_close, NULL ); } mlt_filter_process( obscure, frame ); } return frame; } /** Constructor for the filter. */ mlt_filter filter_autotrack_rectangle_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; // Initialize with the supplied geometry if ther is one if( arg != NULL ) mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "geometry", arg ); else mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "geometry", "100/100:100x100" ); // create an instance of the motion_est and obscure filter mlt_filter motion_est = mlt_factory_filter( profile, "motion_est", NULL ); if( motion_est != NULL ) mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_motion_est", motion_est, 0, (mlt_destructor)mlt_filter_close, NULL ); else { mlt_filter_close( this ); return NULL; } } return this; } /** This source code will self destruct in 5...4...3... */ mlt-0.9.0/src/modules/motion_est/filter_autotrack_rectangle.yml000066400000000000000000000003011215300731300250310ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: autotrack_rectangle title: Autotrack Rectangle version: 1 copyright: Zachary Drew creator: Zachary Drew license: GPLv2 language: en tags: - Video mlt-0.9.0/src/modules/motion_est/filter_crop_detect.c000066400000000000000000000155471215300731300227460ustar00rootroot00000000000000/** * /brief Crop Detection filter * * /author Zachary Drew, Copyright 2005 * * inspired by mplayer's cropdetect filter * * Note: The goemetry generated is zero-indexed and is inclusive of the end values * * Options: * -filter crop_detect debug=1 // Visualize crop * -filter crop_detect frequency=25 // Detect the crop once a second * -filter crop_detect frequency=0 // Never detect unless the producer changes * -filter crop_detect thresh=100 // Changes the threshold (default = 25) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define DEBUG #define DEFAULT_THRESH 20 #include #include #include #include #include #include "arrow_code.h" #define ABS(a) ((a) >= 0 ? (a) : (-(a))) // Image stack(able) method static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter object and properties mlt_filter filter = mlt_frame_pop_service( this ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); // Get the new image int error = mlt_frame_get_image( this, image, format, width, height, 1 ); if( error != 0 ) { mlt_properties_debug( MLT_FRAME_PROPERTIES(this), "error after mlt_frame_get_image()", stderr ); return error; } // Parameter that describes how often to check for the crop int frequency = mlt_properties_get_int( properties, "frequency"); // Producers may start with blank footage, by default we will skip, oh, 5 frames unless overridden int skip = mlt_properties_get_int( properties, "skip"); mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); // The result mlt_geometry_item bounds = mlt_properties_get_data( properties, "bounds", NULL ); // Initialize if needed if( bounds == NULL ) { bounds = calloc( 1, sizeof( struct mlt_geometry_item_s ) ); bounds->w = *width; bounds->h = *height; mlt_properties_set_data( properties, "bounds", bounds, sizeof( struct mlt_geometry_item_s ), free, NULL ); } // For periodic detection (with offset of 'skip') if( frequency == 0 || (int)(mlt_filter_get_position(filter, this)+skip) % frequency != 0) { // Inject in stream mlt_properties_set_data( MLT_FRAME_PROPERTIES(this), "bounds", bounds, sizeof( struct mlt_geometry_item_s ), NULL, NULL ); return 0; } // There is no way to detect a crop for sure, so make up an arbitrary one int thresh = mlt_properties_get_int( properties, "thresh" ); *format = mlt_image_yuv422; int xstride = 2; int ystride = 2 * *width; int x, y, average_brightness, deviation; // Scratch variables uint8_t *q; // Top crop for( y = 0; y < *height/2; y++ ) { bounds->y = y; average_brightness = 0; deviation = 0; q = *image + y*ystride; for( x = 0; x < *width; x++ ) average_brightness += q[x*xstride]; average_brightness /= *width; for( x = 0; x < *width; x++ ) deviation += abs(average_brightness - q[x*xstride]); if( deviation*10 >= thresh * *width ) break; } // Bottom crop for( y = *height - 1; y >= *height/2; y-- ) { bounds->h = y; average_brightness = 0; deviation = 0; q = *image + y*ystride; for( x = 0; x < *width; x++ ) average_brightness += q[x*xstride]; average_brightness /= *width; for( x = 0; x < *width; x++ ) deviation += abs(average_brightness - q[x*xstride]); if( deviation*10 >= thresh * *width) break; } // Left crop for( x = 0; x < *width/2; x++ ) { bounds->x = x; average_brightness = 0; deviation = 0; q = *image + x*xstride; for( y = 0; y < *height; y++ ) average_brightness += q[y*ystride]; average_brightness /= *height; for( y = 0; y < *height; y++ ) deviation += abs(average_brightness - q[y*ystride]); if( deviation*10 >= thresh * *width ) break; } // Right crop for( x = *width - 1; x >= *width/2; x-- ) { bounds->w = x; average_brightness = 0; deviation = 0; q = *image + x*xstride; for( y = 0; y < *height; y++ ) average_brightness += q[y*ystride]; average_brightness /= *height; for( y = 0; y < *height; y++ ) deviation += abs(average_brightness - q[y*ystride]); if( deviation*10 >= thresh * *width ) break; } /* Debug: Draw arrows to show crop */ if( mlt_properties_get_int( properties, "debug") == 1 ) { init_arrows( format, *width, *height ); draw_arrow(*image, bounds->x, *height/2, bounds->x+50, *height/2, 100); draw_arrow(*image, *width/2, bounds->y, *width/2, bounds->y+50, 100); draw_arrow(*image, bounds->w, *height/2, bounds->w-50, *height/2, 100); draw_arrow(*image, *width/2, bounds->h, *width/2, bounds->h-50, 100); draw_arrow(*image, bounds->x, bounds->y, bounds->x+40, bounds->y+30, 100); draw_arrow(*image, bounds->x, bounds->h, bounds->x+40, bounds->h-30, 100); draw_arrow(*image, bounds->w, bounds->y, bounds->w-40, bounds->y+30, 100); draw_arrow(*image, bounds->w, bounds->h, bounds->w-40, bounds->h-30, 100); } // Convert to width and correct indexing bounds->w -= bounds->x - 1; bounds->h -= bounds->y - 1; if( mlt_properties_get_int( properties, "debug") == 1 ) fprintf(stderr, "Top:%f Left:%f Width:%f Height:%f\n", bounds->y, bounds->x, bounds->w, bounds->h); /* inject into frame */ mlt_properties_set_data( MLT_FRAME_PROPERTIES(this), "bounds", bounds, sizeof( struct mlt_geometry_item_s ), NULL, NULL ); mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Put the filter object somewhere we can find it mlt_frame_push_service( frame, this); // Push the frame filter mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_crop_detect_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; /* defaults */ mlt_properties_set_int( MLT_FILTER_PROPERTIES(this), "frequency", 1); mlt_properties_set_int( MLT_FILTER_PROPERTIES(this), "thresh", 5); mlt_properties_set_int( MLT_FILTER_PROPERTIES(this), "clip", 5); mlt_properties_set_int( MLT_FILTER_PROPERTIES(this), "former_producer_id", -1); } return this; } /** This source code will self destruct in 5...4...3... */ mlt-0.9.0/src/modules/motion_est/filter_motion_est.c000066400000000000000000001021231215300731300226160ustar00rootroot00000000000000/* * /brief fast motion estimation filter * /author Zachary Drew, Copyright 2005 * * Currently only uses Gamma data for comparisonon (bug or feature?) * SSE optimized where available. * * Vector orientation: The vector data that is generated for the current frame specifies * the motion from the previous frame to the current frame. To know how a macroblock * in the current frame will move in the future, the next frame is needed. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "filter_motion_est.h" #include #include #include #include #include #include #include #ifdef USE_SSE #include "sad_sse.h" #endif #define NDEBUG #include #undef DEBUG #undef DEBUG_ASM #undef BENCHMARK #undef COUNT_COMPARES #define DIAMOND_SEARCH 0x0 #define FULL_SEARCH 0x1 #define SHIFT 8 #define MIN(a,b) ((a) > (b) ? (b) : (a)) #define ABS(a) ((a) >= 0 ? (a) : (-(a))) struct motion_est_context_s { int initialized; // true if filter has been initialized #ifdef COUNT_COMPARES int compares; #endif /* same as mlt_frame's parameters */ int width, height; /* Operational details */ int mb_w, mb_h; int xstride, ystride; uint8_t *cache_image; // Copy of current frame uint8_t *former_image; // Copy of former frame int search_method; int skip_prediction; int shot_change; int limit_x, limit_y; // max x and y of a motion vector int initial_thresh; int check_chroma; // if check_chroma == 1 then compare chroma int denoise; int previous_msad; int show_reconstruction; int toggle_when_paused; int show_residual; /* bounds */ struct mlt_geometry_item_s bounds; // Current bounds (from filters crop_detect, autotrack rectangle, or other) /* bounds in macroblock units; macroblocks are completely contained within the boundry */ int left_mb, prev_left_mb, right_mb, prev_right_mb; int top_mb, prev_top_mb, bottom_mb, prev_bottom_mb; /* size of our vector buffers */ int mv_buffer_height, mv_buffer_width, mv_size; /* vector buffers */ int former_vectors_valid; // right || x2 + *w > right ) w_remains = right - ((*x > x2) ? *x : x2); // Origin of macroblock moves above image boundy if( *y < top || y2 < top ) { h_remains = *h - top + ((*y < y2) ? *y : y2); *y += *h - h_remains; } // Portion of macroblock moves bellow image boundry else if( *y + *h > bottom || y2 + *h > bottom ) h_remains = bottom - ((*y > y2) ? *y : y2); if( w_remains == *w && h_remains == *h ) return penalty; if( w_remains <= 0 || h_remains <= 0) return 0; // Block is clipped out of existance penalty = (*w * *h * penalty) / ( w_remains * h_remains); // Recipricol of the fraction of the block that remains assert(*x >= left); assert(x2 + *w - w_remains >= left); assert(*y >= top); assert(y2 + *h - h_remains >= top); assert(*x + w_remains <= right); assert(x2 + w_remains <= right); assert(*y + h_remains <= bottom); assert(y2 + h_remains <= bottom); *w = w_remains; // Update the width and height *h = h_remains; return penalty; } /** /brief Reference Sum of Absolute Differences comparison function * */ static int sad_reference( uint8_t *block1, uint8_t *block2, const int xstride, const int ystride, const int w, const int h ) { int i, j, score = 0; for ( j = 0; j < h; j++ ){ for ( i = 0; i < w; i++ ){ score += ABS( block1[i*xstride] - block2[i*xstride] ); } block1 += ystride; block2 += ystride; } return score; } /** /brief Abstracted block comparison function */ inline static int block_compare( uint8_t *block1, uint8_t *block2, int x, int y, int dx, int dy, struct motion_est_context_s *c) { #ifdef COUNT_COMPARES c->compares++; #endif int score; // Default comparison may be overridden by the slower, more capable reference comparison int (*cmp)(uint8_t *, uint8_t *, int, int, int, int) = c->compare_optimized; // vector displacement limited has been exceeded if( ABS( dx ) >= c->limit_x || ABS( dy ) >= c->limit_y ) return MAX_MSAD; int mb_w = c->mb_w; // Some writeable local copies int mb_h = c->mb_h; // Determine if either macroblock got clipped int penalty = constrain( &x, &y, &mb_w, &mb_h, dx, dy, 0, c->width, 0, c->height); // Some gotchas if( penalty == 0 ) // Clipped out of existance: Return worst score return MAX_MSAD; else if( penalty != 1<compare_reference; // Calculate the memory locations of the macroblocks block1 += x * c->xstride + y * c->ystride; block2 += (x+dx) * c->xstride + (y+dy) * c->ystride; #ifdef DEBUG_ASM if( penalty == 1<compare_reference( block1, block2, c->xstride, c->ystride, mb_w, mb_h ); int score2 = c->compare_optimized( block1, block2, c->xstride, c->ystride, mb_w, mb_h ); if ( score != score2 ) fprintf(stderr, "Your assembly doesn't work! Reference: %d Asm: %d\n", score, score2); } else #endif score = cmp( block1, block2, c->xstride, c->ystride, mb_w, mb_h ); return ( score * penalty ) >> SHIFT; // Ditch the extra precision } static inline void check_candidates ( uint8_t *ref, uint8_t *candidate_base, const int x, const int y, const motion_vector *candidates,// Contains to_x & to_y const int count, // Number of candidates const int unique, // Sometimes we know the candidates are unique motion_vector *result, struct motion_est_context_s *c ) { int score, i, j; /* Scan for the best candidate */ for ( i = 0; i < count; i++ ) { // this little dohicky ignores duplicate candidates, if they are possible if ( unique == 0 ) { j = 0; while ( j < i ) { if ( candidates[j].dx == candidates[i].dx && candidates[j].dy == candidates[i].dy ) goto next_for_loop; j++; } } // Luma score = block_compare( ref, candidate_base, x, y, candidates[i].dx, // from candidates[i].dy, c); if ( score < result->msad ) { // New minimum result->dx = candidates[i].dx; result->dy = candidates[i].dy; result->msad = score; } next_for_loop:; } } /* /brief Diamond search * Operates on a single macroblock */ static inline void diamond_search( uint8_t *ref, //dx; current.dy = result->dy; if ( first == 1 ) // Set the initial pattern { candidates[0].dx = result->dx + 1; candidates[0].dy = result->dy + 0; candidates[1].dx = result->dx + 0; candidates[1].dy = result->dy + 1; candidates[2].dx = result->dx - 1; candidates[2].dy = result->dy + 0; candidates[3].dx = result->dx + 0; candidates[3].dy = result->dy - 1; i = 4; } else // Construct the next portion of the search pattern { candidates[0].dx = result->dx + best.dx; candidates[0].dy = result->dy + best.dy; if (best.dx == former.dx && best.dy == former.dy) { candidates[1].dx = result->dx + best.dy; candidates[1].dy = result->dy + best.dx; // Yes, the wires candidates[2].dx = result->dx - best.dy; // are crossed candidates[2].dy = result->dy - best.dx; i = 3; } else { candidates[1].dx = result->dx + former.dx; candidates[1].dy = result->dy + former.dy; i = 2; } former.dx = best.dx; former.dy = best.dy; // Keep track of new former best } check_candidates ( ref, candidate_base, x, y, candidates, i, 1, result, c ); // Which candidate was the best? best.dx = result->dx - current.dx; best.dy = result->dy - current.dy; // A better canidate was not found if ( best.dx == 0 && best.dy == 0 ) return; if ( first == 1 ){ first = 0; former.dx = best.dx; former.dy = best.dy; // First iteration, sensible value for former.d* } } } /* /brief Full (brute) search * Operates on a single macroblock */ __attribute__((used)) static void full_search( uint8_t *ref, //mb_w; i <= c->mb_w; i++ ){ for( j = -c->mb_h; j <= c->mb_h; j++ ){ score = block_compare( ref, candidate_base, x, y, x + i, y + j, c); if ( score < result->msad ) { result->dx = i; result->dy = j; result->msad = score; } } } } // Macros for pointer calculations #define CURRENT(i,j) ( c->current_vectors + (j)*c->mv_buffer_width + (i) ) #define FORMER(i,j) ( c->former_vectors + (j)*c->mv_buffer_width + (i) ) #define DENOISE(i,j) ( c->denoise_vectors + (j)*c->mv_buffer_width + (i) ) int ncompare (const void * a, const void * b) { return ( *(const int*)a - *(const int*)b ); } // motion vector denoising // for x and y components seperately, // change the vector to be the median value of the 9 adjacent vectors static void median_denoise( motion_vector *v, struct motion_est_context_s *c ) { int xvalues[9], yvalues[9]; int i,j,n; for( j = c->top_mb; j <= c->bottom_mb; j++ ) for( i = c->left_mb; i <= c->right_mb; i++ ){ { n = 0; xvalues[n ] = CURRENT(i,j)->dx; // Center yvalues[n++] = CURRENT(i,j)->dy; if( i > c->left_mb ) // Not in First Column { xvalues[n ] = CURRENT(i-1,j)->dx; // Left yvalues[n++] = CURRENT(i-1,j)->dy; if( j > c->top_mb ) { xvalues[n ] = CURRENT(i-1,j-1)->dx; // Upper Left yvalues[n++] = CURRENT(i-1,j-1)->dy; } if( j < c->bottom_mb ) { xvalues[n ] = CURRENT(i-1,j+1)->dx; // Bottom Left yvalues[n++] = CURRENT(i-1,j+1)->dy; } } if( i < c->right_mb ) // Not in Last Column { xvalues[n ] = CURRENT(i+1,j)->dx; // Right yvalues[n++] = CURRENT(i+1,j)->dy; if( j > c->top_mb ) { xvalues[n ] = CURRENT(i+1,j-1)->dx; // Upper Right yvalues[n++] = CURRENT(i+1,j-1)->dy; } if( j < c->bottom_mb ) { xvalues[n ] = CURRENT(i+1,j+1)->dx; // Bottom Right yvalues[n++] = CURRENT(i+1,j+1)->dy; } } if( j > c->top_mb ) // Not in First Row { xvalues[n ] = CURRENT(i,j-1)->dx; // Top yvalues[n++] = CURRENT(i,j-1)->dy; } if( j < c->bottom_mb ) // Not in Last Row { xvalues[n ] = CURRENT(i,j+1)->dx; // Bottom yvalues[n++] = CURRENT(i,j+1)->dy; } qsort (xvalues, n, sizeof(int), ncompare); qsort (yvalues, n, sizeof(int), ncompare); if( n % 2 == 1 ) { DENOISE(i,j)->dx = xvalues[n/2]; DENOISE(i,j)->dy = yvalues[n/2]; } else { DENOISE(i,j)->dx = (xvalues[n/2] + xvalues[n/2+1])/2; DENOISE(i,j)->dy = (yvalues[n/2] + yvalues[n/2+1])/2; } } } motion_vector *t = c->current_vectors; c->current_vectors = c->denoise_vectors; c->denoise_vectors = t; } // Credits: ffmpeg // return the median static inline int median_predictor(int a, int b, int c) { if ( a > b ){ if ( c > b ){ if ( c > a ) b = a; else b = c; } } else { if ( b > c ){ if ( c > a ) b = c; else b = a; } } return b; } /** /brief Motion search * * For each macroblock in the current frame, estimate the block from the last frame that * matches best. * * Vocab: Colocated - the pixel in the previous frame at the current position * * Based on enhanced predictive zonal search. [Tourapis 2002] */ static void motion_search( uint8_t *from, //left_mb; i <= c->right_mb; i++ ){ for( j = c->top_mb; j <= c->bottom_mb; j++ ){ here = CURRENT(i,j); here->valid = 1; here->color = 100; here->msad = MAX_MSAD; count++; n = 0; /* Stack the predictors [i.e. checked in reverse order] */ /* Adjacent to collocated */ if( c->former_vectors_valid ) { // Top of colocated if( j > c->prev_top_mb ){// && COL_TOP->valid ){ candidates[n ].dx = FORMER(i,j-1)->dx; candidates[n++].dy = FORMER(i,j-1)->dy; } // Left of colocated if( i > c->prev_left_mb ){// && COL_LEFT->valid ){ candidates[n ].dx = FORMER(i-1,j)->dx; candidates[n++].dy = FORMER(i-1,j)->dy; } // Right of colocated if( i < c->prev_right_mb ){// && COL_RIGHT->valid ){ candidates[n ].dx = FORMER(i+1,j)->dx; candidates[n++].dy = FORMER(i+1,j)->dy; } // Bottom of colocated if( j < c->prev_bottom_mb ){// && COL_BOTTOM->valid ){ candidates[n ].dx = FORMER(i,j+1)->dx; candidates[n++].dy = FORMER(i,j+1)->dy; } // And finally, colocated candidates[n ].dx = FORMER(i,j)->dx; candidates[n++].dy = FORMER(i,j)->dy; } // For macroblocks not in the top row if ( j > c->top_mb) { // Top if ( TOP->valid ) { candidates[n ].dx = CURRENT(i,j-1)->dx; candidates[n++].dy = CURRENT(i,j-1)->dy; //} // Top-Right, macroblocks not in the right row if ( i < c->right_mb ){// && TOP_RIGHT->valid ) { candidates[n ].dx = CURRENT(i+1,j-1)->dx; candidates[n++].dy = CURRENT(i+1,j-1)->dy; } } // Left, Macroblocks not in the left column if ( i > c->left_mb ){// && LEFT->valid ) { candidates[n ].dx = CURRENT(i-1,j)->dx; candidates[n++].dy = CURRENT(i-1,j)->dy; } /* Median predictor vector (median of left, top, and top right adjacent vectors) */ if ( i > c->left_mb && j > c->top_mb && i < c->right_mb )//&& LEFT->valid && TOP->valid && TOP_RIGHT->valid ) { candidates[n ].dx = median_predictor( CURRENT(i-1,j)->dx, CURRENT(i,j-1)->dx, CURRENT(i+1,j-1)->dx); candidates[n++].dy = median_predictor( CURRENT(i-1,j)->dy, CURRENT(i,j-1)->dy, CURRENT(i+1,j-1)->dy); } // Zero vector candidates[n ].dx = 0; candidates[n++].dy = 0; int x = i * c->mb_w; int y = j * c->mb_h; check_candidates ( to, from, x, y, candidates, n, 0, here, c ); #ifndef FULLSEARCH diamond_search( to, from, x, y, here, c); #else full_search( to, from, x, y, here, c); #endif assert( x + c->mb_w + here->dx > 0 ); // All macroblocks must have area > 0 assert( y + c->mb_h + here->dy > 0 ); assert( x + here->dx < c->width ); assert( y + here->dy < c->height ); } /* End column loop */ } /* End row loop */ #ifdef USE_SSE asm volatile ( "emms" ); #endif #ifdef COUNT_COMPARES fprintf(stderr, "%d comparisons per block were made", compares/count); #endif return; } void collect_post_statistics( struct motion_est_context_s *c ) { c->comparison_average = 0; c->average_length = 0; c->average_x = 0; c->average_y = 0; int i, j, count = 0; for ( i = c->left_mb; i <= c->right_mb; i++ ){ for ( j = c->top_mb; j <= c->bottom_mb; j++ ){ count++; c->comparison_average += CURRENT(i,j)->msad; c->average_x += CURRENT(i,j)->dx; c->average_y += CURRENT(i,j)->dy; } } if ( count > 0 ) { c->comparison_average /= count; c->average_x /= count; c->average_y /= count; c->average_length = sqrt( c->average_x * c->average_x + c->average_y * c->average_y ); } } static void init_optimizations( struct motion_est_context_s *c ) { switch(c->mb_w){ #ifdef USE_SSE case 4: if(c->mb_h == 4) c->compare_optimized = sad_sse_422_luma_4x4; else c->compare_optimized = sad_sse_422_luma_4w; break; case 8: if(c->mb_h == 8) c->compare_optimized = sad_sse_422_luma_8x8; else c->compare_optimized = sad_sse_422_luma_8w; break; case 16: if(c->mb_h == 16) c->compare_optimized = sad_sse_422_luma_16x16; else c->compare_optimized = sad_sse_422_luma_16w; break; case 32: if(c->mb_h == 32) c->compare_optimized = sad_sse_422_luma_32x32; else c->compare_optimized = sad_sse_422_luma_32w; break; case 64: c->compare_optimized = sad_sse_422_luma_64w; break; #endif default: c->compare_optimized = sad_reference; break; } } inline static void set_red(uint8_t *image, struct motion_est_context_s *c) { int n; for( n = 0; n < c->width * c->height * 2; n+=4 ) { image[n] = 79; image[n+1] = 91; image[n+2] = 79; image[n+3] = 237; } } static void show_residual( uint8_t *result, struct motion_est_context_s *c ) { int i, j; int x,y,w,h; int dx, dy; int tx,ty; uint8_t *b, *r; // set_red(result,c); for( j = c->top_mb; j <= c->bottom_mb; j++ ){ for( i = c->left_mb; i <= c->right_mb; i++ ){ dx = CURRENT(i,j)->dx; dy = CURRENT(i,j)->dy; w = c->mb_w; h = c->mb_h; x = i * w; y = j * h; // Denoise function caused some blocks to be completely clipped, ignore them if (constrain( &x, &y, &w, &h, dx, dy, 0, c->width, 0, c->height) == 0 ) continue; for( ty = y; ty < y + h ; ty++ ){ for( tx = x; tx < x + w ; tx++ ){ b = c->former_image + (tx+dx)*c->xstride + (ty+dy)*c->ystride; r = result + tx*c->xstride + ty*c->ystride; r[0] = 16 + ABS( r[0] - b[0] ); if( dx % 2 == 0 ) r[1] = 128 + ABS( r[1] - b[1] ); else // FIXME: may exceed boundies r[1] = 128 + ABS( r[1] - ( *(b-1) + b[3] ) /2 ); } } } } } static void show_reconstruction( uint8_t *result, struct motion_est_context_s *c ) { int i, j; int x,y,w,h; int dx,dy; uint8_t *r, *s; int tx,ty; for( i = c->left_mb; i <= c->right_mb; i++ ){ for( j = c->top_mb; j <= c->bottom_mb; j++ ){ dx = CURRENT(i,j)->dx; dy = CURRENT(i,j)->dy; w = c->mb_w; h = c->mb_h; x = i * w; y = j * h; // Denoise function caused some blocks to be completely clipped, ignore them if (constrain( &x, &y, &w, &h, dx, dy, 0, c->width, 0, c->height) == 0 ) continue; for( ty = y; ty < y + h ; ty++ ){ for( tx = x; tx < x + w ; tx++ ){ r = result + tx*c->xstride + ty*c->ystride; s = c->former_image + (tx+dx)*c->xstride + (ty+dy)*c->ystride; r[0] = s[0]; if( dx % 2 == 0 ) r[1] = s[1]; else // FIXME: may exceed boundies r[1] = ( *(s-1) + s[3] ) /2; } } } } } // Image stack(able) method static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter mlt_filter filter = mlt_frame_pop_service( frame ); mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); // Get the motion_est context object struct motion_est_context_s *c = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), "context", NULL); // Get the new image and frame number *format = mlt_image_yuv422; int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); #ifdef BENCHMARK struct timeval start; gettimeofday(&start, NULL ); #endif if( error != 0 ) mlt_properties_debug( MLT_FRAME_PROPERTIES(frame), "error after mlt_frame_get_image() in motion_est", stderr ); c->current_frame_position = mlt_frame_get_position( frame ); /* Context Initialization */ if ( c->initialized == 0 ) { // Get the filter properties object mlt_properties properties = mlt_filter_properties( filter ); c->width = *width; c->height = *height; /* Get parameters that may have been overridden */ if( mlt_properties_get( properties, "macroblock_width") != NULL ) c->mb_w = mlt_properties_get_int( properties, "macroblock_width"); if( mlt_properties_get( properties, "macroblock_height") != NULL ) c->mb_h = mlt_properties_get_int( properties, "macroblock_height"); if( mlt_properties_get( properties, "prediction_thresh") != NULL ) c->initial_thresh = mlt_properties_get_int( properties, "prediction_thresh" ); else c->initial_thresh = c->mb_w * c->mb_h; if( mlt_properties_get( properties, "search_method") != NULL ) c->search_method = mlt_properties_get_int( properties, "search_method"); if( mlt_properties_get( properties, "skip_prediction") != NULL ) c->skip_prediction = mlt_properties_get_int( properties, "skip_prediction"); if( mlt_properties_get( properties, "limit_x") != NULL ) c->limit_x = mlt_properties_get_int( properties, "limit_x"); if( mlt_properties_get( properties, "limit_y") != NULL ) c->limit_y = mlt_properties_get_int( properties, "limit_y"); if( mlt_properties_get( properties, "check_chroma" ) != NULL ) c->check_chroma = mlt_properties_get_int( properties, "check_chroma" ); if( mlt_properties_get( properties, "denoise" ) != NULL ) c->denoise = mlt_properties_get_int( properties, "denoise" ); if( mlt_properties_get( properties, "show_reconstruction" ) != NULL ) c->show_reconstruction = mlt_properties_get_int( properties, "show_reconstruction" ); if( mlt_properties_get( properties, "show_residual" ) != NULL ) c->show_residual = mlt_properties_get_int( properties, "show_residual" ); if( mlt_properties_get( properties, "toggle_when_paused" ) != NULL ) c->toggle_when_paused = mlt_properties_get_int( properties, "toggle_when_paused" ); init_optimizations( c ); // Calculate the dimensions in macroblock units c->mv_buffer_width = (*width / c->mb_w); c->mv_buffer_height = (*height / c->mb_h); // Size of the motion vector buffer c->mv_size = c->mv_buffer_width * c->mv_buffer_height * sizeof(struct motion_vector_s); // Allocate the motion vector buffers c->former_vectors = mlt_pool_alloc( c->mv_size ); c->current_vectors = mlt_pool_alloc( c->mv_size ); c->denoise_vectors = mlt_pool_alloc( c->mv_size ); // Register motion buffers for destruction mlt_properties_set_data( properties, "current_motion_vectors", (void *)c->current_vectors, 0, mlt_pool_release, NULL ); mlt_properties_set_data( properties, "former_motion_vectors", (void *)c->former_vectors, 0, mlt_pool_release, NULL ); mlt_properties_set_data( properties, "denoise_motion_vectors", (void *)c->denoise_vectors, 0, mlt_pool_release, NULL ); c->former_vectors_valid = 0; memset( c->former_vectors, 0, c->mv_size ); c->xstride = 2; c->ystride = c->xstride * *width; // Allocate a cache for the previous frame's image c->former_image = mlt_pool_alloc( *width * *height * 2 ); c->cache_image = mlt_pool_alloc( *width * *height * 2 ); // Register for destruction mlt_properties_set_data( properties, "cache_image", (void *)c->cache_image, 0, mlt_pool_release, NULL ); mlt_properties_set_data( properties, "former_image", (void *)c->former_image, 0, mlt_pool_release, NULL ); c->former_frame_position = c->current_frame_position; c->previous_msad = 0; c->initialized = 1; } /* Check to see if somebody else has given us bounds */ struct mlt_geometry_item_s *bounds = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "bounds", NULL ); if ( !bounds ) { char *property = mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "bounding" ); if ( property ) { mlt_geometry geometry = mlt_geometry_init( ); mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE(filter) ); if ( geometry ) { mlt_geometry_parse( geometry, property, 0, profile->width, profile->height ); bounds = calloc( 1, sizeof(*bounds) ); mlt_properties_set_data( MLT_FILTER_PROPERTIES(filter), "bounds", bounds, sizeof(*bounds), free, NULL ); mlt_geometry_fetch( geometry, bounds, 0 ); } } } if( bounds != NULL ) { // translate pixel units (from bounds) to macroblock units // make sure whole macroblock stays within bounds c->left_mb = ( bounds->x + c->mb_w - 1 ) / c->mb_w; c->top_mb = ( bounds->y + c->mb_h - 1 ) / c->mb_h; c->right_mb = ( bounds->x + bounds->w ) / c->mb_w - 1; c->bottom_mb = ( bounds->y + bounds->h ) / c->mb_h - 1; c->bounds.x = bounds->x; c->bounds.y = bounds->y; c->bounds.w = bounds->w; c->bounds.h = bounds->h; } else { c->left_mb = c->prev_left_mb = 0; c->top_mb = c->prev_top_mb = 0; c->right_mb = c->prev_right_mb = c->mv_buffer_width - 1; // Zero indexed c->bottom_mb = c->prev_bottom_mb = c->mv_buffer_height - 1; c->bounds.x = 0; c->bounds.y = 0; c->bounds.w = *width; c->bounds.h = *height; } // If video is advancing, run motion vector algorithm and etc... if( c->former_frame_position + 1 == c->current_frame_position ) { // Swap the motion vector buffers and reuse allocated memory struct motion_vector_s *temp = c->current_vectors; c->current_vectors = c->former_vectors; c->former_vectors = temp; // This is done because filter_vismv doesn't pay attention to frame boundry memset( c->current_vectors, 0, c->mv_size ); // Perform the motion search motion_search( c->cache_image, *image, c ); collect_post_statistics( c ); // Detect shot changes if( c->comparison_average > 10 * c->mb_w * c->mb_h && c->comparison_average > c->previous_msad * 2 ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_log_verbose( MLT_FILTER_SERVICE(filter), "shot change: %d\n", c->comparison_average); mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "shot_change", 1); c->shot_change = 1; // Add the shot change to the list mlt_geometry key_frames = mlt_properties_get_data( properties, "shot_change_list", NULL ); if ( !key_frames ) { key_frames = mlt_geometry_init(); mlt_properties_set_data( properties, "shot_change_list", key_frames, 0, (mlt_destructor) mlt_geometry_close, (mlt_serialiser) mlt_geometry_serialise ); if ( key_frames ) mlt_geometry_set_length( key_frames, mlt_filter_get_length2( filter, frame ) ); } if ( key_frames ) { struct mlt_geometry_item_s item; item.frame = (int) c->current_frame_position; item.x = c->comparison_average; item.f[0] = 1; item.f[1] = item.f[2] = item.f[3] = item.f[4] = 0; mlt_geometry_insert( key_frames, &item ); } } else { c->former_vectors_valid = 1; c->shot_change = 0; //fprintf(stderr, " - SAD: %d\n", c->comparison_average); } c->previous_msad = c->comparison_average; if( c->comparison_average != 0 ) { // If the frame is not a duplicate of the previous frame // denoise the vector buffer if( c->denoise ) median_denoise( c->current_vectors, c ); // Pass the new vector data into the frame mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "motion_est.vectors", (void*)c->current_vectors, c->mv_size, NULL, NULL ); // Cache the frame's image. Save the old cache. Reuse memory. // After this block, exactly two unique frames will be cached uint8_t *timg = c->cache_image; c->cache_image = c->former_image; c->former_image = timg; memcpy( c->cache_image, *image, *width * *height * c->xstride ); } else { // Undo the Swap, This fixes the ugliness caused by a duplicate frame temp = c->current_vectors; c->current_vectors = c->former_vectors; c->former_vectors = temp; mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "motion_est.vectors", (void*)c->former_vectors, c->mv_size, NULL, NULL ); } if( c->shot_change == 1) ; else if( c->show_reconstruction ) show_reconstruction( *image, c ); else if( c->show_residual ) show_residual( *image, c ); } // paused else if( c->former_frame_position == c->current_frame_position ) { // Pass the old vector data into the frame if it's valid if( c->former_vectors_valid == 1 ) { mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "motion_est.vectors", (void*)c->current_vectors, c->mv_size, NULL, NULL ); if( c->shot_change == 1) ; else if( c->toggle_when_paused == 1 ) { if( c->show_reconstruction ) show_reconstruction( *image, c ); else if( c->show_residual ) show_residual( *image, c ); c->toggle_when_paused = 2; } else if( c->toggle_when_paused == 2 ) c->toggle_when_paused = 1; else { if( c->show_reconstruction ) show_reconstruction( *image, c ); else if( c->show_residual ) show_residual( *image, c ); } } mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "shot_change", c->shot_change); } // there was jump in frame number else { // fprintf(stderr, "Warning: there was a frame number jumped from %d to %d.\n", c->former_frame_position, c->current_frame_position); c->former_vectors_valid = 0; } // Cache our bounding geometry for the next frame's processing c->prev_left_mb = c->left_mb; c->prev_top_mb = c->top_mb; c->prev_right_mb = c->right_mb; c->prev_bottom_mb = c->bottom_mb; // Remember which frame this is c->former_frame_position = c->current_frame_position; mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.macroblock_width", c->mb_w ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.macroblock_height", c->mb_h ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.left_mb", c->left_mb ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.right_mb", c->right_mb ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.top_mb", c->top_mb ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.bottom_mb", c->bottom_mb ); #ifdef BENCHMARK struct timeval finish; gettimeofday(&finish, NULL ); int difference = (finish.tv_sec - start.tv_sec) * 1000000 + (finish.tv_usec - start.tv_usec); fprintf(stderr, " in frame %d:%d usec\n", c->current_frame_position, difference); #endif mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); return error; } /** filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Keeps tabs on the filter object mlt_frame_push_service( frame, this); // Push the frame filter mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_motion_est_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { // Get the properties object mlt_properties properties = MLT_FILTER_PROPERTIES( this ); // Initialize the motion estimation context struct motion_est_context_s *context; context = mlt_pool_alloc( sizeof(struct motion_est_context_s) ); mlt_properties_set_data( properties, "context", (void *)context, sizeof( struct motion_est_context_s ), mlt_pool_release, NULL ); // Register the filter this->process = filter_process; /* defaults that may be overridden */ context->mb_w = 16; context->mb_h = 16; context->skip_prediction = 0; context->limit_x = 64; context->limit_y = 64; context->search_method = DIAMOND_SEARCH; // FIXME: not used context->check_chroma = 0; context->denoise = 1; context->show_reconstruction = 0; context->show_residual = 0; context->toggle_when_paused = 0; /* reference functions that may have optimized versions */ context->compare_reference = sad_reference; // The rest of the buffers will be initialized when the filter is first processed context->initialized = 0; } return this; } mlt-0.9.0/src/modules/motion_est/filter_motion_est.h000066400000000000000000000026141215300731300226270ustar00rootroot00000000000000/* * Perform motion estimation * Zachary K Drew, Copyright 2004 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _FILTER_MOTION_EST_H_ #define _FILTER_MOTION_EST_H_ #include extern mlt_filter filter_motion_est_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); #define MAX_MSAD 0xffff struct motion_vector_s { int msad; // #include #include #include #include #define ABS(a) ((a) >= 0 ? (a) : (-(a))) static void paint_arrows( uint8_t *image, struct motion_vector_s *vectors, int w, int h, int mb_w, int mb_h ) { int i, j, x, y; struct motion_vector_s *p; for( i = 0; i < w/mb_w; i++ ){ for( j = 0; j < h/mb_h; j++ ){ x = i*mb_w; y = j*mb_h; p = vectors + (w/mb_w)*j + i; if ( p->valid == 1 ) { //draw_rectangle_outline(image, x-1, y-1, mb_w+1, mb_h+1,100); //x += mb_w/4; //y += mb_h/4; //draw_rectangle_outline(image, x + p->dx, y + p->dy, mb_w, mb_h,100); x += mb_w/2; y += mb_h/2; draw_arrow(image, x, y, x + p->dx, y + p->dy, 100); //draw_rectangle_fill(image, x + p->dx, y + p->dy, mb_w, mb_h, 100); } else if ( p->valid == 2 ) { draw_rectangle_outline(image, x+1, y+1, mb_w-2, mb_h-2,100); } else if ( p->valid == 3 ) { draw_rectangle_fill(image, x-p->dx, y-p->dy, mb_w, mb_h,0); } else if ( p->valid == 4 ) { draw_line(image, x, y, x + 4, y, 100); draw_line(image, x, y, x, y + 4, 100); draw_line(image, x + 4, y, x, y + 4, 100); draw_line(image, x+mb_w-1, y+mb_h-1, x+mb_w-5, y+mb_h-1, 100); draw_line(image, x+mb_w-1, y+mb_h-1, x+mb_w-1, y+mb_h-5, 100); draw_line(image, x+mb_w-5, y+mb_h-1, x+mb_w-1, y+mb_h-5, 100); } } } } // Image stack(able) method static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the frame properties mlt_properties properties = MLT_FRAME_PROPERTIES(frame); // Get the new image *format = mlt_image_yuv422; int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); if( error != 0 ) mlt_properties_debug( MLT_FRAME_PROPERTIES(frame), "error after mlt_frame_get_image()", stderr ); // Get the size of macroblocks in pixel units int macroblock_height = mlt_properties_get_int( properties, "motion_est.macroblock_height" ); int macroblock_width = mlt_properties_get_int( properties, "motion_est.macroblock_width" ); // Get the motion vectors struct motion_vector_s *current_vectors = mlt_properties_get_data( properties, "motion_est.vectors", NULL ); init_arrows( format, *width, *height ); if ( mlt_properties_get_int( properties, "shot_change" ) == 1 ) { draw_line(*image, 0, 0, *width, *height, 100); draw_line(*image, 0, *height, *width, 0, 100); } if( current_vectors != NULL ) { paint_arrows( *image, current_vectors, *width, *height, macroblock_width, macroblock_height); } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Push the frame filter mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_vismv_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; } return this; } /** This source code will self destruct in 5...4...3... */ mlt-0.9.0/src/modules/motion_est/filter_vismv.yml000066400000000000000000000002701215300731300221610ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: vismv title: Visualize Motion Vectors version: 1 copyright: Zachary Drew creator: Zachary Drew license: GPLv2 language: en tags: - Video mlt-0.9.0/src/modules/motion_est/gpl000066400000000000000000000000001215300731300174210ustar00rootroot00000000000000mlt-0.9.0/src/modules/motion_est/producer_slowmotion.c000066400000000000000000000321561215300731300232160ustar00rootroot00000000000000/* * producer_slowmotion.c -- create subspeed frames * Author: Zachary Drew * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "filter_motion_est.h" #include #include #include #include #include #include #include #define SHIFT 8 #define ABS(a) ((a) >= 0 ? (a) : (-(a))) // This is used to constrains pixel operations between two blocks to be within the image boundry inline static int constrain( int *x, int *y, int *w, int *h, const int dx, const int dy, const int left, const int right, const int top, const int bottom) { uint32_t penalty = 1 << SHIFT; // Retain a few extra bits of precision int x2 = *x + dx; int y2 = *y + dy; int w_remains = *w; int h_remains = *h; // Origin of macroblock moves left of image boundy if( *x < left || x2 < left ) { w_remains = *w - left + ((*x < x2) ? *x : x2); *x += *w - w_remains; } // Portion of macroblock moves right of image boundry else if( *x + *w > right || x2 + *w > right ) w_remains = right - ((*x > x2) ? *x : x2); // Origin of macroblock moves above image boundy if( *y < top || y2 < top ) { h_remains = *h - top + ((*y < y2) ? *y : y2); *y += *h - h_remains; } // Portion of macroblock moves bellow image boundry else if( *y + *h > bottom || y2 + *h > bottom ) h_remains = bottom - ((*y > y2) ? *y : y2); if( w_remains == *w && h_remains == *h ) return penalty; if( w_remains <= 0 || h_remains <= 0) return 0; // Block is clipped out of existance penalty = (*w * *h * penalty) / ( w_remains * h_remains); // Recipricol of the fraction of the block that remains *w = w_remains; // Update the width and height *h = h_remains; return penalty; } static void motion_interpolate( uint8_t *first_image, uint8_t *second_image, uint8_t *output, int top_mb, int bottom_mb, int left_mb, int right_mb, int mb_w, int mb_h, int width, int height, int xstride, int ystride, double scale, motion_vector *vectors ) { assert ( scale >= 0.0 && scale <= 1.0 ); int i, j; int x,y,w,h; int dx, dy; int scaled_dx, scaled_dy; int tx,ty; uint8_t *f,*s,*r; motion_vector *here; int mv_width = width / mb_w; for( j = top_mb; j <= bottom_mb; j++ ){ for( i = left_mb; i <= right_mb; i++ ){ here = vectors + j*mv_width + i; scaled_dx = (1.0 - scale) * (double)here->dx; scaled_dy = (1.0 - scale) * (double)here->dy; dx = here->dx; dy = here->dy; w = mb_w; h = mb_h; x = i * w; y = j * h; // Denoise function caused some blocks to be completely clipped, ignore them if (constrain( &x, &y, &w, &h, dx, dy, 0, width, 0, height) == 0 ) continue; for( ty = y; ty < y + h ; ty++ ){ for( tx = x; tx < x + w ; tx++ ){ f = first_image + (tx + dx )*xstride + (ty + dy )*ystride; s = second_image + (tx )*xstride + (ty )*ystride; r = output + (tx+scaled_dx)*xstride + (ty+scaled_dy)*ystride; /* if( ABS(f[0] - s[0]) > 3 * here->msad / (mb_w * mb_h * 2) ) { r[0] = f[0]; r[1] = f[1]; } else { */ r[0] = ( 1.0 - scale ) * (double)f[0] + scale * (double)s[0]; if( dx % 2 == 0 ) { if( scaled_dx % 2 == 0 ) r[1] = ( 1.0 - scale ) * (double)f[1] + scale * (double) s[1]; else *(r-1) = ( 1.0 - scale ) * (double)f[1] + scale * (double) s[1]; } else { if( scaled_dx %2 == 0 ) // FIXME: may exceed boundies r[1] = ( 1.0 - scale ) * ( (double)(*(f-1) + (double)f[3]) / 2.0 ) + scale * (double) s[1]; else // FIXME: may exceed boundies *(r-1) = ( 1.0 - scale ) * ( (double)(*(f-1) + (double)f[3]) / 2.0 ) + scale * (double) s[1]; } // } } } } } } // Image stack(able) method static int slowmotion_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter object and properties mlt_producer producer = mlt_frame_pop_service( this ); mlt_frame second_frame = mlt_frame_pop_service( this ); mlt_frame first_frame = mlt_frame_pop_service( this ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); // Frame properties objects mlt_properties frame_properties = MLT_FRAME_PROPERTIES( this ); mlt_properties first_frame_properties = MLT_FRAME_PROPERTIES( first_frame ); mlt_properties second_frame_properties = MLT_FRAME_PROPERTIES( second_frame ); // image stride *format = mlt_image_yuv422; int size = *width * *height * 2; int xstride = 2; int ystride = 2 * *width; uint8_t *output = mlt_properties_get_data( producer_properties, "output_buffer", 0 ); if( output == NULL ) { output = mlt_pool_alloc( size ); // Let someone else clean up mlt_properties_set_data( producer_properties, "output_buffer", output, size, mlt_pool_release, NULL ); } uint8_t *first_image = mlt_properties_get_data( first_frame_properties, "image", NULL ); uint8_t *second_image = mlt_properties_get_data( second_frame_properties, "image", NULL ); // which frames are buffered? int error = 0; if( first_image == NULL ) { error = mlt_frame_get_image( first_frame, &first_image, format, width, height, writable ); if( error != 0 ) { fprintf(stderr, "first_image == NULL get image died\n"); return error; } } if( second_image == NULL ) { error = mlt_frame_get_image( second_frame, &second_image, format, width, height, writable ); if( error != 0 ) { fprintf(stderr, "second_image == NULL get image died\n"); return error; } } // These need to passed onto the frame for other mlt_properties_pass_list( frame_properties, second_frame_properties, "motion_est.left_mb, motion_est.right_mb, \ motion_est.top_mb, motion_est.bottom_mb, \ motion_est.macroblock_width, motion_est.macroblock_height" ); // Pass the pointer to the vectors without serializing mlt_properties_set_data( frame_properties, "motion_est.vectors", mlt_properties_get_data( second_frame_properties, "motion_est.vectors", NULL ), 0, NULL, NULL ); // Start with a base image memcpy( output, first_image, size ); if( mlt_properties_get_int( producer_properties, "method" ) == 1 ) { mlt_position first_position = mlt_frame_get_position( first_frame ); double actual_position = mlt_producer_get_speed( producer ) * (double)mlt_frame_get_position( this ); double scale = actual_position - first_position; motion_interpolate ( first_image, second_image, output, mlt_properties_get_int( second_frame_properties, "motion_est.top_mb" ), mlt_properties_get_int( second_frame_properties, "motion_est.bottom_mb" ), mlt_properties_get_int( second_frame_properties, "motion_est.left_mb" ), mlt_properties_get_int( second_frame_properties, "motion_est.right_mb" ), mlt_properties_get_int( second_frame_properties, "motion_est.macroblock_width" ), mlt_properties_get_int( second_frame_properties, "motion_est.macroblock_height" ), *width, *height, xstride, ystride, scale, mlt_properties_get_data( second_frame_properties, "motion_est.vectors", NULL ) ); if( mlt_properties_get_int( producer_properties, "debug" ) == 1 ) { mlt_filter watermark = mlt_properties_get_data( producer_properties, "watermark", NULL ); if( watermark == NULL ) { mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); watermark = mlt_factory_filter( profile, "watermark", NULL ); mlt_properties_set_data( producer_properties, "watermark", watermark, 0, (mlt_destructor)mlt_filter_close, NULL ); mlt_producer_attach( producer, watermark ); } mlt_properties wm_properties = MLT_FILTER_PROPERTIES( watermark ); char disp[30]; sprintf(disp, "+%10.2f.txt", actual_position); mlt_properties_set( wm_properties, "resource", disp ); } } *image = output; mlt_frame_set_image( this, output, size, NULL ); // Make sure that no further scaling is done mlt_properties_set( frame_properties, "rescale.interps", "none" ); mlt_properties_set( frame_properties, "scale", "off" ); mlt_frame_close( first_frame ); mlt_frame_close( second_frame ); return 0; } static int slowmotion_get_frame( mlt_producer this, mlt_frame_ptr frame, int index ) { if ( !frame ) return 1; // Construct a new frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( this ) ); mlt_properties properties = MLT_PRODUCER_PROPERTIES(this); if( frame != NULL ) { mlt_frame first_frame = mlt_properties_get_data( properties, "first_frame", NULL ); mlt_frame second_frame = mlt_properties_get_data( properties, "second_frame", NULL ); mlt_position first_position = (first_frame != NULL) ? mlt_frame_get_position( first_frame ) : -1; mlt_position second_position = (second_frame != NULL) ? mlt_frame_get_position( second_frame ) : -1; // Get the real producer mlt_producer real_producer = mlt_properties_get_data( properties, "producer", NULL ); // Our "in" needs to be the same, keep it so mlt_properties_pass_list( MLT_PRODUCER_PROPERTIES( real_producer ), properties, "in" ); // Calculate our positions double actual_position = mlt_producer_get_speed( this ) * (double)mlt_producer_position( this ); mlt_position need_first = floor( actual_position ); mlt_position need_second = need_first + 1; if( need_first != first_position ) { mlt_frame_close( first_frame ); first_position = -1; first_frame = NULL; } if( need_second != second_position) { mlt_frame_close( second_frame ); second_position = -1; second_frame = NULL; } if( first_frame == NULL ) { // Seek the producer to the correct place mlt_producer_seek( real_producer, need_first ); // Get the frame mlt_service_get_frame( MLT_PRODUCER_SERVICE( real_producer ), &first_frame, index ); } if( second_frame == NULL ) { // Seek the producer to the correct place mlt_producer_seek( real_producer, need_second ); // Get the frame mlt_service_get_frame( MLT_PRODUCER_SERVICE( real_producer ), &second_frame, index ); } // Make sure things are in their place mlt_properties_set_data( properties, "first_frame", first_frame, 0, NULL, NULL ); mlt_properties_set_data( properties, "second_frame", second_frame, 0, NULL, NULL ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_image", 0 ); // Stack the producer and producer's get image mlt_frame_push_service( *frame, first_frame ); mlt_properties_inc_ref( MLT_FRAME_PROPERTIES( first_frame ) ); mlt_frame_push_service( *frame, second_frame ); mlt_properties_inc_ref( MLT_FRAME_PROPERTIES( second_frame ) ); mlt_frame_push_service( *frame, this ); mlt_frame_push_service( *frame, slowmotion_get_image ); // Give the returned frame temporal identity mlt_frame_set_position( *frame, mlt_producer_position( this ) ); } return 0; } mlt_producer producer_slowmotion_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_producer this = mlt_producer_new( profile ); // Wrap the loader mlt_producer real_producer = mlt_factory_producer( profile, NULL, arg ); // We need to apply the motion estimation filter manually mlt_filter filter = mlt_factory_filter( profile, "motion_est", NULL ); if ( this != NULL && real_producer != NULL && filter != NULL) { // attach the motion_est filter to the real producer mlt_producer_attach( real_producer, filter ); // Get the properties of this producer mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); // The loader normalised it for us already mlt_properties_set_int( properties, "loader_normalised", 1); // Store the producer and fitler mlt_properties_set_data( properties, "producer", real_producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); mlt_properties_set_data( properties, "motion_est", filter, 0, ( mlt_destructor )mlt_filter_close, NULL ); mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "macroblock_width", 16 ); mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "macroblock_height", 16 ); mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "denoise", 0 ); // Grap some stuff from the real_producer mlt_properties_pass_list( properties, MLT_PRODUCER_PROPERTIES( real_producer ), "in, out, length, resource" ); // Since we control the seeking, prevent it from seeking on its own mlt_producer_set_speed( real_producer, 0 ); //mlt_properties_set( properties, "method", "onefield" ); // Override the get_frame method this->get_frame = slowmotion_get_frame; } else { if ( this ) mlt_producer_close( this ); if ( real_producer ) mlt_producer_close( real_producer ); if ( filter ) mlt_filter_close( filter ); this = NULL; } return this; } mlt-0.9.0/src/modules/motion_est/producer_slowmotion.yml000066400000000000000000000002621215300731300235660ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: slowmotion title: Slow Motion version: 1 copyright: Zachary Drew creator: Zachary Drew license: GPLv2 language: en tags: - Video mlt-0.9.0/src/modules/motion_est/sad_sse.h000066400000000000000000000226601215300731300205260ustar00rootroot00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define SAD_SSE_INIT \ asm volatile ( "pxor %%mm6,%%mm6\n\t" :: );\ // Sum two 8x1 pixel blocks #define SAD_SSE_SUM_8(OFFSET) \ "movq " #OFFSET "(%0),%%mm0 \n\t"\ "movq " #OFFSET "(%1),%%mm1 \n\t"\ "psadbw %%mm1,%%mm0 \n\t"\ "paddw %%mm0,%%mm6 \n\t"\ #define SAD_SSE_FINISH(RESULT) \ asm volatile( "movd %%mm6,%0" : "=r" (RESULT) : ); // Advance by ystride #define SAD_SSE_NEXTROW \ "add %2,%0 \n\t"\ "add %2,%1 \n\t"\ // BROKEN! inline static int sad_sse_4x4( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_INIT #define ROW SAD_SSE_SUM_8(0) SAD_SSE_NEXTROW asm volatile ( ROW ROW ROW ROW :: "r" (block1), "r" (block2), "r" ((long int)(ystride))); SAD_SSE_FINISH(result) return result; #undef ROW } inline static int sad_sse_8x8( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_INIT #define ROW SAD_SSE_SUM_8(0) SAD_SSE_NEXTROW asm volatile ( ROW ROW ROW ROW ROW ROW ROW ROW :: "r" (block1), "r" (block2), "r" ((long int)(ystride))); SAD_SSE_FINISH(result) return result; #undef ROW } inline static int sad_sse_16x16( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_INIT #define ROW SAD_SSE_SUM_8(0) SAD_SSE_SUM_8(8) SAD_SSE_NEXTROW asm volatile ( ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW :: "r" (block1), "r" (block2), "r" ((long int)(ystride))); SAD_SSE_FINISH(result) return result; #undef ROW } inline static int sad_sse_32x32( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_INIT #define ROW SAD_SSE_SUM_8(0) SAD_SSE_SUM_8(8) SAD_SSE_SUM_8(16) SAD_SSE_SUM_8(24)\ SAD_SSE_NEXTROW asm volatile ( ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW :: "r" (block1), "r" (block2), "r" ((long int)(ystride))); SAD_SSE_FINISH(result) return result; #undef ROW } // BROKEN! inline static int sad_sse_4w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_INIT while( h != 0 ) { asm volatile ( SAD_SSE_SUM_8(0) :: "r" (block1), "r" (block2) ); h--; block1 += ystride; block2 += ystride; } SAD_SSE_FINISH(result) return result; } inline static int sad_sse_8w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_INIT while( h != 0 ) { asm volatile ( SAD_SSE_SUM_8(0) :: "r" (block1), "r" (block2) ); h--; block1 += ystride; block2 += ystride; } SAD_SSE_FINISH(result) return result; } inline static int sad_sse_16w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_INIT while( h != 0 ) { asm volatile ( SAD_SSE_SUM_8(0) SAD_SSE_SUM_8(8) :: "r" (block1), "r" (block2) ); h--; block1 += ystride; block2 += ystride; } SAD_SSE_FINISH(result) return result; } inline static int sad_sse_32w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_INIT while( h != 0 ) { asm volatile ( SAD_SSE_SUM_8(0) SAD_SSE_SUM_8(8) SAD_SSE_SUM_8(16) SAD_SSE_SUM_8(24) :: "r" (block1), "r" (block2) ); h--; block1 += ystride; block2 += ystride; } SAD_SSE_FINISH(result) return result; } inline static int sad_sse_64w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_INIT while( h != 0 ) { asm volatile ( SAD_SSE_SUM_8(0) SAD_SSE_SUM_8(8) SAD_SSE_SUM_8(16) SAD_SSE_SUM_8(24) SAD_SSE_SUM_8(32) SAD_SSE_SUM_8(40) SAD_SSE_SUM_8(48) SAD_SSE_SUM_8(56) :: "r" (block1), "r" (block2) ); h--; block1 += ystride; block2 += ystride; } SAD_SSE_FINISH(result) return result; } static __attribute__((used)) __attribute__((aligned(8))) uint64_t sad_sse_422_mask_chroma = 0x00ff00ff00ff00ffULL; #define SAD_SSE_422_LUMA_INIT \ asm volatile ( "movq %0,%%mm7\n\t"\ "pxor %%mm6,%%mm6\n\t" :: "m" (sad_sse_422_mask_chroma) );\ // Sum two 4x1 pixel blocks #define SAD_SSE_422_LUMA_SUM_4(OFFSET) \ "movq " #OFFSET "(%0),%%mm0 \n\t"\ "movq " #OFFSET "(%1),%%mm1 \n\t"\ "pand %%mm7,%%mm0 \n\t"\ "pand %%mm7,%%mm1 \n\t"\ "psadbw %%mm1,%%mm0 \n\t"\ "paddw %%mm0,%%mm6 \n\t"\ static int sad_sse_422_luma_4x4( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_422_LUMA_INIT #define ROW SAD_SSE_422_LUMA_SUM_4(0) SAD_SSE_NEXTROW asm volatile ( ROW ROW ROW ROW :: "r" (block1), "r" (block2), "r" ((long int)(ystride))); SAD_SSE_FINISH(result) return result; #undef ROW } static int sad_sse_422_luma_8x8( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_422_LUMA_INIT #define ROW SAD_SSE_422_LUMA_SUM_4(0) SAD_SSE_422_LUMA_SUM_4(8) SAD_SSE_NEXTROW asm volatile ( ROW ROW ROW ROW ROW ROW ROW ROW :: "r" (block1), "r" (block2), "r" ((long int)(ystride))); SAD_SSE_FINISH(result) return result; #undef ROW } static int sad_sse_422_luma_16x16( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_422_LUMA_INIT #define ROW SAD_SSE_422_LUMA_SUM_4(0) SAD_SSE_422_LUMA_SUM_4(8) SAD_SSE_422_LUMA_SUM_4(16) SAD_SSE_422_LUMA_SUM_4(24) SAD_SSE_NEXTROW asm volatile ( ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW :: "r" (block1), "r" (block2), "r" ((long int)(ystride))); SAD_SSE_FINISH(result) return result; #undef ROW } static int sad_sse_422_luma_32x32( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_422_LUMA_INIT #define ROW SAD_SSE_422_LUMA_SUM_4(0) SAD_SSE_422_LUMA_SUM_4(8) SAD_SSE_422_LUMA_SUM_4(16) SAD_SSE_422_LUMA_SUM_4(24)\ SAD_SSE_422_LUMA_SUM_4(32) SAD_SSE_422_LUMA_SUM_4(40) SAD_SSE_422_LUMA_SUM_4(48) SAD_SSE_422_LUMA_SUM_4(56)\ SAD_SSE_NEXTROW asm volatile ( ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW ROW :: "r" (block1), "r" (block2), "r" ((long int)(ystride))); SAD_SSE_FINISH(result) return result; #undef ROW } static int sad_sse_422_luma_4w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_422_LUMA_INIT while( h != 0 ) { asm volatile ( SAD_SSE_422_LUMA_SUM_4(0) :: "r" (block1), "r" (block2) ); h--; block1 += ystride; block2 += ystride; } SAD_SSE_FINISH(result) return result; } static int sad_sse_422_luma_8w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_422_LUMA_INIT while( h != 0 ) { asm volatile ( SAD_SSE_422_LUMA_SUM_4(0) SAD_SSE_422_LUMA_SUM_4(8) :: "r" (block1), "r" (block2) ); h--; block1 += ystride; block2 += ystride; } SAD_SSE_FINISH(result) return result; } static int sad_sse_422_luma_16w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_422_LUMA_INIT while( h != 0 ) { asm volatile ( SAD_SSE_422_LUMA_SUM_4(0) SAD_SSE_422_LUMA_SUM_4(8) SAD_SSE_422_LUMA_SUM_4(16) SAD_SSE_422_LUMA_SUM_4(24) :: "r" (block1), "r" (block2) ); h--; block1 += ystride; block2 += ystride; } SAD_SSE_FINISH(result) return result; } static int sad_sse_422_luma_32w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_422_LUMA_INIT while( h != 0 ) { asm volatile ( SAD_SSE_422_LUMA_SUM_4(0) SAD_SSE_422_LUMA_SUM_4(8) SAD_SSE_422_LUMA_SUM_4(16) SAD_SSE_422_LUMA_SUM_4(24) SAD_SSE_422_LUMA_SUM_4(32) SAD_SSE_422_LUMA_SUM_4(40) SAD_SSE_422_LUMA_SUM_4(48) SAD_SSE_422_LUMA_SUM_4(56) :: "r" (block1), "r" (block2) ); h--; block1 += ystride; block2 += ystride; } SAD_SSE_FINISH(result) return result; } static int sad_sse_422_luma_64w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) { int result; SAD_SSE_422_LUMA_INIT while( h != 0 ) { asm volatile ( SAD_SSE_422_LUMA_SUM_4(0) SAD_SSE_422_LUMA_SUM_4(8) SAD_SSE_422_LUMA_SUM_4(16) SAD_SSE_422_LUMA_SUM_4(24) SAD_SSE_422_LUMA_SUM_4(32) SAD_SSE_422_LUMA_SUM_4(40) SAD_SSE_422_LUMA_SUM_4(48) SAD_SSE_422_LUMA_SUM_4(56) SAD_SSE_422_LUMA_SUM_4(64) SAD_SSE_422_LUMA_SUM_4(72) SAD_SSE_422_LUMA_SUM_4(80) SAD_SSE_422_LUMA_SUM_4(88) SAD_SSE_422_LUMA_SUM_4(96) SAD_SSE_422_LUMA_SUM_4(104) SAD_SSE_422_LUMA_SUM_4(112) SAD_SSE_422_LUMA_SUM_4(120) :: "r" (block1), "r" (block2) ); h--; block1 += ystride; block2 += ystride; } SAD_SSE_FINISH(result) return result; } mlt-0.9.0/src/modules/normalize/000077500000000000000000000000001215300731300165465ustar00rootroot00000000000000mlt-0.9.0/src/modules/normalize/Makefile000066400000000000000000000012001215300731300201770ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lm include ../../../config.mak TARGET = ../libmltnormalize$(LIBSUF) OBJS = factory.o \ filter_audiolevel.o \ filter_volume.o SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/normalize" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/normalize" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/normalize/factory.c000066400000000000000000000033121215300731300203600ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include extern mlt_filter filter_audiolevel_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_volume_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/normalize/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( filter_type, "audiolevel", filter_audiolevel_init ); MLT_REGISTER( filter_type, "volume", filter_volume_init ); MLT_REGISTER_METADATA( filter_type, "audiolevel", metadata, "filter_audiolevel.yml" ); MLT_REGISTER_METADATA( filter_type, "volume", metadata, "filter_volume.yml" ); } mlt-0.9.0/src/modules/normalize/filter_audiolevel.c000066400000000000000000000101171215300731300224100ustar00rootroot00000000000000/* * filter_audiolevel.c -- get the audio level of each channel * Copyright (C) 2002 Steve Harris * Copyright (C) 2010 Marco Gittler * Copyright (C) 2012 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #define AMPTODBFS(n) (log10(n) * 20.0) //---------------------------------------------------------------------------- // IEC standard dB scaling -- as borrowed from meterbridge (c) Steve Harris static inline double IEC_Scale(double dB) { double fScale = 1.0f; if (dB < -70.0f) fScale = 0.0f; else if (dB < -60.0f) // 0.0 .. 2.5 fScale = (dB + 70.0f) * 0.0025f; else if (dB < -50.0f) // 2.5 .. 7.5 fScale = (dB + 60.0f) * 0.005f + 0.025f; else if (dB < -40.0) // 7.5 .. 15.0 fScale = (dB + 50.0f) * 0.0075f + 0.075f; else if (dB < -30.0f) // 15.0 .. 30.0 fScale = (dB + 40.0f) * 0.015f + 0.15f; else if (dB < -20.0f) // 30.0 .. 50.0 fScale = (dB + 30.0f) * 0.02f + 0.3f; else if (dB < -0.001f || dB > 0.001f) // 50.0 .. 100.0 fScale = (dB + 20.0f) * 0.025f + 0.5f; return fScale; } static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { mlt_filter filter = mlt_frame_pop_audio( frame ); int iec_scale = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "iec_scale" ); *format = mlt_audio_s16; int error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); if ( error || !buffer ) return error; int num_channels = *channels; int num_samples = *samples > 200 ? 200 : *samples; int num_oversample = 0; int c, s; char key[ 50 ]; int16_t *pcm = (int16_t*) *buffer; for ( c = 0; c < *channels; c++ ) { long val = 0; double level = 0.0; for ( s = 0; s < num_samples; s++ ) { int sample = abs( pcm[c + s * num_channels] / 128 ); val += sample; if ( sample == 128 ) num_oversample++; else num_oversample = 0; // 10 samples @max => show max signal if ( num_oversample > 10 ) { level = 1.0; break; } // if 3 samples over max => 1 peak over 0 db (0 dB = 40.0) if ( num_oversample > 3 ) level = 41.0/42.0; } // max amplitude = 40/42, 3to10 oversamples=41, more then 10 oversamples=42 if ( level == 0.0 ) level = val / num_samples * 40.0/42.0 / 127.0; if ( iec_scale ) level = IEC_Scale( AMPTODBFS( level ) ); sprintf( key, "meta.media.audio_level.%d", c ); mlt_properties_set_double( MLT_FRAME_PROPERTIES( frame ), key, level ); sprintf( key, "_audio_level.%d", c ); mlt_properties_set_double( MLT_FILTER_PROPERTIES( filter ), key, level ); mlt_log_debug( MLT_FILTER_SERVICE( filter ), "channel %d level %f\n", c, level ); } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { mlt_frame_push_audio( frame, filter ); mlt_frame_push_audio( frame, filter_get_audio ); return frame; } /** Constructor for the filter. */ mlt_filter filter_audiolevel_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = mlt_filter_new(); if ( filter ) { filter->process = filter_process; mlt_properties_set_int( MLT_FILTER_PROPERTIES(filter), "iec_scale", 1 ); } return filter; } mlt-0.9.0/src/modules/normalize/filter_audiolevel.yml000066400000000000000000000017671215300731300230020ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: audiolevel title: Audio Levels version: 1 copyright: Dan Dennedy, Marco Gittler, and Steve Harris creator: Dan Dennedy contributor: - Marco Gittler - Steve Harris license: GPLv2 language: en description: Compute the audio amplitude. notes: > This filter provides the amplitude level as a percentage value in floating point. This does not do any "slowing" of the data by averaging out peaks and troughs of short duration like a VU meter. Applications can also get this data on the frame as meta.media.audio_level. where is the channel number starting with 0. tags: - Audio parameters: - identifier: iec_scale title: Use IEC 60268-18 Scale type: integer minimum: 0 maximum: 1 default: 1 widget: checkbox - identifier: _audio_level. description: > is the channel number starting with 0. This is updated on every frame with audio. readonly: yes type: float minimum: 0 maximum: 1 mlt-0.9.0/src/modules/normalize/filter_volume.c000066400000000000000000000315041215300731300215710ustar00rootroot00000000000000/* * filter_volume.c -- adjust audio volume * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #define MAX_CHANNELS 6 #define EPSILON 0.00001 /* The following normalise functions come from the normalize utility: Copyright (C) 1999--2002 Chris Vaill */ #define samp_width 16 #ifndef ROUND # define ROUND(x) floor((x) + 0.5) #endif #define DBFSTOAMP(x) pow(10,(x)/20.0) /** Return nonzero if the two strings are equal, ignoring case, up to the first n characters. */ int strncaseeq(const char *s1, const char *s2, size_t n) { for ( ; n > 0; n--) { if (tolower(*s1++) != tolower(*s2++)) return 0; } return 1; } /** Limiter function. / tanh((x + lev) / (1-lev)) * (1-lev) - lev (for x < -lev) | x' = | x (for |x| <= lev) | \ tanh((x - lev) / (1-lev)) * (1-lev) + lev (for x > lev) With limiter level = 0, this is equivalent to a tanh() function; with limiter level = 1, this is equivalent to clipping. */ static inline double limiter( double x, double lmtr_lvl ) { double xp = x; if (x < -lmtr_lvl) xp = tanh((x + lmtr_lvl) / (1-lmtr_lvl)) * (1-lmtr_lvl) - lmtr_lvl; else if (x > lmtr_lvl) xp = tanh((x - lmtr_lvl) / (1-lmtr_lvl)) * (1-lmtr_lvl) + lmtr_lvl; // if ( x != xp ) // fprintf( stderr, "filter_volume: sample %f limited %f\n", x, xp ); return xp; } /** Takes a full smoothing window, and returns the value of the center element, smoothed. Currently, just does a mean filter, but we could do a median or gaussian filter here instead. */ static inline double get_smoothed_data( double *buf, int count ) { int i, j; double smoothed = 0; for ( i = 0, j = 0; i < count; i++ ) { if ( buf[ i ] != -1.0 ) { smoothed += buf[ i ]; j++; } } if (j) smoothed /= j; // fprintf( stderr, "smoothed over %d values, result %f\n", j, smoothed ); return smoothed; } /** Get the max power level (using RMS) and peak level of the audio segment. */ double signal_max_power( int16_t *buffer, int channels, int samples, int16_t *peak ) { // Determine numeric limits int bytes_per_samp = (samp_width - 1) / 8 + 1; int16_t max = (1 << (bytes_per_samp * 8 - 1)) - 1; int16_t min = -max - 1; double *sums = (double *) calloc( channels, sizeof(double) ); int c, i; int16_t sample; double pow, maxpow = 0; /* initialize peaks to effectively -inf and +inf */ int16_t max_sample = min; int16_t min_sample = max; for ( i = 0; i < samples; i++ ) { for ( c = 0; c < channels; c++ ) { sample = *buffer++; sums[ c ] += (double) sample * (double) sample; /* track peak */ if ( sample > max_sample ) max_sample = sample; else if ( sample < min_sample ) min_sample = sample; } } for ( c = 0; c < channels; c++ ) { pow = sums[ c ] / (double) samples; if ( pow > maxpow ) maxpow = pow; } free( sums ); /* scale the pow value to be in the range 0.0 -- 1.0 */ maxpow /= ( (double) min * (double) min); if ( -min_sample > max_sample ) *peak = min_sample / (double) min; else *peak = max_sample / (double) max; return sqrt( maxpow ); } /* ------ End normalize functions --------------------------------------- */ /** Get the audio. */ static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the filter from the frame mlt_filter this = mlt_frame_pop_audio( frame ); // Get the properties from the filter mlt_properties filter_props = MLT_FILTER_PROPERTIES( this ); // Get the frame's filter instance properties mlt_properties instance_props = mlt_frame_unique_properties( frame, MLT_FILTER_SERVICE( this ) ); // Get the parameters double gain = mlt_properties_get_double( instance_props, "gain" ); double max_gain = mlt_properties_get_double( instance_props, "max_gain" ); double limiter_level = 0.5; /* -6 dBFS */ int normalise = mlt_properties_get_int( instance_props, "normalise" ); double amplitude = mlt_properties_get_double( instance_props, "amplitude" ); int i, j; double sample; int16_t peak; if ( mlt_properties_get( instance_props, "limiter" ) != NULL ) limiter_level = mlt_properties_get_double( instance_props, "limiter" ); // Get the producer's audio *format = mlt_audio_s16; mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); // fprintf( stderr, "filter_volume: frequency %d\n", *frequency ); // Determine numeric limits int bytes_per_samp = (samp_width - 1) / 8 + 1; int samplemax = (1 << (bytes_per_samp * 8 - 1)) - 1; int samplemin = -samplemax - 1; mlt_service_lock( MLT_FILTER_SERVICE( this ) ); if ( normalise ) { int window = mlt_properties_get_int( filter_props, "window" ); double *smooth_buffer = mlt_properties_get_data( filter_props, "smooth_buffer", NULL ); if ( window > 0 && smooth_buffer != NULL ) { int smooth_index = mlt_properties_get_int( filter_props, "_smooth_index" ); // Compute the signal power and put into smoothing buffer smooth_buffer[ smooth_index ] = signal_max_power( *buffer, *channels, *samples, &peak ); // fprintf( stderr, "filter_volume: raw power %f ", smooth_buffer[ smooth_index ] ); if ( smooth_buffer[ smooth_index ] > EPSILON ) { mlt_properties_set_int( filter_props, "_smooth_index", ( smooth_index + 1 ) % window ); // Smooth the data and compute the gain // fprintf( stderr, "smoothed %f over %d frames\n", get_smoothed_data( smooth_buffer, window ), window ); gain *= amplitude / get_smoothed_data( smooth_buffer, window ); } } else { gain *= amplitude / signal_max_power( (int16_t*) *buffer, *channels, *samples, &peak ); } } // if ( gain > 1.0 && normalise ) // fprintf(stderr, "filter_volume: limiter level %f gain %f\n", limiter_level, gain ); if ( max_gain > 0 && gain > max_gain ) gain = max_gain; // Initialise filter's previous gain value to prevent an inadvertant jump from 0 mlt_position last_position = mlt_properties_get_position( filter_props, "_last_position" ); mlt_position current_position = mlt_frame_get_position( frame ); if ( mlt_properties_get( filter_props, "_previous_gain" ) == NULL || current_position != last_position + 1 ) mlt_properties_set_double( filter_props, "_previous_gain", gain ); // Start the gain out at the previous double previous_gain = mlt_properties_get_double( filter_props, "_previous_gain" ); // Determine ramp increment double gain_step = ( gain - previous_gain ) / *samples; // fprintf( stderr, "filter_volume: previous gain %f current gain %f step %f\n", previous_gain, gain, gain_step ); // Save the current gain for the next iteration mlt_properties_set_double( filter_props, "_previous_gain", gain ); mlt_properties_set_position( filter_props, "_last_position", current_position ); mlt_service_unlock( MLT_FILTER_SERVICE( this ) ); // Ramp from the previous gain to the current gain = previous_gain; int16_t *p = (int16_t*) *buffer; // Apply the gain for ( i = 0; i < *samples; i++ ) { for ( j = 0; j < *channels; j++ ) { sample = *p * gain; *p = ROUND( sample ); if ( gain > 1.0 ) { /* use limiter function instead of clipping */ if ( normalise ) *p = ROUND( samplemax * limiter( sample / (double) samplemax, limiter_level ) ); /* perform clipping */ else if ( sample > samplemax ) *p = samplemax; else if ( sample < samplemin ) *p = samplemin; } p++; } gain += gain_step; } return 0; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { mlt_properties filter_props = MLT_FILTER_PROPERTIES( this ); mlt_properties instance_props = mlt_frame_unique_properties( frame, MLT_FILTER_SERVICE( this ) ); double gain = 1.0; // no adjustment // Parse the gain property if ( mlt_properties_get( filter_props, "gain" ) != NULL ) { char *p = mlt_properties_get( filter_props, "gain" ); if ( strncaseeq( p, "normalise", 9 ) ) mlt_properties_set( filter_props, "normalise", "" ); else { if ( strcmp( p, "" ) != 0 ) gain = strtod( p, &p ); while ( isspace( *p ) ) p++; /* check if "dB" is given after number */ if ( strncaseeq( p, "db", 2 ) ) gain = DBFSTOAMP( gain ); else gain = fabs( gain ); // If there is an end adjust gain to the range if ( mlt_properties_get( filter_props, "end" ) != NULL ) { double end = -1; char *p = mlt_properties_get( filter_props, "end" ); if ( strcmp( p, "" ) != 0 ) end = strtod( p, &p ); while ( isspace( *p ) ) p++; /* check if "dB" is given after number */ if ( strncaseeq( p, "db", 2 ) ) end = DBFSTOAMP( gain ); else end = fabs( end ); if ( end != -1 ) gain += ( end - gain ) * mlt_filter_get_progress( this, frame ); } } } mlt_properties_set_double( instance_props, "gain", gain ); // Parse the maximum gain property if ( mlt_properties_get( filter_props, "max_gain" ) != NULL ) { char *p = mlt_properties_get( filter_props, "max_gain" ); double gain = strtod( p, &p ); // 0 = no max while ( isspace( *p ) ) p++; /* check if "dB" is given after number */ if ( strncaseeq( p, "db", 2 ) ) gain = DBFSTOAMP( gain ); else gain = fabs( gain ); mlt_properties_set_double( instance_props, "max_gain", gain ); } // Parse the limiter property if ( mlt_properties_get( filter_props, "limiter" ) != NULL ) { char *p = mlt_properties_get( filter_props, "limiter" ); double level = 0.5; /* -6dBFS */ if ( strcmp( p, "" ) != 0 ) level = strtod( p, &p); while ( isspace( *p ) ) p++; /* check if "dB" is given after number */ if ( strncaseeq( p, "db", 2 ) ) { if ( level > 0 ) level = -level; level = DBFSTOAMP( level ); } else { if ( level < 0 ) level = -level; } mlt_properties_set_double( instance_props, "limiter", level ); } // Parse the normalise property if ( mlt_properties_get( filter_props, "normalise" ) != NULL ) { char *p = mlt_properties_get( filter_props, "normalise" ); double amplitude = 0.2511886431509580; /* -12dBFS */ if ( strcmp( p, "" ) != 0 ) amplitude = strtod( p, &p); while ( isspace( *p ) ) p++; /* check if "dB" is given after number */ if ( strncaseeq( p, "db", 2 ) ) { if ( amplitude > 0 ) amplitude = -amplitude; amplitude = DBFSTOAMP( amplitude ); } else { if ( amplitude < 0 ) amplitude = -amplitude; if ( amplitude > 1.0 ) amplitude = 1.0; } // If there is an end adjust gain to the range if ( mlt_properties_get( filter_props, "end" ) != NULL ) { amplitude *= mlt_filter_get_progress( this, frame ); } mlt_properties_set_int( instance_props, "normalise", 1 ); mlt_properties_set_double( instance_props, "amplitude", amplitude ); } // Parse the window property and allocate smoothing buffer if needed int window = mlt_properties_get_int( filter_props, "window" ); if ( mlt_properties_get( filter_props, "smooth_buffer" ) == NULL && window > 1 ) { // Create a smoothing buffer for the calculated "max power" of frame of audio used in normalisation double *smooth_buffer = (double*) calloc( window, sizeof( double ) ); int i; for ( i = 0; i < window; i++ ) smooth_buffer[ i ] = -1.0; mlt_properties_set_data( filter_props, "smooth_buffer", smooth_buffer, 0, free, NULL ); } // Push the filter onto the stack mlt_frame_push_audio( frame, this ); // Override the get_audio method mlt_frame_push_audio( frame, filter_get_audio ); return frame; } /** Constructor for the filter. */ mlt_filter filter_volume_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = calloc( 1, sizeof( struct mlt_filter_s ) ); if ( this != NULL && mlt_filter_init( this, NULL ) == 0 ) { mlt_properties properties = MLT_FILTER_PROPERTIES( this ); this->process = filter_process; if ( arg != NULL ) mlt_properties_set( properties, "gain", arg ); mlt_properties_set_int( properties, "window", 75 ); mlt_properties_set( properties, "max_gain", "20dB" ); } return this; } mlt-0.9.0/src/modules/normalize/filter_volume.yml000066400000000000000000000041621215300731300221500ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: volume title: Volume version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Denneedy license: GPLv2 language: en tags: - Audio description: > Adjust an audio stream's volume level. This filter is based on the 'normalize' utility parameters: - identifier: argument title: Gain type: string description: > The gain may be indicated as a floating point value of the gain adjustment. The gain may also be indicated as a numeric value with the suffix "dB" to adjust in terms of decibels. The gain may also be set to "normalise" to normalise the volume to the target amplitude -12dBFS. - identifier: window title: Window type: integer description: > The number of video frames over which to smooth normalisation. default: 75 mutable: yes - identifier: normalise title: Normalise type: string description: > Normalise the volume to the specified amplitude. The normalization may be indicated as a floating point value of the relative volume. The normalisation may also be indicated as a numeric value with the suffix "dB" to set the amplitude in decibels. default: -12dBFS mutable: yes - identifier: limiter title: Limiter type: string description: > Limit all samples above the specified amplitude. The limiting may be indicated as a floating point value of the relative volume. The limiting may also be indicated as a numeric value with the suffix "dB" to set the limiting amplitude in decibels. default: -6dBFS mutable: yes - identifier: max_gain title: Max gain type: string description: > A floating point or decibel value of the maximum gain that can be applied during normalisation. default: 20dB mutable: yes - identifier: end title: End gain type: string description: > A gain value just like the Gain property. This causes the gain to be interpolated from 'gain' to 'end' over the duration. mutable: yes mlt-0.9.0/src/modules/normalize/gpl000066400000000000000000000000001215300731300172410ustar00rootroot00000000000000mlt-0.9.0/src/modules/oldfilm/000077500000000000000000000000001215300731300161745ustar00rootroot00000000000000mlt-0.9.0/src/modules/oldfilm/Makefile000066400000000000000000000014031215300731300176320ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lm include ../../../config.mak TARGET = ../libmltoldfilm$(LIBSUF) OBJS = factory.o \ filter_oldfilm.o \ filter_dust.o \ filter_lines.o \ filter_grain.o \ filter_tcolor.o \ filter_vignette.o SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d $(DESTDIR)$(mltdatadir)/oldfilm install -m 644 *.svg "$(DESTDIR)$(mltdatadir)/oldfilm" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/oldfilm" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/oldfilm/dust1.svg000066400000000000000000000124011215300731300177530ustar00rootroot00000000000000 image/svg+xml mlt-0.9.0/src/modules/oldfilm/dust2.svg000066400000000000000000000525621215300731300177700ustar00rootroot00000000000000 image/svg+xml mlt-0.9.0/src/modules/oldfilm/dust3.svg000066400000000000000000000047151215300731300177660ustar00rootroot00000000000000 image/svg+xml mlt-0.9.0/src/modules/oldfilm/dust4.svg000066400000000000000000000074141215300731300177660ustar00rootroot00000000000000 image/svg+xml mlt-0.9.0/src/modules/oldfilm/dust5.svg000066400000000000000000000046171215300731300177710ustar00rootroot00000000000000 image/svg+xml mlt-0.9.0/src/modules/oldfilm/factory.c000066400000000000000000000051451215300731300200140ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (c) 2007 Marco Gittler * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include extern mlt_filter filter_dust_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_grain_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_lines_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_oldfilm_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_tcolor_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_vignette_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties oldfilm_metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/oldfilm/filter_%s.yml", mlt_environment( "MLT_DATA" ), id ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( filter_type, "oldfilm", filter_oldfilm_init ); MLT_REGISTER( filter_type, "dust", filter_dust_init ); MLT_REGISTER( filter_type, "lines", filter_lines_init ); MLT_REGISTER( filter_type, "grain", filter_grain_init ); MLT_REGISTER( filter_type, "tcolor", filter_tcolor_init ); MLT_REGISTER( filter_type, "vignette", filter_vignette_init ); MLT_REGISTER_METADATA( filter_type, "vignette", oldfilm_metadata, NULL ); MLT_REGISTER_METADATA( filter_type, "tcolor", oldfilm_metadata, NULL ); MLT_REGISTER_METADATA( filter_type, "grain", oldfilm_metadata, NULL ); MLT_REGISTER_METADATA( filter_type, "lines", oldfilm_metadata, NULL ); MLT_REGISTER_METADATA( filter_type, "dust", oldfilm_metadata, NULL ); MLT_REGISTER_METADATA( filter_type, "oldfilm", oldfilm_metadata, NULL ); } mlt-0.9.0/src/modules/oldfilm/fdust.svg000066400000000000000000000107071215300731300200470ustar00rootroot00000000000000 image/svg+xml mlt-0.9.0/src/modules/oldfilm/filter_dust.c000066400000000000000000000164011215300731300206660ustar00rootroot00000000000000/* * filter_dust.c -- dust filter * Copyright (c) 2007 Marco Gittler * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ //#include //#include #include #include #include #include #include #include static void overlay_image(uint8_t *src, int src_width, int src_height , uint8_t * overlay, int overlay_width, int overlay_height, uint8_t * alpha , int xpos, int ypos, int upsidedown , int mirror ){ int x,y; for (y=ypos;y=0 && (y-ypos)0 ){ int overlay_x = mirror ? overlay_width - ( x - xpos ) -1 : ( x - xpos ); double alp=(double)*(alpha+ overlay_width * overlay_y + overlay_x )/255.0; uint8_t* image_pixel = scanline_image + x * 2; uint8_t* overlay_pixel = scanline_overlay + overlay_x * 2; *image_pixel=(double)(*overlay_pixel)*alp+ (double)*image_pixel*(1.0-alp) ; if (xpos%2==0) image_pixel++; else image_pixel+=3; mirror? overlay_pixel-- : overlay_pixel++; *image_pixel=(double)(*(overlay_pixel))*alp + (double)(*image_pixel )*(1.0-alp) ; } } } } } static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = mlt_frame_pop_service( this ); int maxdia = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "maxdiameter" ); int maxcount = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "maxcount" ); *format = mlt_image_yuv422; int error = mlt_frame_get_image( this, image, format, width, height, 1 ); // load svg mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); char *factory = mlt_properties_get( properties, "factory" ); char temp[1204]=""; sprintf( temp, "%s/oldfilm/", mlt_environment( "MLT_DATA" ) ); mlt_properties direntries=mlt_properties_new(); mlt_properties_dir_list(direntries,temp,"dust*.svg",1); if (!maxcount) return 0; double position = mlt_filter_get_progress( filter, this ); srand(position*10000); mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); int im=rand()%maxcount; int piccount=mlt_properties_count(direntries); while (im-- && piccount){ int picnum=rand()%piccount; int y1=rand()%*height; int x1=rand()%*width; char resource[1024]=""; char savename[1024]="",savename1[1024]="", cachedy[100]; int dx=(*width*maxdia/100); int luma_width,luma_height; uint8_t *luma_image = NULL; uint8_t *alpha =NULL; int updown= rand()%2; int mirror=rand()%2; sprintf(resource,"%s",mlt_properties_get_value(direntries,picnum)); sprintf(savename,"cache-%d-%d",picnum,dx); sprintf(savename1,"cache-alpha-%d-%d",picnum,dx); sprintf(cachedy,"cache-dy-%d-%d",picnum,dx); luma_image= mlt_properties_get_data( properties , savename , NULL ); alpha= mlt_properties_get_data( properties , savename1 , NULL ); if (luma_image == NULL || alpha == NULL ){ mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); mlt_producer producer = mlt_factory_producer( profile, factory, resource ); if ( producer != NULL ) { mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_properties_set( producer_properties, "eof", "loop" ); mlt_frame luma_frame = NULL; if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &luma_frame, 0 ) == 0 ){ mlt_image_format luma_format = mlt_image_yuv422; luma_width = dx; luma_height = luma_width * mlt_properties_get_int( MLT_FRAME_PROPERTIES ( luma_frame ) , "height" ) / mlt_properties_get_int( MLT_FRAME_PROPERTIES ( luma_frame ) , "width" ); mlt_properties_set( MLT_FRAME_PROPERTIES( luma_frame ), "rescale.interp", "best" );// none/nearest/tiles/hyper mlt_frame_get_image( luma_frame, &luma_image, &luma_format, &luma_width, &luma_height, 0 ); alpha =mlt_frame_get_alpha_mask(luma_frame); uint8_t* savealpha=mlt_pool_alloc ( luma_width * luma_height ); uint8_t* savepic=mlt_pool_alloc ( luma_width * luma_height * 2); if (savealpha && savepic ){ memcpy (savealpha, alpha , luma_width * luma_height ); memcpy (savepic, luma_image , luma_width * luma_height * 2); mlt_properties_set_data ( properties , savename , savepic , sizeof(savepic) , mlt_pool_release, NULL ); mlt_properties_set_data ( properties , savename1 , savealpha , sizeof(savealpha) , mlt_pool_release, NULL ); mlt_properties_set_int ( properties , cachedy , luma_height ); overlay_image(*image,*width,*height,luma_image,luma_width,luma_height, alpha, x1, y1 , updown , mirror ); } mlt_frame_close( luma_frame ); } mlt_producer_close( producer ); } }else { overlay_image ( *image , *width, *height , luma_image , dx , mlt_properties_get_int ( properties , cachedy ) , alpha , x1 , y1 , updown , mirror ); } } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); if (piccount>0 ) return 0; if ( error == 0 && *image ) { int h = *height; int w = *width; int im=rand()%maxcount; while (im-- ){ int type=im%2; int y1=rand()%h; int x1=rand()%w; int dx=rand()%maxdia; int dy=rand()%maxdia; int x=0,y=0;//,v=0; double v=0.0; for ( x = -dx ; x < dx ; x++ ) for ( y = -dy ; y < dy ; y++ ) { if ( x1+x < w && x1+x > 0 && y1+y < h && y1+y > 0 ){ uint8_t *pix=*image+(y+y1)*w*2+(x+x1)*2; //v=(1.0-fabs(x)/dx)*(1.0-fabs(y)/dy); v=pow((double)x/(double)dx*5.0,2.0)+pow((double)y/(double)dy*5.0,2.0); if (v>10) v=10; v=1.0-(v/10.0); switch(type){ case 0: *pix-=(*pix)*v; break; case 1: *pix+=(255-*pix)*v; break; } } } } } return error; } static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { mlt_frame_push_service( frame, this ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } mlt_filter filter_dust_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "maxdiameter", "2" ); mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "maxcount", "10" ); } return this; } mlt-0.9.0/src/modules/oldfilm/filter_dust.yml000066400000000000000000000021701215300731300212430ustar00rootroot00000000000000schema_version: 0.1 type: filter # consumer, filter, producer, or transition identifier: dust title: Dust version: 0.2.5 copyright: Copyright (C) 2008 Marco Gittler license: GPL language: en url: none creator: Marco Gittler tags: - Video # this may produce video description: Add dust and specks to the Video, as in old movies icon: filename: oldfilm/fdust.svg # relative to $MLT_DATA/modules/ content-type: image/svg notes: Implementation or additional usage notes go here. bugs: # this can be just for documentation, or the tool may disclose it to help user avoid pitfalls - need to do some speed improvement. parameters: - identifier: maxdiameter title: Maximal Diameter type: integer description: Maximal diameter of a dust piece readonly: no required: yes minimum: 0 maximum: 100 default: 2 mutable: no widget: spinner unit: "%" - identifier: maxcount title: Maximal number of dust type: integer description: How many dust pieces are on the image readonly: no required: yes minimum: 0 maximum: 400 default: 10 mutable: no widget: spinner mlt-0.9.0/src/modules/oldfilm/filter_grain.c000066400000000000000000000054301215300731300210070ustar00rootroot00000000000000/* * filter_grain.c -- grain filter * Copyright (c) 2007 Marco Gittler * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #define MIN(a,b) (ab?a:b) static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = mlt_frame_pop_service( this ); *format = mlt_image_yuv422; int error = mlt_frame_get_image( this, image, format, width, height, 1 ); if ( error == 0 && *image ) { int h = *height; int w = *width; double position = mlt_filter_get_progress( filter, this ); srand(position*10000); int noise = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "noise" ); double contrast = mlt_properties_get_double( MLT_FILTER_PROPERTIES( filter ), "contrast" )/100.0; double brightness = 127.0 * (mlt_properties_get_double( MLT_FILTER_PROPERTIES( filter ), "brightness" )-100.0)/100.0; int x=0,y=0,pix=0; for (x=0;x20){ pix= MIN ( MAX ( ( (double)*pixel -127.0 ) * contrast + 127.0 + brightness , 0 ) , 255 ) ; if (noise>0) pix-=(rand()%noise-noise); *pixel= MIN ( MAX ( pix , 0 ) , 255 ); } //*(pixel+1)= MIN ( MAX ( ( (double)*(pixel+1) -127.0 ) * .5 + 127.0 , 0 ) , 255 ) ; } } return error; } static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { mlt_frame_push_service( frame, this ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } mlt_filter filter_grain_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "noise", "40" ); mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "contrast", "160" ); mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "brightness", "70" ); } return this; } mlt-0.9.0/src/modules/oldfilm/filter_grain.yml000066400000000000000000000024301215300731300213630ustar00rootroot00000000000000schema_version: 0.1 type: filter # consumer, filter, producer, or transition identifier: grain title: Grain version: 0.2.5 copyright: Copyright (C) 2008 Marco Gittler license: GPL language: en url: none creator: Marco Gittler tags: - Video # this may produce video description: Grain over the Image icon: filename: oldfilm/grain.svg # relative to $MLT_DATA/modules/ content-type: image/svg notes: Implementation or additional usage notes go here. bugs: # this can be just for documentation, or the tool may disclose it to help user avoid pitfalls - need to do some speed improvement. parameters: - identifier: noise title: Noise type: integer description: Maximal value of noise readonly: no required: yes minimum: 0 maximum: 200 default: 40 mutable: no widget: spinner unit: "%" - identifier: contrast title: Contrast type: integer description: Adjust contrast for the image readonly: no required: yes minimum: 0 maximum: 400 default: 160 mutable: no widget: spinner - identifier: brightness title: Brightness type: integer description: Adjust brightness for the image readonly: no required: yes minimum: 0 maximum: 400 default: 70 mutable: no widget: spinner mlt-0.9.0/src/modules/oldfilm/filter_lines.c000066400000000000000000000104211215300731300210150ustar00rootroot00000000000000/* * filter_lines.c -- lines filter * Copyright (c) 2007 Marco Gittler * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = mlt_frame_pop_service( this ); *format = mlt_image_yuv422; int error = mlt_frame_get_image( this, image, format, width, height, 1 ); if ( error == 0 && *image ) { int h = *height; int w = *width; int line_width = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "line_width" ); int num = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "num" ); double maxdarker= (double)mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "darker" ) ; double maxlighter=(double)mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "lighter" ) ; //int frame = mlt_properties_get_int( this, "_position" ); char buf[256]; char typebuf[256]; if ( line_width < 1 ) return 0; double position = mlt_filter_get_progress( filter, this ); srand(position*10000); mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); while (num--){ int type=(rand()%3)+1; int x1=(double)w*rand()/RAND_MAX; int dx=rand()%line_width; int x=0,y=0; int ystart=rand()%h; int yend=rand()%h; sprintf(buf,"line%d",num); sprintf(typebuf,"typeline%d",num); maxlighter+=rand()%30-15; maxdarker+=rand()%30-15; if (mlt_properties_get_int(MLT_FILTER_PROPERTIES( filter ),buf)==0){ mlt_properties_set_int(MLT_FILTER_PROPERTIES( filter ),buf,x1); } if (mlt_properties_get_int(MLT_FILTER_PROPERTIES( filter ),typebuf)==0 ){ mlt_properties_set_int(MLT_FILTER_PROPERTIES( filter ),typebuf,type); } x1=mlt_properties_get_int(MLT_FILTER_PROPERTIES( filter ),buf); type=mlt_properties_get_int(MLT_FILTER_PROPERTIES( filter ),typebuf); if (position!=mlt_properties_get_double(MLT_FILTER_PROPERTIES( filter ),"last_oldfilm_line_pos")){ x1+=(rand()%11-5); } if (yend0){ uint8_t* pixel=(*image+(y)*w*2+(x+x1)*2); double diff=1.0-fabs(x)/dx; switch(type){ case 1: //blackline *pixel-=((double)*pixel*diff*maxdarker/100.0); break; case 2: //whiteline *pixel+=((255.0-(double)*pixel)*diff*maxlighter/100.0); break; case 3: //greenline *(pixel+1)-=((*(pixel+1))*diff*maxlighter/100.0); break; } } mlt_properties_set_int(MLT_FILTER_PROPERTIES( filter ),buf,x1); } mlt_properties_set_double(MLT_FILTER_PROPERTIES( filter ),"last_oldfilm_line_pos",position); mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); } return error; } static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { mlt_frame_push_service( frame, this ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } mlt_filter filter_lines_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "line_width", 2 ); mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "num", 5 ); mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "darker" , 40 ) ; mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "lighter" , 40 ) ; } return this; } mlt-0.9.0/src/modules/oldfilm/filter_lines.yml000066400000000000000000000031171215300731300214000ustar00rootroot00000000000000schema_version: 0.1 type: filter # consumer, filter, producer, or transition identifier: lines title: Scratchlines version: 0.2.6 copyright: Copyright (C) 2008 Marco Gittler license: GPL language: en url: none creator: Marco Gittler tags: - Video # this may produce video description: Scratchlines over the Picture icon: filename: oldfilm/lines.svg # relative to $MLT_DATA/modules/ content-type: image/svg notes: Implementation or additional usage notes go here. bugs: # this can be just for documentation, or the tool may disclose it to help user avoid pitfalls - need to do some speed improvement. parameters: - identifier: line_width title: Width of line type: integer description: Linewidth in picture readonly: no required: yes minimum: 0 maximum: 100 default: 2 mutable: no widget: spinner unit: pixel - identifier: num title: Max number of lines type: integer description: Maximal number of lines in picture readonly: no required: yes minimum: 0 maximum: 100 default: 5 mutable: no widget: spinner unit: lines - identifier: darker title: Max darker type: integer description: Make image up to n values darker behind line readonly: no required: yes minimum: 0 maximum: 100 default: 40 mutable: no widget: spinner - identifier: lighter title: Max lighter type: integer description: Make image up to n values lighter behind line readonly: no required: yes minimum: 0 maximum: 100 default: 40 mutable: no widget: spinner mlt-0.9.0/src/modules/oldfilm/filter_oldfilm.c000066400000000000000000000166771215300731300213540ustar00rootroot00000000000000/* * filter_oldfilm.c -- oldfilm filter * Copyright (c) 2007 Marco Gittler * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include static double sinarr[]={ // 0.0,0.125270029508395,0.2485664757507,0.3679468485397,0.481530353985902, // 0.587527525713892,0.684268417247276,0.770228911401552,0.84405473219009,0.904582780944473, // 0.95085946050647,0.982155698800724,0.997978435097294,0.99807838800221,0.982453982794196, // 0.951351376233828,0.90526057845426,0.844907733031696,0.771243676860277,0.685428960066342, // 0.588815561967795,0.48292559113694,0.369427305139443,0.250108827749629,0.12684997771773, // 0.00159265291648683,-0.123689763546002,-0.247023493251739,-0.366465458626247,-0.48013389541149, // -0.586237999170027,-0.683106138750633,-0.769212192222595,-0.84319959036574,-0.903902688919827, // -0.950365132881376,-0.981854923525203,-0.997875950775248,-0.998175809236459,-0.982749774749007, // -0.951840878815686,-0.905936079729926,-0.845758590726883,-0.772256486024771,-0.68658776426406, // -0.590102104664575,-0.484319603325524,-0.37090682467023,-0.251650545336281,-0.128429604166398,0.0 0.0,0.0627587292804297,0.125270029508395,0.18728744713136,0.2485664757507,0.308865520098932,0.3679468485397,0.425577530335206,0.481530353985902,0.535584723021826,0.587527525713892,0.637153975276265,0.684268417247276,0.728685100865749,0.770228911401552,0.80873606055313,0.84405473219009,0.876045680894979,0.904582780944473,0.929553523565587,0.95085946050647,0.968416592172968,0.982155698800724,0.99202261335714,0.997978435097294,0.999999682931835,0.99807838800221,0.992222125098244,0.982453982794196,0.968812472421035,0.951351376233828,0.930139535372831,0.90526057845426,0.876812591860795,0.844907733031696,0.809671788277164,0.771243676860277,0.72977490330168,0.685428960066342,0.638380682987321,0.588815561967795,0.536929009678953,0.48292559113694,0.427018217196276,0.369427305139443,0.310379909672042,0.250108827749629,0.188851680765468,0.12684997771773,0.064348163049637,0.00159265291648683,-0.0611691363208864,-0.123689763546002,-0.18572273843423,-0.247023493251739,-0.307350347074556,-0.366465458626247,-0.424135763977612,-0.48013389541149,-0.534239077829989,-0.586237999170027,-0.635925651395529,-0.683106138750633,-0.727593450087328,-0.769212192222595,-0.807798281433749,-0.84319959036574,-0.875276547799941,-0.903902688919827,-0.928965153904073,-0.950365132881376,-0.968018255492714,-0.981854923525203,-0.991820585306115,-0.997875950775248,-0.999997146387718,-0.998175809236459,-0.992419120023356,-0.982749774749007,-0.969205895232745,-0.951840878815686,-0.930723187839362,-0.905936079729926,-0.877577278752084,-0.845758590726883,-0.810605462232336,-0.772256486024771,-0.730862854630786,-0.68658776426406,-0.639605771417098,-0.590102104664575,-0.538271934391528,-0.484319603325524,-0.428457820906457,-0.37090682467023,-0.311893511952568,-0.251650545336281,-0.190415435368805,-0.128429604166398,-0.0659374335968388,0.0, }; static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = mlt_frame_pop_service( this ); *format = mlt_image_yuv422; int error = mlt_frame_get_image( this, image, format, width, height, 1 ); if ( error == 0 && *image ) { int h = *height; int w = *width; int x=0; int y=0; double position = mlt_filter_get_progress( filter, this ); srand(position*10000); int delta = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "delta" ); int every = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "every" ); int bdu = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "brightnessdelta_up" ); int bdd = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "brightnessdelta_down" ); int bevery = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "brightnessdelta_every" ); int udu = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "unevendevelop_up" ); int udd = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "unevendevelop_down" ); int uduration = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "unevendevelop_duration" ); int diffpic=0; if (delta) diffpic=rand()%delta*2-delta; int brightdelta=0; if ((bdu+bdd)!=0) brightdelta=rand()%(bdu+bdd)-bdd; if (rand()%100>every) diffpic=0; if (rand()%100>bevery) brightdelta=0; int yend,ydiff; int unevendevelop_delta=0; if (uduration>0){ float uval= sinarr[ ( ((int)position) % uduration) * 100 / uduration ] ; unevendevelop_delta = uval * ( uval>0 ? udu : udd ); } if (diffpic<=0){ y=h; yend=0; ydiff=-1; }else{ y=0; yend=h; ydiff=1; } while(y!=yend){ //int newy=y+diffpic; for (x=0;x0 && newyw)?w-x:-1; int randy=((newy)<=frameborder)?(newy):((newy)+frameborder>h)?h-(y+diffpic):-1; if (randx>=0 ){ oldval=oldval*pow(((double)randx/(double)frameborder),1.5); } if (randy>=0 ){ oldval=oldval*pow(((double)randy/(double)frameborder),1.5); } if (randx>=0 && randy>=0){ //oldval=oldval*(randx*randy)/500.0; } */ if ( ((int) oldval + brightdelta + unevendevelop_delta ) >255) *pic=255; else if ( ( (int) oldval + brightdelta + unevendevelop_delta ) <0){ *pic=0; }else *pic = oldval + brightdelta + unevendevelop_delta; *(pic+1)=*(pic+diffpic*w*2+1); }else{ *pic=0; //*(pic-1)=127; } } y+=ydiff; } } return error; } static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { mlt_frame_push_service( frame, this ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } mlt_filter filter_oldfilm_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "delta", "14" ); mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "every", "20" ); mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "brightnessdelta_up" , "20" ); mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "brightnessdelta_down" , "30" ); mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "brightnessdelta_every" , "70" ); mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "unevendevelop_up" , "60" ); mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "unevendevelop_down" , "20" ); mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "unevendevelop_duration" , "70" ); } return this; } mlt-0.9.0/src/modules/oldfilm/filter_oldfilm.yml000066400000000000000000000051771215300731300217240ustar00rootroot00000000000000schema_version: 0.1 type: filter # consumer, filter, producer, or transition identifier: oldfilm title: Oldfilm version: 0.2.5 copyright: Copyright (C) 2008 Marco Gittler license: GPL language: en url: none creator: Marco Gittler tags: - Video # this may produce video description: Moves the Picture up and down and random brightness change icon: filename: oldfilm/oldfilm.svg # relative to $MLT_DATA/modules/ content-type: image/svg notes: Implementation or additional usage notes go here. bugs: # this can be just for documentation, or the tool may disclose it to help user avoid pitfalls - need to do some speed improvement. parameters: - identifier: delta title: Y-Delta type: integer description: Maximum delta value of Up/Down move readonly: no required: yes minimum: 0 maximum: 400 default: 14 mutable: no widget: spinner unit: pixel - identifier: every title: "% of picture have a delta" type: integer description: n'th % have a Y-Delta in picture readonly: no required: yes minimum: 0 maximum: 100 default: 20 mutable: no widget: spinner unit: "%" - identifier: brightnessdelta_up title: Brightness up type: integer description: Makes image n values lighter readonly: no required: yes minimum: 0 maximum: 100 default: 20 mutable: no widget: spinner - identifier: brightnessdelta_down title: Brightness down type: integer description: Makes image n values darker readonly: no required: yes minimum: 0 maximum: 100 default: 30 mutable: no widget: spinner - identifier: brightnessdelta_every title: Brightness every type: integer description: Change value only for n/100 readonly: no required: yes minimum: 0 maximum: 100 default: 70 mutable: no widget: spinner unit: "%" - identifier: unevendevelop_up title: Unevendevelop up type: integer description: Makes image n values lighter readonly: no required: yes minimum: 0 maximum: 100 default: 60 mutable: no widget: spinner - identifier: unevendevelop_down title: Unevendevelop down type: integer description: Makes image n values darker readonly: no required: yes minimum: 0 maximum: 100 default: 20 mutable: no widget: spinner - identifier: unevendevelop_duration title: Unevendevelop Duration type: integer description: Time (in frames) of a up/down cycle readonly: no required: yes minimum: 0 maximum: 10000 default: 70 mutable: no widget: spinner unit: "%" mlt-0.9.0/src/modules/oldfilm/filter_tcolor.c000066400000000000000000000051311215300731300212070ustar00rootroot00000000000000/* * filter_tcolor.c -- tcolor filter * Copyright (c) 2007 Marco Gittler * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #define MIN(a,b) (aprocess = filter_process; mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "oversaturate_cr", "190" ); mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "oversaturate_cb", "190" ); } return this; } mlt-0.9.0/src/modules/oldfilm/filter_tcolor.yml000066400000000000000000000023151215300731300215670ustar00rootroot00000000000000schema_version: 0.1 type: filter # consumer, filter, producer, or transition identifier: tcolor title: Technicolor version: 0.2.5 copyright: Copyright (C) 2008 Marco Gittler license: GPL language: en url: none creator: Marco Gittler tags: - Video # this may produce video description: Oversaturate the Color in Video, like in old Technicolor movies icon: filename: oldfilm/tcolor.svg # relative to $MLT_DATA/modules/ content-type: image/svg notes: Implementation or additional usage notes go here. bugs: # this can be just for documentation, or the tool may disclose it to help user avoid pitfalls - need to do some speed improvement. parameters: - identifier: oversaturate_cr # 'argument' is a reserved name for a value supplied to the factory title: Blue/Yellow- axis type: integer description: Adjust factor for Blue/Yellow axis readonly: no required: yes minimum: -400 maximum: 400 default: 190 mutable: no widget: spinner - identifier: oversaturate_cb title: Red/Green-axis type: integer description: Adjust factor for Red/Green axis readonly: no required: yes minimum: -400 maximum: 400 default: 190 mutable: no widget: spinner mlt-0.9.0/src/modules/oldfilm/filter_vignette.c000066400000000000000000000105411215300731300215330ustar00rootroot00000000000000/* * filter_vignette.c -- vignette filter * Copyright (c) 2007 Marco Gittler * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #define MIN(a,b) (adx){ //center, make not darker continue; } else if (radius+smooth<=dx){//max dark after smooth area delta=0.0; }else{ // linear pos from of opacity (from 0 to 1) delta=(double)(radius+smooth-dx)/(2.0*smooth); if (mode==1){ //make cos for smoother non linear fade delta = (double)pow(cos(((1.0-delta)*3.14159/2.0)),3.0); } } delta=MAX(max_opac,delta); *pix=(double)(*pix)*delta; *(pix+1)=((double)(*(pix+1)-127.0)*delta)+127.0; } } } return error; } static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { mlt_frame_push_service( frame, this ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } mlt_filter filter_vignette_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); //int i=0; if ( this != NULL ) { /* for (i=-SIGMOD_STEPS/2;iprocess = filter_process; mlt_properties_set_double( MLT_FILTER_PROPERTIES( this ), "smooth", 0.8 ); mlt_properties_set_double( MLT_FILTER_PROPERTIES( this ), "radius", 0.5 ); mlt_properties_set_double( MLT_FILTER_PROPERTIES( this ), "x", 0.5 ); mlt_properties_set_double( MLT_FILTER_PROPERTIES( this ), "y", 0.5 ); mlt_properties_set_double( MLT_FILTER_PROPERTIES( this ), "opacity", 0.0 ); mlt_properties_set_double( MLT_FILTER_PROPERTIES( this ), "mode", 0 ); //mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "end", "" ); } return this; } mlt-0.9.0/src/modules/oldfilm/filter_vignette.yml000066400000000000000000000033201215300731300221070ustar00rootroot00000000000000schema_version: 0.1 type: filter # consumer, filter, producer, or transition identifier: vignette title: Vignette Effect version: 0.2.5 copyright: Copyright (C) 2008 Marco Gittler license: GPL language: en url: none creator: Marco Gittler tags: - Video # this may produce video description: > Vignette around a point with adjustable smooth, radius, position and transparency icon: filename: oldfilm/vignette.svg # relative to $MLT_DATA/modules/ content-type: image/svg notes: Implementation or additional usage notes go here. bugs: # this can be just for documentation, or the tool may disclose it to help user avoid pitfalls - need to do some speed improvement. parameters: - identifier: smooth title: Feathering type: float readonly: no required: yes mutable: no minimum: 0.0 maximum: 1.0 default: 0.8 - identifier: radius title: Radius type: float readonly: no required: yes mutable: no minimum: 0.0 maximum: 1.0 default: 0.5 - identifier: x title: X Position type: float readonly: no required: yes mutable: no minimum: 0.0 maximum: 1.0 default: 0.5 - identifier: y title: Y Position type: float readonly: no required: yes mutable: no minimum: 0.0 maximum: 1.0 default: 0.5 - identifier: opacity title: Opacity type: float readonly: no required: yes mutable: no minimum: 0.0 maximum: 1.0 default: 0.0 - identifier: mode title: Mode type: integer description: Use linear (0) or cosinus (1) mode to fade from opac to black readonly: no required: yes mutable: no minimum: 0 maximum: 1 default: 0 widget: checkbox mlt-0.9.0/src/modules/oldfilm/grain.svg000066400000000000000000000075521215300731300200260ustar00rootroot00000000000000 image/svg+xml mlt-0.9.0/src/modules/oldfilm/lines.svg000066400000000000000000000044221215300731300200310ustar00rootroot00000000000000 image/svg+xml mlt-0.9.0/src/modules/oldfilm/oldfilm.svg000066400000000000000000000044351215300731300203510ustar00rootroot00000000000000 image/svg+xml mlt-0.9.0/src/modules/oldfilm/tcolor.svg000066400000000000000000000057641215300731300202330ustar00rootroot00000000000000 image/svg+xml mlt-0.9.0/src/modules/oldfilm/vignette.svg000066400000000000000000000063441215300731300205510ustar00rootroot00000000000000 image/svg+xml mlt-0.9.0/src/modules/opengl/000077500000000000000000000000001215300731300160325ustar00rootroot00000000000000mlt-0.9.0/src/modules/opengl/Makefile000066400000000000000000000035601215300731300174760ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lm include ../../../config.mak TARGET = ../libmltopengl$(LIBSUF) OBJS = factory.o CPPOBJS = fbo_input.o CPPOBJS += filter_glsl_manager.o CPPOBJS += filter_movit_blur.o CPPOBJS += filter_movit_convert.o CPPOBJS += filter_movit_crop.o CPPOBJS += filter_deconvolution_sharpen.o CPPOBJS += filter_movit_diffusion.o CPPOBJS += filter_movit_glow.o CPPOBJS += filter_lift_gamma_gain.o CPPOBJS += filter_movit_mirror.o CPPOBJS += filter_movit_opacity.o CPPOBJS += filter_movit_rect.o CPPOBJS += filter_movit_resample.o CPPOBJS += filter_movit_resize.o CPPOBJS += filter_movit_saturation.o CPPOBJS += filter_movit_vignette.o CPPOBJS += filter_white_balance.o CPPOBJS += mlt_movit_input.o CPPOBJS += transition_movit_mix.o CPPOBJS += transition_movit_overlay.o CXXFLAGS += -Wno-deprecated $(CFLAGS) CXXFLAGS += `pkg-config --cflags movit 2> /dev/null` SHADERDIR = `pkg-config --variable=shaderdir movit` CXXFLAGS += -DSHADERDIR=\"$(SHADERDIR)\" LDFLAGS += -L../../mlt++ -lmlt++ ifeq ($(targetos), MinGW) CXXFLAGS += `pkg-config --cflags glew` LDFLAGS += -lmovit `pkg-config --libs-only-L glew` -lglew32 -lopengl32 else LDFLAGS += `pkg-config --libs movit 2> /dev/null` ifeq ($(targetos), Darwin) CXXFLAGS += -FOpenGL LDFLAGS += -framework OpenGL else OBJS += consumer_xgl.o LDFLAGS += -lpthread -lGL -lX11 endif endif SRCS := $(OBJS:.o=.c) $(CPPOBJS:.o=.cpp) all: $(TARGET) $(TARGET): $(OBJS) $(CPPOBJS) $(CXX) $(SHFLAGS) -o $@ $(OBJS) $(CPPOBJS) $(LDFLAGS) depend: $(SRCS) $(CXX) -MM $(CXXFLAGS) $^ 1>.depend distclean: clean rm -f .depend config.h config.mak clean: rm -f $(OBJS) $(TARGET) $(CPPOBJS) install: all install -m 755 $(TARGET) "$(DESTDIR)$(libdir)/mlt" install -d "$(DESTDIR)$(datadir)/mlt/opengl/movit" install -m 644 *.yml "$(DESTDIR)$(datadir)/mlt/opengl" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/opengl/configure000077500000000000000000000003571215300731300177460ustar00rootroot00000000000000#!/bin/sh if [ "$help" != "1" ] then if ! $(pkg-config movit) then echo "- movit not found: disabling" touch ../disable-opengl exit 0 fi echo > config.mak case $targetos in Darwin) ;; MinGW) ;; *) ;; esac exit 0 fi mlt-0.9.0/src/modules/opengl/consumer_xgl.c000066400000000000000000000416011215300731300207050ustar00rootroot00000000000000/* * consumer_xgl.c * Copyright (C) 2012 Christophe Thommeret * Author: Christophe Thommeret * Based on Nehe's GLX port by Mihael.Vrbanec@stud.uni-karlsruhe.de * http://nehe.gamedev.net/ * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define GL_GLEXT_PROTOTYPES #include #include #include #include #include #include #include #include #include #include #include #define STARTWIDTH 1280 #define STARTHEIGHT 720 extern int XInitThreads(); typedef struct consumer_xgl_s *consumer_xgl; struct consumer_xgl_s { struct mlt_consumer_s parent; mlt_properties properties; mlt_deque queue; pthread_t thread; int joined; int running; int playing; int xgl_started; }; typedef struct { pthread_t thread; int running; } thread_video; typedef struct { int width; int height; double aspect_ratio; GLuint texture; pthread_mutex_t mutex; int new; mlt_frame mlt_frame_ref; } frame_new; typedef struct { int width; int height; GLuint fbo; GLuint texture; } fbo; typedef struct { Display *dpy; int screen; Window win; GLXContext ctx; } HiddenContext; typedef struct { Display *dpy; int screen; Window win; GLXContext ctx; XSetWindowAttributes attr; int x, y; unsigned int width, height; unsigned int depth; } GLWindow; static GLWindow GLWin; static HiddenContext hiddenctx; static frame_new new_frame; static fbo fb; static thread_video vthread; static consumer_xgl xgl; static mlt_filter glsl_manager; static void* video_thread( void *arg ); static void update() { int _width = GLWin.width; int _height = GLWin.height; GLfloat left, right, top, bottom; GLfloat war = (GLfloat)_width/(GLfloat)_height; if ( war < new_frame.aspect_ratio ) { left = -1.0; right = 1.0; top = war / new_frame.aspect_ratio; bottom = -war / new_frame.aspect_ratio; } else { top = 1.0; bottom = -1.0; left = -new_frame.aspect_ratio / war; right = new_frame.aspect_ratio / war; } glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glLoadIdentity(); glPushMatrix(); glTranslatef( _width/2, _height/2, 0 ); glScalef( _width/2, _height/2, 1.0 ); glBindTexture( GL_TEXTURE_2D, fb.texture ); glBegin( GL_QUADS ); glTexCoord2f( 0.0f, 0.0f ); glVertex2f( left, top ); glTexCoord2f( 0.0f, 1.0f ); glVertex2f( left, bottom ); glTexCoord2f( 1.0f, 1.0f ); glVertex2f( right, bottom ); glTexCoord2f( 1.0f, 0.0f ); glVertex2f( right, top ); glEnd(); glPopMatrix(); glXSwapBuffers( GLWin.dpy, GLWin.win ); if ( !vthread.running ) { pthread_create( &vthread.thread, NULL, video_thread, NULL ); vthread.running = 1; } } static void show_frame() { if ( (fb.width != new_frame.width) || (fb.height != new_frame.height) ) { glDeleteFramebuffers( 1, &fb.fbo ); glDeleteTextures( 1, &fb.texture ); fb.fbo = 0; fb.width = new_frame.width; fb.height = new_frame.height; glGenFramebuffers( 1, &fb.fbo ); glGenTextures( 1, &fb.texture ); glBindTexture( GL_TEXTURE_2D, fb.texture ); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, fb.width, fb.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glBindFramebuffer( GL_FRAMEBUFFER, fb.fbo ); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.texture, 0 ); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); } glPushAttrib(GL_VIEWPORT_BIT); glMatrixMode(GL_PROJECTION); glPushMatrix(); glBindFramebuffer( GL_FRAMEBUFFER, fb.fbo ); glViewport( 0, 0, new_frame.width, new_frame.height ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glOrtho( 0.0, new_frame.width, 0.0, new_frame.height, -1.0, 1.0 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glActiveTexture( GL_TEXTURE0 ); glBindTexture( GL_TEXTURE_2D, new_frame.texture ); glBegin( GL_QUADS ); glTexCoord2f( 0.0f, 0.0f ); glVertex2f( 0.0f, 0.0f ); glTexCoord2f( 0.0f, 1.0f ); glVertex2f( 0.0f, new_frame.height ); glTexCoord2f( 1.0f, 1.0f ); glVertex2f( new_frame.width, new_frame.height ); glTexCoord2f( 1.0f, 0.0f ); glVertex2f( new_frame.width, 0.0f ); glEnd(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); mlt_events_fire( MLT_CONSUMER_PROPERTIES(&xgl->parent), "consumer-frame-show", new_frame.mlt_frame_ref, NULL ); mlt_frame_close( new_frame.mlt_frame_ref ); new_frame.mlt_frame_ref = NULL; glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopAttrib(); update(); new_frame.new = 0; } void* video_thread( void *arg ) { mlt_frame next = NULL; mlt_consumer consumer = &xgl->parent; mlt_properties consumer_props = MLT_CONSUMER_PROPERTIES( consumer ); struct timeval start, end; double duration = 0; gettimeofday( &start, NULL ); while ( vthread.running ) { // Get a frame from the attached producer next = mlt_consumer_rt_frame( consumer ); if ( !mlt_properties_get_int( MLT_FILTER_PROPERTIES( glsl_manager ), "glsl_supported" ) ) { mlt_log_error( MLT_CONSUMER_SERVICE(consumer), "OpenGL Shading Language is not supported on this machine.\n" ); xgl->running = 0; break; } // Ensure that we have a frame if ( next ) { mlt_properties properties = MLT_FRAME_PROPERTIES( next ); if ( mlt_properties_get_int( properties, "rendered" ) == 1 ) { // Get the image, width and height mlt_image_format vfmt = mlt_image_glsl_texture; int width = 0, height = 0; GLuint *image = 0; int error = mlt_frame_get_image( next, (uint8_t**) &image, &vfmt, &width, &height, 0 ); if ( !error && image && width && height && !new_frame.new ) { new_frame.width = width; new_frame.height = height; new_frame.texture = *image; new_frame.mlt_frame_ref = next; new_frame.aspect_ratio = ((double)width / (double)height) * mlt_properties_get_double( properties, "aspect_ratio" ); new_frame.new = 1; int loop = 200; while ( new_frame.new && --loop ) usleep( 500 ); } else { mlt_frame_close( next ); } new_frame.new = 0; gettimeofday( &end, NULL ); duration = 1000000.0 / mlt_properties_get_double( consumer_props, "fps" ); duration -= ( end.tv_sec * 1000000 + end.tv_usec ) - ( start.tv_sec * 1000000 + start.tv_usec ); if ( duration > 0 ) usleep( (int)duration ); gettimeofday( &start, NULL ); } else { mlt_frame_close( next ); static int dropped = 0; mlt_log_info( MLT_CONSUMER_SERVICE(consumer), "dropped video frame %d\n", ++dropped ); } } else usleep( 1000 ); } mlt_consumer_stopped( consumer ); return NULL; } static void resizeGLScene() { glXMakeCurrent( GLWin.dpy, GLWin.win, GLWin.ctx ); if ( GLWin.height == 0 ) GLWin.height = 1; if ( GLWin.width == 0 ) GLWin.width = 1; glViewport( 0, 0, GLWin.width, GLWin.height ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glOrtho( 0.0, GLWin.width, 0.0, GLWin.height, -1.0, 1.0 ); glMatrixMode( GL_MODELVIEW ); update(); } static void initGL( void ) { glXMakeCurrent( GLWin.dpy, GLWin.win, GLWin.ctx ); glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); glClearDepth( 1.0f ); glDepthFunc( GL_LEQUAL ); glEnable( GL_DEPTH_TEST ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glEnable( GL_BLEND ); glShadeModel( GL_SMOOTH ); glEnable( GL_TEXTURE_2D ); glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); typedef int (*GLXSWAPINTERVALSGI) ( int ); GLXSWAPINTERVALSGI mglXSwapInterval = (GLXSWAPINTERVALSGI)glXGetProcAddressARB( (const GLubyte*)"glXSwapIntervalSGI" ); if ( mglXSwapInterval ) mglXSwapInterval( 1 ); fb.fbo = 0; fb.width = STARTWIDTH; fb.height = STARTHEIGHT; glGenFramebuffers( 1, &fb.fbo ); glGenTextures( 1, &fb.texture ); glBindTexture( GL_TEXTURE_2D, fb.texture ); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, fb.width, fb.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glBindFramebuffer( GL_FRAMEBUFFER, fb.fbo ); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.texture, 0 ); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); resizeGLScene(); } static void createGLWindow() { const char* title = "OpenGL consumer"; int width = STARTWIDTH; int height = STARTHEIGHT; int attrListSgl[] = { GLX_RGBA, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 16, None }; int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 16, None }; XVisualInfo *vi; Colormap cmap; Atom wmDelete; Window winDummy; unsigned int borderDummy; GLWin.dpy = XOpenDisplay( 0 ); GLWin.screen = DefaultScreen( GLWin.dpy ); vi = glXChooseVisual( GLWin.dpy, GLWin.screen, attrListDbl ); if ( !vi ) vi = glXChooseVisual( GLWin.dpy, GLWin.screen, attrListSgl ); GLWin.ctx = glXCreateContext( GLWin.dpy, vi, 0, GL_TRUE ); cmap = XCreateColormap( GLWin.dpy, RootWindow( GLWin.dpy, vi->screen ), vi->visual, AllocNone ); GLWin.attr.colormap = cmap; GLWin.attr.border_pixel = 0; GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask; GLWin.win = XCreateWindow( GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask, &GLWin.attr ); wmDelete = XInternAtom( GLWin.dpy, "WM_DELETE_WINDOW", True ); XSetWMProtocols( GLWin.dpy, GLWin.win, &wmDelete, 1 ); XSetStandardProperties( GLWin.dpy, GLWin.win, title, title, None, NULL, 0, NULL ); XMapRaised( GLWin.dpy, GLWin.win ); glXMakeCurrent( GLWin.dpy, GLWin.win, GLWin.ctx ); XGetGeometry( GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y, &GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth ); // Verify GLSL works on this machine hiddenctx.ctx = glXCreateContext( GLWin.dpy, vi, GLWin.ctx, GL_TRUE ); if ( hiddenctx.ctx ) { hiddenctx.dpy = GLWin.dpy; hiddenctx.screen = GLWin.screen; hiddenctx.win = RootWindow( hiddenctx.dpy, hiddenctx.screen ); } initGL(); } static void killGLWindow() { if ( GLWin.ctx ) { if ( !glXMakeCurrent( GLWin.dpy, None, NULL ) ) { printf("Error releasing drawing context : killGLWindow\n"); } glXDestroyContext( GLWin.dpy, GLWin.ctx ); GLWin.ctx = NULL; } if ( hiddenctx.ctx ) glXDestroyContext( hiddenctx.dpy, hiddenctx.ctx ); XCloseDisplay( GLWin.dpy ); } static void run() { XEvent event; while ( xgl->running ) { while ( XPending( GLWin.dpy ) > 0 ) { XNextEvent( GLWin.dpy, &event ); switch ( event.type ) { case Expose: if ( event.xexpose.count != 0 ) break; break; case ConfigureNotify: if ( (event.xconfigure.width != GLWin.width) || (event.xconfigure.height != GLWin.height) ) { GLWin.width = event.xconfigure.width; GLWin.height = event.xconfigure.height; resizeGLScene(); } break; case KeyPress: switch ( XLookupKeysym( &event.xkey, 0 ) ) { case XK_Escape: xgl->running = 0; break; default: { mlt_producer producer = mlt_properties_get_data( xgl->properties, "transport_producer", NULL ); char keyboard[ 2 ] = " "; void (*callback)( mlt_producer, char * ) = mlt_properties_get_data( xgl->properties, "transport_callback", NULL ); if ( callback != NULL && producer != NULL ) { keyboard[ 0 ] = ( char )XLookupKeysym( &event.xkey, 0 ); callback( producer, keyboard ); } break; } } break; case ClientMessage: if ( *XGetAtomName( GLWin.dpy, event.xclient.message_type ) == *"WM_PROTOCOLS" ) xgl->running = 0; break; default: break; } } if ( new_frame.new ) show_frame(); else usleep( 1000 ); } } void start_xgl( consumer_xgl consumer ) { xgl = consumer; pthread_mutex_init( &new_frame.mutex, NULL ); new_frame.aspect_ratio = 16.0 / 9.0; new_frame.new = 0; new_frame.width = STARTWIDTH; new_frame.height = STARTHEIGHT; new_frame.mlt_frame_ref = NULL; vthread.running = 0; xgl->xgl_started = 1; createGLWindow(); run(); if ( vthread.running ) { vthread.running = 0; pthread_join( vthread.thread, NULL ); } xgl->running = 0; } static void on_consumer_thread_started( mlt_properties owner, HiddenContext* context ) { // Initialize this thread's OpenGL state glXMakeCurrent( context->dpy, context->win, context->ctx ); mlt_events_fire( MLT_FILTER_PROPERTIES(glsl_manager), "init glsl", NULL ); } /** Forward references to static functions. */ static int consumer_start( mlt_consumer parent ); static int consumer_stop( mlt_consumer parent ); static int consumer_is_stopped( mlt_consumer parent ); static void consumer_close( mlt_consumer parent ); static void *consumer_thread( void * ); /** This is what will be called by the factory - anything can be passed in via the argument, but keep it simple. */ mlt_consumer consumer_xgl_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create the consumer object consumer_xgl this = calloc( sizeof( struct consumer_xgl_s ), 1 ); // If no malloc'd and consumer init ok if ( this != NULL && mlt_consumer_init( &this->parent, this, profile ) == 0 ) { // Create the queue this->queue = mlt_deque_init( ); // Get the parent consumer object mlt_consumer parent = &this->parent; // We have stuff to clean up, so override the close method parent->close = consumer_close; // get a handle on properties mlt_service service = MLT_CONSUMER_SERVICE( parent ); this->properties = MLT_SERVICE_PROPERTIES( service ); // Default scaler mlt_properties_set( this->properties, "rescale", "bilinear" ); mlt_properties_set( this->properties, "deinterlace_method", "onefield" ); // default image format mlt_properties_set( this->properties, "mlt_image_format", "glsl" ); // Default buffer for low latency mlt_properties_set_int( this->properties, "buffer", 1 ); // Ensure we don't join on a non-running object this->joined = 1; this->xgl_started = 0; // Allow thread to be started/stopped parent->start = consumer_start; parent->stop = consumer_stop; parent->is_stopped = consumer_is_stopped; // "init glsl" is required to instantiate glsl filters. glsl_manager = mlt_factory_filter( profile, "glsl.manager", NULL ); if ( glsl_manager ) { mlt_events_listen( this->properties, &hiddenctx, "consumer-thread-started", (mlt_listener) on_consumer_thread_started ); } else { mlt_consumer_close( parent ); parent = NULL; } // Return the consumer produced return parent; } // malloc or consumer init failed free( this ); // Indicate failure return NULL; } int consumer_start( mlt_consumer parent ) { consumer_xgl this = parent->child; if ( !this->running ) { consumer_stop( parent ); this->running = 1; this->joined = 0; pthread_create( &this->thread, NULL, consumer_thread, this ); } return 0; } int consumer_stop( mlt_consumer parent ) { // Get the actual object consumer_xgl this = parent->child; if ( this->running && this->joined == 0 ) { // Kill the thread and clean up this->joined = 1; this->running = 0; if ( this->thread ) pthread_join( this->thread, NULL ); } return 0; } int consumer_is_stopped( mlt_consumer parent ) { consumer_xgl this = parent->child; return !this->running; } static void *consumer_thread( void *arg ) { // Identify the arg consumer_xgl this = arg; XInitThreads(); start_xgl( this ); return NULL; } /** Callback to allow override of the close method. */ static void consumer_close( mlt_consumer parent ) { // Get the actual object consumer_xgl this = parent->child; // Stop the consumer ///mlt_consumer_stop( parent ); mlt_filter_close( glsl_manager ); // Now clean up the rest mlt_consumer_close( parent ); // Close the queue mlt_deque_close( this->queue ); if ( this->xgl_started ) killGLWindow(); // Finally clean up this free( this ); } mlt-0.9.0/src/modules/opengl/factory.c000066400000000000000000000137411215300731300176530ustar00rootroot00000000000000/* * Copyright (C) 2013 Dan Dennedy * factory.c -- the factory method interfaces * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include extern mlt_consumer consumer_xgl_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_glsl_manager_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_movit_blur_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_movit_convert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_movit_crop_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_deconvolution_sharpen_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_movit_diffusion_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_movit_glow_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_lift_gamma_gain_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_movit_mirror_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_movit_opacity_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_movit_rect_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_movit_resample_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_movit_resize_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_movit_saturation_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_movit_vignette_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_white_balance_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_transition transition_movit_mix_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_transition transition_movit_overlay_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/opengl/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { #if !defined(__DARWIN__) && !defined(WIN32) MLT_REGISTER( consumer_type, "xgl", consumer_xgl_init ); #endif MLT_REGISTER( filter_type, "glsl.manager", filter_glsl_manager_init ); MLT_REGISTER( filter_type, "movit.blur", filter_movit_blur_init ); MLT_REGISTER( filter_type, "movit.convert", filter_movit_convert_init ); MLT_REGISTER( filter_type, "movit.crop", filter_movit_crop_init ); MLT_REGISTER( filter_type, "movit.diffusion", filter_movit_diffusion_init ); MLT_REGISTER( filter_type, "movit.glow", filter_movit_glow_init ); MLT_REGISTER( filter_type, "movit.lift_gamma_gain", filter_lift_gamma_gain_init ); MLT_REGISTER( filter_type, "movit.mirror", filter_movit_mirror_init ); MLT_REGISTER( filter_type, "movit.opacity", filter_movit_opacity_init ); MLT_REGISTER( filter_type, "movit.rect", filter_movit_rect_init ); MLT_REGISTER( filter_type, "movit.resample", filter_movit_resample_init ); MLT_REGISTER( filter_type, "movit.resize", filter_movit_resize_init ); MLT_REGISTER( filter_type, "movit.saturation", filter_movit_saturation_init ); MLT_REGISTER( filter_type, "movit.sharpen", filter_deconvolution_sharpen_init ); MLT_REGISTER( filter_type, "movit.vignette", filter_movit_vignette_init ); MLT_REGISTER( filter_type, "movit.white_balance", filter_white_balance_init ); MLT_REGISTER( transition_type, "movit.mix", transition_movit_mix_init ); MLT_REGISTER( transition_type, "movit.overlay", transition_movit_overlay_init ); MLT_REGISTER_METADATA( filter_type, "movit.blur", metadata, "filter_movit_blur.yml" ); MLT_REGISTER_METADATA( filter_type, "movit.diffusion", metadata, "filter_movit_diffusion.yml" ); MLT_REGISTER_METADATA( filter_type, "movit.glow", metadata, "filter_movit_glow.yml" ); MLT_REGISTER_METADATA( filter_type, "movit.lift_gamma_gain", metadata, "filter_lift_gamma_gain.yml" ); MLT_REGISTER_METADATA( filter_type, "movit.mirror", metadata, "filter_movit_mirror.yml" ); MLT_REGISTER_METADATA( filter_type, "movit.opacity", metadata, "filter_movit_opacity.yml" ); MLT_REGISTER_METADATA( filter_type, "movit.rect", metadata, "filter_movit_rect.yml" ); MLT_REGISTER_METADATA( filter_type, "movit.saturation", metadata, "filter_movit_saturation.yml" ); MLT_REGISTER_METADATA( filter_type, "movit.sharpen", metadata, "filter_deconvolution_sharpen.yml" ); MLT_REGISTER_METADATA( filter_type, "movit.vignette", metadata, "filter_movit_vignette.yml" ); MLT_REGISTER_METADATA( filter_type, "movit.white_balance", metadata, "filter_white_balance.yml" ); MLT_REGISTER_METADATA( transition_type, "movit.mix", metadata, "transition_movit_mix.yml" ); MLT_REGISTER_METADATA( transition_type, "movit.overlay", metadata, "transition_movit_overlay.yml" ); } mlt-0.9.0/src/modules/opengl/fbo_input.cpp000066400000000000000000000032631215300731300205270ustar00rootroot00000000000000/* * fbo_input.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "fbo_input.h" #include // comes from unexported effect_util.h extern void set_uniform_int(GLuint glsl_program_num, const std::string &prefix, const std::string &key, int value); FBOInput::FBOInput(unsigned width, unsigned height) : texture_num(0) , needs_mipmaps(false) , width(width) , height(height) { register_int("needs_mipmaps", &needs_mipmaps); } void FBOInput::set_gl_state(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num) { glActiveTexture(GL_TEXTURE0 + *sampler_num); check_error(); glBindTexture(GL_TEXTURE_2D, texture_num); check_error(); // Bind it to a sampler. set_uniform_int(glsl_program_num, prefix, "tex", *sampler_num); ++*sampler_num; } std::string FBOInput::output_fragment_shader() { return read_file("flat_input.frag"); // return "uniform sampler2D PREFIX(tex); vec4 FUNCNAME(vec2 tc) { return texture2D(PREFIX(tex), tc); }\n"; } mlt-0.9.0/src/modules/opengl/fbo_input.h000066400000000000000000000032221215300731300201670ustar00rootroot00000000000000/* * fbo_input.h * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef FBO_INPUT_H #define FBO_INPUT_H #include class FBOInput : public Input { public: FBOInput(unsigned width, unsigned height); virtual std::string effect_type_id() const { return "FBOInput"; } void finalize() {} bool can_output_linear_gamma() const { return false; } AlphaHandling alpha_handling() const { return OUTPUT_POSTMULTIPLIED_ALPHA; } std::string output_fragment_shader(); void set_gl_state(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num); unsigned get_width() const { return width; } unsigned get_height() const { return height; } Colorspace get_color_space() const { return COLORSPACE_sRGB; } GammaCurve get_gamma_curve() const { return GAMMA_sRGB; } void set_texture(GLuint texture) { texture_num = texture; } private: GLuint texture_num; int needs_mipmaps; unsigned width, height; }; #endif // FBO_INPUT_H mlt-0.9.0/src/modules/opengl/filter_deconvolution_sharpen.cpp000066400000000000000000000063641215300731300245240ustar00rootroot00000000000000/* * filter_deconvolution_sharpen.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "glsl_manager.h" #include static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); Effect* effect = GlslManager::get_effect( filter, frame ); if ( effect ) { mlt_position position = mlt_filter_get_position( filter, frame ); mlt_position length = mlt_filter_get_length2( filter, frame ); bool ok = effect->set_int( "matrix_size", mlt_properties_anim_get_int( properties, "matrix_size", position, length ) ); ok |= effect->set_float( "cirlce_radius", mlt_properties_anim_get_double( properties, "circle_radius", position, length ) ); ok |= effect->set_float( "gaussian_radius", mlt_properties_anim_get_double( properties, "gaussian_radius", position, length ) ); ok |= effect->set_float( "correlation", mlt_properties_anim_get_double( properties, "correlation", position, length ) ); ok |= effect->set_float( "noise", mlt_properties_anim_get_double( properties, "noise", position, length ) ); assert(ok); } GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; return mlt_frame_get_image( frame, image, format, width, height, writable ); } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { if ( !mlt_frame_is_test_card( frame ) ) { if ( !GlslManager::get_effect( filter, frame ) ) GlslManager::add_effect( filter, frame, new DeconvolutionSharpenEffect() ); } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; } extern "C" { mlt_filter filter_deconvolution_sharpen_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( filter = mlt_filter_new() ) ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties_set_int( properties, "matrix_size", 5 ); mlt_properties_set_double( properties, "circle_radius", 2.0 ); mlt_properties_set_double( properties, "gaussian_radius", 0.0 ); mlt_properties_set_double( properties, "correlation", 0.95 ); mlt_properties_set_double( properties, "noise", 0.01 ); filter->process = process; } return filter; } } mlt-0.9.0/src/modules/opengl/filter_deconvolution_sharpen.yml000066400000000000000000000025731215300731300245410ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: movit.sharpen title: Deconvolution Sharpen (GLSL) version: 1 copyright: Dan Dennedy creator: Steinar H. Gunderson license: GPLv2 language: en tags: - Video description: > Deconvolution Sharpen is a filter that sharpens by way of deconvolution (i.e., trying to reverse the blur kernel, as opposed to just boosting high frequencies), more specifically by FIR Wiener filters. It is the same algorithm as used by the (now largely abandoned) Refocus plug-in for GIMP, and I suspect the same as in Photoshop's “Smart Sharpen†filter. The effect gives generally better results than unsharp masking, but can be very GPU intensive, and requires a fair bit of tweaking to get good results without ringing and/or excessive noise. parameters: - identifier: matrix_size title: Matrix Size type: integer minimum: 0 maximum: 10 default: 5 mutable: yes - identifier: circle_radius title: Circle Radius type: float minimum: 0 default: 2 mutable: yes - identifier: gaussian_radius title: Gaussian Radius type: float minimum: 0 default: 0 mutable: yes - identifier: correlation title: Correlation type: float minimum: 0 default: 0.95 mutable: yes - identifier: noise title: Noise Level type: float minimum: 0 default: 0.01 mutable: yes mlt-0.9.0/src/modules/opengl/filter_glsl_manager.cpp000066400000000000000000000235541215300731300225470ustar00rootroot00000000000000/* * filter_glsl_manager.cpp * Copyright (C) 2011-2012 Christophe Thommeret * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "glsl_manager.h" #include #include #include "mlt_movit_input.h" #include "mlt_flip_effect.h" #include #include extern "C" { #include } void deleteManager(GlslManager *p) { delete p; } GlslManager::GlslManager() : Mlt::Filter( mlt_filter_new() ) , pbo(0) , initEvent(0) { mlt_filter filter = get_filter(); if ( filter ) { // Set the mlt_filter child in case we choose to override virtual functions. filter->child = this; mlt_properties_set_data(mlt_global_properties(), "glslManager", this, 0, (mlt_destructor) deleteManager, NULL); mlt_events_register( get_properties(), "init glsl", NULL ); initEvent = listen("init glsl", this, (mlt_listener) GlslManager::onInit); } } GlslManager::~GlslManager() { mlt_log_debug(get_service(), "%s\n", __FUNCTION__); while (fbo_list.peek_back()) delete (glsl_fbo) fbo_list.pop_back(); while (texture_list.peek_back()) delete (glsl_texture) texture_list.pop_back(); delete pbo; delete initEvent; } GlslManager* GlslManager::get_instance() { return (GlslManager*) mlt_properties_get_data(mlt_global_properties(), "glslManager", 0); } glsl_fbo GlslManager::get_fbo(int width, int height) { for (int i = 0; i < fbo_list.count(); ++i) { glsl_fbo fbo = (glsl_fbo) fbo_list.peek(i); if (!fbo->used && (fbo->width == width) && (fbo->height == height)) { fbo->used = 1; return fbo; } } GLuint fb = 0; glGenFramebuffers(1, &fb); if (!fb) return NULL; glsl_fbo fbo = new glsl_fbo_s; if (!fbo) { glDeleteFramebuffers(1, &fb); return NULL; } fbo->fbo = fb; fbo->width = width; fbo->height = height; fbo->used = 1; fbo_list.push_back(fbo); return fbo; } void GlslManager::release_fbo(glsl_fbo fbo) { fbo->used = 0; } glsl_texture GlslManager::get_texture(int width, int height, GLint internal_format) { for (int i = 0; i < texture_list.count(); ++i) { glsl_texture tex = (glsl_texture) texture_list.peek(i); if (!tex->used && (tex->width == width) && (tex->height == height) && (tex->internal_format == internal_format)) { glBindTexture(GL_TEXTURE_2D, tex->texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glBindTexture( GL_TEXTURE_2D, 0); tex->used = 1; return tex; } } GLuint tex = 0; glGenTextures(1, &tex); if (!tex) return NULL; glsl_texture gtex = new glsl_texture_s; if (!gtex) { glDeleteTextures(1, &tex); return NULL; } glBindTexture( GL_TEXTURE_2D, tex ); glTexImage2D( GL_TEXTURE_2D, 0, internal_format, width, height, 0, internal_format, GL_UNSIGNED_BYTE, NULL ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glBindTexture( GL_TEXTURE_2D, 0 ); gtex->texture = tex; gtex->width = width; gtex->height = height; gtex->internal_format = internal_format; gtex->used = 1; texture_list.push_back(gtex); return gtex; } void GlslManager::release_texture(glsl_texture texture) { texture->used = 0; } glsl_pbo GlslManager::get_pbo(int size) { if (!pbo) { GLuint pb = 0; glGenBuffers(1, &pb); if (!pb) return NULL; pbo = new glsl_pbo_s; if (!pbo) { glDeleteBuffers(1, &pb); return NULL; } pbo->pbo = pb; } if (size > pbo->size) { glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo->pbo); glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, size, NULL, GL_STREAM_DRAW); glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); pbo->size = size; } return pbo; } void GlslManager::onInit( mlt_properties owner, GlslManager* filter ) { mlt_log_debug( filter->get_service(), "%s\n", __FUNCTION__ ); #ifdef WIN32 std::string path = std::string(mlt_environment("MLT_APPDIR")).append("\\share\\movit"); #elif defined(__DARWIN__) && defined(RELOCATABLE) std::string path = std::string(mlt_environment("MLT_APPDIR")).append("/share/movit"); #else std::string path = std::string(getenv("MLT_MOVIT_PATH") ? getenv("MLT_MOVIT_PATH") : SHADERDIR); #endif ::init_movit( path, mlt_log_get_level() == MLT_LOG_DEBUG? MOVIT_DEBUG_ON : MOVIT_DEBUG_OFF ); filter->set( "glsl_supported", movit_initialized ); } void GlslManager::onServiceChanged( mlt_properties owner, mlt_service aservice ) { Mlt::Service service( aservice ); service.lock(); service.set( "movit chain", NULL, 0 ); service.set( "movit input", NULL, 0 ); // Destroy the effect list. GlslManager::get_instance()->set( service.get( "_unique_id" ), NULL, 0 ); service.unlock(); } void GlslManager::onPropertyChanged( mlt_properties owner, mlt_service service, const char* property ) { if ( property && std::string( property ) == "disable" ) onServiceChanged( owner, service ); } extern "C" { mlt_filter filter_glsl_manager_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { GlslManager* g = GlslManager::get_instance(); if (g) g->inc_ref(); else g = new GlslManager(); return g->get_filter(); } } // extern "C" Mlt::Properties GlslManager::effect_list( Mlt::Service& service ) { char *unique_id = service.get( "_unique_id" ); mlt_properties properties = (mlt_properties) get_data( unique_id ); if ( !properties ) { properties = mlt_properties_new(); set( unique_id, properties, 0, (mlt_destructor) mlt_properties_close ); } Mlt::Properties p( properties ); return p; } static void deleteChain( EffectChain* chain ) { delete chain; } bool GlslManager::init_chain( mlt_service aservice ) { bool error = true; Mlt::Service service( aservice ); EffectChain* chain = (EffectChain*) service.get_data( "movit chain" ); if ( !chain ) { mlt_profile profile = mlt_service_profile( aservice ); Input* input = new MltInput( profile->width, profile->height ); chain = new EffectChain( profile->display_aspect_num, profile->display_aspect_den ); chain->add_input( input ); service.set( "movit chain", chain, 0, (mlt_destructor) deleteChain ); service.set( "movit input", input, 0 ); service.set( "_movit finalized", 0 ); service.listen( "service-changed", aservice, (mlt_listener) GlslManager::onServiceChanged ); service.listen( "property-changed", aservice, (mlt_listener) GlslManager::onPropertyChanged ); error = false; } return error; } EffectChain* GlslManager::get_chain( mlt_service service ) { return (EffectChain*) mlt_properties_get_data( MLT_SERVICE_PROPERTIES(service), "movit chain", NULL ); } MltInput *GlslManager::get_input( mlt_service service ) { return (MltInput*) mlt_properties_get_data( MLT_SERVICE_PROPERTIES(service), "movit input", NULL ); } void GlslManager::reset_finalized( mlt_service service ) { mlt_properties_set_int( MLT_SERVICE_PROPERTIES(service), "_movit finalized", 0 ); } Effect* GlslManager::get_effect( mlt_filter filter, mlt_frame frame ) { Mlt::Producer producer( mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ) ); char *unique_id = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "_unique_id" ); return (Effect*) GlslManager::get_instance()->effect_list( producer ).get_data( unique_id ); } Effect* GlslManager::add_effect( mlt_filter filter, mlt_frame frame, Effect* effect ) { Mlt::Producer producer( mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ) ); EffectChain* chain = (EffectChain*) producer.get_data( "movit chain" ); chain->add_effect( effect ); char *unique_id = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "_unique_id" ); GlslManager::get_instance()->effect_list( producer ).set( unique_id, effect, 0 ); return effect; } Effect* GlslManager::add_effect( mlt_filter filter, mlt_frame frame, Effect* effect, Effect* input_b ) { Mlt::Producer producer( mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ) ); EffectChain* chain = (EffectChain*) producer.get_data( "movit chain" ); chain->add_effect( effect, chain->last_added_effect(), input_b? input_b : chain->last_added_effect() ); char *unique_id = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "_unique_id" ); GlslManager::get_instance()->effect_list( producer ).set( unique_id, effect, 0 ); return effect; } void GlslManager::render( mlt_service service, void* chain, GLuint fbo, int width, int height ) { EffectChain* effect_chain = (EffectChain*) chain; mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); if ( !mlt_properties_get_int( properties, "_movit finalized" ) ) { mlt_properties_set_int( properties, "_movit finalized", 1 ); effect_chain->add_effect( new Mlt::VerticalFlip() ); effect_chain->finalize(); } effect_chain->render_to_fbo( fbo, width, height ); } void GlslManager::lock_service( mlt_frame frame ) { Mlt::Producer producer( mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ) ); producer.lock(); } void GlslManager::unlock_service( mlt_frame frame ) { Mlt::Producer producer( mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ) ); producer.unlock(); } mlt-0.9.0/src/modules/opengl/filter_lift_gamma_gain.cpp000066400000000000000000000073671215300731300232160ustar00rootroot00000000000000/* * filter_lift_gamma_gain.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "glsl_manager.h" #include static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); Effect* effect = GlslManager::get_effect( filter, frame ); if ( effect ) { mlt_position position = mlt_filter_get_position( filter, frame ); mlt_position length = mlt_filter_get_length2( filter, frame ); RGBTriplet triplet( mlt_properties_anim_get_double( properties, "lift_r", position, length ), mlt_properties_anim_get_double( properties, "lift_g", position, length ), mlt_properties_anim_get_double( properties, "lift_b", position, length ) ); bool ok = effect->set_vec3( "lift", (float*) &triplet ); triplet.r = mlt_properties_anim_get_double( properties, "gamma_r", position, length ); triplet.g = mlt_properties_anim_get_double( properties, "gamma_g", position, length ); triplet.b = mlt_properties_anim_get_double( properties, "gamma_b", position, length ); ok |= effect->set_vec3( "gamma", (float*) &triplet ); triplet.r = mlt_properties_anim_get_double( properties, "gain_r", position, length ); triplet.g = mlt_properties_anim_get_double( properties, "gain_g", position, length ); triplet.b = mlt_properties_anim_get_double( properties, "gain_b", position, length ); ok |= effect->set_vec3( "gain", (float*) &triplet ); assert(ok); } GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; return mlt_frame_get_image( frame, image, format, width, height, writable ); } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { if ( !mlt_frame_is_test_card( frame ) ) { if ( !GlslManager::get_effect( filter, frame ) ) GlslManager::add_effect( filter, frame, new LiftGammaGainEffect ); } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; } extern "C" { mlt_filter filter_lift_gamma_gain_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( filter = mlt_filter_new() ) ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties_set_double( properties, "lift_r", 0.0 ); mlt_properties_set_double( properties, "lift_g", 0.0 ); mlt_properties_set_double( properties, "lift_b", 0.0 ); mlt_properties_set_double( properties, "gamma_r", 1.0 ); mlt_properties_set_double( properties, "gamma_g", 1.0 ); mlt_properties_set_double( properties, "gamma_b", 1.0 ); mlt_properties_set_double( properties, "gain_r", 1.0 ); mlt_properties_set_double( properties, "gain_g", 1.0 ); mlt_properties_set_double( properties, "gain_b", 1.0 ); filter->process = process; } return filter; } } mlt-0.9.0/src/modules/opengl/filter_lift_gamma_gain.yml000066400000000000000000000040331215300731300232200ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: movit.lift_gamma_gain title: Lift, Gamma, and Gain (GLSL) version: 1 copyright: Dan Dennedy creator: Steinar H. Gunderson license: GPLv2 language: en tags: - Video description: > A simple lift/gamma/gain effect, used for color grading. notes: > Very roughly speaking, lift=shadows, gamma=midtones and gain=highlights, although all parameters affect the entire curve. Mathematically speaking, it is a bit unusual to look at gamma as a color, but it works pretty well in practice. The classic formula is: output = (gain * (x + lift * (1-x)))^(1/gamma). The lift is actually a case where we actually would _not_ want linear light; since black by definition becomes equal to the lift color, we want lift to be pretty close to black, but in linear light that means lift affects the rest of the curve relatively little. Thus, we actually convert to gamma 2.2 before lift, and then back again afterwards. (Gain and gamma are, up to constants, commutative with the de-gamma operation.) parameters: - identifier: lift_r title: Lift Red type: float minimum: 0.0 default: 0.0 mutable: yes - identifier: lift_g title: Lift Green type: float minimum: 0.0 default: 0.0 mutable: yes - identifier: lift_b title: Lift Blue type: float minimum: 0.0 default: 0.0 mutable: yes - identifier: gamma_r title: Gamma Red type: float minimum: 0.0 default: 1.0 mutable: yes - identifier: gamma_g title: Gamma Green type: float minimum: 0.0 default: 1.0 mutable: yes - identifier: gamma_b title: Gamma Blue type: float minimum: 0.0 default: 1.0 mutable: yes - identifier: gain_r title: Gain Red type: float minimum: 0.0 default: 1.0 mutable: yes - identifier: gain_g title: Gain Green type: float minimum: 0.0 default: 1.0 mutable: yes - identifier: gain_b title: Gain Blue type: float minimum: 0.0 default: 1.0 mutable: yes mlt-0.9.0/src/modules/opengl/filter_movit_blur.cpp000066400000000000000000000047261215300731300222760ustar00rootroot00000000000000/* * filter_movit_blur.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "glsl_manager.h" #include static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); Effect* effect = GlslManager::get_effect( filter, frame ); if ( effect ) { double radius = mlt_properties_anim_get_double( properties, "radius", mlt_filter_get_position( filter, frame ), mlt_filter_get_length2( filter, frame ) ); bool ok = effect->set_float( "radius", radius ); assert(ok); } GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; return mlt_frame_get_image( frame, image, format, width, height, writable ); } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { if ( !mlt_frame_is_test_card( frame ) ) { Effect* effect = GlslManager::get_effect( filter, frame ); if ( !effect ) { effect = GlslManager::add_effect( filter, frame, new BlurEffect() ); assert(effect); } } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; } extern "C" { mlt_filter filter_movit_blur_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( filter = mlt_filter_new() ) ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties_set_double( properties, "radius", 3 ); filter->process = process; } return filter; } } mlt-0.9.0/src/modules/opengl/filter_movit_blur.yml000066400000000000000000000007751215300731300223150ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: movit.blur title: Blur (GLSL) version: 1 copyright: Dan Dennedy creator: Steinar H. Gunderson license: GPLv2 language: en tags: - Video description: > A separable 2D blur implemented by a combination of mipmap filtering and convolution (essentially giving a convolution with a piecewise linear approximation to the true impulse response). parameters: - identifier: radius title: Radius type: float minimum: 0 default: 3 mutable: yes mlt-0.9.0/src/modules/opengl/filter_movit_convert.cpp000066400000000000000000000332401215300731300230030ustar00rootroot00000000000000/* * filter_movit_convert.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include "glsl_manager.h" #include #include #include "mlt_movit_input.h" #include #include "mlt_flip_effect.h" static void yuv422_to_yuv422p( uint8_t *yuv422, uint8_t *yuv422p, int width, int height ) { uint8_t *Y = yuv422p; uint8_t *U = Y + width * height; uint8_t *V = U + width * height / 2; int n = width * height / 2 + 1; while ( --n ) { *Y++ = *yuv422++; *U++ = *yuv422++; *Y++ = *yuv422++; *V++ = *yuv422++; } } static int convert_on_cpu( mlt_frame frame, uint8_t **image, mlt_image_format *format, mlt_image_format output_format ) { int error = 0; mlt_filter cpu_csc = (mlt_filter) mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "cpu_csc", NULL ); if ( cpu_csc ) { int (* save_fp )( mlt_frame self, uint8_t **image, mlt_image_format *input, mlt_image_format output ) = frame->convert_image; frame->convert_image = NULL; mlt_filter_process( cpu_csc, frame ); error = frame->convert_image( frame, image, format, output_format ); frame->convert_image = save_fp; } else { error = 1; } return error; } static void delete_chain( EffectChain* chain ) { delete chain; } static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, mlt_image_format output_format ) { // Nothing to do! if ( *format == output_format ) return 0; mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_log_debug( NULL, "filter_movit_convert: %s -> %s\n", mlt_image_format_name( *format ), mlt_image_format_name( output_format ) ); // Use CPU if glsl not initialized or not supported. GlslManager* glsl = GlslManager::get_instance(); if ( !glsl || !glsl->get_int("glsl_supported" ) ) return convert_on_cpu( frame, image, format, output_format ); // Do non-GL image conversions on a CPU-based image converter. if ( *format != mlt_image_glsl && output_format != mlt_image_glsl && output_format != mlt_image_glsl_texture ) return convert_on_cpu( frame, image, format, output_format ); int error = 0; int width = mlt_properties_get_int( properties, "width" ); int height = mlt_properties_get_int( properties, "height" ); int img_size = mlt_image_format_size( *format, width, height, NULL ); mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); mlt_service service = MLT_PRODUCER_SERVICE(producer); GlslManager::get_instance()->lock_service( frame ); EffectChain* chain = GlslManager::get_chain( service ); MltInput* input = GlslManager::get_input( service ); if ( !chain || !input ) { GlslManager::get_instance()->unlock_service( frame ); return 2; } if ( *format != mlt_image_glsl ) { bool finalize_chain = false; if ( output_format == mlt_image_glsl_texture ) { // We might already have a texture from a previous conversion from mlt_image_glsl. glsl_texture texture = (glsl_texture) mlt_properties_get_data( properties, "movit.convert.texture", NULL ); // XXX: requires a special property set on the frame by the app for now // because we do not have reliable way to clear the texture property // when a downstream filter has changed image. if ( texture && mlt_properties_get_int( properties, "movit.convert.use_texture") ) { *image = (uint8_t*) &texture->texture; mlt_frame_set_image( frame, *image, 0, NULL ); mlt_properties_set_int( properties, "format", output_format ); *format = output_format; GlslManager::get_instance()->unlock_service( frame ); return error; } else { // Use a separate chain to convert image in RAM to OpenGL texture. // Use cached chain if available and compatible. Mlt::Producer producer( mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ) ); chain = (EffectChain*) producer.get_data( "movit.convert.chain" ); input = (MltInput*) producer.get_data( "movit.convert.input" ); int w = producer.get_int( "movit.convert.width" ); int h = producer.get_int( "movit.convert.height" ); mlt_image_format f = (mlt_image_format) producer.get_int( "movit.convert.format" ); if ( !chain || width != w || height != h || output_format != f ) { chain = new EffectChain( width, height ); input = new MltInput( width, height ); chain->add_input( input ); chain->add_effect( new Mlt::VerticalFlip() ); finalize_chain = true; producer.set( "movit.convert.chain", chain, 0, (mlt_destructor) delete_chain ); producer.set( "movit.convert.width", width ); producer.set( "movit.convert.height", height ); producer.set( "movit.convert.width", output_format ); } } } if ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) { input->useFlatInput( chain, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, width, height ); input->set_pixel_data( *image ); } else if ( *format == mlt_image_rgb24 ) { input->useFlatInput( chain, FORMAT_RGB, width, height ); input->set_pixel_data( *image ); } else if ( *format == mlt_image_yuv420p ) { ImageFormat image_format; YCbCrFormat ycbcr_format; if ( 709 == mlt_properties_get_int( properties, "colorspace" ) ) { image_format.color_space = COLORSPACE_REC_709; image_format.gamma_curve = GAMMA_REC_709; ycbcr_format.luma_coefficients = YCBCR_REC_709; } else if ( 576 == mlt_properties_get_int( properties, "height" ) ) { image_format.color_space = COLORSPACE_REC_601_625; image_format.gamma_curve = GAMMA_REC_601; ycbcr_format.luma_coefficients = YCBCR_REC_601; } else { image_format.color_space = COLORSPACE_REC_601_525; image_format.gamma_curve = GAMMA_REC_601; ycbcr_format.luma_coefficients = YCBCR_REC_601; } ycbcr_format.full_range = mlt_properties_get_int( properties, "force_full_luma" ); ycbcr_format.chroma_subsampling_x = ycbcr_format.chroma_subsampling_y = 2; // TODO: make new frame properties set by producers ycbcr_format.cb_x_position = ycbcr_format.cr_x_position = 0.0f; ycbcr_format.cb_y_position = ycbcr_format.cr_y_position = 0.5f; input->useYCbCrInput( chain, image_format, ycbcr_format, width, height ); input->set_pixel_data( *image ); } else if ( *format == mlt_image_yuv422 ) { ImageFormat image_format; YCbCrFormat ycbcr_format; if ( 709 == mlt_properties_get_int( properties, "colorspace" ) ) { image_format.color_space = COLORSPACE_REC_709; image_format.gamma_curve = GAMMA_REC_709; ycbcr_format.luma_coefficients = YCBCR_REC_709; } else if ( 576 == height ) { image_format.color_space = COLORSPACE_REC_601_625; image_format.gamma_curve = GAMMA_REC_601; ycbcr_format.luma_coefficients = YCBCR_REC_601; } else { image_format.color_space = COLORSPACE_REC_601_525; image_format.gamma_curve = GAMMA_REC_601; ycbcr_format.luma_coefficients = YCBCR_REC_601; } ycbcr_format.full_range = mlt_properties_get_int( properties, "force_full_luma" ); ycbcr_format.chroma_subsampling_x = 2; ycbcr_format.chroma_subsampling_y = 1; // TODO: make new frame properties set by producers ycbcr_format.cb_x_position = ycbcr_format.cr_x_position = 0.0f; ycbcr_format.cb_y_position = ycbcr_format.cr_y_position = 0.5f; input->useYCbCrInput( chain, image_format, ycbcr_format, width, height ); // convert chunky to planar uint8_t* planar = (uint8_t*) mlt_pool_alloc( img_size ); yuv422_to_yuv422p( *image, planar, width, height ); input->set_pixel_data( planar ); mlt_frame_set_image( frame, planar, img_size, mlt_pool_release ); } // Finalize the separate conversion chain if needed. if ( finalize_chain ) chain->finalize(); } if ( output_format != mlt_image_glsl ) { glsl_fbo fbo = glsl->get_fbo( width, height ); if ( output_format == mlt_image_glsl_texture ) { glsl_texture texture = glsl->get_texture( width, height, GL_RGBA ); glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo ); check_error(); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 ); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); GlslManager::render( service, chain, fbo->fbo, width, height ); glFinish(); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); *image = (uint8_t*) &texture->texture; mlt_frame_set_image( frame, *image, 0, NULL ); mlt_properties_set_data( properties, "movit.convert.texture", texture, 0, (mlt_destructor) GlslManager::release_texture, NULL ); mlt_properties_set_int( properties, "format", output_format ); *format = output_format; } else { // Use a PBO to hold the data we read back with glReadPixels() // (Intel/DRI goes into a slow path if we don't read to PBO) GLenum gl_format = ( output_format == mlt_image_rgb24a || output_format == mlt_image_opengl )? GL_RGBA : GL_RGB; img_size = width * height * ( gl_format == GL_RGB? 3 : 4 ); glsl_pbo pbo = glsl->get_pbo( img_size ); glsl_texture texture = glsl->get_texture( width, height, gl_format ); if ( fbo && pbo && texture ) { // Set the FBO glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo ); check_error(); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 ); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); GlslManager::render( service, chain, fbo->fbo, width, height ); // Read FBO into PBO glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, pbo->pbo ); check_error(); glBufferData( GL_PIXEL_PACK_BUFFER_ARB, img_size, NULL, GL_STREAM_READ ); check_error(); glReadPixels( 0, 0, width, height, gl_format, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0) ); check_error(); // Copy from PBO uint8_t* buf = (uint8_t*) glMapBuffer( GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY ); check_error(); *image = (uint8_t*) mlt_pool_alloc( img_size ); mlt_frame_set_image( frame, *image, img_size, mlt_pool_release ); memcpy( *image, buf, img_size ); if ( output_format == mlt_image_yuv422 || output_format == mlt_image_yuv420p ) { *format = mlt_image_rgb24; error = convert_on_cpu( frame, image, format, output_format ); } // Release PBO and FBO glUnmapBuffer( GL_PIXEL_PACK_BUFFER_ARB ); check_error(); glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, 0 ); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); glBindTexture( GL_TEXTURE_2D, 0 ); check_error(); mlt_properties_set_data( properties, "movit.convert.texture", texture, 0, (mlt_destructor) GlslManager::release_texture, NULL); mlt_properties_set_int( properties, "format", output_format ); *format = output_format; } else { error = 1; } } if ( fbo ) GlslManager::release_fbo( fbo ); } else { mlt_properties_set_int( properties, "format", output_format ); *format = output_format; } GlslManager::get_instance()->unlock_service( frame ); return error; } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { // Set a default colorspace on the frame if not yet set by the producer. // The producer may still change it during get_image. // This way we do not have to modify each producer to set a valid colorspace. mlt_properties properties = MLT_FRAME_PROPERTIES(frame); if ( mlt_properties_get_int( properties, "colorspace" ) <= 0 ) mlt_properties_set_int( properties, "colorspace", mlt_service_profile( MLT_FILTER_SERVICE(filter) )->colorspace ); frame->convert_image = convert_image; mlt_filter cpu_csc = (mlt_filter) mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), "cpu_csc", NULL ); mlt_properties_inc_ref( MLT_FILTER_PROPERTIES(cpu_csc) ); mlt_properties_set_data( properties, "cpu_csc", cpu_csc, 0, (mlt_destructor) mlt_filter_close, NULL ); return frame; } static mlt_filter create_filter( mlt_profile profile, char *effect ) { mlt_filter filter; char *id = strdup( effect ); char *arg = strchr( id, ':' ); if ( arg != NULL ) *arg ++ = '\0'; // The swscale and avcolor_space filters require resolution as arg to test compatibility if ( !strcmp( effect, "avcolor_space" ) ) filter = mlt_factory_filter( profile, id, &profile->width ); else filter = mlt_factory_filter( profile, id, arg ); if ( filter ) mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "_loader", 1 ); free( id ); return filter; } extern "C" { mlt_filter filter_movit_convert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( filter = mlt_filter_new() ) ) { #ifdef WIN32 // XXX avcolor_space is crashing on Windows in this context! mlt_filter cpu_csc = NULL; #else mlt_filter cpu_csc = create_filter( profile, "avcolor_space" ); #endif if ( !cpu_csc ) cpu_csc = create_filter( profile, "imageconvert" ); if ( cpu_csc ) mlt_properties_set_data( MLT_FILTER_PROPERTIES( filter ), "cpu_csc", cpu_csc, 0, (mlt_destructor) mlt_filter_close, NULL ); filter->process = process; } return filter; } } mlt-0.9.0/src/modules/opengl/filter_movit_crop.cpp000066400000000000000000000106531215300731300222710ustar00rootroot00000000000000/* * filter_movit_crop.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "glsl_manager.h" #include static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); mlt_image_format requested_format = *format; // Correct width/height if necessary *width = mlt_properties_get_int( properties, "crop.original_width" ); *height = mlt_properties_get_int( properties, "crop.original_height" ); if ( *width == 0 || *height == 0 ) { *width = mlt_properties_get_int( properties, "meta.media.width" ); *height = mlt_properties_get_int( properties, "meta.media.height" ); } if ( *width == 0 || *height == 0 ) { *width = profile->width; *height = profile->height; } mlt_properties_set_int( properties, "rescale_width", *width ); mlt_properties_set_int( properties, "rescale_height", *height ); // Get the image as requested // *format = (mlt_image_format) mlt_properties_get_int( MLT_PRODUCER_PROPERTIES(producer), "_movit image_format" ); *format = mlt_image_none; if ( mlt_properties_get_int( properties, "test_image" ) ) *format = mlt_image_yuv422; error = mlt_frame_get_image( frame, image, format, width, height, writable ); // Skip processing if requested. if ( requested_format == mlt_image_none ) return error; if ( !error && *format != mlt_image_glsl && frame->convert_image ) { // Pin the requested format to the first one returned. // mlt_properties_set_int( MLT_PRODUCER_PROPERTIES(producer), "_movit image_format", *format ); error = frame->convert_image( frame, image, format, mlt_image_glsl ); } if ( !error ) { double left = mlt_properties_get_double( properties, "crop.left" ); double right = mlt_properties_get_double( properties, "crop.right" ); double top = mlt_properties_get_double( properties, "crop.top" ); double bottom = mlt_properties_get_double( properties, "crop.bottom" ); int owidth = *width - left - right; int oheight = *height - top - bottom; owidth = owidth < 0 ? 0 : owidth; oheight = oheight < 0 ? 0 : oheight; mlt_log_debug( MLT_FILTER_SERVICE(filter), "%dx%d -> %dx%d\n", *width, *height, owidth, oheight); GlslManager::get_instance()->lock_service( frame ); Effect* effect = GlslManager::get_effect( filter, frame ); if ( effect ) { bool ok = effect->set_int( "width", owidth ); ok |= effect->set_int( "height", oheight ); ok |= effect->set_float( "left", -left ); ok |= effect->set_float( "top", -top ); assert(ok); *width = owidth; *height = oheight; } GlslManager::get_instance()->unlock_service( frame ); } return error; } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); if ( !GlslManager::init_chain( MLT_PRODUCER_SERVICE(producer) ) ) { Effect* effect = GlslManager::add_effect( filter, frame, new PaddingEffect ); RGBATuple border_color( 0.0f, 0.0f, 0.0f, 1.0f ); bool ok = effect->set_vec4( "border_color", (float*) &border_color ); assert(ok); } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; } extern "C" mlt_filter filter_movit_crop_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( filter = mlt_filter_new() ) ) { filter->process = process; } return filter; } mlt-0.9.0/src/modules/opengl/filter_movit_diffusion.cpp000066400000000000000000000052121215300731300233070ustar00rootroot00000000000000/* * filter_movit_diffusion.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "glsl_manager.h" #include static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); Effect* effect = GlslManager::get_effect( filter, frame ); if ( effect ) { mlt_position position = mlt_filter_get_position( filter, frame ); mlt_position length = mlt_filter_get_length2( filter, frame ); bool ok = effect->set_float( "radius", mlt_properties_anim_get_double( properties, "radius", position, length ) ); ok |= effect->set_float( "blurred_mix_amount", mlt_properties_anim_get_double( properties, "mix", position, length ) ); assert(ok); } GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; return mlt_frame_get_image( frame, image, format, width, height, writable ); } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { if ( !mlt_frame_is_test_card( frame ) ) { if ( !GlslManager::get_effect( filter, frame ) ) GlslManager::add_effect( filter, frame, new DiffusionEffect() ); } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; } extern "C" { mlt_filter filter_movit_diffusion_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( filter = mlt_filter_new() ) ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties_set_double( properties, "radius", 3.0 ); mlt_properties_set_double( properties, "mix", 0.3 ); filter->process = process; } return filter; } } mlt-0.9.0/src/modules/opengl/filter_movit_diffusion.yml000066400000000000000000000020211215300731300233210ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: movit.diffusion title: Diffusion (GLSL) version: 1 copyright: Dan Dennedy creator: Steinar H. Gunderson license: GPLv2 language: en tags: - Video description: > There are many different effects that go under the name of "diffusion", seemingly all of the inspired by the effect you get when you put a diffusion filter in front of your camera lens. The effect most people want is a general flattening/smoothing of the light, and reduction of fine detail (most notably, blemishes in people's skin), without ruining edges, which a regular blur would do. We do a relatively simple version, sometimes known as "white diffusion", where we first blur the picture, and then overlay it on the original using the original as a matte. parameters: - identifier: radius title: Blur Radius type: float minimum: 0.0 default: 3.0 mutable: yes - identifier: mix title: Blurriness type: float minimum: 0.0 maximum: 1.0 default: 0.3 mutable: yes mlt-0.9.0/src/modules/opengl/filter_movit_glow.cpp000066400000000000000000000055151215300731300222770ustar00rootroot00000000000000/* * filter_movit_glow.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "glsl_manager.h" #include static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); Effect* effect = GlslManager::get_effect( filter, frame ); if ( effect ) { mlt_position position = mlt_filter_get_position( filter, frame ); mlt_position length = mlt_filter_get_length2( filter, frame ); bool ok = effect->set_float( "radius", mlt_properties_anim_get_double( properties, "radius", position, length ) ); ok |= effect->set_float( "blurred_mix_amount", mlt_properties_anim_get_double( properties, "blur_mix", position, length ) ); ok |= effect->set_float( "highlight_cutoff", mlt_properties_anim_get_double( properties, "highlight_cutoff", position, length ) ); assert(ok); } GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; return mlt_frame_get_image( frame, image, format, width, height, writable ); } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { if ( !mlt_frame_is_test_card( frame ) ) { if ( !GlslManager::get_effect( filter, frame ) ) GlslManager::add_effect( filter, frame, new GlowEffect() ); } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; } extern "C" { mlt_filter filter_movit_glow_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( filter = mlt_filter_new() ) ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties_set_double( properties, "radius", 20.0 ); mlt_properties_set_double( properties, "blur_mix", 1.0 ); mlt_properties_set_double( properties, "highlight_cutoff", 0.2 ); filter->process = process; } return filter; } } mlt-0.9.0/src/modules/opengl/filter_movit_glow.yml000066400000000000000000000013571215300731300223160ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: movit.glow title: Glow (GLSL) version: 1 copyright: Dan Dennedy creator: Steinar H. Gunderson license: GPLv2 language: en tags: - Video description: > Cut out the highlights of the image (everything above a certain threshold), blur them, and overlay them onto the original image. parameters: - identifier: radius title: Radius type: float minimum: 0.0 default: 20.0 mutable: yes - identifier: blur_mix title: Highlight Blurriness type: float minimum: 0.0 maximum: 1.0 default: 1.0 mutable: yes - identifier: highlight_cutoff title: Highlight Cutoff Threshold type: float minimum: 0.0 maximum: 1.0 default: 0.2 mutable: yes mlt-0.9.0/src/modules/opengl/filter_movit_mirror.cpp000066400000000000000000000027451215300731300226430ustar00rootroot00000000000000/* * filter_movit_mirror.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "glsl_manager.h" #include static mlt_frame process( mlt_filter filter, mlt_frame frame ) { if ( !mlt_frame_is_test_card( frame ) ) { Effect* effect = GlslManager::get_effect( filter, frame ); if ( !effect ) GlslManager::add_effect( filter, frame, new MirrorEffect() ); } return frame; } extern "C" { mlt_filter filter_movit_mirror_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( filter = mlt_filter_new() ) ) { filter->process = process; } return filter; } } mlt-0.9.0/src/modules/opengl/filter_movit_mirror.yml000066400000000000000000000003471215300731300226560ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: movit.mirror title: Mirror (GLSL) version: 1 copyright: Dan Dennedy creator: Steinar H. Gunderson license: GPLv2 language: en description: A simple horizontal mirroring. tags: - Video mlt-0.9.0/src/modules/opengl/filter_movit_opacity.cpp000066400000000000000000000052141215300731300227730ustar00rootroot00000000000000/* * filter_movit_opacity.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "glsl_manager.h" #include static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); Effect* effect = GlslManager::get_effect( filter, frame ); if ( effect ) { mlt_position position = mlt_filter_get_position( filter, frame ); mlt_position length = mlt_filter_get_length2( filter, frame ); bool ok = effect->set_float( "strength_first", mlt_properties_anim_get_double( properties, "opacity", position, length ) ); assert(ok); } GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; return mlt_frame_get_image( frame, image, format, width, height, writable ); } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { if ( !mlt_frame_is_test_card( frame ) ) { Effect* effect = GlslManager::get_effect( filter, frame ); if ( !effect ) { effect = GlslManager::add_effect( filter, frame, new MixEffect, 0 ); assert(effect); bool ok = effect->set_float( "strength_first", 1.0f ); ok |= effect->set_float( "strength_second", 0.0f ); assert(ok); } } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; } extern "C" mlt_filter filter_movit_opacity_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( filter = mlt_filter_new() ) ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties_set( properties, "opacity", arg? arg : "1" ); filter->process = process; } return filter; } mlt-0.9.0/src/modules/opengl/filter_movit_opacity.yml000066400000000000000000000013231215300731300230070ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: movit.opacity title: Opacity (GLSL) version: 1 copyright: Dan Dennedy creator: Steinar H. Gunderson license: GPLv2 language: en tags: - Video description: Adjust the opacity of an image through the alpha channel. notes: > When used in some transitions this will cause this video to be mixed with the other video. If the video this is applied to already has an alpha channel, then this preserves that by multiplying the opacity level with the alpha channel. This filter is especially handy when used in conjunction with movit.overlay. parameters: - identifier: opacity title: Opacity type: float minimum: 0 maximum: 1 default: 1 mutable: yes mlt-0.9.0/src/modules/opengl/filter_movit_rect.cpp000066400000000000000000000036501215300731300222620ustar00rootroot00000000000000/* * filter_movit_rect.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "glsl_manager.h" static mlt_frame process( mlt_filter filter, mlt_frame frame ) { // Drive the resize and resample filters on the b_frame for these composite parameters mlt_properties properties = MLT_FILTER_PROPERTIES(filter); mlt_properties frame_props = MLT_FRAME_PROPERTIES(frame); mlt_properties_set( frame_props, "resize.rect", mlt_properties_get( properties, "rect" ) ); mlt_properties_set( frame_props, "resize.fill", mlt_properties_get( properties, "fill" ) ); mlt_properties_set( frame_props, "resize.halign", mlt_properties_get( properties, "halign" ) ); mlt_properties_set( frame_props, "resize.valign", mlt_properties_get( properties, "valign" ) ); return frame; } extern "C" mlt_filter filter_movit_rect_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( filter = mlt_filter_new() ) ) { mlt_properties_set( MLT_FILTER_PROPERTIES(filter), "rect", arg ); mlt_properties_set_int( MLT_FILTER_PROPERTIES(filter), "fill", 1 ); filter->process = process; } return filter; } mlt-0.9.0/src/modules/opengl/filter_movit_rect.yml000066400000000000000000000024031215300731300222740ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: movit.rect title: Position and Size (GLSL) version: 1 copyright: Dan Dennedy creator: Steinar H. Gunderson license: GPLv2 language: en tags: - Video description: > Change the coordinates and scale to fit within a rectangle. parameters: - identifier: rect title: Rectangle type: geometry description: > Keyframable rectangle specification. mutable: yes - identifier: fill title: Upscale to Fill description: > Determines whether the image will be scaled up to fill the rectangle or whether the size will be constrained to 100% of the profile resolution. type: integer default: 1 minimum: 0 maximum: 1 mutable: yes widget: checkbox - identifier: halign title: Horizontal alignment description: > Set the horizontal alignment within the geometry rectangle. type: string default: left values: - left - center - right mutable: yes widget: combo - identifier: valign title: Vertical alignment description: > Set the vertical alignment within the geometry rectangle. type: string default: top values: - top - middle - bottom mutable: yes widget: combo mlt-0.9.0/src/modules/opengl/filter_movit_resample.cpp000066400000000000000000000065671215300731300231470ustar00rootroot00000000000000/* * filter_movit_resample.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "glsl_manager.h" #include static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); // Correct width/height if necessary if ( *width == 0 || *height == 0 ) { *width = profile->width; *height = profile->height; } int iwidth = *width; int iheight = *height; double factor = mlt_properties_get_double( filter_properties, "factor" ); factor = factor > 0 ? factor : 1.0; int owidth = *width * factor; int oheight = *height * factor; // If meta.media.width/height exist, we want that as minimum information if ( mlt_properties_get_int( properties, "meta.media.width" ) ) { iwidth = mlt_properties_get_int( properties, "meta.media.width" ); iheight = mlt_properties_get_int( properties, "meta.media.height" ); } mlt_properties_set_int( properties, "rescale_width", *width ); mlt_properties_set_int( properties, "rescale_height", *height ); // Deinterlace if height is changing to prevent fields mixing on interpolation if ( iheight != oheight ) mlt_properties_set_int( properties, "consumer_deinterlace", 1 ); // Get the image as requested if ( *format != mlt_image_none ) *format = mlt_image_glsl; error = mlt_frame_get_image( frame, image, format, &iwidth, &iheight, writable ); if ( !error ) { GlslManager::get_instance()->lock_service( frame ); Effect* effect = GlslManager::get_effect( filter, frame ); if ( effect ) { bool ok = effect->set_int( "width", owidth ); ok |= effect->set_int( "height", oheight ); assert(ok); *width = owidth; *height = oheight; } GlslManager::get_instance()->unlock_service( frame ); } return error; } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { if ( !GlslManager::get_effect( filter, frame ) ) GlslManager::add_effect( filter, frame, new ResampleEffect ); mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; } extern "C" mlt_filter filter_movit_resample_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( filter = mlt_filter_new() ) ) { filter->process = process; } return filter; } mlt-0.9.0/src/modules/opengl/filter_movit_resize.cpp000066400000000000000000000150741215300731300226310ustar00rootroot00000000000000/* * filter_movit_resize.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include "glsl_manager.h" #include #include static float alignment_parse( char* align ) { int ret = 0.0f; if ( align == NULL ); else if ( isdigit( align[ 0 ] ) ) ret = atoi( align ); else if ( align[ 0 ] == 'c' || align[ 0 ] == 'm' ) ret = 1.0f; else if ( align[ 0 ] == 'r' || align[ 0 ] == 'b' ) ret = 2.0f; return ret; } static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); // Retrieve the aspect ratio double aspect_ratio = mlt_frame_get_aspect_ratio( frame ); double consumer_aspect = mlt_profile_sar( profile ); // Correct Width/height if necessary if ( *width == 0 || *height == 0 ) { *width = profile->width; *height = profile->height; } // Assign requested width/height from our subordinate int owidth = *width; int oheight = *height; // Use a mlt_rect to compute position and size mlt_rect rect; rect.x = rect.y = 0.0; if ( mlt_properties_get( properties, "resize.rect" ) ) { mlt_position position = mlt_filter_get_position( filter, frame ); mlt_position length = mlt_filter_get_length2( filter, frame ); rect = mlt_properties_anim_get_rect( properties, "resize.rect", position, length ); if ( strchr( mlt_properties_get( properties, "resize.rect" ), '%' ) ) { rect.x *= profile->width; rect.w *= profile->width; rect.y *= profile->height; rect.h *= profile->height; } if ( !mlt_properties_get_int( properties, "resize.fill" ) ) { int x = mlt_properties_get_int( properties, "meta.media.width" ); rect.w = rect.w > x ? x : rect.w; x = mlt_properties_get_int( properties, "meta.media.height" ); rect.h = rect.h > x ? x : rect.h; } owidth = lrintf( rect.w ); oheight = lrintf( rect.h ); } // Check for the special case - no aspect ratio means no problem :-) if ( aspect_ratio == 0.0 ) aspect_ratio = consumer_aspect; // Reset the aspect ratio mlt_properties_set_double( properties, "aspect_ratio", aspect_ratio ); // Skip processing if requested. char *rescale = mlt_properties_get( properties, "rescale.interp" ); if ( *format == mlt_image_none || ( rescale && !strcmp( rescale, "none" ) ) ) return mlt_frame_get_image( frame, image, format, width, height, writable ); if ( mlt_properties_get_int( properties, "distort" ) == 0 ) { // Normalise the input and out display aspect int normalised_width = profile->width; int normalised_height = profile->height; int real_width = mlt_properties_get_int( properties, "meta.media.width" ); int real_height = mlt_properties_get_int( properties, "meta.media.height" ); if ( real_width == 0 ) real_width = mlt_properties_get_int( properties, "width" ); if ( real_height == 0 ) real_height = mlt_properties_get_int( properties, "height" ); double input_ar = aspect_ratio * real_width / real_height; double output_ar = consumer_aspect * owidth / oheight; // Optimised for the input_ar > output_ar case (e.g. widescreen on standard) int scaled_width = lrint( ( input_ar * normalised_width ) / output_ar ); int scaled_height = normalised_height; // Now ensure that our images fit in the output frame if ( scaled_width > normalised_width ) { scaled_width = normalised_width; scaled_height = lrint( ( output_ar * normalised_height ) / input_ar ); } // Now calculate the actual image size that we want owidth = lrint( scaled_width * owidth / normalised_width ); oheight = lrint( scaled_height * oheight / normalised_height ); mlt_log_debug( MLT_FILTER_SERVICE(filter), "real %dx%d normalised %dx%d output %dx%d sar %f in-dar %f out-dar %f\n", real_width, real_height, normalised_width, normalised_height, owidth, oheight, aspect_ratio, input_ar, output_ar); // Tell frame we have conformed the aspect to the consumer mlt_frame_set_aspect_ratio( frame, consumer_aspect ); } mlt_properties_set_int( properties, "distort", 0 ); // Now get the image *format = mlt_image_glsl; error = mlt_frame_get_image( frame, image, format, &owidth, &oheight, writable ); // Offset the position according to alignment float w = float( *width - owidth ); float h = float( *height - oheight ); if ( mlt_properties_get( properties, "resize.rect" ) ) { // default left if rect supplied rect.x += w * alignment_parse( mlt_properties_get( properties, "resize.halign" ) ) / 2.0f; rect.y += h * alignment_parse( mlt_properties_get( properties, "resize.valign" ) ) / 2.0f; } else { // default center if no rect rect.x = w * 0.5f; rect.y = h * 0.5f; } if ( !error ) { GlslManager::get_instance()->lock_service( frame ); Effect* effect = GlslManager::get_effect( filter, frame ); if ( effect ) { bool ok = effect->set_int( "width", *width ); ok |= effect->set_int( "height", *height ); ok |= effect->set_float( "left", rect.x ); ok |= effect->set_float( "top", rect.y ); assert(ok); } GlslManager::get_instance()->unlock_service( frame ); } return error; } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { if ( !GlslManager::get_effect( filter, frame ) ) GlslManager::add_effect( filter, frame, new PaddingEffect ); mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; } extern "C" mlt_filter filter_movit_resize_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( filter = mlt_filter_new() ) ) { filter->process = process; } return filter; } mlt-0.9.0/src/modules/opengl/filter_movit_saturation.cpp000066400000000000000000000047541215300731300235240ustar00rootroot00000000000000/* * filter_movit_saturation.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "glsl_manager.h" #include static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); Effect* effect = GlslManager::get_effect( filter, frame ); if ( effect ) { mlt_position position = mlt_filter_get_position( filter, frame ); mlt_position length = mlt_filter_get_length2( filter, frame ); bool ok = effect->set_float( "saturation", mlt_properties_anim_get_double( properties, "saturation", position, length ) ); assert(ok); } GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; return mlt_frame_get_image( frame, image, format, width, height, writable ); } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { if ( !mlt_frame_is_test_card( frame ) ) { if ( !GlslManager::get_effect( filter, frame ) ) GlslManager::add_effect( filter, frame, new SaturationEffect() ); } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; } extern "C" { mlt_filter filter_movit_saturation_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( filter = mlt_filter_new() ) ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties_set( properties, "saturation", arg? arg : "1.0" ); filter->process = process; } return filter; } } mlt-0.9.0/src/modules/opengl/filter_movit_saturation.yml000066400000000000000000000012141215300731300235270ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: movit.saturation title: Saturation (GLSL) version: 1 copyright: Dan Dennedy creator: Steinar H. Gunderson license: GPLv2 language: en tags: - Video description: > A simple desaturation/saturation effect. We use the Rec. 709 definition of luminance (in linear light, of course) and linearly interpolate between that (saturation=0) and the original signal (saturation=1). Extrapolating that curve further (ie., saturation > 1) gives us increased saturation if so desired. parameters: - identifier: saturation title: Saturation type: float minimum: 0 default: 1 mutable: yes mlt-0.9.0/src/modules/opengl/filter_movit_vignette.cpp000066400000000000000000000051711215300731300231520ustar00rootroot00000000000000/* * filter_movit_vignette.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "glsl_manager.h" #include static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); Effect* effect = GlslManager::get_effect( filter, frame ); if ( effect ) { mlt_position position = mlt_filter_get_position( filter, frame ); mlt_position length = mlt_filter_get_length2( filter, frame ); bool ok = effect->set_float( "radius", mlt_properties_anim_get_double( properties, "radius", position, length ) ); ok |= effect->set_float( "inner_radius", mlt_properties_anim_get_double( properties, "inner_radius", position, length ) ); assert(ok); } GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; return mlt_frame_get_image( frame, image, format, width, height, writable ); } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { if ( !mlt_frame_is_test_card( frame ) ) { if ( !GlslManager::get_effect( filter, frame ) ) GlslManager::add_effect( filter, frame, new VignetteEffect() ); } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; } extern "C" { mlt_filter filter_movit_vignette_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( filter = mlt_filter_new() ) ) { filter->process = process; mlt_properties_set_double( MLT_FILTER_PROPERTIES(filter), "radius", 0.3 ); mlt_properties_set_double( MLT_FILTER_PROPERTIES(filter), "inner_radius", 0.3 ); } return filter; } } mlt-0.9.0/src/modules/opengl/filter_movit_vignette.yml000066400000000000000000000011531215300731300231650ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: movit.vignette title: Vignette (GLSL) version: 1 copyright: Dan Dennedy creator: Steinar H. Gunderson license: GPLv2 language: en tags: - Video description: > A circular vignette, falling off as cos² of the distance from the center (the classic formula for approximating a real lens). parameters: - identifier: radius title: Outer Radius type: float minimum: 0.0 maximum: 1.0 default: 0.3 mutable: yes - identifier: inner_radius title: Inner Radius type: float minimum: 0.0 maximum: 1.0 default: 0.3 mutable: yes mlt-0.9.0/src/modules/opengl/filter_white_balance.cpp000066400000000000000000000056111215300731300226730ustar00rootroot00000000000000/* * filter_white_balance.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "glsl_manager.h" #include static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); Effect* effect = GlslManager::get_effect( filter, frame ); if ( effect ) { mlt_position position = mlt_filter_get_position( filter, frame ); mlt_position length = mlt_filter_get_length2( filter, frame ); int color_int = mlt_properties_anim_get_int( properties, "neutral_color", position, length ); RGBTriplet color( float((color_int >> 24) & 0xff) / 255.0f, float((color_int >> 16) & 0xff) / 255.0f, float((color_int >> 8) & 0xff) / 255.0f ); bool ok = effect->set_vec3( "neutral_color", (float*) &color ); ok |= effect->set_float( "output_color_temperature", mlt_properties_anim_get_double( properties, "color_temperature", position, length ) ); assert(ok); } GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; return mlt_frame_get_image( frame, image, format, width, height, writable ); } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { if ( !mlt_frame_is_test_card( frame ) ) { if ( !GlslManager::get_effect( filter, frame ) ) GlslManager::add_effect( filter, frame, new WhiteBalanceEffect ); } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; } extern "C" { mlt_filter filter_white_balance_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( filter = mlt_filter_new() ) ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties_set( properties, "neutral_color", arg? arg : "#7f7f7f" ); mlt_properties_set_double( properties, "color_temperature", 6500.0 ); filter->process = process; } return filter; } } mlt-0.9.0/src/modules/opengl/filter_white_balance.yml000066400000000000000000000010721215300731300227070ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: movit.white_balance title: White Balance (GLSL) version: 1 copyright: Dan Dennedy creator: Steinar H. Gunderson license: GPLv2 language: en tags: - Video description: Color correction in LMS color space. parameters: - identifier: neutral_color title: Neutral Color type: string widget: color default: 0x7f7f7f00 mutable: yes - identifier: color_temperature title: Color Temperature type: float minimum: 1000.0 maximum: 15000.0 default: 6500.0 unit: Kelvin mutable: yes mlt-0.9.0/src/modules/opengl/glsl_manager.h000066400000000000000000000055041215300731300206420ustar00rootroot00000000000000/* * glsl_manager.h * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef GLSL_MANAGER_H #define GLSL_MANAGER_H #include #include #include #define MAXLISTCOUNT 1024 typedef struct glsl_list_s *glsl_list; struct glsl_list_s { void *items[MAXLISTCOUNT]; int count; int ( *add )( glsl_list, void* ); void* ( *at )( glsl_list, int ); void* ( *take_at )( glsl_list, int ); void* ( *take )( glsl_list, void* ); }; struct glsl_texture_s { int used; GLuint texture; int width; int height; GLint internal_format; }; typedef struct glsl_texture_s *glsl_texture; struct glsl_fbo_s { int used; int width; int height; GLuint fbo; }; typedef struct glsl_fbo_s *glsl_fbo; struct glsl_pbo_s { int size; GLuint pbo; }; typedef struct glsl_pbo_s *glsl_pbo; class Effect; class EffectChain; class MltInput; class GlslManager : public Mlt::Filter { public: GlslManager(); ~GlslManager(); static GlslManager* get_instance(); glsl_fbo get_fbo(int width, int height); static void release_fbo(glsl_fbo); glsl_texture get_texture(int width, int height, GLint internal_format); static void release_texture(glsl_texture); glsl_pbo get_pbo(int size); Properties effect_list( Mlt::Service &service ); static bool init_chain(mlt_service); static EffectChain* get_chain(mlt_service); static MltInput* get_input(mlt_service); static void reset_finalized(mlt_service); static Effect* get_effect(mlt_filter, mlt_frame); static Effect* add_effect(mlt_filter, mlt_frame, Effect*); static Effect* add_effect(mlt_filter, mlt_frame, Effect*, Effect* input_b); static void render(mlt_service, void *chain, GLuint fbo, int width, int height); static void lock_service(mlt_frame frame); static void unlock_service(mlt_frame frame); private: static void onInit( mlt_properties owner, GlslManager* filter ); static void onServiceChanged( mlt_properties owner, mlt_service service ); static void onPropertyChanged( mlt_properties owner, mlt_service service, const char* property ); Mlt::Deque fbo_list; Mlt::Deque texture_list; glsl_pbo pbo; Mlt::Event* initEvent; }; #endif // GLSL_MANAGER_H mlt-0.9.0/src/modules/opengl/mlt_flip_effect.h000066400000000000000000000025321215300731300213270ustar00rootroot00000000000000/* * mlt_flip_effect.h * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef MLT_FLIP_EFFECT_H #define MLT_FLIP_EFFECT_H namespace Mlt { class VerticalFlip : public Effect { public: VerticalFlip() {} virtual std::string effect_type_id() const { return "MltVerticalFlip"; } std::string output_fragment_shader() { return "vec4 FUNCNAME(vec2 tc) { tc.y = 1.0 - tc.y; return INPUT(tc); }\n"; } virtual bool needs_linear_light() const { return false; } virtual bool needs_srgb_primaries() const { return false; } AlphaHandling alpha_handling() const { return DONT_CARE_ALPHA_TYPE; } }; } // namespace Mlt #endif // MLT_FLIP_EFFECT_H mlt-0.9.0/src/modules/opengl/mlt_movit_input.cpp000066400000000000000000000074311215300731300217740ustar00rootroot00000000000000/* * mlt_movit_input.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "mlt_movit_input.h" #include "fbo_input.h" MltInput::MltInput(unsigned width, unsigned height) : m_width(width) , m_height(height) , output_linear_gamma(false) , needs_mipmaps(false) , input(0) , isRGB(true) { register_int("output_linear_gamma", &output_linear_gamma); register_int("needs_mipmaps", &needs_mipmaps); } MltInput::~MltInput() { // XXX: this is crashing when a producer is closed // on Windows when using melt with qglsl. // delete input; } std::string MltInput::output_fragment_shader() { assert(input); return input->output_fragment_shader(); } void MltInput::set_gl_state(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num) { assert(input); input->set_gl_state(glsl_program_num, prefix, sampler_num); } Effect::AlphaHandling MltInput::alpha_handling() const { assert(input); return input->alpha_handling(); } void MltInput::finalize() { assert(input); bool ok = input->set_int("output_linear_gamma", output_linear_gamma); ok |= input->set_int("needs_mipmaps", needs_mipmaps); assert(ok); input->finalize(); } bool MltInput::can_output_linear_gamma() const { assert(input); return input->can_output_linear_gamma(); } Colorspace MltInput::get_color_space() const { assert(input); return input->get_color_space(); } GammaCurve MltInput::get_gamma_curve() const { assert(input); return input->get_gamma_curve(); } void MltInput::useFlatInput(EffectChain* chain, MovitPixelFormat pix_fmt, unsigned width, unsigned height) { if (!input) { m_width = width; m_height = height; ImageFormat image_format; image_format.color_space = COLORSPACE_sRGB; image_format.gamma_curve = GAMMA_sRGB; input = new FlatInput(image_format, pix_fmt, GL_UNSIGNED_BYTE, width, height); chain->add_output(image_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED); chain->set_dither_bits(8); } } void MltInput::useYCbCrInput(EffectChain* chain, const ImageFormat& image_format, const YCbCrFormat& ycbcr_format, unsigned width, unsigned height) { if (!input) { m_width = width; m_height = height; input = new YCbCrInput(image_format, ycbcr_format, width, height); ImageFormat output_format; output_format.color_space = COLORSPACE_sRGB; output_format.gamma_curve = GAMMA_sRGB; chain->add_output(output_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED); chain->set_dither_bits(8); isRGB = false; m_ycbcr_format = ycbcr_format; } } void MltInput::useFBOInput(EffectChain *chain, GLuint texture) { if (!input) { FBOInput* fboInput = new FBOInput(m_width, m_height); input = fboInput; fboInput->set_texture(texture); } } void MltInput::set_pixel_data(const unsigned char* data) { assert(input); if (isRGB) { FlatInput* flat = (FlatInput*) input; flat->set_pixel_data(data); } else { YCbCrInput* ycbcr = (YCbCrInput*) input; ycbcr->set_pixel_data(0, data); ycbcr->set_pixel_data(1, &data[m_width * m_height]); ycbcr->set_pixel_data(2, &data[m_width * m_height + (m_width / m_ycbcr_format.chroma_subsampling_x * m_height / m_ycbcr_format.chroma_subsampling_y)]); } } mlt-0.9.0/src/modules/opengl/mlt_movit_input.h000066400000000000000000000040501215300731300214330ustar00rootroot00000000000000/* * mlt_movit_input.h * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef MLT_MOVIT_INPUT_H #define MLT_MOVIT_INPUT_H #include #include #include class MltInput : public Input { public: MltInput(unsigned width, unsigned height); ~MltInput(); // Effect overrides std::string effect_type_id() const { return "MltInput"; } Effect::AlphaHandling alpha_handling() const; std::string output_fragment_shader(); void set_gl_state(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num); // Input ovverrides void finalize(); bool can_output_linear_gamma() const; unsigned get_width() const { return m_width; } unsigned get_height() const { return m_height; } Colorspace get_color_space() const; GammaCurve get_gamma_curve() const; // Custom methods void useFlatInput(EffectChain* chain, MovitPixelFormat pix_fmt, unsigned width, unsigned height); void useYCbCrInput(EffectChain* chain, const ImageFormat& image_format, const YCbCrFormat& ycbcr_format, unsigned width, unsigned height); void useFBOInput(EffectChain* chain, GLuint texture); void set_pixel_data(const unsigned char* data); private: unsigned m_width, m_height; int output_linear_gamma, needs_mipmaps; Input *input; bool isRGB; YCbCrFormat m_ycbcr_format; }; #endif // MLT_MOVIT_INPUT_H mlt-0.9.0/src/modules/opengl/transition_movit_mix.cpp000066400000000000000000000176451215300731300230400ustar00rootroot00000000000000/* * transition_movit_mix.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "glsl_manager.h" #include #include #include #include #include "mlt_movit_input.h" #include "mlt_flip_effect.h" static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; // Get the b frame from the stack mlt_frame b_frame = (mlt_frame) mlt_frame_pop_frame( a_frame ); // Get the transition object mlt_transition transition = (mlt_transition) mlt_frame_pop_service( a_frame ); // Get the properties of the transition mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); // Get the properties of the a frame mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); // Get the movit objects mlt_service service = MLT_TRANSITION_SERVICE( transition ); mlt_service_lock( service ); EffectChain* chain = GlslManager::get_chain( service ); Effect* effect = (Effect*) mlt_properties_get_data( properties, "movit effect", NULL ); MltInput* a_input = GlslManager::get_input( service ); MltInput* b_input = (MltInput*) mlt_properties_get_data( properties, "movit input B", NULL ); mlt_image_format output_format = *format; if ( !chain || !a_input ) { mlt_service_unlock( service ); return 2; } // Get the transition parameters mlt_position position = mlt_transition_get_position( transition, a_frame ); mlt_position length = mlt_transition_get_length( transition ); int reverse = mlt_properties_get_int( properties, "reverse" ); double mix = mlt_properties_get( properties, "mix" ) ? mlt_properties_anim_get_double( properties, "mix", position, length ) : mlt_transition_get_progress( transition, a_frame ); double inverse = 1.0 - mix; // Set the movit parameters bool ok = effect->set_float( "strength_first", reverse ? mix : inverse ); ok |= effect->set_float( "strength_second", reverse ? inverse : mix ); assert( ok ); // Get the frames' textures GLuint* texture_id[2] = {0, 0}; *format = mlt_image_glsl_texture; mlt_frame_get_image( a_frame, (uint8_t**) &texture_id[0], format, width, height, 0 ); a_input->useFBOInput( chain, *texture_id[0] ); *format = mlt_image_glsl_texture; mlt_frame_get_image( b_frame, (uint8_t**) &texture_id[1], format, width, height, 0 ); b_input->useFBOInput( chain, *texture_id[1] ); // Set resolution to that of the a_frame *width = mlt_properties_get_int( a_props, "width" ); *height = mlt_properties_get_int( a_props, "height" ); // Setup rendering to an FBO GlslManager* glsl = GlslManager::get_instance(); glsl_fbo fbo = glsl->get_fbo( *width, *height ); if ( output_format == mlt_image_glsl_texture ) { glsl_texture texture = glsl->get_texture( *width, *height, GL_RGBA ); glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo ); check_error(); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 ); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); GlslManager::render( service, chain, fbo->fbo, *width, *height ); glFinish(); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); *image = (uint8_t*) &texture->texture; mlt_frame_set_image( a_frame, *image, 0, NULL ); mlt_properties_set_data( properties, "movit.convert", texture, 0, (mlt_destructor) GlslManager::release_texture, NULL ); *format = output_format; } else { // Use a PBO to hold the data we read back with glReadPixels() // (Intel/DRI goes into a slow path if we don't read to PBO) GLenum gl_format = ( output_format == mlt_image_rgb24a || output_format == mlt_image_opengl )? GL_RGBA : GL_RGB; int img_size = *width * *height * ( gl_format == GL_RGB? 3 : 4 ); glsl_pbo pbo = glsl->get_pbo( img_size ); glsl_texture texture = glsl->get_texture( *width, *height, gl_format ); if ( fbo && pbo && texture ) { // Set the FBO glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo ); check_error(); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 ); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); GlslManager::render( service, chain, fbo->fbo, *width, *height ); // Read FBO into PBO glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, pbo->pbo ); check_error(); glBufferData( GL_PIXEL_PACK_BUFFER_ARB, img_size, NULL, GL_STREAM_READ ); check_error(); glReadPixels( 0, 0, *width, *height, gl_format, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0) ); check_error(); // Copy from PBO uint8_t* buf = (uint8_t*) glMapBuffer( GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY ); check_error(); *format = gl_format == GL_RGBA ? mlt_image_rgb24a : mlt_image_rgb24; *image = (uint8_t*) mlt_pool_alloc( img_size ); mlt_frame_set_image( a_frame, *image, img_size, mlt_pool_release ); memcpy( *image, buf, img_size ); // Release PBO and FBO glUnmapBuffer( GL_PIXEL_PACK_BUFFER_ARB ); check_error(); glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, 0 ); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); glBindTexture( GL_TEXTURE_2D, 0 ); check_error(); GlslManager::release_texture( texture ); } else { error = 1; } } if ( fbo ) GlslManager::release_fbo( fbo ); mlt_service_unlock( service ); return error; } static mlt_frame process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ) { mlt_service service = MLT_TRANSITION_SERVICE(transition); if ( !GlslManager::init_chain( service ) ) { // Create the Movit effect chain EffectChain* chain = GlslManager::get_chain( service ); mlt_profile profile = mlt_service_profile( service ); Input* b_input = new MltInput( profile->width, profile->height ); ImageFormat output_format; output_format.color_space = COLORSPACE_sRGB; output_format.gamma_curve = GAMMA_sRGB; chain->add_input( b_input ); chain->add_output( output_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED ); chain->set_dither_bits( 8 ); Effect* effect = chain->add_effect( new MixEffect(), GlslManager::get_input( service ), b_input ); // Save these new effects on properties for get_image mlt_properties properties = MLT_TRANSITION_PROPERTIES(transition); mlt_properties_set_data( properties, "movit effect", effect, 0, NULL, NULL ); mlt_properties_set_data( properties, "movit input B", b_input, 0, NULL, NULL ); } // Push the transition on to the frame mlt_frame_push_service( a_frame, transition ); // Push the b_frame on to the stack mlt_frame_push_frame( a_frame, b_frame ); // Push the transition method mlt_frame_push_get_image( a_frame, get_image ); return a_frame; } extern "C" mlt_transition transition_movit_mix_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_transition transition = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( transition = mlt_transition_new() ) ) { transition->process = process; mlt_properties_set( MLT_TRANSITION_PROPERTIES( transition ), "mix", arg ); // Inform apps and framework that this is a video only transition mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "_transition_type", 1 ); } return transition; } mlt-0.9.0/src/modules/opengl/transition_movit_mix.yml000066400000000000000000000014041215300731300230410ustar00rootroot00000000000000schema_version: 0.1 type: transition identifier: movit.mix title: Dissolve (GLSL) version: 1 copyright: Dan Dennedy creator: Steinar H. Gunderson license: GPLv2 language: en tags: - Video description: A simple video cross-fade or mixing effect. parameters: - identifier: argument title: Mix Level description: Performs a dissolve if a mix level is not supplied. type: float minimum: 0 maximum: 1 mutable: yes - identifier: mix title: Mix Level description: Performs a dissolve if a mix level is not supplied. type: float minimum: 0 maximum: 1 mutable: yes - identifier: reverse title: Reverse type: integer mutable: yes description: > Reverse the direction of the transition. default: 0 mlt-0.9.0/src/modules/opengl/transition_movit_overlay.cpp000066400000000000000000000160121215300731300237070ustar00rootroot00000000000000/* * transition_movit_overlay.cpp * Copyright (C) 2013 Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "glsl_manager.h" #include #include #include #include #include "mlt_movit_input.h" #include "mlt_flip_effect.h" static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; // Get the b frame from the stack mlt_frame b_frame = (mlt_frame) mlt_frame_pop_frame( a_frame ); // Get the transition object mlt_transition transition = (mlt_transition) mlt_frame_pop_service( a_frame ); // Get the properties of the transition mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); // Get the properties of the a frame mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); // Get the movit objects mlt_service service = MLT_TRANSITION_SERVICE( transition ); mlt_service_lock( service ); EffectChain* chain = GlslManager::get_chain( service ); MltInput* a_input = GlslManager::get_input( service ); MltInput* b_input = (MltInput*) mlt_properties_get_data( properties, "movit input B", NULL ); mlt_image_format output_format = *format; if ( !chain || !a_input ) { mlt_service_unlock( service ); return 2; } // Get the frames' textures GLuint* texture_id[2] = {0, 0}; *format = mlt_image_glsl_texture; mlt_frame_get_image( a_frame, (uint8_t**) &texture_id[0], format, width, height, 0 ); a_input->useFBOInput( chain, *texture_id[0] ); *format = mlt_image_glsl_texture; mlt_frame_get_image( b_frame, (uint8_t**) &texture_id[1], format, width, height, 0 ); b_input->useFBOInput( chain, *texture_id[1] ); // Set resolution to that of the a_frame *width = mlt_properties_get_int( a_props, "width" ); *height = mlt_properties_get_int( a_props, "height" ); // Setup rendering to an FBO GlslManager* glsl = GlslManager::get_instance(); glsl_fbo fbo = glsl->get_fbo( *width, *height ); if ( output_format == mlt_image_glsl_texture ) { glsl_texture texture = glsl->get_texture( *width, *height, GL_RGBA ); glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo ); check_error(); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 ); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); GlslManager::render( service, chain, fbo->fbo, *width, *height ); glFinish(); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); *image = (uint8_t*) &texture->texture; mlt_frame_set_image( a_frame, *image, 0, NULL ); mlt_properties_set_data( properties, "movit.convert", texture, 0, (mlt_destructor) GlslManager::release_texture, NULL ); *format = output_format; } else { // Use a PBO to hold the data we read back with glReadPixels() // (Intel/DRI goes into a slow path if we don't read to PBO) GLenum gl_format = ( output_format == mlt_image_rgb24a || output_format == mlt_image_opengl )? GL_RGBA : GL_RGB; int img_size = *width * *height * ( gl_format == GL_RGB? 3 : 4 ); glsl_pbo pbo = glsl->get_pbo( img_size ); glsl_texture texture = glsl->get_texture( *width, *height, gl_format ); if ( fbo && pbo && texture ) { // Set the FBO glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo ); check_error(); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 ); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); GlslManager::render( service, chain, fbo->fbo, *width, *height ); // Read FBO into PBO glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, pbo->pbo ); check_error(); glBufferData( GL_PIXEL_PACK_BUFFER_ARB, img_size, NULL, GL_STREAM_READ ); check_error(); glReadPixels( 0, 0, *width, *height, gl_format, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0) ); check_error(); // Copy from PBO uint8_t* buf = (uint8_t*) glMapBuffer( GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY ); check_error(); *format = gl_format == GL_RGBA ? mlt_image_rgb24a : mlt_image_rgb24; *image = (uint8_t*) mlt_pool_alloc( img_size ); mlt_frame_set_image( a_frame, *image, img_size, mlt_pool_release ); memcpy( *image, buf, img_size ); // Release PBO and FBO glUnmapBuffer( GL_PIXEL_PACK_BUFFER_ARB ); check_error(); glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, 0 ); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); glBindTexture( GL_TEXTURE_2D, 0 ); check_error(); GlslManager::release_texture( texture ); } else { error = 1; } } if ( fbo ) GlslManager::release_fbo( fbo ); mlt_service_lock( service ); return error; } static mlt_frame process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ) { mlt_service service = MLT_TRANSITION_SERVICE(transition); if ( !GlslManager::init_chain( service ) ) { // Create the Movit effect chain EffectChain* chain = GlslManager::get_chain( service ); mlt_profile profile = mlt_service_profile( service ); Input* b_input = new MltInput( profile->width, profile->height ); ImageFormat output_format; output_format.color_space = COLORSPACE_sRGB; output_format.gamma_curve = GAMMA_sRGB; chain->add_input( b_input ); chain->add_output( output_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED ); chain->set_dither_bits( 8 ); Effect* effect = chain->add_effect( new OverlayEffect(), GlslManager::get_input( service ), b_input ); // Save these new input on properties for get_image mlt_properties_set_data( MLT_TRANSITION_PROPERTIES(transition), "movit input B", b_input, 0, NULL, NULL ); } // Push the transition on to the frame mlt_frame_push_service( a_frame, transition ); // Push the b_frame on to the stack mlt_frame_push_frame( a_frame, b_frame ); // Push the transition method mlt_frame_push_get_image( a_frame, get_image ); return a_frame; } extern "C" mlt_transition transition_movit_overlay_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_transition transition = NULL; GlslManager* glsl = GlslManager::get_instance(); if ( glsl && ( transition = mlt_transition_new() ) ) { transition->process = process; // Inform apps and framework that this is a video only transition mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "_transition_type", 1 ); } return transition; } mlt-0.9.0/src/modules/opengl/transition_movit_overlay.yml000066400000000000000000000004541215300731300237310ustar00rootroot00000000000000schema_version: 0.1 type: transition identifier: movit.overlay title: Dissolve (GLSL) version: 1 copyright: Dan Dennedy creator: Steinar H. Gunderson license: GPLv2 language: en tags: - Video description: > A simple video overlay or alpha-compositing effect using the Porter-Duff over operation. mlt-0.9.0/src/modules/plus/000077500000000000000000000000001215300731300155315ustar00rootroot00000000000000mlt-0.9.0/src/modules/plus/Makefile000066400000000000000000000012641215300731300171740ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lm include ../../../config.mak TARGET = ../libmltplus$(LIBSUF) OBJS = factory.o \ filter_affine.o \ filter_charcoal.o \ filter_invert.o \ filter_sepia.o \ transition_affine.o SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/plus" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/plus" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/plus/factory.c000066400000000000000000000047261215300731300173550ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include extern mlt_filter filter_affine_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_charcoal_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_invert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_sepia_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_transition transition_affine_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/plus/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( filter_type, "affine", filter_affine_init ); MLT_REGISTER( filter_type, "charcoal", filter_charcoal_init ); MLT_REGISTER( filter_type, "invert", filter_invert_init ); MLT_REGISTER( filter_type, "sepia", filter_sepia_init ); MLT_REGISTER( transition_type, "affine", transition_affine_init ); MLT_REGISTER_METADATA( filter_type, "affine", metadata, "filter_affine.yml" ); MLT_REGISTER_METADATA( filter_type, "charcoal", metadata, "filter_charcoal.yml" ); MLT_REGISTER_METADATA( filter_type, "invert", metadata, "filter_invert.yml" ); MLT_REGISTER_METADATA( filter_type, "sepia", metadata, "filter_sepia.yml" ); MLT_REGISTER_METADATA( transition_type, "affine", metadata, "transition_affine.yml" ); } mlt-0.9.0/src/modules/plus/filter_affine.c000066400000000000000000000121561215300731300204770ustar00rootroot00000000000000/* * filter_affine.c -- affine filter * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include /** Do it :-). */ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter mlt_filter filter = mlt_frame_pop_service( this ); // Get the properties mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); // Get the image int error = 0; *format = mlt_image_rgb24a; //mlt_frame_get_image( this, image, format, width, height, 0 ); // Only process if we have no error and a valid colour space if ( error == 0 ) { mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL ); mlt_transition transition = mlt_properties_get_data( properties, "transition", NULL ); mlt_frame a_frame = NULL; mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); if ( producer == NULL ) { char *background = mlt_properties_get( properties, "background" ); producer = mlt_factory_producer( profile, NULL, background ); mlt_properties_set_data( properties, "producer", producer, 0, (mlt_destructor)mlt_producer_close, NULL ); } if ( transition == NULL ) { transition = mlt_factory_transition( profile, "affine", NULL ); mlt_properties_set_data( properties, "transition", transition, 0, (mlt_destructor)mlt_transition_close, NULL ); if ( transition ) mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "b_alpha", 1 ); } if ( producer != NULL && transition != NULL ) { mlt_position position = mlt_filter_get_position( filter, this ); mlt_properties frame_properties = MLT_FRAME_PROPERTIES( this ); mlt_position in = mlt_filter_get_in( filter ); mlt_position out = mlt_filter_get_out( filter ); double consumer_ar = mlt_profile_sar( profile ); mlt_transition_set_in_and_out( transition, in, out ); if ( out > 0 ) { mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( producer ), "length", out - in + 1 ); mlt_producer_set_in_and_out( producer, in, out ); } mlt_producer_seek( producer, in + position ); mlt_frame_set_position( this, position ); mlt_properties_pass( MLT_PRODUCER_PROPERTIES( producer ), properties, "producer." ); mlt_properties_pass( MLT_TRANSITION_PROPERTIES( transition ), properties, "transition." ); mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &a_frame, 0 ); mlt_frame_set_position( a_frame, in + position ); // mlt_properties_set_int( MLT_FRAME_PROPERTIES( a_frame ), "distort", 1 ); // Special case - aspect_ratio = 0 if ( mlt_frame_get_aspect_ratio( this ) == 0 ) mlt_frame_set_aspect_ratio( this, consumer_ar ); if ( mlt_frame_get_aspect_ratio( a_frame ) == 0 ) mlt_frame_set_aspect_ratio( a_frame, consumer_ar ); // Add the affine transition onto the frame stack mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); mlt_transition_process( transition, a_frame, this ); if ( mlt_properties_get_int( properties, "use_normalised" ) ) { // Use the normalised width & height mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); *width = profile->width; *height = profile->height; } mlt_frame_get_image( a_frame, image, format, width, height, writable ); mlt_properties_set_data( frame_properties, "affine_frame", a_frame, 0, (mlt_destructor)mlt_frame_close, NULL ); mlt_frame_set_image( this, *image, *width * *height * 4, NULL ); mlt_frame_set_alpha( this, mlt_frame_get_alpha_mask( a_frame ), *width * *height, NULL ); } else { mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); } } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Push the frame filter mlt_frame_push_service( frame, this ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_affine_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "background", arg ? arg : "colour:0" ); } return this; } mlt-0.9.0/src/modules/plus/filter_affine.yml000066400000000000000000000002761215300731300210560ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: affine title: Transform version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/plus/filter_charcoal.c000066400000000000000000000122111215300731300210130ustar00rootroot00000000000000/* * filter_charcoal.c -- charcoal filter * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include static inline int get_Y( uint8_t *pixels, int width, int height, int x, int y ) { if ( x < 0 || x >= width || y < 0 || y >= height ) { return 235; } else { uint8_t *pixel = pixels + y * ( width << 1 ) + ( x << 1 ); return *pixel; } } static inline int sqrti( int n ) { int p = 0; int q = 1; int r = n; int h = 0; while( q <= n ) q = q << 2; while( q != 1 ) { q = q >> 2; h = p + q; p = p >> 1; if ( r >= h ) { p = p + q; r = r - h; } } return p; } /** Do it :-). */ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter mlt_filter filter = mlt_frame_pop_service( this ); // Get the image *format = mlt_image_yuv422; int error = mlt_frame_get_image( this, image, format, width, height, 1 ); // Only process if we have no error and a valid colour space if ( error == 0 ) { // Get the charcoal scatter value int x_scatter = mlt_properties_get_double( MLT_FILTER_PROPERTIES( filter ), "x_scatter" ); int y_scatter = mlt_properties_get_double( MLT_FILTER_PROPERTIES( filter ), "y_scatter" ); float scale = mlt_properties_get_double( MLT_FILTER_PROPERTIES( filter ), "scale" ); float mix = mlt_properties_get_double( MLT_FILTER_PROPERTIES( filter ), "mix" ); int invert = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "invert" ); // We'll process pixel by pixel int x = 0; int y = 0; // We need to create a new frame as this effect modifies the input uint8_t *temp = mlt_pool_alloc( *width * *height * 2 ); uint8_t *p = temp; uint8_t *q = *image; // Calculations are carried out on a 3x3 matrix int matrix[ 3 ][ 3 ]; // Used to carry out the matrix calculations int sum1; int sum2; float sum; int val; // Loop for each row for ( y = 0; y < *height; y ++ ) { // Loop for each pixel for ( x = 0; x < *width; x ++ ) { // Populate the matrix matrix[ 0 ][ 0 ] = get_Y( *image, *width, *height, x - x_scatter, y - y_scatter ); matrix[ 0 ][ 1 ] = get_Y( *image, *width, *height, x , y - y_scatter ); matrix[ 0 ][ 2 ] = get_Y( *image, *width, *height, x + x_scatter, y - y_scatter ); matrix[ 1 ][ 0 ] = get_Y( *image, *width, *height, x - x_scatter, y ); matrix[ 1 ][ 2 ] = get_Y( *image, *width, *height, x + x_scatter, y ); matrix[ 2 ][ 0 ] = get_Y( *image, *width, *height, x - x_scatter, y + y_scatter ); matrix[ 2 ][ 1 ] = get_Y( *image, *width, *height, x , y + y_scatter ); matrix[ 2 ][ 2 ] = get_Y( *image, *width, *height, x + x_scatter, y + y_scatter ); // Do calculations sum1 = (matrix[2][0] - matrix[0][0]) + ( (matrix[2][1] - matrix[0][1]) << 1 ) + (matrix[2][2] - matrix[2][0]); sum2 = (matrix[0][2] - matrix[0][0]) + ( (matrix[1][2] - matrix[1][0]) << 1 ) + (matrix[2][2] - matrix[2][0]); sum = scale * sqrti( sum1 * sum1 + sum2 * sum2 ); // Assign value *p ++ = !invert ? ( sum >= 16 && sum <= 235 ? 251 - sum : sum < 16 ? 235 : 16 ) : ( sum >= 16 && sum <= 235 ? sum : sum < 16 ? 16 : 235 ); q ++; val = 128 + mix * ( *q ++ - 128 ); val = val < 16 ? 16 : val > 240 ? 240 : val; *p ++ = val; } } // Return the created image *image = temp; // Store new and destroy old mlt_frame_set_image( this, *image, *width * *height * 2, mlt_pool_release ); } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Push the frame filter mlt_frame_push_service( frame, this ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_charcoal_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "x_scatter", 1 ); mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "y_scatter", 1 ); mlt_properties_set_double( MLT_FILTER_PROPERTIES( this ), "scale", 1.5 ); mlt_properties_set_double( MLT_FILTER_PROPERTIES( this ), "mix", 0.0 ); } return this; } mlt-0.9.0/src/modules/plus/filter_charcoal.yml000066400000000000000000000002771215300731300214030ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: charcoal title: Charcoal version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/plus/filter_invert.c000066400000000000000000000046451215300731300205620ustar00rootroot00000000000000/* * filter_invert.c -- invert filter * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include static inline int clamp( int v, int l, int u ) { return v < l ? l : ( v > u ? u : v ); } /** Do it :-). */ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the image mlt_filter filter = mlt_frame_pop_service( this ); int mask = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "alpha" ); *format = mlt_image_yuv422; int error = mlt_frame_get_image( this, image, format, width, height, 1 ); // Only process if we have no error and a valid colour space if ( error == 0 ) { uint8_t *p = *image; uint8_t *q = *image + *width * *height * 2; uint8_t *r = *image; while ( p != q ) { *p ++ = clamp( 251 - *r ++, 16, 235 ); *p ++ = clamp( 256 - *r ++, 16, 240 ); } if ( mask ) { uint8_t *alpha = mlt_frame_get_alpha_mask( this ); int size = *width * *height; memset( alpha, mask, size ); } } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Push the frame filter mlt_frame_push_service( frame, this ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_invert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) this->process = filter_process; return this; } mlt-0.9.0/src/modules/plus/filter_invert.yml000066400000000000000000000002731215300731300211320ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: invert title: Invert version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/plus/filter_sepia.c000066400000000000000000000050541215300731300203470ustar00rootroot00000000000000/* * filter_sepia.c -- sepia filter * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include /** Do it :-). */ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter mlt_filter filter = mlt_frame_pop_service( this ); // Get the image *format = mlt_image_yuv422; int error = mlt_frame_get_image( this, image, format, width, height, 1 ); // Only process if we have no error and a valid colour space if ( error == 0 && *image ) { // We modify the whole image uint8_t *p = *image; int h = *height; int uneven = *width % 2; int w = ( *width - uneven ) / 2; int t; // Get u and v values int u = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "u" ); int v = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "v" ); // Loop through image while( h -- ) { t = w; while( t -- ) { p ++; *p ++ = u; p ++; *p ++ = v; } if ( uneven ) { p ++; *p ++ = u; } } } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Push the frame filter mlt_frame_push_service( frame, this ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_sepia_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "u", "75" ); mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "v", "150" ); } return this; } mlt-0.9.0/src/modules/plus/filter_sepia.yml000066400000000000000000000002711215300731300207220ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: sepia title: Sepia version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/plus/interp.h000066400000000000000000000503111215300731300172030ustar00rootroot00000000000000//interp.c /* * Copyright (C) 2010 Marko Cebokli http://lea.hamradio.si/~s57uuu * This file is a part of the Frei0r plugin "c0rners" * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /******************************************************************* * The remapping functions use a map aray, which contains a pair * of floating values fo each pixel of the output image. These * represent the location in the input image, from where the value * of the given output pixel should be interpolated. * They are given in pixels of the input image. * If the output image is wo pixels wide, then the x coordinate * of the pixel in row r and column c is at 2*(r*wo+c) in the map * array, and y at 2*(r*wo+c)+1 * * The map array is usually computation intensive to generate, and * he purpose of the map array is to allow fast remapping of * several images (video) using the same map array. ******************************************************************/ //compile: gcc -c -O2 -Wall -std=c99 -fPIC interp.c -o interp.o // -std=c99 za rintf() // -fPIC da lahko linkas v .so (za frei0r) #include #include /* za debug printoute */ #include //#define TEST_XY_LIMITS //-------------------------------------------------------- //pointer to an interpolating function //parameters: // source image // source width // source height // X coordinate // Y coordinate // opacity // destination image // flag to overwrite alpha channel typedef int (*interpp)(unsigned char*, int, int, float, float, float, unsigned char*, int); //************************************** //HERE BEGIN THE INTERPOLATION FUNCTIONS //------------------------------------------------------ //za debugging - z izpisovanjem //interpolacija "najblizji sosed" (ni prava interpolacija) //za byte (char) vrednosti // *sl vhodni array (slika) // w,h dimenzija slike je wxh // x,y tocka, za katero izracuna interpolirano vrednost // o opacity // *v interpolirana vrednost int interpNNpr_b(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_alpha) { //printf("u=%5.2f v=%5.2f ",x,y); printf("u=%5.3f v=%5.3f ",x/(w-1),y/(h-1)); //printf("U=%2d V=%2d ",(int)rintf(x),(int)rintf(y)); #ifdef TEST_XY_LIMITS if ((x<0)||(x>=(w-1))||(y<0)||(y>=(h-1))) return -1; #endif *v=sl[(int)rintf(x)+(int)rintf(y)*w]; return 0; } //------------------------------------------------------ //interpolacija "najblizji sosed" (ni prava interpolacija) //za byte (char) vrednosti // *sl vhodni array (slika) // w,h dimenzija slike je wxh // x,y tocka, za katero izracuna interpolirano vrednost // o opacity // *v interpolirana vrednost int interpNN_b(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_alpha) { #ifdef TEST_XY_LIMITS if ((x<0)||(x>=(w-1))||(y<0)||(y>=(h-1))) return -1; #endif *v=sl[(int)rintf(x)+(int)rintf(y)*w]; return 0; } //------------------------------------------------------ //interpolacija "najblizji sosed" (ni prava interpolacija) //za byte (char) vrednosti v packed color 32 bitnem formatu //little endian !! // *sl vhodni array (slika) // w,h dimenzija slike je wxh // x,y tocka, za katero izracuna interpolirano vrednost // o opacity // *v interpolirana vrednost int interpNN_b32(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_alpha) { #ifdef TEST_XY_LIMITS if ((x<0)||(x>=(w-1))||(y<0)||(y>=(h-1))) return -1; #endif int p = (int) rintf(x) * 4 + (int) rintf(y) * 4 * w; float alpha = (float) sl[p + 3] / 255.0 * o; v[0]= v[0] * (1.0 - alpha) + sl[p] * alpha; v[1]= v[1] * (1.0 - alpha) + sl[p + 1] * alpha; v[2]= v[2] * (1.0 - alpha) + sl[p + 2] * alpha; if (is_alpha) v[3] = sl[p +3]; return 0; } //------------------------------------------------------ //bilinearna interpolacija //za byte (char) vrednosti // *sl vhodni array (slika) // w,h dimenzija slike je wxh // x,y tocka, za katero izracuna interpolirano vrednost // o opacity // *v interpolirana vrednost int interpBL_b(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_alpha) { int m,n,k,l; float a,b; #ifdef TEST_XY_LIMITS if ((x<0)||(x>=(w-1))||(y<0)||(y>=(h-1))) return -1; #endif m=(int)floorf(x); n=(int)floorf(y); k=n*w+m; l=(n+1)*w+m; a=sl[k]+(sl[k+1]-sl[k])*(x-(float)m); b=sl[l]+(sl[l+1]-sl[l])*(x-(float)m); *v=a+(b-a)*(y-(float)n); return 0; } //------------------------------------------------------ //bilinearna interpolacija //za byte (char) vrednosti v packed color 32 bitnem formatu int interpBL_b32(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_alpha) { int m,n,k,l,n1,l1,k1; float a,b; #ifdef TEST_XY_LIMITS if ((x<0)||(x>=(w-1))||(y<0)||(y>=(h-1))) return -1; #endif m=(int)floorf(x); n=(int)floorf(y); k=n*w+m; l=(n+1)*w+m; k1=4*(k+1); l1=4*(l+1); n1=4*((n+1)*w+m); l=4*l; k=4*k; a=sl[k+3]+(sl[k1+3]-sl[k+3])*(x-(float)m); b=sl[l+3]+(sl[l1+3]-sl[n1+3])*(x-(float)m); float alpha = a+(b-a)*(y-(float)n); if (is_alpha) v[3] = alpha; alpha = alpha / 255.0 * o; a=sl[k]+(sl[k1]-sl[k])*(x-(float)m); b=sl[l]+(sl[l1]-sl[n1])*(x-(float)m); v[0]= v[0] * (1.0 - alpha) + (a+(b-a)*(y-(float)n)) * alpha; a=sl[k+1]+(sl[k1+1]-sl[k+1])*(x-(float)m); b=sl[l+1]+(sl[l1+1]-sl[n1+1])*(x-(float)m); v[1]= v[1] * (1.0 - alpha) + (a+(b-a)*(y-(float)n)) * alpha; a=sl[k+2]+(sl[k1+2]-sl[k+2])*(x-(float)m); b=sl[l+2]+(sl[l1+2]-sl[n1+2])*(x-(float)m); v[2]= v[2] * (1.0 - alpha) + (a+(b-a)*(y-(float)n)) * alpha; return 0; } //------------------------------------------------------ //bikubicna interpolacija "smooth" //za byte (char) vrednosti //kar Aitken-Neville formula iz Bronstajna // *sl vhodni array (slika) // w,h dimenzija slike je wxh // x,y tocka, za katero izracuna interpolirano vrednost // o opacity // *v interpolirana vrednost int interpBC_b(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_alpha) { int i,j,l,m,n; float k; float p[4],p1[4],p2[4],p3[4],p4[4]; #ifdef TEST_XY_LIMITS if ((x<0)||(x>=(w-1))||(y<0)||(y>=(h-1))) return -1; #endif m=(int)ceilf(x)-2; if (m<0) m=0; if ((m+5)>w) m=w-4; n=(int)ceilf(y)-2; if (n<0) n=0; if ((n+5)>h) n=h-4; //njaprej po y (stiri stolpce) for (i=0;i<4;i++) { l=m+(i+n)*w; p1[i]=sl[l]; p2[i]=sl[l+1]; p3[i]=sl[l+2]; p4[i]=sl[l+3]; } for (j=1;j<4;j++) for (i=3;i>=j;i--) { k=(y-i-n)/j; p1[i]=p1[i]+k*(p1[i]-p1[i-1]); p2[i]=p2[i]+k*(p2[i]-p2[i-1]); p3[i]=p3[i]+k*(p3[i]-p3[i-1]); p4[i]=p4[i]+k*(p4[i]-p4[i-1]); } //zdaj pa po x p[0]=p1[3]; p[1]=p2[3]; p[2]=p3[3]; p[3]=p4[3]; for (j=1;j<4;j++) for (i=3;i>=j;i--) p[i]=p[i]+(x-i-m)/j*(p[i]-p[i-1]); if (p[3]<0.0) p[3]=0.0; //printf("p=%f ",p[3]); if (p[3]>256.0) p[3]=255.0; //printf("p=%f ",p[3]); *v=p[3]; return 0; } //------------------------------------------------------ //bikubicna interpolacija "smooth" //za byte (char) vrednosti v packed color 32 bitnem formatu int interpBC_b32(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_alpha) { int i,j,b,l,m,n; float k; float p[4],p1[4],p2[4],p3[4],p4[4]; float alpha = 1.0; #ifdef TEST_XY_LIMITS if ((x<0)||(x>=(w-1))||(y<0)||(y>=(h-1))) return -1; #endif m=(int)ceilf(x)-2; if (m<0) m=0; if ((m+5)>w) m=w-4; n=(int)ceilf(y)-2; if (n<0) n=0; if ((n+5)>h) n=h-4; for (b=3;b>-1;b--) { //njaprej po y (stiri stolpce) for (i=0;i<4;i++) { l=m+(i+n)*w; p1[i]=sl[4*l+b]; p2[i]=sl[4*(l+1)+b]; p3[i]=sl[4*(l+2)+b]; p4[i]=sl[4*(l+3)+b]; } for (j=1;j<4;j++) for (i=3;i>=j;i--) { k=(y-i-n)/j; p1[i]=p1[i]+k*(p1[i]-p1[i-1]); p2[i]=p2[i]+k*(p2[i]-p2[i-1]); p3[i]=p3[i]+k*(p3[i]-p3[i-1]); p4[i]=p4[i]+k*(p4[i]-p4[i-1]); } //zdaj pa po x p[0]=p1[3]; p[1]=p2[3]; p[2]=p3[3]; p[3]=p4[3]; for (j=1;j<4;j++) for (i=3;i>=j;i--) p[i]=p[i]+(x-i-m)/j*(p[i]-p[i-1]); if (p[3]<0.0) p[3]=0.0; if (p[3]>255.0) p[3]=255.0; if (b == 3) { alpha = p[3] / 255.0 * o; if (is_alpha) v[3] = p[3]; } else { v[b] = v[b] * (1.0 - alpha) + p[3] * alpha; } } return 0; } //------------------------------------------------------ //bikubicna interpolacija "sharp" //za byte (char) vrednosti //Helmut Dersch polinom // *sl vhodni array (slika) // w,h dimenzija slike je wxh // x,y tocka, za katero izracuna interpolirano vrednost // o opacity // *v interpolirana vrednost //!!! ODKOD SUM??? (ze po eni rotaciji v interp_test !!) //!!! v defish tega suma ni??? int interpBC2_b(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_alpha) { int i,k,l,m,n; float pp,p[4],wx[4],wy[4],xx; #ifdef TEST_XY_LIMITS if ((x<0)||(x>=(w-1))||(y<0)||(y>=(h-1))) return -1; #endif m=(int)ceilf(x)-2; if (m<0) m=0; if ((m+5)>w) m=w-4; n=(int)ceilf(y)-2; if (n<0) n=0; if ((n+5)>h) n=h-4; //najprej po y (stiri stolpce) xx=y-n; wy[0]=(-0.75*(xx-5.0)*xx-6.0)*xx+3.0; xx=xx-1.0; wy[1]=(1.25*xx-2.25)*xx*xx+1.0; xx=1.0-xx; wy[2]=(1.25*xx-2.25)*xx*xx+1.0; xx=xx+1.0; wy[3]=(-0.75*(xx-5.0)*xx-6.0)*xx+3.0; //se po x xx=x-m; wx[0]=(-0.75*(xx-5.0)*xx-6.0)*xx+3.0; xx=xx-1.0; wx[1]=(1.25*xx-2.25)*xx*xx+1.0; xx=1.0-xx; wx[2]=(1.25*xx-2.25)*xx*xx+1.0; xx=xx+1.0; wx[3]=(-0.75*(xx-5.0)*xx-6.0)*xx+3.0; k=n*w+m; for (i=0;i<4;i++) { p[i]=0.0; l=k+i; p[i]=wy[0]*sl[l]; l+=w; p[i]+=wy[1]*sl[l]; l+=w; p[i]+=wy[2]*sl[l]; l+=w; p[i]+=wy[3]*sl[l]; } pp=wx[0]*p[0]; pp+=wx[1]*p[1]; pp+=wx[2]*p[2]; pp+=wx[3]*p[3]; if (pp<0.0) pp=0.0; if (pp>256.0) pp=255.0; *v=pp; return 0; } //------------------------------------------------------ //bikubicna interpolacija "sharp" //za byte (char) vrednosti v packed color 32 bitnem formatu //!!! ODKOD SUM??? (ze po eni rotaciji v interp_test !!) //!!! v defish tega suma ni??? int interpBC2_b32(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_alpha) { int b,i,k,l,m,n,u; float pp,p[4],wx[4],wy[4],xx; #ifdef TEST_XY_LIMITS if ((x<0)||(x>=(w-1))||(y<0)||(y>=(h-1))) return -1; #endif m=(int)ceilf(x)-2; if (m<0) m=0; if ((m+5)>w) m=w-4; n=(int)ceilf(y)-2; if (n<0) n=0; if ((n+5)>h) n=h-4; //najprej po y (stiri stolpce) xx=y-n; wy[0]=(-0.75*(xx-5.0)*xx-6.0)*xx+3.0; xx=xx-1.0; wy[1]=(1.25*xx-2.25)*xx*xx+1.0; xx=1.0-xx; wy[2]=(1.25*xx-2.25)*xx*xx+1.0; xx=xx+1.0; wy[3]=(-0.75*(xx-5.0)*xx-6.0)*xx+3.0; //se po x xx=x-m; wx[0]=(-0.75*(xx-5.0)*xx-6.0)*xx+3.0; xx=xx-1.0; wx[1]=(1.25*xx-2.25)*xx*xx+1.0; xx=1.0-xx; wx[2]=(1.25*xx-2.25)*xx*xx+1.0; xx=xx+1.0; wx[3]=(-0.75*(xx-5.0)*xx-6.0)*xx+3.0; k=4*(n*w+m); u=4*w; for (b=0;b<4;b++) { for (i=0;i<4;i++) { p[i]=0.0; l=k+4*i; p[i]=wy[0]*sl[l]; l+=u; p[i]+=wy[1]*sl[l]; l+=u; p[i]+=wy[2]*sl[l]; l+=u; p[i]+=wy[3]*sl[l]; } k++; pp=wx[0]*p[0]; pp+=wx[1]*p[1]; pp+=wx[2]*p[2]; pp+=wx[3]*p[3]; if (pp<0.0) pp=0.0; if (pp>256.0) pp=255.0; v[b]=pp; } return 0; } //------------------------------------------------------ //spline 4x4 interpolacija //za byte (char) vrednosti //Helmut Dersch polinom // *sl vhodni array (slika) // w,h dimenzija slike je wxh // x,y tocka, za katero izracuna interpolirano vrednost // o opacity // *v interpolirana vrednost int interpSP4_b(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_alpha) { int i,j,m,n; float pp,p[4],wx[4],wy[4],xx; #ifdef TEST_XY_LIMITS if ((x<0)||(x>=(w-1))||(y<0)||(y>=(h-1))) return -1; #endif m=(int)ceilf(x)-2; if (m<0) m=0; if ((m+5)>w) m=w-4; n=(int)ceilf(y)-2; if (n<0) n=0; if ((n+5)>h) n=h-4; //najprej po y (stiri stolpce) xx=y-n; wy[0]=((-0.333333*(xx-1.0)+0.8)*(xx-1.0)-0.466667)*(xx-1.0); xx=xx-1.0; wy[1]=((xx-1.8)*xx-0.2)*xx+1.0; xx=1.0-xx; wy[2]=((xx-1.8)*xx-0.2)*xx+1.0; xx=xx+1.0; wy[3]=((-0.333333*(xx-1.0)+0.8)*(xx-1.0)-0.466667)*(xx-1.0); //se po x xx=x-m; wx[0]=((-0.333333*(xx-1.0)+0.8)*(xx-1.0)-0.466667)*(xx-1.0); xx=xx-1.0; wx[1]=((xx-1.8)*xx-0.2)*xx+1.0; xx=1.0-xx; wx[2]=((xx-1.8)*xx-0.2)*xx+1.0; xx=xx+1.0; wx[3]=((-0.333333*(xx-1.0)+0.8)*(xx-1.0)-0.466667)*(xx-1.0); for (i=0;i<4;i++) { p[i]=0.0; for (j=0;j<4;j++) { p[i]=p[i]+wy[j]*sl[(j+n)*w+i+m]; } } pp=0.0; for (i=0;i<4;i++) pp=pp+wx[i]*p[i]; if (pp<0.0) pp=0.0; if (pp>256.0) pp=255.0; *v=pp; return 0; } //------------------------------------------------------ //spline 4x4 interpolacija //za byte (char) vrednosti v packed color 32 bitnem formatu int interpSP4_b32(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_alpha) { int i,j,m,n,b; float pp,p[4],wx[4],wy[4],xx; #ifdef TEST_XY_LIMITS if ((x<0)||(x>=(w-1))||(y<0)||(y>=(h-1))) return -1; #endif m=(int)ceilf(x)-2; if (m<0) m=0; if ((m+5)>w) m=w-4; n=(int)ceilf(y)-2; if (n<0) n=0; if ((n+5)>h) n=h-4; //najprej po y (stiri stolpce) xx=y-n; wy[0]=((-0.333333*(xx-1.0)+0.8)*(xx-1.0)-0.466667)*(xx-1.0); xx=xx-1.0; wy[1]=((xx-1.8)*xx-0.2)*xx+1.0; xx=1.0-xx; wy[2]=((xx-1.8)*xx-0.2)*xx+1.0; xx=xx+1.0; wy[3]=((-0.333333*(xx-1.0)+0.8)*(xx-1.0)-0.466667)*(xx-1.0); //se po x xx=x-m; wx[0]=((-0.333333*(xx-1.0)+0.8)*(xx-1.0)-0.466667)*(xx-1.0); xx=xx-1.0; wx[1]=((xx-1.8)*xx-0.2)*xx+1.0; xx=1.0-xx; wx[2]=((xx-1.8)*xx-0.2)*xx+1.0; xx=xx+1.0; wx[3]=((-0.333333*(xx-1.0)+0.8)*(xx-1.0)-0.466667)*(xx-1.0); for (b=0;b<4;b++) { for (i=0;i<4;i++) { p[i]=0.0; for (j=0;j<4;j++) { p[i]=p[i]+wy[j]*sl[4*((j+n)*w+i+m)+b]; } } pp=0.0; for (i=0;i<4;i++) pp=pp+wx[i]*p[i]; if (pp<0.0) pp=0.0; if (pp>256.0) pp=255.0; v[b]=pp; } return 0; } //------------------------------------------------------ //spline 6x6 interpolacija //za byte (char) vrednosti //Helmut Dersch polinom // *sl vhodni array (slika) // w,h dimenzija slike je wxh // x,y tocka, za katero izracuna interpolirano vrednost // o opacity // *v interpolirana vrednost //!!! PAZI, TOLE NE DELA CISTO PRAV ??? belina se siri //!!! zaenkrat sem dodal fudge factor... int interpSP6_b(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_alpha) { int i,j,m,n; float pp,p[6],wx[6],wy[6],xx; #ifdef TEST_XY_LIMITS if ((x<0)||(x>=(w-1))||(y<0)||(y>=(h-1))) return -1; #endif m=(int)ceilf(x)-3; if (m<0) m=0; if ((m+7)>w) m=w-6; n=(int)ceilf(y)-3; if (n<0) n=0; if ((n+7)>h) n=h-6; //najprej po y (sest stolpcev) xx=y-n; wy[0]=((0.090909*(xx-2.0)-0.215311)*(xx-2.0)+0.124402)*(xx-2.0); xx=xx-1.0; wy[1]=((-0.545455*(xx-1.0)+1.291866)*(xx-1.0)-0.746411)*(xx-1.0); xx=xx-1.0; wy[2]=((1.181818*xx-2.167464)*xx+0.014354)*xx+1.0; xx=1.0-xx; wy[3]=((1.181818*xx-2.167464)*xx+0.014354)*xx+1.0; xx=xx+1.0; wy[4]=((-0.545455*(xx-1.0)+1.291866)*(xx-1.0)-0.746411)*(xx-1.0); xx=xx+1.0; wy[5]=((0.090909*(xx-2.0)-0.215311)*(xx-2.0)+0.124402)*(xx-2.0); //se po x xx=x-m; wx[0]=((0.090909*(xx-2.0)-0.215311)*(xx-2.0)+0.124402)*(xx-2.0); xx=xx-1.0; wx[1]=((-0.545455*(xx-1.0)+1.291866)*(xx-1.0)-0.746411)*(xx-1.0); xx=xx-1.0; wx[2]=((1.181818*xx-2.167464)*xx+0.014354)*xx+1.0; xx=1.0-xx; wx[3]=((1.181818*xx-2.167464)*xx+0.014354)*xx+1.0; xx=xx+1.0; wx[4]=((-0.545455*(xx-1.0)+1.291866)*(xx-1.0)-0.746411)*(xx-1.0); xx=xx+1.0; wx[5]=((0.090909*(xx-2.0)-0.215311)*(xx-2.0)+0.124402)*(xx-2.0); for (i=0;i<6;i++) { p[i]=0.0; for (j=0;j<6;j++) { p[i]=p[i]+wy[j]*sl[(j+n)*w+i+m]; } } pp=0.0; for (i=0;i<6;i++) pp=pp+wx[i]*p[i]; pp=0.947*pp; //fudge factor...!!! cca 0.947... if (pp<0.0) pp=0.0; if (pp>256.0) pp=255.0; *v=pp; return 0; } //------------------------------------------------------ //spline 6x6 interpolacija //za byte (char) vrednosti v packed color 32 bitnem formatu //!!! PAZI, TOLE NE DELA CISTO PRAV ??? belina se siri //!!! zaenkrat sem dodal fudge factor... int interpSP6_b32(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_alpha) { int i,b,j,m,n; float pp,p[6],wx[6],wy[6],xx; #ifdef TEST_XY_LIMITS if ((x<0)||(x>=(w-1))||(y<0)||(y>=(h-1))) return -1; #endif m=(int)ceilf(x)-3; if (m<0) m=0; if ((m+7)>w) m=w-6; n=(int)ceilf(y)-3; if (n<0) n=0; if ((n+7)>h) n=h-6; //najprej po y (sest stolpcev) xx=y-n; wy[0]=((0.090909*(xx-2.0)-0.215311)*(xx-2.0)+0.124402)*(xx-2.0); xx=xx-1.0; wy[1]=((-0.545455*(xx-1.0)+1.291866)*(xx-1.0)-0.746411)*(xx-1.0); xx=xx-1.0; wy[2]=((1.181818*xx-2.167464)*xx+0.014354)*xx+1.0; xx=1.0-xx; wy[3]=((1.181818*xx-2.167464)*xx+0.014354)*xx+1.0; xx=xx+1.0; wy[4]=((-0.545455*(xx-1.0)+1.291866)*(xx-1.0)-0.746411)*(xx-1.0); xx=xx+1.0; wy[5]=((0.090909*(xx-2.0)-0.215311)*(xx-2.0)+0.124402)*(xx-2.0); //se po x xx=x-m; wx[0]=((0.090909*(xx-2.0)-0.215311)*(xx-2.0)+0.124402)*(xx-2.0); xx=xx-1.0; wx[1]=((-0.545455*(xx-1.0)+1.291866)*(xx-1.0)-0.746411)*(xx-1.0); xx=xx-1.0; wx[2]=((1.181818*xx-2.167464)*xx+0.014354)*xx+1.0; xx=1.0-xx; wx[3]=((1.181818*xx-2.167464)*xx+0.014354)*xx+1.0; xx=xx+1.0; wx[4]=((-0.545455*(xx-1.0)+1.291866)*(xx-1.0)-0.746411)*(xx-1.0); xx=xx+1.0; wx[5]=((0.090909*(xx-2.0)-0.215311)*(xx-2.0)+0.124402)*(xx-2.0); for (b=0;b<4;b++) { for (i=0;i<6;i++) { p[i]=0.0; for (j=0;j<6;j++) { p[i]=p[i]+wy[j]*sl[4*((j+n)*w+i+m)+b]; } } pp=0.0; for (i=0;i<6;i++) pp=pp+wx[i]*p[i]; pp=0.947*pp; //fudge factor...!!! cca 0.947... if (pp<0.0) pp=0.0; if (pp>256.0) pp=255.0; v[b]=pp; } return 0; } //------------------------------------------------------ //truncated sinc "lanczos" 16x16 interpolacija //za byte (char) vrednosti // *sl vhodni array (slika) // w,h dimenzija slike je wxh // x,y tocka, za katero izracuna interpolirano vrednost // o opacity // *v interpolirana vrednost int interpSC16_b(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_alpha) { int i,j,m,n; float pp,p[16],wx[16],wy[16],xx,xxx,x1; float PI=3.141592654; #ifdef TEST_XY_LIMITS if ((x<0)||(x>=(w-1))||(y<0)||(y>=(h-1))) return -1; #endif m=(int)ceilf(x)-8; if (m<0) m=0; if ((m+17)>w) m=w-16; n=(int)ceilf(y)-8; if (n<0) n=0; if ((n+17)>h) n=h-16; //najprej po y xx=y-n; for (i=7;i>=0;i--) { x1=xx*PI; wy[7-i]=(sin(x1)/(x1))*(sin(x1*0.125)/(x1*0.125)); xxx=(float)(2*i+1)-xx; x1=xxx*PI; wy[8+i]=(sin(x1)/(x1))*(sin(x1*0.125)/(x1*0.125)); xx=xx-1.0; } //se po x xx=x-m; for (i=7;i>=0;i--) { x1=xx*PI; wx[7-i]=(sin(x1)/(x1))*(sin(x1*0.125)/(x1*0.125)); xxx=(float)(2*i+1)-xx; x1=xxx*PI; wx[8+i]=(sin(x1)/(x1))*(sin(x1*0.125)/(x1*0.125)); xx=xx-1.0; } for (i=0;i<16;i++) { p[i]=0.0; for (j=0;j<16;j++) { p[i]=p[i]+wy[j]*sl[(j+n)*w+i+m]; } } pp=0.0; for (i=0;i<16;i++) pp=pp+wx[i]*p[i]; if (pp<0.0) pp=0.0; if (pp>256.0) pp=255.0; *v=pp; return 0; } //------------------------------------------------------ //truncated sinc "lanczos" 16x16 interpolacija //za byte (char) vrednosti v packed color 32 bitnem formatu int interpSC16_b32(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_alpha) { int i,j,m,b,n; float pp,p[16],wx[16],wy[16],xx,xxx,x1; float PI=3.141592654; #ifdef TEST_XY_LIMITS if ((x<0)||(x>=(w-1))||(y<0)||(y>=(h-1))) return -1; #endif m=(int)ceilf(x)-8; if (m<0) m=0; if ((m+17)>w) m=w-16; n=(int)ceilf(y)-8; if (n<0) n=0; if ((n+17)>h) n=h-16; //najprej po y xx=y-n; for (i=7;i>=0;i--) { x1=xx*PI; wy[7-i]=(sin(x1)/(x1))*(sin(x1*0.125)/(x1*0.125)); xxx=(float)(2*i+1)-xx; x1=xxx*PI; wy[8+i]=(sin(x1)/(x1))*(sin(x1*0.125)/(x1*0.125)); xx=xx-1.0; } //se po x xx=x-m; for (i=7;i>=0;i--) { x1=xx*PI; wx[7-i]=(sin(x1)/(x1))*(sin(x1*0.125)/(x1*0.125)); xxx=(float)(2*i+1)-xx; x1=xxx*PI; wx[8+i]=(sin(x1)/(x1))*(sin(x1*0.125)/(x1*0.125)); xx=xx-1.0; } for (b=0;b<4;b++) { for (i=0;i<16;i++) { p[i]=0.0; for (j=0;j<16;j++) { p[i]=p[i]+wy[j]*sl[4*((j+n)*w+i+m)+b]; } } pp=0.0; for (i=0;i<16;i++) pp=pp+wx[i]*p[i]; if (pp<0.0) pp=0.0; if (pp>256.0) pp=255.0; v[b]=pp; } return 0; } mlt-0.9.0/src/modules/plus/transition_affine.c000066400000000000000000000452751215300731300214140ustar00rootroot00000000000000/* * transition_affine.c -- affine transformations * Copyright (C) 2003-2010 Ushodaya Enterprises Limited * Author: Charles Yates * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include "interp.h" /** Calculate real geometry. */ static void geometry_calculate( mlt_transition transition, const char *store, struct mlt_geometry_item_s *output, float position ) { mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); mlt_geometry geometry = mlt_properties_get_data( properties, store, NULL ); int mirror_off = mlt_properties_get_int( properties, "mirror_off" ); int repeat_off = mlt_properties_get_int( properties, "repeat_off" ); int length = mlt_geometry_get_length( geometry ); // Allow wrapping if ( !repeat_off && position >= length && length != 0 ) { int section = position / length; position -= section * length; if ( !mirror_off && section % 2 == 1 ) position = length - position; } // Fetch the key for the position mlt_geometry_fetch( geometry, output, position ); } static mlt_geometry transition_parse_keys( mlt_transition transition, const char *name, const char *store, int normalised_width, int normalised_height ) { // Get the properties of the transition mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); // Try to fetch it first mlt_geometry geometry = mlt_properties_get_data( properties, store, NULL ); // Determine length and obtain cycle mlt_position length = mlt_transition_get_length( transition ); double cycle = mlt_properties_get_double( properties, "cycle" ); // Allow a geometry repeat cycle if ( cycle >= 1 ) length = cycle; else if ( cycle > 0 ) length *= cycle; if ( geometry == NULL ) { // Get the new style geometry string char *property = mlt_properties_get( properties, name ); // Create an empty geometries object geometry = mlt_geometry_init( ); // Parse the geometry if we have one mlt_geometry_parse( geometry, property, length, normalised_width, normalised_height ); // Store it mlt_properties_set_data( properties, store, geometry, 0, ( mlt_destructor )mlt_geometry_close, NULL ); } else { // Check for updates and refresh if necessary mlt_geometry_refresh( geometry, mlt_properties_get( properties, name ), length, normalised_width, normalised_height ); } return geometry; } static mlt_geometry composite_calculate( mlt_transition transition, struct mlt_geometry_item_s *result, int nw, int nh, float position ) { // Structures for geometry mlt_geometry start = transition_parse_keys( transition, "geometry", "geometries", nw, nh ); // Do the calculation geometry_calculate( transition, "geometries", result, position ); return start; } static inline float composite_calculate_key( mlt_transition transition, const char *name, const char *store, int norm, float position ) { // Struct for the result struct mlt_geometry_item_s result; // Structures for geometry transition_parse_keys( transition, name, store, norm, 0 ); // Do the calculation geometry_calculate( transition, store, &result, position ); return result.x; } typedef struct { float matrix[3][3]; } affine_t; static void affine_init( float affine[3][3] ) { affine[0][0] = 1; affine[0][1] = 0; affine[0][2] = 0; affine[1][0] = 0; affine[1][1] = 1; affine[1][2] = 0; affine[2][0] = 0; affine[2][1] = 0; affine[2][2] = 1; } // Multiply two this affine transform with that static void affine_multiply( float affine[3][3], float matrix[3][3] ) { float output[3][3]; int i; int j; for ( i = 0; i < 3; i ++ ) for ( j = 0; j < 3; j ++ ) output[i][j] = affine[i][0] * matrix[j][0] + affine[i][1] * matrix[j][1] + affine[i][2] * matrix[j][2]; affine[0][0] = output[0][0]; affine[0][1] = output[0][1]; affine[0][2] = output[0][2]; affine[1][0] = output[1][0]; affine[1][1] = output[1][1]; affine[1][2] = output[1][2]; affine[2][0] = output[2][0]; affine[2][1] = output[2][1]; affine[2][2] = output[2][2]; } // Rotate by a given angle static void affine_rotate_x( float affine[3][3], float angle ) { float matrix[3][3]; matrix[0][0] = cos( angle * M_PI / 180 ); matrix[0][1] = 0 - sin( angle * M_PI / 180 ); matrix[0][2] = 0; matrix[1][0] = sin( angle * M_PI / 180 ); matrix[1][1] = cos( angle * M_PI / 180 ); matrix[1][2] = 0; matrix[2][0] = 0; matrix[2][1] = 0; matrix[2][2] = 1; affine_multiply( affine, matrix ); } static void affine_rotate_y( float affine[3][3], float angle ) { float matrix[3][3]; matrix[0][0] = cos( angle * M_PI / 180 ); matrix[0][1] = 0; matrix[0][2] = 0 - sin( angle * M_PI / 180 ); matrix[1][0] = 0; matrix[1][1] = 1; matrix[1][2] = 0; matrix[2][0] = sin( angle * M_PI / 180 ); matrix[2][1] = 0; matrix[2][2] = cos( angle * M_PI / 180 ); affine_multiply( affine, matrix ); } static void affine_rotate_z( float affine[3][3], float angle ) { float matrix[3][3]; matrix[0][0] = 1; matrix[0][1] = 0; matrix[0][2] = 0; matrix[1][0] = 0; matrix[1][1] = cos( angle * M_PI / 180 ); matrix[1][2] = sin( angle * M_PI / 180 ); matrix[2][0] = 0; matrix[2][1] = - sin( angle * M_PI / 180 ); matrix[2][2] = cos( angle * M_PI / 180 ); affine_multiply( affine, matrix ); } static void affine_scale( float affine[3][3], float sx, float sy ) { float matrix[3][3]; matrix[0][0] = sx; matrix[0][1] = 0; matrix[0][2] = 0; matrix[1][0] = 0; matrix[1][1] = sy; matrix[1][2] = 0; matrix[2][0] = 0; matrix[2][1] = 0; matrix[2][2] = 1; affine_multiply( affine, matrix ); } // Shear by a given value static void affine_shear( float affine[3][3], float shear_x, float shear_y, float shear_z ) { float matrix[3][3]; matrix[0][0] = 1; matrix[0][1] = tan( shear_x * M_PI / 180 ); matrix[0][2] = 0; matrix[1][0] = tan( shear_y * M_PI / 180 ); matrix[1][1] = 1; matrix[1][2] = tan( shear_z * M_PI / 180 ); matrix[2][0] = 0; matrix[2][1] = 0; matrix[2][2] = 1; affine_multiply( affine, matrix ); } static void affine_offset( float affine[3][3], float x, float y ) { affine[0][2] += x; affine[1][2] += y; } // Obtain the mapped x coordinate of the input static inline double MapX( float affine[3][3], float x, float y ) { return affine[0][0] * x + affine[0][1] * y + affine[0][2]; } // Obtain the mapped y coordinate of the input static inline double MapY( float affine[3][3], float x, float y ) { return affine[1][0] * x + affine[1][1] * y + affine[1][2]; } static inline double MapZ( float affine[3][3], float x, float y ) { return affine[2][0] * x + affine[2][1] * y + affine[2][2]; } #define MAX( x, y ) x > y ? x : y #define MIN( x, y ) x < y ? x : y static void affine_max_output( float affine[3][3], float *w, float *h, float dz, float max_width, float max_height ) { int tlx = MapX( affine, -max_width, max_height ) / dz; int tly = MapY( affine, -max_width, max_height ) / dz; int trx = MapX( affine, max_width, max_height ) / dz; int try = MapY( affine, max_width, max_height ) / dz; int blx = MapX( affine, -max_width, -max_height ) / dz; int bly = MapY( affine, -max_width, -max_height ) / dz; int brx = MapX( affine, max_width, -max_height ) / dz; int bry = MapY( affine, max_width, -max_height ) / dz; int max_x; int max_y; int min_x; int min_y; max_x = MAX( tlx, trx ); max_x = MAX( max_x, blx ); max_x = MAX( max_x, brx ); min_x = MIN( tlx, trx ); min_x = MIN( min_x, blx ); min_x = MIN( min_x, brx ); max_y = MAX( tly, try ); max_y = MAX( max_y, bly ); max_y = MAX( max_y, bry ); min_y = MIN( tly, try ); min_y = MIN( min_y, bly ); min_y = MIN( min_y, bry ); *w = ( float )( max_x - min_x + 1 ) / max_width / 2.0; *h = ( float )( max_y - min_y + 1 ) / max_height / 2.0; } #define IN_RANGE( v, r ) ( v >= - r / 2 && v < r / 2 ) static inline void get_affine( affine_t *affine, mlt_transition transition, float position ) { mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); int keyed = mlt_properties_get_int( properties, "keyed" ); if ( keyed == 0 ) { float fix_rotate_x = mlt_properties_get_double( properties, "fix_rotate_x" ); float fix_rotate_y = mlt_properties_get_double( properties, "fix_rotate_y" ); float fix_rotate_z = mlt_properties_get_double( properties, "fix_rotate_z" ); float rotate_x = mlt_properties_get_double( properties, "rotate_x" ); float rotate_y = mlt_properties_get_double( properties, "rotate_y" ); float rotate_z = mlt_properties_get_double( properties, "rotate_z" ); float fix_shear_x = mlt_properties_get_double( properties, "fix_shear_x" ); float fix_shear_y = mlt_properties_get_double( properties, "fix_shear_y" ); float fix_shear_z = mlt_properties_get_double( properties, "fix_shear_z" ); float shear_x = mlt_properties_get_double( properties, "shear_x" ); float shear_y = mlt_properties_get_double( properties, "shear_y" ); float shear_z = mlt_properties_get_double( properties, "shear_z" ); float ox = mlt_properties_get_double( properties, "ox" ); float oy = mlt_properties_get_double( properties, "oy" ); affine_rotate_x( affine->matrix, fix_rotate_x + rotate_x * position ); affine_rotate_y( affine->matrix, fix_rotate_y + rotate_y * position ); affine_rotate_z( affine->matrix, fix_rotate_z + rotate_z * position ); affine_shear( affine->matrix, fix_shear_x + shear_x * position, fix_shear_y + shear_y * position, fix_shear_z + shear_z * position ); affine_offset( affine->matrix, ox, oy ); } else { float rotate_x = composite_calculate_key( transition, "rotate_x", "rotate_x_info", 360, position ); float rotate_y = composite_calculate_key( transition, "rotate_y", "rotate_y_info", 360, position ); float rotate_z = composite_calculate_key( transition, "rotate_z", "rotate_z_info", 360, position ); float shear_x = composite_calculate_key( transition, "shear_x", "shear_x_info", 360, position ); float shear_y = composite_calculate_key( transition, "shear_y", "shear_y_info", 360, position ); float shear_z = composite_calculate_key( transition, "shear_z", "shear_z_info", 360, position ); float o_x = composite_calculate_key( transition, "ox", "ox_info", 0, position ); float o_y = composite_calculate_key( transition, "oy", "oy_info", 0, position ); affine_rotate_x( affine->matrix, rotate_x ); affine_rotate_y( affine->matrix, rotate_y ); affine_rotate_z( affine->matrix, rotate_z ); affine_shear( affine->matrix, shear_x, shear_y, shear_z ); affine_offset( affine->matrix, o_x, o_y ); } } /** Get the image. */ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the b frame from the stack mlt_frame b_frame = mlt_frame_pop_frame( a_frame ); // Get the transition object mlt_transition transition = mlt_frame_pop_service( a_frame ); // Get the properties of the transition mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); // Get the properties of the a frame mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); // Get the properties of the b frame mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); // Image, format, width, height and image for the b frame uint8_t *b_image = NULL; mlt_image_format b_format = mlt_image_rgb24a; int b_width; int b_height; // Assign the current position mlt_position position = mlt_transition_get_position( transition, a_frame ); int mirror = mlt_properties_get_position( properties, "mirror" ); int length = mlt_transition_get_length( transition ); if ( mlt_properties_get_int( properties, "always_active" ) ) { mlt_properties props = mlt_properties_get_data( b_props, "_producer", NULL ); mlt_position in = mlt_properties_get_int( props, "in" ); mlt_position out = mlt_properties_get_int( props, "out" ); length = out - in + 1; } // Obtain the normalised width and height from the a_frame mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) ); int normalised_width = profile->width; int normalised_height = profile->height; double consumer_ar = mlt_profile_sar( mlt_service_profile( MLT_TRANSITION_SERVICE(transition) ) ); // Structures for geometry struct mlt_geometry_item_s result; if ( mirror && position > length / 2 ) position = abs( position - length ); // Fetch the a frame image *format = mlt_image_rgb24a; mlt_frame_get_image( a_frame, image, format, width, height, 1 ); // Calculate the region now mlt_service_lock( MLT_TRANSITION_SERVICE( transition ) ); composite_calculate( transition, &result, normalised_width, normalised_height, ( float )position ); mlt_service_unlock( MLT_TRANSITION_SERVICE( transition ) ); // Fetch the b frame image result.w = ( result.w * *width / normalised_width ); result.h = ( result.h * *height / normalised_height ); result.x = ( result.x * *width / normalised_width ); result.y = ( result.y * *height / normalised_height ); // Request full resolution of b frame image. b_width = mlt_properties_get_int( b_props, "meta.media.width" ); b_height = mlt_properties_get_int( b_props, "meta.media.height" ); mlt_properties_set_int( b_props, "rescale_width", b_width ); mlt_properties_set_int( b_props, "rescale_height", b_height ); // Suppress padding and aspect normalization. char *interps = mlt_properties_get( a_props, "rescale.interp" ); if ( interps ) interps = strdup( interps ); mlt_properties_set( b_props, "rescale.interp", "none" ); // This is not a field-aware transform. mlt_properties_set_int( b_props, "consumer_deinterlace", 1 ); mlt_frame_get_image( b_frame, &b_image, &b_format, &b_width, &b_height, 0 ); // Check that both images are of the correct format and process if ( *format == mlt_image_rgb24a && b_format == mlt_image_rgb24a ) { float x, y; float dx, dy; float dz; float sw, sh; uint8_t *p = *image; // Get values from the transition float scale_x = mlt_properties_get_double( properties, "scale_x" ); float scale_y = mlt_properties_get_double( properties, "scale_y" ); int scale = mlt_properties_get_int( properties, "scale" ); int b_alpha = mlt_properties_get_int( properties, "b_alpha" ); float geom_scale_x = (float) b_width / result.w; float geom_scale_y = (float) b_height / result.h; float cx = result.x + result.w / 2.0; float cy = result.y + result.h / 2.0; float lower_x = - cx; float lower_y = - cy; float x_offset = (float) b_width / 2.0; float y_offset = (float) b_height / 2.0; affine_t affine; interpp interp = interpBL_b32; int i, j; // loop counters affine_init( affine.matrix ); // Compute the affine transform get_affine( &affine, transition, ( float )position ); dz = MapZ( affine.matrix, 0, 0 ); if ( ( int )abs( dz * 1000 ) < 25 ) { if ( interps ) free( interps ); return 0; } // Factor scaling into the transformation based on output resolution. if ( mlt_properties_get_int( properties, "distort" ) ) { scale_x = geom_scale_x * ( scale_x == 0 ? 1 : scale_x ); scale_y = geom_scale_y * ( scale_y == 0 ? 1 : scale_y ); } else { // Determine scale with respect to aspect ratio. double consumer_dar = consumer_ar * normalised_width / normalised_height; double b_ar = mlt_properties_get_double( b_props, "aspect_ratio" ); double b_dar = b_ar * b_width / b_height; if ( b_dar > consumer_dar ) { scale_x = geom_scale_x * ( scale_x == 0 ? 1 : scale_x ); scale_y = geom_scale_x * ( scale_y == 0 ? 1 : scale_y ); scale_y *= b_ar / consumer_ar; } else { scale_x = geom_scale_y * ( scale_x == 0 ? 1 : scale_x ); scale_y = geom_scale_y * ( scale_y == 0 ? 1 : scale_y ); scale_x *= consumer_ar / b_ar; } } if ( scale ) { affine_max_output( affine.matrix, &sw, &sh, dz, *width, *height ); affine_scale( affine.matrix, sw * MIN( geom_scale_x, geom_scale_y ), sh * MIN( geom_scale_x, geom_scale_y ) ); } else if ( scale_x != 0 && scale_y != 0 ) { affine_scale( affine.matrix, scale_x, scale_y ); } // Set the interpolation function if ( interps == NULL || strcmp( interps, "nearest" ) == 0 || strcmp( interps, "neighbor" ) == 0 ) interp = interpNN_b32; else if ( strcmp( interps, "tiles" ) == 0 || strcmp( interps, "fast_bilinear" ) == 0 ) interp = interpNN_b32; else if ( strcmp( interps, "bilinear" ) == 0 ) interp = interpBL_b32; else if ( strcmp( interps, "bicubic" ) == 0 ) interp = interpBC_b32; // TODO: lanczos 8x8 else if ( strcmp( interps, "hyper" ) == 0 || strcmp( interps, "sinc" ) == 0 || strcmp( interps, "lanczos" ) == 0 ) interp = interpBC_b32; else if ( strcmp( interps, "spline" ) == 0 ) // TODO: spline 4x4 or 6x6 interp = interpBC_b32; // Do the transform with interpolation for ( i = 0, y = lower_y; i < *height; i++, y++ ) { for ( j = 0, x = lower_x; j < *width; j++, x++ ) { dx = MapX( affine.matrix, x, y ) / dz + x_offset; dy = MapY( affine.matrix, x, y ) / dz + y_offset; if ( dx >= 0 && dx < (b_width - 1) && dy >=0 && dy < (b_height - 1) ) interp( b_image, b_width, b_height, dx, dy, result.mix/100.0, p, b_alpha ); p += 4; } } } if ( interps ) free( interps ); return 0; } /** Affine transition processing. */ static mlt_frame transition_process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ) { // Push the transition on to the frame mlt_frame_push_service( a_frame, transition ); // Push the b_frame on to the stack mlt_frame_push_frame( a_frame, b_frame ); // Push the transition method mlt_frame_push_get_image( a_frame, transition_get_image ); return a_frame; } /** Constructor for the filter. */ mlt_transition transition_affine_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_transition transition = mlt_transition_new( ); if ( transition != NULL ) { mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "distort", 0 ); mlt_properties_set( MLT_TRANSITION_PROPERTIES( transition ), "geometry", "0/0:100%x100%" ); // Inform apps and framework that this is a video only transition mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "_transition_type", 1 ); transition->process = transition_process; } return transition; } mlt-0.9.0/src/modules/plus/transition_affine.yml000066400000000000000000000003371215300731300217610ustar00rootroot00000000000000schema_version: 0.1 type: transition identifier: affine title: Transform version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates contributor: - Dan Dennedy license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/qimage/000077500000000000000000000000001215300731300160115ustar00rootroot00000000000000mlt-0.9.0/src/modules/qimage/Makefile000066400000000000000000000020431215300731300174500ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lpthread -lm -L../../mlt++ -lmlt++ include ../../../config.mak include config.mak TARGET = ../libmltqimage$(LIBSUF) OBJS = factory.o producer_qimage.o producer_kdenlivetitle.o CPPOBJS = qimage_wrapper.o \ kdenlivetitle_wrapper.o \ consumer_qglsl.o ifdef GPL3 CPPOBJS += transition_vqm.o CFLAGS += -DGPL3 endif CXXFLAGS += $(CFLAGS) $(QTCXXFLAGS) $(EXIFCXXFLAGS) $(KDECXXFLAGS) -Wno-deprecated LDFLAGS += $(QTLIBS) $(EXIFLIBS) $(KDELIBS) ifdef USE_KDE3 LDFLAGS += -lkio endif SRCS := $(OBJS:.o=.c) $(CPPOBJS:.o=.cpp) all: $(TARGET) $(TARGET): $(OBJS) $(CPPOBJS) $(CXX) $(SHFLAGS) -o $@ $(OBJS) $(CPPOBJS) $(LDFLAGS) depend: $(SRCS) $(CXX) -MM $(CXXFLAGS) $^ 1>.depend distclean: clean rm -f .depend config.h config.mak clean: rm -f $(OBJS) $(TARGET) $(CPPOBJS) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/qimage" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/qimage" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/qimage/configure000077500000000000000000000131611215300731300177220ustar00rootroot00000000000000#!/bin/sh if [ "$help" = "1" ] then cat << EOF QImage options: --force-qt3 - Force compile against Qt3 if Qt4 is present on the system --qimage-libdir - Location of QT lib directory [/usr/lib/qt4 or /usr/lib/qt3] --qimage-includedir - Location of QT include directory [/usr/include/qt4 or /usr/include/qt3] --kde-libdir - Location of KDE lib directory [/usr/lib] --kde-includedir - Location of KDE include directory [/usr/include/kde] --exif-libdir - Location of libexif lib directory [/usr/lib] --exif-includedir - Location of libexif include directory [/usr/include/libexif] --without-kde - Don't link to KDE libraries EOF else targetos=$(uname -s) case $targetos in MINGW32*) export LIBSUF=.dll ;; Darwin) export LIBSUF=.dylib ;; Linux|FreeBSD|NetBSD) export LIBSUF=.so ;; *) ;; esac qimage_includedir= qimage_libdir= if [ "$QTDIR" != "" ] then qimage_includedir="$QTDIR/include" qimage_libdir="$QTDIR/lib" fi export force_qt3= export qt4_found= export without_kde= for i in "$@" do case $i in --qimage-libdir=* ) qimage_libdir="${i#--qimage-libdir=}" ;; --qimage-includedir=* ) qimage_includedir="${i#--qimage-includedir=}" ;; --kde-libdir=* ) kde_libdir="${i#--kde-libdir=}" ;; --kde-includedir=* ) kde_includedir="${i#--kde-includedir=}" ;; --exif-libdir=* ) exif_libdir="${i#--exif-libdir=}" ;; --exif-includedir=* ) exif_includedir="${i#--exif-includedir=}" ;; --force-qt3 ) force_qt3="true" ;; --without-kde ) without_kde="true" ;; esac done echo > config.h echo > config.mak pkg-config --exists 'libexif' if [ $? -eq 0 ] then echo "Libexif found, enabling auto rotate" echo "#define USE_EXIF" >> config.h echo "USE_EXIF=1" >> config.mak echo EXIFCXXFLAGS=$(pkg-config --cflags libexif ) >> config.mak echo EXIFLIBS=$(pkg-config --libs libexif) >> config.mak elif [ -d "$exif_libdir" -a -d "$exif_includedir" ] then # test if we have a libexif if [ -f "$exif_libdir/exif-data.h" ] then echo "Libexif found, enabling auto rotate" echo "#define USE_EXIF" >> config.h echo "USE_EXIF=1" >> config.mak echo EXIFCXXFLAGS=-I$exif_includedir >> config.mak echo EXIFLIBS=-L$exif_libdir lexif >> config.mak else echo "Libexif not found, disabling exif features (auto rotate)" fi fi if [ -d "$qimage_libdir" -a -d "$qimage_includedir" ] then # test if we have a Qt3 or Qt4 if [ -f "$qimage_libdir/libQtCore.so" ] || [ -d "$qimage_libdir/QtGui.framework" ] || [ -f "$qimage_libdir/libQtCore4.a" ] && [ "$force_qt3" = "" ] then echo "Qt version 4.x detected, will compile Qt4 qimage producer" qt4_found=true else echo "Qt version 3.x detected, will compile Qt3 qimage producer" fi echo "Include directory: " $qimage_includedir if [ "$qt4_found" != "" ] && [ "$force_qt3" = "" ] then echo "#define USE_QT4" >> config.h echo "USE_QT4=1" >> config.mak if [ -d "$qimage_libdir/QtGui.framework" ] then echo QTCXXFLAGS=$(pkg-config --cflags QtCore QtGui QtXml QtSvg QtOpenGL) >> config.mak echo QTLIBS=$(pkg-config --libs QtCore QtGui QtXml QtSvg QtOpenGL) >> config.mak elif [ -f "$qimage_libdir/libQtCore4.a" ] then echo QTCXXFLAGS=-I$qimage_includedir >> config.mak echo QTLIBS=-Wl,-enable-auto-import -L$qimage_libdir -lQtCore4 -lQtGui4 -lQtXml4 -lQtSvg4 -lQtOpenGL4 >> config.mak else echo QTCXXFLAGS=-I$qimage_includedir >> config.mak echo QTLIBS=-L$qimage_libdir -lQtCore -lQtGui -lQtXml -lQtSvg -lQtOpenGL >> config.mak fi else if [ "$without_kde" = "" ] && [ -d "$kde_includedir" ] then echo "#define USE_KDE3" >> config.h echo "USE_KDE3=1" >> config.mak echo "#define USE_QT3" >> config.h echo "USE_QT3=1" >> config.mak echo QTCXXFLAGS=-I$qimage_includedir -I$kde_includedir -DQT_THREAD_SUPPORT >> config.mak echo QTLIBS=-L$qimage_libdir -L$kde_libdir -lqt-mt >> config.mak else echo "qimage: KDE environment not found or disabled by request - disabling extra image formats" echo "#define USE_QT3" >> config.h echo "USE_QT3=1" >> config.mak echo QTCXXFLAGS=-I$qimage_includedir -DQT_THREAD_SUPPORT>> config.mak echo QTLIBS=-L$qimage_libdir -lqt-mt >> config.mak fi fi else pkg-config --exists 'QtGui >= 4' if [ $? -eq 0 ] && [ "$force_qt3" = "" ] then echo "Qt version 4.x detected, will compile Qt4 qimage producer" qt4_found=true echo "#define USE_QT4" >> config.h echo "USE_QT4=1" >> config.mak echo QTCXXFLAGS=$(pkg-config --cflags QtCore QtGui QtXml QtSvg QtOpenGL) >> config.mak echo QTLIBS=$(pkg-config --libs QtCore QtGui QtXml QtSvg QtOpenGL) >> config.mak else echo "qimage: QT environment not found - disabling" touch ../disable-qimage fi fi if [ "$without_kde" = "" ] then kde4-config if [ $? -eq 0 ] && [ "$qt4_found" != "" ] then # test if we have KDE4, required on some systems to get QImage extra formats (xcf, ...) if [ "$kde_includedir" = "" ] then kde_includedir=`kde4-config --install include` fi if [ "$kde_libdir" = "" ] then kde_libdir=`kde4-config --install lib` fi if [ -d "$kde_includedir" ] && [ -d "$kde_libdir" ] then echo "KDE version 4.x detected, will enable extra image formats" echo "#define USE_KDE4" >> config.h echo "USE_KDE4=1" >> config.mak echo KDECXXFLAGS=-I$kde_includedir >> config.mak # the -L with kde4/devel is for Fedora echo KDELIBS=-L$kde_libdir -L${kde_libdir}/kde4/devel -lkdecore >> config.mak fi fi fi [ "$gpl3" = "true" ] && echo GPL3=1 >> config.mak exit 0 fi mlt-0.9.0/src/modules/qimage/consumer_qglsl.cpp000066400000000000000000000067071215300731300215640ustar00rootroot00000000000000/* * consumer_qglsl.cpp * Copyright (C) 2012 Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include static void onThreadStarted(mlt_properties owner, mlt_consumer consumer) { mlt_service service = MLT_CONSUMER_SERVICE(consumer); mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer); mlt_filter filter = (mlt_filter) mlt_properties_get_data(properties, "glslManager", NULL); mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter); QApplication* app = qApp; mlt_log_debug(service, "%s\n", __FUNCTION__); #ifdef linux if ( getenv("DISPLAY") == 0 ) { mlt_log_error(service, "The qglsl consumer requires a X11 environment.\nPlease either run melt from an X session or use a fake X server like xvfb:\nxvfb-run -a melt (...)\n" ); } else #endif if (!app) { int argc = 1; char* argv[1]; argv[0] = (char*) "MLT qglsl consumer"; app = new QApplication(argc, argv); const char *localename = mlt_properties_get_lcnumeric(properties); QLocale::setDefault(QLocale(localename)); } QGLWidget* renderContext = new QGLWidget; renderContext->resize(0, 0); renderContext->show(); mlt_events_fire(filter_properties, "init glsl", NULL); if (!mlt_properties_get_int(filter_properties, "glsl_supported")) { mlt_log_fatal(service, "OpenGL Shading Language rendering is not supported on this machine.\n" ); mlt_events_fire(properties, "consumer-fatal-error", NULL); } else { mlt_properties_set_data(properties, "qglslRenderContext", renderContext, 0, NULL, NULL); } } static void onCleanup(mlt_properties owner, mlt_consumer consumer) { QGLWidget* renderContext = (QGLWidget*) mlt_properties_get_data( MLT_CONSUMER_PROPERTIES(consumer), "qglslRenderContext", NULL); if (renderContext) renderContext->makeCurrent(); delete renderContext; mlt_properties_set_data(MLT_CONSUMER_PROPERTIES(consumer), "qglslRenderContext", NULL, 0, NULL, NULL); } extern "C" { mlt_consumer consumer_qglsl_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_consumer consumer = mlt_factory_consumer(profile, "multi", arg); if (consumer) { mlt_filter filter = mlt_factory_filter(profile, "glsl.manager", 0); if (filter) { mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer); mlt_properties_set_data(properties, "glslManager", filter, 0, (mlt_destructor) mlt_filter_close, NULL); mlt_events_register( properties, "consumer-cleanup", NULL ); mlt_events_listen(properties, consumer, "consumer-thread-started", (mlt_listener) onThreadStarted); mlt_events_listen(properties, consumer, "consumer-cleanup", (mlt_listener) onCleanup); return consumer; } mlt_consumer_close(consumer); } return NULL; } } mlt-0.9.0/src/modules/qimage/factory.c000066400000000000000000000042371215300731300176320ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2006 Visual Media * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include extern mlt_consumer consumer_qglsl_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_qimage_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_kdenlivetitle_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_transition transition_vqm_init( mlt_profile profile, mlt_service_type type, const char *id, void *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/qimage/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( consumer_type, "qglsl", consumer_qglsl_init ); MLT_REGISTER( producer_type, "qimage", producer_qimage_init ); MLT_REGISTER( producer_type, "kdenlivetitle", producer_kdenlivetitle_init ); MLT_REGISTER_METADATA( producer_type, "qimage", metadata, "producer_qimage.yml" ); MLT_REGISTER_METADATA( producer_type, "kdenlivetitle", metadata, "producer_kdenlivetitle.yml" ); #ifdef GPL3 MLT_REGISTER( transition_type, "vqm", transition_vqm_init ); MLT_REGISTER_METADATA( transition_type, "vqm", metadata, "transition_vqm.yml" ); #endif } mlt-0.9.0/src/modules/qimage/gpl000066400000000000000000000000001215300731300165040ustar00rootroot00000000000000mlt-0.9.0/src/modules/qimage/kdenlivetitle_wrapper.cpp000077500000000000000000000504221215300731300231260ustar00rootroot00000000000000/* * kdenlivetitle_wrapper.cpp -- kdenlivetitle wrapper * Copyright (c) 2009 Marco Gittler * Copyright (c) 2009 Jean-Baptiste Mardelle * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "kdenlivetitle_wrapper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= 0x040600 #include #include #include #endif static QApplication *app = NULL; Q_DECLARE_METATYPE(QTextCursor); class ImageItem: public QGraphicsItem { public: ImageItem(QImage img) { m_img = img; } QImage m_img; protected: virtual QRectF boundingRect() const { return QRectF(0, 0, m_img.width(), m_img.height()); } virtual void paint( QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget* ) { painter->setRenderHint(QPainter::SmoothPixmapTransform, true); painter->drawImage(QPoint(), m_img); } }; QRectF stringToRect( const QString & s ) { QStringList l = s.split( ',' ); if ( l.size() < 4 ) return QRectF(); return QRectF( l.at( 0 ).toDouble(), l.at( 1 ).toDouble(), l.at( 2 ).toDouble(), l.at( 3 ).toDouble() ).normalized(); } QColor stringToColor( const QString & s ) { QStringList l = s.split( ',' ); if ( l.size() < 4 ) return QColor(); return QColor( l.at( 0 ).toInt(), l.at( 1 ).toInt(), l.at( 2 ).toInt(), l.at( 3 ).toInt() ); ; } QTransform stringToTransform( const QString& s ) { QStringList l = s.split( ',' ); if ( l.size() < 9 ) return QTransform(); return QTransform( l.at( 0 ).toDouble(), l.at( 1 ).toDouble(), l.at( 2 ).toDouble(), l.at( 3 ).toDouble(), l.at( 4 ).toDouble(), l.at( 5 ).toDouble(), l.at( 6 ).toDouble(), l.at( 7 ).toDouble(), l.at( 8 ).toDouble() ); } static void qscene_delete( void *data ) { QGraphicsScene *scene = ( QGraphicsScene * )data; if (scene) delete scene; scene = NULL; } void loadFromXml( mlt_producer producer, QGraphicsScene *scene, const char *templateXml, const char *templateText ) { scene->clear(); mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); QDomDocument doc; QString data = QString::fromUtf8(templateXml); QString replacementText = QString::fromUtf8(templateText); doc.setContent(data); QDomElement title = doc.documentElement(); // Check for invalid title if ( title.isNull() || title.tagName() != "kdenlivetitle" ) return; // Check title locale if ( title.hasAttribute( "LC_NUMERIC" ) ) { QString locale = title.attribute( "LC_NUMERIC" ); QLocale::setDefault( locale ); } int originalWidth; int originalHeight; if ( title.hasAttribute("width") ) { originalWidth = title.attribute("width").toInt(); originalHeight = title.attribute("height").toInt(); scene->setSceneRect(0, 0, originalWidth, originalHeight); } else { originalWidth = scene->sceneRect().width(); originalHeight = scene->sceneRect().height(); } if ( title.hasAttribute( "out" ) ) { mlt_properties_set_position( producer_props, "_animation_out", title.attribute( "out" ).toDouble() ); } else { mlt_properties_set_position( producer_props, "_animation_out", mlt_producer_get_out( producer ) ); } mlt_properties_set_int( producer_props, "_original_width", originalWidth ); mlt_properties_set_int( producer_props, "_original_height", originalHeight ); QDomNode node; QDomNodeList items = title.elementsByTagName("item"); for ( int i = 0; i < items.count(); i++ ) { QGraphicsItem *gitem = NULL; node = items.item( i ); QDomNamedNodeMap nodeAttributes = node.attributes(); int zValue = nodeAttributes.namedItem( "z-index" ).nodeValue().toInt(); if ( zValue > -1000 ) { if ( nodeAttributes.namedItem( "type" ).nodeValue() == "QGraphicsTextItem" ) { QDomNamedNodeMap txtProperties = node.namedItem( "content" ).attributes(); QFont font( txtProperties.namedItem( "font" ).nodeValue() ); QDomNode propsNode = txtProperties.namedItem( "font-bold" ); if ( !propsNode.isNull() ) { // Old: Bold/Not bold. font.setBold( propsNode.nodeValue().toInt() ); } else { // New: Font weight (QFont::) font.setWeight( txtProperties.namedItem( "font-weight" ).nodeValue().toInt() ); } font.setItalic( txtProperties.namedItem( "font-italic" ).nodeValue().toInt() ); font.setUnderline( txtProperties.namedItem( "font-underline" ).nodeValue().toInt() ); // Older Kdenlive version did not store pixel size but point size if ( txtProperties.namedItem( "font-pixel-size" ).isNull() ) { QFont f2; f2.setPointSize( txtProperties.namedItem( "font-size" ).nodeValue().toInt() ); font.setPixelSize( QFontInfo( f2 ).pixelSize() ); } else font.setPixelSize( txtProperties.namedItem( "font-pixel-size" ).nodeValue().toInt() ); QColor col( stringToColor( txtProperties.namedItem( "font-color" ).nodeValue() ) ); QString text = node.namedItem( "content" ).firstChild().nodeValue(); if ( !replacementText.isEmpty() ) { text = text.replace( "%s", replacementText ); } QGraphicsTextItem *txt = scene->addText(text, font); if (txtProperties.namedItem("font-outline").nodeValue().toDouble()>0.0){ QTextDocument *doc = txt->document(); // Make sure some that the text item does not request refresh by itself doc->blockSignals(true); QTextCursor cursor(doc); cursor.select(QTextCursor::Document); QTextCharFormat format; format.setTextOutline( QPen(QColor( stringToColor( txtProperties.namedItem( "font-outline-color" ).nodeValue() ) ), txtProperties.namedItem("font-outline").nodeValue().toDouble(), Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin) ); format.setForeground(QBrush(col)); cursor.mergeCharFormat(format); } else { txt->setDefaultTextColor( col ); } // Effects if (!txtProperties.namedItem( "typewriter" ).isNull()) { // typewriter effect mlt_properties_set_int( producer_props, "_animated", 1 ); QStringList effetData = QStringList() << "typewriter" << text << txtProperties.namedItem( "typewriter" ).nodeValue(); txt->setData(0, effetData); if ( !txtProperties.namedItem( "textwidth" ).isNull() ) txt->setData( 1, txtProperties.namedItem( "textwidth" ).nodeValue() ); } if ( txtProperties.namedItem( "alignment" ).isNull() == false ) { txt->setTextWidth( txt->boundingRect().width() ); QTextOption opt = txt->document()->defaultTextOption (); opt.setAlignment(( Qt::Alignment ) txtProperties.namedItem( "alignment" ).nodeValue().toInt() ); txt->document()->setDefaultTextOption (opt); } if ( !txtProperties.namedItem( "kdenlive-axis-x-inverted" ).isNull() ) { //txt->setData(OriginXLeft, txtProperties.namedItem("kdenlive-axis-x-inverted").nodeValue().toInt()); } if ( !txtProperties.namedItem( "kdenlive-axis-y-inverted" ).isNull() ) { //txt->setData(OriginYTop, txtProperties.namedItem("kdenlive-axis-y-inverted").nodeValue().toInt()); } gitem = txt; } else if ( nodeAttributes.namedItem( "type" ).nodeValue() == "QGraphicsRectItem" ) { QString rect = node.namedItem( "content" ).attributes().namedItem( "rect" ).nodeValue(); QString br_str = node.namedItem( "content" ).attributes().namedItem( "brushcolor" ).nodeValue(); QString pen_str = node.namedItem( "content" ).attributes().namedItem( "pencolor" ).nodeValue(); double penwidth = node.namedItem( "content" ).attributes().namedItem( "penwidth") .nodeValue().toDouble(); QGraphicsRectItem *rec = scene->addRect( stringToRect( rect ), QPen( QBrush( stringToColor( pen_str ) ), penwidth, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin ), QBrush( stringToColor( br_str ) ) ); gitem = rec; } else if ( nodeAttributes.namedItem( "type" ).nodeValue() == "QGraphicsPixmapItem" ) { const QString url = node.namedItem( "content" ).attributes().namedItem( "url" ).nodeValue(); const QString base64 = items.item(i).namedItem("content").attributes().namedItem("base64").nodeValue(); QImage img; if (base64.isEmpty()){ img.load(url); }else{ img.loadFromData(QByteArray::fromBase64(base64.toAscii())); } ImageItem *rec = new ImageItem(img); scene->addItem( rec ); gitem = rec; } else if ( nodeAttributes.namedItem( "type" ).nodeValue() == "QGraphicsSvgItem" ) { QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue(); QString base64 = items.item(i).namedItem("content").attributes().namedItem("base64").nodeValue(); QGraphicsSvgItem *rec = NULL; if (base64.isEmpty()){ rec = new QGraphicsSvgItem(url); }else{ rec = new QGraphicsSvgItem(); QSvgRenderer *renderer= new QSvgRenderer(QByteArray::fromBase64(base64.toAscii()), rec ); rec->setSharedRenderer(renderer); } if (rec){ scene->addItem(rec); gitem = rec; } } } //pos and transform if ( gitem ) { QPointF p( node.namedItem( "position" ).attributes().namedItem( "x" ).nodeValue().toDouble(), node.namedItem( "position" ).attributes().namedItem( "y" ).nodeValue().toDouble() ); gitem->setPos( p ); gitem->setTransform( stringToTransform( node.namedItem( "position" ).firstChild().firstChild().nodeValue() ) ); int zValue = nodeAttributes.namedItem( "z-index" ).nodeValue().toInt(); gitem->setZValue( zValue ); #if QT_VERSION >= 0x040600 // effects QDomNode eff = items.item(i).namedItem("effect"); if (!eff.isNull()) { QDomElement e = eff.toElement(); if (e.attribute("type") == "blur") { QGraphicsBlurEffect *blur = new QGraphicsBlurEffect(); blur->setBlurRadius(e.attribute("blurradius").toInt()); gitem->setGraphicsEffect(blur); } else if (e.attribute("type") == "shadow") { QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(); shadow->setBlurRadius(e.attribute("blurradius").toInt()); shadow->setOffset(e.attribute("xoffset").toInt(), e.attribute("yoffset").toInt()); gitem->setGraphicsEffect(shadow); } } #endif } } QDomNode n = title.firstChildElement("background"); if (!n.isNull()) { QColor color = QColor( stringToColor( n.attributes().namedItem( "color" ).nodeValue() ) ); if (color.alpha() > 0) { QGraphicsRectItem *rec = scene->addRect(0, 0, scene->width(), scene->height() , QPen( Qt::NoPen ), QBrush( color ) ); rec->setZValue(-1100); } } QString startRect; n = title.firstChildElement( "startviewport" ); // Check if node exists, if it has an x attribute, it is an old version title, don't use viewport if (!n.isNull() && !n.toElement().hasAttribute("x")) { startRect = n.attributes().namedItem( "rect" ).nodeValue(); } n = title.firstChildElement( "endviewport" ); // Check if node exists, if it has an x attribute, it is an old version title, don't use viewport if (!n.isNull() && !n.toElement().hasAttribute("x")) { QString rect = n.attributes().namedItem( "rect" ).nodeValue(); if (startRect != rect) mlt_properties_set( producer_props, "_endrect", rect.toUtf8().data() ); } if (!startRect.isEmpty()) { mlt_properties_set( producer_props, "_startrect", startRect.toUtf8().data() ); } return; } void drawKdenliveTitle( producer_ktitle self, mlt_frame frame, int width, int height, double position, int force_refresh ) { // Obtain the producer mlt_producer producer = &self->parent; mlt_profile profile = mlt_service_profile ( MLT_PRODUCER_SERVICE( producer ) ) ; mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Obtain properties of frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); pthread_mutex_lock( &self->mutex ); // Check if user wants us to reload the image if ( mlt_properties_get( producer_props, "_animated" ) != NULL || force_refresh == 1 || width != self->current_width || height != self->current_height || mlt_properties_get( producer_props, "_endrect" ) != NULL ) { //mlt_cache_item_close( self->image_cache ); self->current_image = NULL; mlt_properties_set_data( producer_props, "cached_image", NULL, 0, NULL, NULL ); mlt_properties_set_int( producer_props, "force_reload", 0 ); } if (self->current_image == NULL) { // restore QGraphicsScene QGraphicsScene *scene = static_cast (mlt_properties_get_data( producer_props, "qscene", NULL )); if ( force_refresh == 1 && scene ) { scene = NULL; mlt_properties_set_data( producer_props, "qscene", NULL, 0, NULL, NULL ); } if ( scene == NULL ) { int argc = 1; char* argv[1]; argv[0] = (char*) "xxx"; // Warning: all Qt graphic objects (QRect, ...) must be initialized AFTER // the QApplication is created, otherwise their will be NULL if ( app == NULL ) { if ( qApp ) { app = qApp; } else { #ifdef linux if ( getenv("DISPLAY") == 0 ) { mlt_log_panic( MLT_PRODUCER_SERVICE( producer ), "Error, cannot render titles without an X11 environment.\nPlease either run melt from an X session or use a fake X server like xvfb:\nxvfb-run -a melt (...)\n" ); pthread_mutex_unlock( &self->mutex ); return; } #endif app = new QApplication( argc, argv ); const char *localename = mlt_properties_get_lcnumeric( MLT_SERVICE_PROPERTIES( MLT_PRODUCER_SERVICE( producer ) ) ); QLocale::setDefault( QLocale( localename ) ); } qRegisterMetaType( "QTextCursor" ); } scene = new QGraphicsScene(); scene->setItemIndexMethod( QGraphicsScene::NoIndex ); scene->setSceneRect(0, 0, mlt_properties_get_int( properties, "width" ), mlt_properties_get_int( properties, "height" )); if ( mlt_properties_get( producer_props, "resource" ) && mlt_properties_get( producer_props, "resource" )[0] != '\0' ) { // The title has a resource property, so we read all properties from the resource. // Do not serialize the xmldata loadFromXml( producer, scene, mlt_properties_get( producer_props, "_xmldata" ), mlt_properties_get( producer_props, "templatetext" ) ); } else { // The title has no resource, all data should be serialized loadFromXml( producer, scene, mlt_properties_get( producer_props, "xmldata" ), mlt_properties_get( producer_props, "templatetext" ) ); } mlt_properties_set_data( producer_props, "qscene", scene, 0, ( mlt_destructor )qscene_delete, NULL ); } QRectF start = stringToRect( QString( mlt_properties_get( producer_props, "_startrect" ) ) ); QRectF end = stringToRect( QString( mlt_properties_get( producer_props, "_endrect" ) ) ); int originalWidth = mlt_properties_get_int( producer_props, "_original_width" ); int originalHeight= mlt_properties_get_int( producer_props, "_original_height" ); const QRectF source( 0, 0, width, height ); if (start.isNull()) { start = QRectF( 0, 0, originalWidth, originalHeight ); } // Effects QList items = scene->items(); QGraphicsTextItem *titem = NULL; for (int i = 0; i < items.count(); i++) { titem = static_cast ( items.at( i ) ); if (titem && !titem->data( 0 ).isNull()) { QStringList params = titem->data( 0 ).toStringList(); if (params.at( 0 ) == "typewriter" ) { // typewriter effect has 2 param values: // the keystroke delay and a start offset, both in frames QStringList values = params.at( 2 ).split( ";" ); int interval = qMax( 0, ( ( int ) position - values.at( 1 ).toInt()) / values.at( 0 ).toInt() ); QTextCursor cursor = titem->textCursor(); cursor.movePosition(QTextCursor::EndOfBlock); // get the font format QTextCharFormat format = cursor.charFormat(); cursor.select(QTextCursor::Document); QString txt = params.at( 1 ).left( interval ); // If the string to insert is empty, insert a space / linebreak so that we don't loose // formatting infos for the next iterations int lines = params.at( 1 ).count( '\n' ); QString empty = " "; for (int i = 0; i < lines; i++) empty.append( "\n " ); cursor.insertText( txt.isEmpty() ? empty : txt, format ); if ( !titem->data( 1 ).isNull() ) titem->setTextWidth( titem->data( 1 ).toDouble() ); } } } //must be extracted from kdenlive title QImage img( width, height, QImage::Format_ARGB32 ); img.fill( 0 ); QPainter p1; p1.begin( &img ); p1.setRenderHints( QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing ); //| QPainter::SmoothPixmapTransform ); mlt_position anim_out = mlt_properties_get_position( producer_props, "_animation_out" ); if (end.isNull()) { scene->render( &p1, source, start, Qt::IgnoreAspectRatio ); } else if ( position > anim_out ) { scene->render( &p1, source, end, Qt::IgnoreAspectRatio ); } else { double percentage = 0; if ( position && anim_out ) percentage = position / anim_out; QPointF topleft = start.topLeft() + ( end.topLeft() - start.topLeft() ) * percentage; QPointF bottomRight = start.bottomRight() + ( end.bottomRight() - start.bottomRight() ) * percentage; const QRectF r1( topleft, bottomRight ); scene->render( &p1, source, r1, Qt::IgnoreAspectRatio ); if ( profile && !profile->progressive ){ int line=0; double percentage_next_filed = ( position + 0.5 ) / anim_out; QPointF topleft_next_field = start.topLeft() + ( end.topLeft() - start.topLeft() ) * percentage_next_filed; QPointF bottomRight_next_field = start.bottomRight() + ( end.bottomRight() - start.bottomRight() ) * percentage_next_filed; const QRectF r2( topleft_next_field, bottomRight_next_field ); QImage img1( width, height, QImage::Format_ARGB32 ); img1.fill( 0 ); QPainter p2; p2.begin(&img1); p2.setRenderHints( QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing ); scene->render(&p2,source,r2, Qt::IgnoreAspectRatio ); p2.end(); int next_field_line = ( mlt_properties_get_int( producer_props, "top_field_first" ) ? 1 : 0 ); for (line = next_field_line ;linecurrent_image = ( uint8_t * )mlt_pool_alloc( size ); uint8_t *dst = self->current_image; for ( int i = 0; i < width * height * 4; i += 4 ) { *dst++=qRed( *src ); *dst++=qGreen( *src ); *dst++=qBlue( *src ); *dst++=qAlpha( *src ); src++; } mlt_properties_set_data( producer_props, "cached_image", self->current_image, size, mlt_pool_release, NULL ); self->current_width = width; self->current_height = height; } pthread_mutex_unlock( &self->mutex ); mlt_properties_set_int( properties, "width", self->current_width ); mlt_properties_set_int( properties, "height", self->current_height ); } mlt-0.9.0/src/modules/qimage/kdenlivetitle_wrapper.h000066400000000000000000000026261215300731300225730ustar00rootroot00000000000000/* * kdenlivetitle_wrapper.h -- kdenlivetitle wrapper * Copyright (c) 2009 Marco Gittler * Copyright (c) 2009 Jean-Baptiste Mardelle * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #ifdef __cplusplus extern "C" { #endif #include #include #include struct producer_ktitle_s { struct mlt_producer_s parent; uint8_t *current_image; int current_width; int current_height; pthread_mutex_t mutex; }; typedef struct producer_ktitle_s *producer_ktitle; extern void drawKdenliveTitle( producer_ktitle self, mlt_frame frame, int, int, double, int ); #ifdef __cplusplus } #endif mlt-0.9.0/src/modules/qimage/producer_kdenlivetitle.c000066400000000000000000000131051215300731300227230ustar00rootroot00000000000000/* * producer_kdenlivetitle.c -- kdenlive producer * Copyright (c) 2009 Marco Gittler * Copyright (c) 2009 Jean-Baptiste Mardelle * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "kdenlivetitle_wrapper.h" #include #include #include void read_xml(mlt_properties properties) { FILE *f = fopen( mlt_properties_get( properties, "resource" ), "r"); if ( f != NULL ) { int size = 0; long lSize; if ( fseek (f , 0 , SEEK_END) < 0 ) goto error; lSize = ftell (f); if ( lSize <= 0 ) goto error; rewind (f); char *infile = (char*) mlt_pool_alloc(lSize); if ( infile ) { size = fread(infile,1,lSize,f); if ( size ) { infile[size] = '\0'; mlt_properties_set(properties, "_xmldata", infile); } mlt_pool_release( infile ); } error: fclose(f); } } static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { /* Obtain properties of frame */ mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); /* Obtain the producer for this frame */ producer_ktitle this = mlt_properties_get_data( properties, "producer_kdenlivetitle", NULL ); /* Obtain properties of producer */ mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( &this->parent ); *width = mlt_properties_get_int( properties, "rescale_width" ); *height = mlt_properties_get_int( properties, "rescale_height" ); mlt_service_lock( MLT_PRODUCER_SERVICE( &this->parent ) ); /* Allocate the image */ *format = mlt_image_rgb24a; if ( mlt_properties_get_int( producer_props, "force_reload" ) ) { if ( mlt_properties_get_int( producer_props, "force_reload" ) > 1 ) read_xml( producer_props ); mlt_properties_set_int( producer_props, "force_reload", 0 ); drawKdenliveTitle( this, frame, *width, *height, mlt_frame_original_position( frame ), 1); } else drawKdenliveTitle( this, frame, *width, *height, mlt_frame_original_position( frame ), 0); // Get width and height (may have changed during the refresh) *width = mlt_properties_get_int( properties, "width" ); *height = mlt_properties_get_int( properties, "height" ); if ( this->current_image ) { // Clone the image and the alpha int image_size = this->current_width * ( this->current_height ) * 4; uint8_t *image_copy = mlt_pool_alloc( image_size ); memcpy( image_copy, this->current_image, image_size ); // Now update properties so we free the copy after mlt_frame_set_image( frame, image_copy, image_size, mlt_pool_release ); // We're going to pass the copy on *buffer = image_copy; mlt_log_debug( MLT_PRODUCER_SERVICE( &this->parent ), "width:%d height:%d %s\n", *width, *height, mlt_image_format_name( *format ) ); } mlt_service_unlock( MLT_PRODUCER_SERVICE( &this->parent ) ); return 0; } static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Get the real structure for this producer producer_ktitle this = producer->child; /* Generate a frame */ *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL ) { /* Obtain properties of frame and producer */ mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); /* Obtain properties of producer */ mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); /* Set the producer on the frame properties */ mlt_properties_set_data( properties, "producer_kdenlivetitle", this, 0, NULL, NULL ); /* Update timecode on the frame we're creating */ mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); /* Set producer-specific frame properties */ mlt_properties_pass_list( properties, producer_props, "progressive, aspect_ratio" ); /* Push the get_image method */ mlt_frame_push_get_image( *frame, producer_get_image ); } /* Calculate the next timecode */ mlt_producer_prepare_next( producer ); return 0; } static void producer_close( mlt_producer producer ) { /* fprintf(stderr, ":::::::::::::: CLOSING TITLE\n"); */ producer->close = NULL; mlt_producer_close( producer ); free( producer ); } mlt_producer producer_kdenlivetitle_init( mlt_profile profile, mlt_service_type type, const char *id, char *filename ) { /* fprintf(stderr, ":::::::::::: CREATE TITLE\n"); */ /* Create a new producer object */ producer_ktitle this = calloc( 1, sizeof( struct producer_ktitle_s ) ); if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 ) { mlt_producer producer = &this->parent; /* Get the properties interface */ mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); /* Callback registration */ producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )producer_close; mlt_properties_set( properties, "resource", filename ); mlt_properties_set_int( properties, "progressive", 1 ); read_xml(properties); return producer; } free( this ); return NULL; } mlt-0.9.0/src/modules/qimage/producer_kdenlivetitle.yml000066400000000000000000000003561215300731300233060ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: kdenlivetitle title: Kdenlive Titler version: 1 copyright: Marco Gittler, Jean-Baptiste Mardelle creator: Marco Gittler, Jean-Baptiste Mardelle license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/qimage/producer_qimage.c000066400000000000000000000271471215300731300213360ustar00rootroot00000000000000/* * producer_image.c -- a QT/QImage based producer for MLT * Copyright (C) 2006 Visual Media * Author: Charles Yates * * NB: This module is designed to be functionally equivalent to the * gtk2 image loading module so it can be used as replacement. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "qimage_wrapper.h" #include #include #include #include #include #include #include #include static void load_filenames( producer_qimage self, mlt_properties producer_properties ); static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ); static void producer_close( mlt_producer parent ); mlt_producer producer_qimage_init( mlt_profile profile, mlt_service_type type, const char *id, char *filename ) { producer_qimage self = calloc( 1, sizeof( struct producer_qimage_s ) ); if ( self != NULL && mlt_producer_init( &self->parent, self ) == 0 ) { mlt_producer producer = &self->parent; // Get the properties interface mlt_properties properties = MLT_PRODUCER_PROPERTIES( &self->parent ); // Initialize KDE image plugins init_qimage(); // Callback registration producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )producer_close; // Set the default properties mlt_properties_set( properties, "resource", filename ); mlt_properties_set_int( properties, "ttl", 25 ); mlt_properties_set_int( properties, "aspect_ratio", 1 ); mlt_properties_set_int( properties, "progressive", 1 ); mlt_properties_set_int( properties, "seekable", 1 ); // Validate the resource if ( filename ) load_filenames( self, properties ); if ( self->count ) { mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( frame ) { mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); mlt_properties_set_data( frame_properties, "producer_qimage", self, 0, NULL, NULL ); mlt_frame_set_position( frame, mlt_producer_position( producer ) ); refresh_qimage( self, frame ); mlt_cache_item_close( self->qimage_cache ); mlt_frame_close( frame ); } } if ( self->current_width == 0 ) { producer_close( producer ); producer = NULL; } return producer; } free( self ); return NULL; } static int load_svg( producer_qimage self, mlt_properties properties, const char *filename ) { int result = 0; // Read xml string if ( strstr( filename, "filenames, key, full ); gap = 0; } else { gap ++; } } if ( mlt_properties_count( self->filenames ) > 0 ) { mlt_properties_set_int( properties, "ttl", 1 ); result = 1; } } return result; } static int load_sequence_deprecated( producer_qimage self, mlt_properties properties, const char *filename ) { int result = 0; const char *start; // Obtain filenames with pattern containing a begin value, e.g. foo%1234d.png if ( ( start = strchr( filename, '%' ) ) ) { const char *end = ++start; while ( isdigit( *end ) ) end++; if ( end > start && ( end[0] == 'd' || end[0] == 'i' || end[0] == 'u' ) ) { int n = end - start; char *s = calloc( 1, n + 1 ); strncpy( s, start, n ); mlt_properties_set( properties, "begin", s ); free( s ); s = calloc( 1, strlen( filename ) + 2 ); strncpy( s, filename, start - filename ); sprintf( s + ( start - filename ), ".%d%s", n, end ); result = load_sequence_sprintf( self, properties, s ); free( s ); } } return result; } static int load_sequence_querystring( producer_qimage self, mlt_properties properties, const char *filename ) { int result = 0; // Obtain filenames with pattern and begin value in query string if ( strchr( filename, '%' ) && strchr( filename, '?' ) ) { // Split filename into pattern and query string char *s = strdup( filename ); char *querystring = strrchr( s, '?' ); *querystring++ = '\0'; if ( strstr( filename, "begin=" ) ) mlt_properties_set( properties, "begin", strstr( querystring, "begin=" ) + 6 ); else if ( strstr( filename, "begin:" ) ) mlt_properties_set( properties, "begin", strstr( querystring, "begin:" ) + 6 ); // Coerce to an int value so serialization does not have any extra query string cruft mlt_properties_set_int( properties, "begin", mlt_properties_get_int( properties, "begin" ) ); result = load_sequence_sprintf( self, properties, s ); free( s ); } return result; } static int load_folder( producer_qimage self, mlt_properties properties, const char *filename ) { int result = 0; // Obtain filenames within folder if ( strstr( filename, "/.all." ) != NULL ) { char wildcard[ 1024 ]; char *dir_name = strdup( filename ); char *extension = strrchr( dir_name, '.' ); *( strstr( dir_name, "/.all." ) + 1 ) = '\0'; sprintf( wildcard, "*%s", extension ); mlt_properties_dir_list( self->filenames, dir_name, wildcard, 1 ); free( dir_name ); result = 1; } return result; } static void load_filenames( producer_qimage self, mlt_properties properties ) { char *filename = mlt_properties_get( properties, "resource" ); self->filenames = mlt_properties_new( ); if (!load_svg( self, properties, filename ) && !load_sequence_querystring( self, properties, filename ) && !load_sequence_sprintf( self, properties, filename ) && !load_sequence_deprecated( self, properties, filename ) && !load_folder( self, properties, filename ) ) { mlt_properties_set( self->filenames, "0", filename ); } self->count = mlt_properties_count( self->filenames ); } static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); producer_qimage self = mlt_properties_get_data( properties, "producer_qimage", NULL ); mlt_producer producer = &self->parent; *width = mlt_properties_get_int( properties, "rescale_width" ); *height = mlt_properties_get_int( properties, "rescale_height" ); mlt_service_lock( MLT_PRODUCER_SERVICE( &self->parent ) ); // Refresh the image self->qimage_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.qimage" ); self->qimage = mlt_cache_item_data( self->qimage_cache, NULL ); self->image_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.image" ); self->current_image = mlt_cache_item_data( self->image_cache, NULL ); self->alpha_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.alpha" ); self->current_alpha = mlt_cache_item_data( self->alpha_cache, NULL ); refresh_image( self, frame, *format, *width, *height ); // Get width and height (may have changed during the refresh) *width = mlt_properties_get_int( properties, "width" ); *height = mlt_properties_get_int( properties, "height" ); *format = self->format; // NB: Cloning is necessary with this producer (due to processing of images ahead of use) // The fault is not in the design of mlt, but in the implementation of the qimage producer... if ( self->current_image ) { // Clone the image and the alpha int image_size = mlt_image_format_size( self->format, self->current_width, self->current_height, NULL ); uint8_t *image_copy = mlt_pool_alloc( image_size ); memcpy( image_copy, self->current_image, image_size ); // Now update properties so we free the copy after mlt_frame_set_image( frame, image_copy, image_size, mlt_pool_release ); // We're going to pass the copy on *buffer = image_copy; mlt_log_debug( MLT_PRODUCER_SERVICE( &self->parent ), "%dx%d (%s)\n", self->current_width, self->current_height, mlt_image_format_name( *format ) ); // Clone the alpha channel if ( self->current_alpha ) { image_copy = mlt_pool_alloc( self->current_width * self->current_height ); memcpy( image_copy, self->current_alpha, self->current_width * self->current_height ); mlt_frame_set_alpha( frame, image_copy, self->current_width * self->current_height, mlt_pool_release ); } } else { error = 1; } // Release references and locks mlt_cache_item_close( self->qimage_cache ); mlt_cache_item_close( self->image_cache ); mlt_cache_item_close( self->alpha_cache ); mlt_service_unlock( MLT_PRODUCER_SERVICE( &self->parent ) ); return error; } static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Get the real structure for this producer producer_qimage self = producer->child; // Fetch the producers properties mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); if ( self->filenames == NULL && mlt_properties_get( producer_properties, "resource" ) != NULL ) load_filenames( self, producer_properties ); // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL && self->count > 0 ) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Set the producer on the frame properties mlt_properties_set_data( properties, "producer_qimage", self, 0, NULL, NULL ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Refresh the image self->qimage_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.qimage" ); self->qimage = mlt_cache_item_data( self->qimage_cache, NULL ); refresh_qimage( self, *frame ); mlt_cache_item_close( self->qimage_cache ); // Set producer-specific frame properties mlt_properties_set_int( properties, "progressive", mlt_properties_get_int( producer_properties, "progressive" ) ); double force_ratio = mlt_properties_get_double( producer_properties, "force_aspect_ratio" ); if ( force_ratio > 0.0 ) mlt_properties_set_double( properties, "aspect_ratio", force_ratio ); else mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_properties, "aspect_ratio" ) ); // Push the get_image method mlt_frame_push_get_image( *frame, producer_get_image ); } // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; } static void producer_close( mlt_producer parent ) { producer_qimage self = parent->child; parent->close = NULL; mlt_service_cache_purge( MLT_PRODUCER_SERVICE(parent) ); mlt_producer_close( parent ); mlt_properties_close( self->filenames ); free( self ); } mlt-0.9.0/src/modules/qimage/producer_qimage.yml000066400000000000000000000057161215300731300217130ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: qimage title: Qt QImage version: 2 copyright: Visual Media ? creator: Charles Yates license: GPLv2 language: en tags: - Video description: > A still graphics to video generator using Qt QImage notes: > QImage has builtin scaling. It will rescale the originally rendered title to whatever the consumer requests. Therefore, it will lose its aspect ratio if so requested, and it is up to the consumer to request a proper width and height that maintains the image aspect. parameters: - identifier: argument title: File type: string description: > The name of a graphics file loadable by Qt. If "%" in filename, the filename is used with sprintf to generate a filename from a counter for multi-file/flipbook animation. The file sequence ends when numeric discontinuity exceeds 100. If the file sequence does not begin within the count of 100 you can pass the begin property like a query string parameter, for example: anim-%04d.png?begin=1000. If filename contains "/.all.", suffix with an extension to load all pictures with matching extension from a directory. If filename contains the string " Reload the file instead of using its cached image. This property automatically resets itself once it has been set 1 and processed. minimum: 0 maximum: 1 mutable: yes - identifier: disable_exif title: Disable auto-rotation type: integer minimum: 0 maximum: 1 widget: checkbox - identifier: force_aspect_ratio title: Sample aspect ratio type: float description: Optionally override a (mis)detected aspect ratio mutable: yes mlt-0.9.0/src/modules/qimage/qimage_wrapper.cpp000066400000000000000000000274671215300731300215400ustar00rootroot00000000000000/* * qimage_wrapper.cpp -- a QT/QImage based producer for MLT * Copyright (C) 2006 Visual Media * Author: Charles Yates * * NB: This module is designed to be functionally equivalent to the * gtk2 image loading module so it can be used as replacement. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "qimage_wrapper.h" #ifdef USE_QT3 #include #include #ifdef USE_KDE3 #include #include #endif #endif #ifdef USE_KDE4 #include #endif #ifdef USE_QT4 #include #include #include #include #include #include #include #endif #ifdef USE_EXIF #include #endif #include #include extern "C" { #include #include #ifdef USE_KDE4 static KComponentData *instance = 0L; #elif USE_KDE3 static KInstance *instance = 0L; #endif static QApplication *app = NULL; static void qimage_delete( void *data ) { QImage *image = ( QImage * )data; delete image; image = NULL; #if defined(USE_KDE3) || defined(USE_KDE4) if (instance) delete instance; instance = 0L; #endif } void init_qimage() { #ifdef USE_KDE4 if ( !instance ) { instance = new KComponentData( "qimage_prod" ); } #elif defined(USE_KDE3) if ( !instance ) { instance = new KInstance( "qimage_prod" ); KImageIO::registerFormats(); } #endif } static QImage* reorient_with_exif( producer_qimage self, int image_idx, QImage *qimage ) { #ifdef USE_EXIF mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( &self->parent ); ExifData *d = exif_data_new_from_file( mlt_properties_get_value( self->filenames, image_idx ) ); ExifEntry *entry; int exif_orientation = 0; /* get orientation and rotate image accordingly if necessary */ if (d) { if ( ( entry = exif_content_get_entry ( d->ifd[EXIF_IFD_0], EXIF_TAG_ORIENTATION ) ) ) exif_orientation = exif_get_short (entry->data, exif_data_get_byte_order (d)); /* Free the EXIF data */ exif_data_unref(d); } // Remember EXIF value, might be useful for someone mlt_properties_set_int( producer_props, "_exif_orientation" , exif_orientation ); if ( exif_orientation > 1 ) { // Rotate image according to exif data QImage processed; QMatrix matrix; switch ( exif_orientation ) { case 2: matrix.scale( -1, 1 ); break; case 3: matrix.rotate( 180 ); break; case 4: matrix.scale( 1, -1 ); break; case 5: matrix.rotate( 270 ); matrix.scale( -1, 1 ); break; case 6: matrix.rotate( 90 ); break; case 7: matrix.rotate( 90 ); matrix.scale( -1, 1 ); break; case 8: matrix.rotate( 270 ); break; } processed = qimage->transformed( matrix ); delete qimage; qimage = new QImage( processed ); } #endif return qimage; } int refresh_qimage( producer_qimage self, mlt_frame frame ) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_producer producer = &self->parent; mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Check if user wants us to reload the image if ( mlt_properties_get_int( producer_props, "force_reload" ) ) { self->qimage = NULL; self->current_image = NULL; mlt_properties_set_int( producer_props, "force_reload", 0 ); } // Get the time to live for each frame double ttl = mlt_properties_get_int( producer_props, "ttl" ); // Get the original position of this frame mlt_position position = mlt_frame_original_position( frame ); position += mlt_producer_get_in( producer ); // Image index int image_idx = ( int )floor( ( double )position / ttl ) % self->count; // Key for the cache char image_key[ 10 ]; sprintf( image_key, "%d", image_idx ); int disable_exif = mlt_properties_get_int( producer_props, "disable_exif" ); if ( app == NULL ) { if ( qApp ) { app = qApp; } else { #ifdef linux if ( getenv("DISPLAY") == 0 ) { mlt_log_panic( MLT_PRODUCER_SERVICE( producer ), "Error, cannot render titles without an X11 environment.\nPlease either run melt from an X session or use a fake X server like xvfb:\nxvfb-run -a melt (...)\n" ); return -1; } #endif int argc = 1; char* argv[1]; argv[0] = (char*) "xxx"; app = new QApplication( argc, argv ); const char *localename = mlt_properties_get_lcnumeric( MLT_SERVICE_PROPERTIES( MLT_PRODUCER_SERVICE( producer ) ) ); QLocale::setDefault( QLocale( localename ) ); } } if ( image_idx != self->qimage_idx ) self->qimage = NULL; if ( !self->qimage || mlt_properties_get_int( producer_props, "_disable_exif" ) != disable_exif ) { self->current_image = NULL; QImage *qimage = new QImage( QString::fromUtf8( mlt_properties_get_value( self->filenames, image_idx ) ) ); self->qimage = qimage; if ( !qimage->isNull( ) ) { // Read the exif value for this file if ( !disable_exif ) qimage = reorient_with_exif( self, image_idx, qimage ); // Register qimage for destruction and reuse mlt_cache_item_close( self->qimage_cache ); mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "qimage.qimage", qimage, 0, ( mlt_destructor )qimage_delete ); self->qimage_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.qimage" ); self->qimage_idx = image_idx; // Store the width/height of the qimage self->current_width = qimage->width( ); self->current_height = qimage->height( ); mlt_events_block( producer_props, NULL ); mlt_properties_set_int( producer_props, "meta.media.width", self->current_width ); mlt_properties_set_int( producer_props, "meta.media.height", self->current_height ); mlt_properties_set_int( producer_props, "_disable_exif", disable_exif ); mlt_events_unblock( producer_props, NULL ); } else { delete qimage; self->qimage = NULL; } } // Set width/height of frame mlt_properties_set_int( properties, "width", self->current_width ); mlt_properties_set_int( properties, "height", self->current_height ); return image_idx; } void refresh_image( producer_qimage self, mlt_frame frame, mlt_image_format format, int width, int height ) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_producer producer = &self->parent; // Get index and qimage int image_idx = refresh_qimage( self, frame ); // optimization for subsequent iterations on single pictur if ( image_idx != self->image_idx || width != self->current_width || height != self->current_height ) self->current_image = NULL; // If we have a qimage and need a new scaled image if ( self->qimage && ( !self->current_image || ( format != mlt_image_none && format != self->format ) ) ) { char *interps = mlt_properties_get( properties, "rescale.interp" ); int interp = 0; QImage *qimage = static_cast( self->qimage ); // QImage has two scaling modes - we'll toggle between them here if ( strcmp( interps, "tiles" ) == 0 || strcmp( interps, "hyper" ) == 0 || strcmp( interps, "bicubic" ) == 0 ) interp = 1; #ifdef USE_QT4 // Note - the original qimage is already safe and ready for destruction if ( qimage->depth() == 1 ) { QImage temp = qimage->convertToFormat( QImage::Format_RGB32 ); delete qimage; qimage = new QImage( temp ); self->qimage = qimage; } QImage scaled = interp == 0 ? qimage->scaled( QSize( width, height ) ) : qimage->scaled( QSize(width, height), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); int has_alpha = scaled.hasAlphaChannel(); #endif #ifdef USE_QT3 // Note - the original qimage is already safe and ready for destruction QImage scaled = interp == 0 ? qimage->scale( width, height, QImage::ScaleFree ) : qimage->smoothScale( width, height, QImage::ScaleFree ); self->has_alpha = 1; #endif // Store width and height self->current_width = width; self->current_height = height; // Allocate/define image int dst_stride = width * ( has_alpha ? 4 : 3 ); int image_size = dst_stride * ( height + 1 ); self->current_image = ( uint8_t * )mlt_pool_alloc( image_size ); self->current_alpha = NULL; self->format = has_alpha ? mlt_image_rgb24a : mlt_image_rgb24; // Copy the image int y = self->current_height + 1; uint8_t *dst = self->current_image; while ( --y ) { QRgb *src = (QRgb*) scaled.scanLine( self->current_height - y ); int x = self->current_width + 1; while ( --x ) { *dst++ = qRed(*src); *dst++ = qGreen(*src); *dst++ = qBlue(*src); if ( has_alpha ) *dst++ = qAlpha(*src); ++src; } } // Convert image to requested format if ( format != mlt_image_none && format != self->format ) { uint8_t *buffer = NULL; // First, set the image so it can be converted when we get it mlt_frame_replace_image( frame, self->current_image, self->format, width, height ); mlt_frame_set_image( frame, self->current_image, image_size, mlt_pool_release ); self->format = format; // get_image will do the format conversion mlt_frame_get_image( frame, &buffer, &format, &width, &height, 0 ); // cache copies of the image and alpha buffers if ( buffer ) { image_size = mlt_image_format_size( format, width, height, NULL ); self->current_image = (uint8_t*) mlt_pool_alloc( image_size ); memcpy( self->current_image, buffer, image_size ); } if ( ( buffer = mlt_frame_get_alpha_mask( frame ) ) ) { self->current_alpha = (uint8_t*) mlt_pool_alloc( width * height ); memcpy( self->current_alpha, buffer, width * height ); } } // Update the cache mlt_cache_item_close( self->image_cache ); mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "qimage.image", self->current_image, image_size, mlt_pool_release ); self->image_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.image" ); self->image_idx = image_idx; mlt_cache_item_close( self->alpha_cache ); self->alpha_cache = NULL; if ( self->current_alpha ) { mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "qimage.alpha", self->current_alpha, width * height, mlt_pool_release ); self->alpha_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.alpha" ); } } // Set width/height of frame mlt_properties_set_int( properties, "width", self->current_width ); mlt_properties_set_int( properties, "height", self->current_height ); } extern void make_tempfile( producer_qimage self, const char *xml ) { // Generate a temporary file for the svg QTemporaryFile tempFile( "mlt.XXXXXX" ); tempFile.setAutoRemove( false ); if ( tempFile.open() ) { // Write the svg into the temp file char *fullname = tempFile.fileName().toUtf8().data(); // Strip leading crap while ( xml[0] != '<' ) xml++; qint64 remaining_bytes = strlen( xml ); while ( remaining_bytes > 0 ) remaining_bytes -= tempFile.write( xml + strlen( xml ) - remaining_bytes, remaining_bytes ); tempFile.close(); mlt_properties_set( self->filenames, "0", fullname ); mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( &self->parent ), "__temporary_file__", fullname, 0, ( mlt_destructor )unlink, NULL ); } } } // extern "C" mlt-0.9.0/src/modules/qimage/qimage_wrapper.h000066400000000000000000000035151215300731300211710ustar00rootroot00000000000000/* * qimage_wrapper.h -- a QT/QImage based producer for MLT * Copyright (C) 2006 Visual Media * Author: Charles Yates * * NB: This module is designed to be functionally equivalent to the * gtk2 image loading module so it can be used as replacement. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef MLT_QIMAGE_WRAPPER #define MLT_QIMAGE_WRAPPER #include #include "config.h" #include #ifdef __cplusplus extern "C" { #endif struct producer_qimage_s { struct mlt_producer_s parent; mlt_properties filenames; int count; int image_idx; int qimage_idx; uint8_t *current_image; uint8_t *current_alpha; int current_width; int current_height; mlt_cache_item image_cache; mlt_cache_item alpha_cache; mlt_cache_item qimage_cache; void *qimage; mlt_image_format format; }; typedef struct producer_qimage_s *producer_qimage; extern int refresh_qimage( producer_qimage self, mlt_frame frame ); extern void refresh_image( producer_qimage, mlt_frame, mlt_image_format, int width, int height ); extern void make_tempfile( producer_qimage, const char *xml ); extern void init_qimage(); #ifdef __cplusplus } #endif #endif mlt-0.9.0/src/modules/qimage/transition_vqm.cpp000066400000000000000000000200571215300731300215760ustar00rootroot00000000000000/* * transition_vqm.c -- video quality measurement * Copyright (c) 2012 Dan Dennedy * Core psnr and ssim routines based on code from * qsnr (C) 2010 E. Oriani, ema fastwebnet it * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ #include #include #include #include #include static QApplication *app = 0; static double calc_psnr( const uint8_t *a, const uint8_t *b, int size, int bpp ) { double mse = 0.0; int n = size + 1; while ( --n ) { int diff = *a - *b; mse += diff * diff; a += bpp; b += bpp; } return 10.0 * log10( 255.0 * 255.0 / ( mse == 0 ? 1e-10 : mse/size ) ); } static double calc_ssim( const uint8_t *a, const uint8_t *b, int width, int height, int window_size, int bpp ) { int windows_x = width / window_size; int windows_y = height / window_size; double avg = 0.0; if ( !windows_x || !windows_y ) return 0.0; // for each window for ( int y = 0; y < windows_y; ++y ) for ( int x = 0; x < windows_x; ++x ) { int base_offset = x * window_size + y * window_size * width; double ref_acc = 0.0, ref_acc_2 = 0.0, cmp_acc = 0.0, cmp_acc_2 = 0.0, ref_cmp_acc = 0.0; // accumulate the pixel values for this window for ( int j = 0; j < window_size; ++j ) for ( int i = 0; i < window_size; ++i ) { uint8_t c_a = a[bpp * (base_offset + j * width + i)]; uint8_t c_b = b[bpp * (base_offset + j * width + i)]; ref_acc += c_a; ref_acc_2 += c_a * c_a; cmp_acc += c_b; cmp_acc_2 += c_b * c_b; ref_cmp_acc += c_a * c_b; } // compute the SSIM for this window // http://en.wikipedia.org/wiki/SSIM // http://en.wikipedia.org/wiki/Variance // http://en.wikipedia.org/wiki/Covariance double n_samples = window_size * window_size, ref_avg = ref_acc / n_samples, ref_var = ref_acc_2 / n_samples - ref_avg * ref_avg, cmp_avg = cmp_acc / n_samples, cmp_var = cmp_acc_2 / n_samples - cmp_avg * cmp_avg, ref_cmp_cov = ref_cmp_acc / n_samples - ref_avg * cmp_avg, c1 = 6.5025, // (0.01*255.0)^2 c2 = 58.5225, // (0.03*255)^2 ssim_num = (2.0 * ref_avg * cmp_avg + c1) * (2.0 * ref_cmp_cov + c2), ssim_den = (ref_avg * ref_avg + cmp_avg * cmp_avg + c1) * (ref_var + cmp_var + c2); // accumulate the SSIM avg += ssim_num / ssim_den; } // return the average SSIM return avg / windows_x / windows_y; } static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_frame b_frame = mlt_frame_pop_frame( a_frame ); mlt_properties properties = MLT_FRAME_PROPERTIES( a_frame ); mlt_transition transition = MLT_TRANSITION( mlt_frame_pop_service( a_frame ) ); uint8_t *b_image; int window_size = mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( transition ), "window_size" ); double psnr[3], ssim[3]; *format = mlt_image_yuv422; mlt_frame_get_image( b_frame, &b_image, format, width, height, writable ); mlt_frame_get_image( a_frame, image, format, width, height, writable ); psnr[0] = calc_psnr( *image, b_image, *width * *height, 2 ); psnr[1] = calc_psnr( *image + 1, b_image + 1, *width * *height / 2, 4 ); psnr[2] = calc_psnr( *image + 3, b_image + 3, *width * *height / 2, 4 ); ssim[0] = calc_ssim( *image, b_image, *width, *height, window_size, 2 ); ssim[1] = calc_ssim( *image + 1, b_image + 1, *width / 2, *height, window_size, 4 ); ssim[2] = calc_ssim( *image + 3, b_image + 3, *width / 2, *height, window_size, 4 ); mlt_properties_set_double( properties, "meta.vqm.psnr.y", psnr[0] ); mlt_properties_set_double( properties, "meta.vqm.psnr.cb", psnr[1] ); mlt_properties_set_double( properties, "meta.vqm.psnr.cr", psnr[2] ); mlt_properties_set_double( properties, "meta.vqm.ssim.y", ssim[0] ); mlt_properties_set_double( properties, "meta.vqm.ssim.cb", ssim[1] ); mlt_properties_set_double( properties, "meta.vqm.ssim.cr", ssim[2] ); printf( "%05d %05.2f %05.2f %05.2f %5.3f %5.3f %5.3f\n", mlt_frame_get_position( a_frame ), psnr[0], psnr[1], psnr[2], ssim[0], ssim[1], ssim[2] ); // copy the B frame to the bottom of the A frame for comparison window_size = mlt_image_format_size( *format, *width, *height, NULL ) / 2; memcpy( *image + window_size, b_image + window_size, window_size ); if ( !mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( transition ), "render" ) ) return 0; // get RGBA image for Qt drawing *format = mlt_image_rgb24a; mlt_frame_get_image( a_frame, image, format, width, height, 1 ); // convert mlt image to qimage QImage img( *width, *height, QImage::Format_ARGB32 ); int y = *height + 1; uint8_t *src = *image; while ( --y ) { QRgb *dst = (QRgb*) img.scanLine( *height - y ); int x = *width + 1; while ( --x ) { *dst++ = qRgba( src[0], src[1], src[2], 255 ); src += 4; } } // create QApplication, if needed if ( !app ) { if ( qApp ) { app = qApp; } else { int argc = 1; char* argv[] = { strdup( "unknown" ) }; app = new QApplication( argc, argv ); const char *localename = mlt_properties_get_lcnumeric( MLT_TRANSITION_PROPERTIES(transition) ); QLocale::setDefault( QLocale( localename ) ); free( argv[0] ); } } // setup Qt drawing QPainter painter; painter.begin( &img ); painter.setRenderHints( QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing ); // draw some stuff with Qt QPalette palette; QFont font; QString s; font.setBold( true ); font.setPointSize( 30 * *height / 1080 ); painter.setPen( QColor("black") ); painter.drawLine( 0, *height/2 + 1, *width, *height/2 ); painter.setPen( QColor("white") ); painter.drawLine( 0, *height/2 - 1, *width, *height/2 ); painter.setFont( font ); s.sprintf( "Frame: %05d\nPSNR: %05.2f (Y) %05.2f (Cb) %05.2f (Cr)\nSSIM: %5.3f (Y) %5.3f (Cb) %5.3f (Cr)", mlt_frame_get_position( a_frame ), psnr[0], psnr[1], psnr[2], ssim[0], ssim[1], ssim[2] ); painter.setPen( QColor("black") ); painter.drawText( 52, *height * 8 / 10 + 2, *width, *height, 0, s ); painter.setPen( QColor("white") ); painter.drawText( 50, *height * 8 / 10, *width, *height, 0, s ); // finish Qt drawing painter.end(); window_size = mlt_image_format_size( *format, *width, *height, NULL ); uint8_t *dst = (uint8_t *) mlt_pool_alloc( window_size ); mlt_properties_set_data( MLT_FRAME_PROPERTIES(a_frame), "image", dst, window_size, mlt_pool_release, NULL ); *image = dst; // convert qimage to mlt y = *height + 1; while ( --y ) { QRgb *src = (QRgb*) img.scanLine( *height - y ); int x = *width + 1; while ( --x ) { *dst++ = qRed( *src ); *dst++ = qGreen( *src ); *dst++ = qBlue( *src ); *dst++ = qAlpha( *src ); src++; } } return 0; } static mlt_frame process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ) { mlt_frame_push_service( a_frame, transition ); mlt_frame_push_frame( a_frame, b_frame ); mlt_frame_push_get_image( a_frame, get_image ); return a_frame; } extern "C" { mlt_transition transition_vqm_init( mlt_profile profile, mlt_service_type type, const char *id, void *arg ) { mlt_transition transition = mlt_transition_new(); if ( transition ) { mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); transition->process = process; mlt_properties_set_int( properties, "_transition_type", 1 ); // video only mlt_properties_set_int( properties, "window_size", 8 ); printf( "frame psnr[Y] psnr[Cb] psnr[Cr] ssim[Y] ssim[Cb] ssim[Cr]\n" ); } return transition; } } // extern "C" mlt-0.9.0/src/modules/qimage/transition_vqm.yml000066400000000000000000000013471215300731300216160ustar00rootroot00000000000000schema_version: 0.1 type: transition identifier: vqm title: Video Quality Measurement version: 1 copyright: Dan Dennedy creator: Dan Dennedy license: GPLv3 language: en description: > This performs the PSNR and SSIM video quality measurements by comparing the B frames to the reference frame A. It outputs the numbers to stdout in space-delimited format for easy by another tool. The bottom half of the B frame is placed below the top half of the A frame for visual comparison. tags: - Video parameters: - identifier: render title: Render description: > Render a line between top and bottom halves and the values atop the video. type: integer default: 0 minimum: 0 maximum: 1 widget: checkbox mlt-0.9.0/src/modules/resample/000077500000000000000000000000001215300731300163565ustar00rootroot00000000000000mlt-0.9.0/src/modules/resample/Makefile000066400000000000000000000012701215300731300200160ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt include ../../../config.mak TARGET = ../libmltresample$(LIBSUF) OBJS = factory.o \ filter_resample.o CFLAGS += `pkg-config --cflags samplerate` LDFLAGS += `pkg-config --libs samplerate` SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/resample" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/resample" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/resample/configure000077500000000000000000000003501215300731300202630ustar00rootroot00000000000000#!/bin/sh if [ "$help" != "1" ] then pkg-config samplerate 2> /dev/null disable_samplerate=$? if [ "$disable_samplerate" != "0" ] then echo "- libsamplerate not found: disabling" touch ../disable-resample fi exit 0 fi mlt-0.9.0/src/modules/resample/factory.c000066400000000000000000000027051215300731300201750ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include extern mlt_filter filter_resample_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/resample/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( filter_type, "resample", filter_resample_init ); MLT_REGISTER_METADATA( filter_type, "resample", metadata, "filter_resample.yml" ); } mlt-0.9.0/src/modules/resample/filter_resample.c000066400000000000000000000113651215300731300217050ustar00rootroot00000000000000/* * filter_resample.c -- adjust audio sample frequency * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include // BUFFER_LEN is based on a maximum of 96KHz, 5 fps, 8 channels // TODO: dynamically allocate larger buffer size #define BUFFER_LEN ((96000/5) * 8 * sizeof(float)) #define RESAMPLE_TYPE SRC_SINC_FASTEST /** Get the audio. */ static int resample_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); // Get the resample information int output_rate = mlt_properties_get_int( filter_properties, "frequency" ); // If no resample frequency is specified, default to requested value if ( output_rate == 0 ) output_rate = *frequency; // Get the producer's audio int error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); if ( error ) return error; // Return now if no work to do if ( output_rate != *frequency && *frequency > 0 && *channels > 0 ) { mlt_log_debug( MLT_FILTER_SERVICE(filter), "channels %d samples %d frequency %d -> %d\n", *channels, *samples, *frequency, output_rate ); // Do not convert to float unless we need to change the rate if ( *format != mlt_audio_f32le ) frame->convert_audio( frame, buffer, format, mlt_audio_f32le ); mlt_service_lock( MLT_FILTER_SERVICE(filter) ); SRC_DATA data; data.data_in = *buffer; data.data_out = mlt_properties_get_data( filter_properties, "output_buffer", NULL ); data.src_ratio = ( float ) output_rate / ( float ) *frequency; data.input_frames = *samples; data.output_frames = BUFFER_LEN / *channels; data.end_of_input = 0; SRC_STATE *state = mlt_properties_get_data( filter_properties, "state", NULL ); if ( !state || mlt_properties_get_int( filter_properties, "channels" ) != *channels ) { // Recreate the resampler if the number of channels changed state = src_new( RESAMPLE_TYPE, *channels, &error ); mlt_properties_set_data( filter_properties, "state", state, 0, (mlt_destructor) src_delete, NULL ); mlt_properties_set_int( filter_properties, "channels", *channels ); } // Resample the audio error = src_process( state, &data ); if ( !error ) { // Update output variables *samples = data.output_frames_gen; *frequency = output_rate; *buffer = data.data_out; } else { mlt_log_error( MLT_FILTER_SERVICE( filter ), "%s %d,%d,%d\n", src_strerror( error ), *frequency, *samples, output_rate ); } mlt_service_unlock( MLT_FILTER_SERVICE(filter) ); } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { if ( mlt_frame_is_test_audio( frame ) == 0 ) { mlt_frame_push_audio( frame, this ); mlt_frame_push_audio( frame, resample_get_audio ); } return frame; } /** Constructor for the filter. */ mlt_filter filter_resample_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { int error; SRC_STATE *state = src_new( RESAMPLE_TYPE, 2 /* channels */, &error ); if ( error == 0 ) { void *output_buffer = mlt_pool_alloc( BUFFER_LEN ); this->process = filter_process; if ( arg != NULL ) mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "frequency", atoi( arg ) ); mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "channels", 2 ); mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "state", state, 0, (mlt_destructor)src_delete, NULL ); mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "output_buffer", output_buffer, BUFFER_LEN, mlt_pool_release, NULL ); } else { fprintf( stderr, "filter_resample_init: %s\n", src_strerror( error ) ); } } return this; } mlt-0.9.0/src/modules/resample/filter_resample.yml000066400000000000000000000013441215300731300222600ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: resample title: Resample version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Audio - Hidden description: > Adjust an audio stream's sampling rate, and duplicate channels if producer provides less than consumer requested. This filter is automatically invoked by the loader producer for the sake of normalisation over inputs and with the consumer. bugs: - > Assumes 2 channels during libsamplerate initialisation. Untested with >2 channels. parameters: - identifier: argument title: Frequency type: integer description: The target sample rate. required: no readonly: no mlt-0.9.0/src/modules/resample/gpl000066400000000000000000000000001215300731300170510ustar00rootroot00000000000000mlt-0.9.0/src/modules/rotoscoping/000077500000000000000000000000001215300731300171145ustar00rootroot00000000000000mlt-0.9.0/src/modules/rotoscoping/Makefile000066400000000000000000000012361215300731300205560ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lm include ../../../config.mak TARGET = ../libmltrotoscoping$(LIBSUF) OBJS = factory.o \ filter_rotoscoping.o \ cJSON.o LDFLAGS += -lm SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d $(DESTDIR)$(mltdatadir)/rotoscoping install -m 644 filter_rotoscoping.yml "$(DESTDIR)$(mltdatadir)/rotoscoping" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/rotoscoping/cJSON.c000066400000000000000000000442551215300731300202060ustar00rootroot00000000000000/* Copyright (c) 2009 Dave Gamble 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. */ // cJSON // JSON parser in C. #include #include #include #include #include #include #include #include "cJSON.h" static int cJSON_strcasecmp(const char *s1,const char *s2) { if (!s1) return (s1==s2)?0:1;if (!s2) return 1; for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); } static void *(*cJSON_malloc)(size_t sz) = malloc; static void (*cJSON_free)(void *ptr) = free; static char* cJSON_strdup(const char* str) { size_t len; char* copy; len = strlen(str) + 1; if (!(copy = (char*)cJSON_malloc(len))) return 0; memcpy(copy,str,len); return copy; } void cJSON_InitHooks(cJSON_Hooks* hooks) { if (!hooks) { /* Reset hooks */ cJSON_malloc = malloc; cJSON_free = free; return; } cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; cJSON_free = (hooks->free_fn)?hooks->free_fn:free; } // Internal constructor. static cJSON *cJSON_New_Item() { cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); if (node) memset(node,0,sizeof(cJSON)); return node; } // Delete a cJSON structure. void cJSON_Delete(cJSON *c) { cJSON *next; while (c) { next=c->next; if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); if (c->string) cJSON_free(c->string); cJSON_free(c); c=next; } } // Parse the input text to generate a number, and populate the result into item. static const char *parse_number(cJSON *item,const char *num) { double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; // Could use sscanf for this? if (*num=='-') sign=-1,num++; // Has sign? if (*num=='0') num++; // is zero if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); // Number? if (*num=='.') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} // Fractional part? if (*num=='e' || *num=='E') // Exponent? { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; // With sign? while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); // Number? } n=sign*n*pow(10.0,(scale+subscale*signsubscale)); // number = +/- number.fraction * 10^+/- exponent item->valuedouble=n; item->valueint=(int)n; item->type=cJSON_Number; return num; } // Render the number nicely from the given item into a string. static char *print_number(cJSON *item) { char *str; double d=item->valuedouble; if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) { str=(char*)cJSON_malloc(21); // 2^64+1 can be represented in 21 chars. if (str) sprintf(str,"%d",item->valueint); } else { str=(char*)cJSON_malloc(64); // This is a nice tradeoff. if (str) { if (fabs(floor(d)-d)<=DBL_EPSILON) sprintf(str,"%.0f",d); else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); else sprintf(str,"%f",d); } } return str; } // Parse the input text into an unescaped cstring, and populate item. static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; static const char *parse_string(cJSON *item,const char *str) { const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc; if (*str!='\"') return 0; // not a string! while (*ptr!='\"' && (unsigned char)*ptr>31 && ++len) if (*ptr++ == '\\') ptr++; // Skip escaped quotes. out=(char*)cJSON_malloc(len+1); // This is how long we need for the string, roughly. if (!out) return 0; ptr=str+1;ptr2=out; while (*ptr!='\"' && (unsigned char)*ptr>31) { if (*ptr!='\\') *ptr2++=*ptr++; else { ptr++; switch (*ptr) { case 'b': *ptr2++='\b'; break; case 'f': *ptr2++='\f'; break; case 'n': *ptr2++='\n'; break; case 'r': *ptr2++='\r'; break; case 't': *ptr2++='\t'; break; case 'u': // transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY. sscanf(ptr+1,"%4x",&uc); // get the unicode char. len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len; switch (len) { case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; case 1: *--ptr2 =(uc | firstByteMark[len]); } ptr2+=len;ptr+=4; break; default: *ptr2++=*ptr; break; } ptr++; } } *ptr2=0; if (*ptr=='\"') ptr++; item->valuestring=out; item->type=cJSON_String; return ptr; } // Render the cstring provided to an escaped version that can be printed. static char *print_string_ptr(const char *str) { const char *ptr;char *ptr2,*out;int len=0; if (!str) return cJSON_strdup(""); ptr=str;while (*ptr && ++len) {if ((unsigned char)*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;} out=(char*)cJSON_malloc(len+3); if (!out) return 0; ptr2=out;ptr=str; *ptr2++='\"'; while (*ptr) { if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; else { *ptr2++='\\'; switch (*ptr++) { case '\\': *ptr2++='\\'; break; case '\"': *ptr2++='\"'; break; case '\b': *ptr2++='b'; break; case '\f': *ptr2++='f'; break; case '\n': *ptr2++='n'; break; case '\r': *ptr2++='r'; break; case '\t': *ptr2++='t'; break; default: ptr2--; break; // eviscerate with prejudice. } } } *ptr2++='\"';*ptr2++=0; return out; } // Invote print_string_ptr (which is useful) on an item. static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);} // Predeclare these prototypes. static const char *parse_value(cJSON *item,const char *value); static char *print_value(cJSON *item,int depth,int fmt); static const char *parse_array(cJSON *item,const char *value); static char *print_array(cJSON *item,int depth,int fmt); static const char *parse_object(cJSON *item,const char *value); static char *print_object(cJSON *item,int depth,int fmt); // Utility to jump whitespace and cr/lf static const char *skip(const char *in) {while (in && (unsigned char)*in<=32) in++; return in;} // Parse an object - create a new root, and populate. cJSON *cJSON_Parse(const char *value) { cJSON *c=cJSON_New_Item(); if (!c) return 0; /* memory fail */ if (!parse_value(c,skip(value))) {cJSON_Delete(c);return 0;} return c; } // Render a cJSON item/entity/structure to text. char *cJSON_Print(cJSON *item) {return print_value(item,0,1);} char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);} // Parser core - when encountering text, process appropriately. static const char *parse_value(cJSON *item,const char *value) { if (!value) return 0; // Fail on null. if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } if (*value=='\"') { return parse_string(item,value); } if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } if (*value=='[') { return parse_array(item,value); } if (*value=='{') { return parse_object(item,value); } return 0; // failure. } // Render a value to text. static char *print_value(cJSON *item,int depth,int fmt) { char *out=0; if (!item) return 0; switch ((item->type)&255) { case cJSON_NULL: out=cJSON_strdup("null"); break; case cJSON_False: out=cJSON_strdup("false");break; case cJSON_True: out=cJSON_strdup("true"); break; case cJSON_Number: out=print_number(item);break; case cJSON_String: out=print_string(item);break; case cJSON_Array: out=print_array(item,depth,fmt);break; case cJSON_Object: out=print_object(item,depth,fmt);break; } return out; } // Build an array from input text. static const char *parse_array(cJSON *item,const char *value) { cJSON *child; if (*value!='[') return 0; // not an array! item->type=cJSON_Array; value=skip(value+1); if (*value==']') return value+1; // empty array. item->child=child=cJSON_New_Item(); if (!item->child) return 0; // memory fail value=skip(parse_value(child,skip(value))); // skip any spacing, get the value. if (!value) return 0; while (*value==',') { cJSON *new_item; if (!(new_item=cJSON_New_Item())) return 0; // memory fail child->next=new_item;new_item->prev=child;child=new_item; value=skip(parse_value(child,skip(value+1))); if (!value) return 0; // memory fail } if (*value==']') return value+1; // end of array return 0; // malformed. } // Render an array to text static char *print_array(cJSON *item,int depth,int fmt) { char **entries; char *out=0,*ptr,*ret;int len=5; cJSON *child=item->child; int numentries=0,i=0,fail=0; // How many entries in the array? while (child) numentries++,child=child->next; // Allocate an array to hold the values for each entries=(char**)cJSON_malloc(numentries*sizeof(char*)); if (!entries) return 0; memset(entries,0,numentries*sizeof(char*)); // Retrieve all the results: child=item->child; while (child && !fail) { ret=print_value(child,depth+1,fmt); entries[i++]=ret; if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; child=child->next; } // If we didn't fail, try to malloc the output string if (!fail) out=cJSON_malloc(len); // If that fails, we fail. if (!out) fail=1; // Handle failure. if (fail) { for (i=0;itype=cJSON_Object; value=skip(value+1); if (*value=='}') return value+1; // empty array. item->child=child=cJSON_New_Item(); if (!item->child) return 0; value=skip(parse_string(child,skip(value))); if (!value) return 0; child->string=child->valuestring;child->valuestring=0; if (*value!=':') return 0; // fail! value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value. if (!value) return 0; while (*value==',') { cJSON *new_item; if (!(new_item=cJSON_New_Item())) return 0; // memory fail child->next=new_item;new_item->prev=child;child=new_item; value=skip(parse_string(child,skip(value+1))); if (!value) return 0; child->string=child->valuestring;child->valuestring=0; if (*value!=':') return 0; // fail! value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value. if (!value) return 0; } if (*value=='}') return value+1; // end of array return 0; // malformed. } // Render an object to text. static char *print_object(cJSON *item,int depth,int fmt) { char **entries=0,**names=0; char *out=0,*ptr,*ret,*str;int len=7,i=0,j; cJSON *child=item->child; int numentries=0,fail=0; // Count the number of entries. while (child) numentries++,child=child->next; // Allocate space for the names and the objects entries=(char**)cJSON_malloc(numentries*sizeof(char*)); if (!entries) return 0; names=(char**)cJSON_malloc(numentries*sizeof(char*)); if (!names) {cJSON_free(entries);return 0;} memset(entries,0,sizeof(char*)*numentries); memset(names,0,sizeof(char*)*numentries); // Collect all the results into our arrays: child=item->child;depth++;if (fmt) len+=depth; while (child) { names[i]=str=print_string_ptr(child->string); entries[i++]=ret=print_value(child,depth,fmt); if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; child=child->next; } // Try to allocate the output string if (!fail) out=(char*)cJSON_malloc(len); if (!out) fail=1; // Handle failure if (fail) { for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} // Utility for array list handling. static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} // Utility for handling references. static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} // Add item to array/object. void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} // Replace array/object items with new ones. void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} // Create basic types: cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} cJSON *cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} cJSON *cJSON_CreateObject() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} // Create Arrays: cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} cJSON *cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} mlt-0.9.0/src/modules/rotoscoping/cJSON.h000066400000000000000000000125161215300731300202060ustar00rootroot00000000000000/* Copyright (c) 2009 Dave Gamble 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 cJSON__h #define cJSON__h #ifdef __cplusplus extern "C" { #endif // cJSON Types: #define cJSON_False 0 #define cJSON_True 1 #define cJSON_NULL 2 #define cJSON_Number 3 #define cJSON_String 4 #define cJSON_Array 5 #define cJSON_Object 6 #define cJSON_IsReference 256 // The cJSON structure: typedef struct cJSON { struct cJSON *next,*prev; // next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem struct cJSON *child; // An array or object item will have a child pointer pointing to a chain of the items in the array/object. int type; // The type of the item, as above. char *valuestring; // The item's string, if type==cJSON_String int valueint; // The item's number, if type==cJSON_Number double valuedouble; // The item's number, if type==cJSON_Number char *string; // The item's name string, if this item is the child of, or is in the list of subitems of an object. } cJSON; typedef struct cJSON_Hooks { void *(*malloc_fn)(size_t sz); void (*free_fn)(void *ptr); } cJSON_Hooks; // Supply malloc, realloc and free functions to cJSON extern void cJSON_InitHooks(cJSON_Hooks* hooks); // Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. extern cJSON *cJSON_Parse(const char *value); // Render a cJSON entity to text for transfer/storage. Free the char* when finished. extern char *cJSON_Print(cJSON *item); // Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. extern char *cJSON_PrintUnformatted(cJSON *item); // Delete a cJSON entity and all subentities. extern void cJSON_Delete(cJSON *c); // Returns the number of items in an array (or object). extern int cJSON_GetArraySize(cJSON *array); // Retrieve item number "item" from array "array". Returns NULL if unsuccessful. extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); // Get item "string" from object. Case insensitive. extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); // These calls create a cJSON item of the appropriate type. extern cJSON *cJSON_CreateNull(); extern cJSON *cJSON_CreateTrue(); extern cJSON *cJSON_CreateFalse(); extern cJSON *cJSON_CreateBool(int b); extern cJSON *cJSON_CreateNumber(double num); extern cJSON *cJSON_CreateString(const char *string); extern cJSON *cJSON_CreateArray(); extern cJSON *cJSON_CreateObject(); // These utilities create an Array of count items. extern cJSON *cJSON_CreateIntArray(int *numbers,int count); extern cJSON *cJSON_CreateFloatArray(float *numbers,int count); extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count); extern cJSON *cJSON_CreateStringArray(const char **strings,int count); // Append item to the specified array/object. extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); // Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); // Remove/Detatch items from Arrays/Objects. extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); extern void cJSON_DeleteItemFromArray(cJSON *array,int which); extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); // Update array items. extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) #ifdef __cplusplus } #endif #endif mlt-0.9.0/src/modules/rotoscoping/factory.c000066400000000000000000000027631215300731300207370ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include extern mlt_filter filter_rotoscoping_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties rotoscoping_metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/rotoscoping/filter_%s.yml", mlt_environment( "MLT_DATA" ), id ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( filter_type, "rotoscoping", filter_rotoscoping_init ); MLT_REGISTER_METADATA( filter_type, "rotoscoping", rotoscoping_metadata, NULL ); } mlt-0.9.0/src/modules/rotoscoping/filter_rotoscoping.c000066400000000000000000000513321215300731300231770ustar00rootroot00000000000000/* * rotoscoping.c -- keyframable vector based rotoscoping * Copyright (C) 2011 Till Theato * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "cJSON.h" #include #include #include #include #define MAX( x, y ) ( ( x ) > ( y ) ? ( x ) : ( y ) ) #define MIN( x, y ) ( ( x ) < ( y ) ? ( x ) : ( y ) ) #define SQR( x ) ( x ) * ( x ) /** x, y tuple with double precision */ typedef struct PointF { double x; double y; } PointF; typedef struct BPointF { struct PointF h1; struct PointF p; struct PointF h2; } BPointF; enum MODES { MODE_RGB, MODE_ALPHA, MODE_LUMA }; const char *MODESTR[3] = { "rgb", "alpha", "luma" }; enum ALPHAOPERATIONS { ALPHA_CLEAR, ALPHA_MAX, ALPHA_MIN, ALPHA_ADD, ALPHA_SUB }; const char *ALPHAOPERATIONSTR[5] = { "clear", "max", "min", "add", "sub" }; /** Returns the index of \param string in \param stringList. * Useful for assigning string parameters to enums. */ static int stringValue( const char *string, const char **stringList, int max ) { int i; for ( i = 0; i < max; i++ ) if ( strcmp( stringList[i], string ) == 0 ) return i; return 0; } /** Sets "spline_is_dirty" to 1 if property "spline" was changed. * We then know when to parse the json stored in "spline" */ static void rotoPropertyChanged( mlt_service owner, mlt_filter this, char *name ) { if ( !strcmp( name, "spline" ) ) mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "_spline_is_dirty", 1 ); } /** Linear interp */ static inline void lerp( const PointF *a, const PointF *b, PointF *result, double t ) { result->x = a->x + ( b->x - a->x ) * t; result->y = a->y + ( b->y - a->y ) * t; } /** Linear interp. with t = 0.5 * Speed gain? */ static inline void lerpHalf( const PointF *a, const PointF *b, PointF *result ) { result->x = ( a->x + b->x ) * .5; result->y = ( a->y + b->y ) * .5; } /** Helper for using qsort with an array of integers. */ int ncompare( const void *a, const void *b ) { return *(const int*)a - *(const int*)b; } /** Turns a json array with two children into a point (x, y tuple). */ static void jsonGetPoint( cJSON *json, PointF *point ) { if ( cJSON_GetArraySize( json ) == 2 ) { point->x = json->child->valuedouble; point->y = json->child->next->valuedouble; } } /** * Turns the array of json elements into an array of Bézier points. * \param array cJSON array. values have to be Bézier points: handle 1, point , handl2 * ( [ [ [h1x, h1y], [px, py], [h2x, h2y] ], ... ] ) * \param points pointer to array of points. Will be allocated and filled with the points in \param array * \return number of points */ static int json2BCurves( cJSON *array, BPointF **points ) { int count = cJSON_GetArraySize( array ); cJSON *child = array->child; *points = mlt_pool_alloc( count * sizeof( BPointF ) ); int i = 0; do { if ( child && cJSON_GetArraySize( child ) == 3 ) { jsonGetPoint( child->child , &(*points)[i].h1 ); jsonGetPoint( child->child->next, &(*points)[i].p ); jsonGetPoint( child->child->next->next, &(*points)[i].h2 ); i++; } } while ( child && ( child = child->next ) ); if ( i < count ) *points = mlt_pool_realloc( *points, i * sizeof( BPointF ) ); return i; } /** Blurs \param src horizontally. \See funtion blur. */ static void blurHorizontal( uint8_t *src, uint8_t *dst, int width, int height, int radius) { int x, y, kx, yOff, total, amount, amountInit; amountInit = radius * 2 + 1; for (y = 0; y < height; ++y) { total = 0; yOff = y * width; // Process entire window for first pixel int size = MIN(radius + 1, width); for ( kx = 0; kx < size; ++kx ) total += src[yOff + kx]; dst[yOff] = total / ( radius + 1 ); // Subsequent pixels just update window total for ( x = 1; x < width; ++x ) { amount = amountInit; // Subtract pixel leaving window if ( x - radius - 1 >= 0 ) total -= src[yOff + x - radius - 1]; else amount -= radius - x; // Add pixel entering window if ( x + radius < width ) total += src[yOff + x + radius]; else amount -= radius - width + x; dst[yOff + x] = total / amount; } } } /** Blurs \param src vertically. \See funtion blur. */ static void blurVertical( uint8_t *src, uint8_t *dst, int width, int height, int radius) { int x, y, ky, total, amount, amountInit; amountInit = radius * 2 + 1; for (x = 0; x < width; ++x) { total = 0; int size = MIN(radius + 1, height); for ( ky = 0; ky < size; ++ky ) total += src[x + ky * width]; dst[x] = total / ( radius + 1 ); for ( y = 1; y < height; ++y ) { amount = amountInit; if ( y - radius - 1 >= 0 ) total -= src[( y - radius - 1 ) * width + x]; else amount -= radius - y; if ( y + radius < height ) total += src[( y + radius ) * width + x]; else amount -= radius - height + y; dst[y * width + x] = total / amount; } } } /** * Blurs the \param map using a simple "average" blur. * \param map Will be blured; 1bpp * \param width x dimension of channel stored in \param map * \param height y dimension of channel stored in \param map * \param radius blur radius * \param passes blur passes */ static void blur( uint8_t *map, int width, int height, int radius, int passes ) { uint8_t *src = mlt_pool_alloc( width * height ); uint8_t *tmp = mlt_pool_alloc( width * height ); int i; for ( i = 0; i < passes; ++i ) { memcpy( src, map, width * height ); blurHorizontal( src, tmp, width, height, radius ); blurVertical( tmp, map, width, height, radius ); } mlt_pool_release(src); mlt_pool_release(tmp); } /** * Determines which points are located in the polygon and sets their value in \param map to \param value * \param vertices points defining the polygon * \param count number of vertices * \param with x range * \param height y range * \param value value identifying points in the polygon * \param map array of integers of the dimension width * height. * The map entries belonging to the points in the polygon will be set to \param set * 255 the others to !set * 255. */ static void fillMap( PointF *vertices, int count, int width, int height, int invert, uint8_t *map ) { int nodes, nodeX[1024], pixelY, i, j, value; value = !invert * 255; memset( map, invert * 255, width * height ); // Loop through the rows of the image for ( pixelY = 0; pixelY < height; pixelY++ ) { /* * Build a list of nodes. * nodes are located at the borders of the polygon * and therefore indicate a move from in to out or vice versa */ nodes = 0; for ( i = 0, j = count - 1; i < count; j = i++ ) if ( (vertices[i].y > (double)pixelY) != (vertices[j].y > (double)pixelY) ) nodeX[nodes++] = (int)(vertices[i].x + (pixelY - vertices[i].y) / (vertices[j].y - vertices[i].y) * (vertices[j].x - vertices[i].x) ); qsort( nodeX, nodes, sizeof( int ), ncompare ); // Set map values for points between the node pairs to 1 for ( i = 0; i < nodes; i += 2 ) { if ( nodeX[i] >= width ) break; if ( nodeX[i+1] > 0 ) { nodeX[i] = MAX( 0, nodeX[i] ); nodeX[i+1] = MIN( nodeX[i+1], width ); memset( map + width * pixelY + nodeX[i], value, nodeX[i+1] - nodeX[i] ); } } } } /** Determines the point in the middle of the Bézier curve (t = 0.5) defined by \param p1 and \param p2 * using De Casteljau's algorithm. */ static void deCasteljau( BPointF *p1, BPointF *p2, BPointF *mid ) { struct PointF ab, bc, cd; lerpHalf( &(p1->p), &(p1->h2), &ab ); lerpHalf( &(p1->h2), &(p2->h1), &bc ); lerpHalf( &(p2->h1), &(p2->p), &cd ); lerpHalf( &ab, &bc, &(mid->h1) ); // mid->h1 = abbc lerpHalf( &bc, &cd, &(mid->h2) ); // mid->h2 = bccd lerpHalf( &(mid->h1), &(mid->h2), &(mid->p) ); p1->h2 = ab; p2->h1 = cd; } /** * Calculates points for the cubic Bézier curve defined by \param p1 and \param p2. * Points are calculated until the squared distanced between neighbour points is smaller than 2. * \param points Pointer to list of points. Will be allocted and filled with calculated points. * \param count Number of calculated points in \param points * \param size Allocated size of \param points (in elements not in bytes) */ static void curvePoints( BPointF p1, BPointF p2, PointF **points, int *count, int *size ) { double errorSqr = SQR( p1.p.x - p2.p.x ) + SQR( p1.p.y - p2.p.y ); if ( *size + 1 >= *count ) { *size += (int)sqrt( errorSqr / 2 ); *points = mlt_pool_realloc( *points, *size * sizeof ( struct PointF ) ); } (*points)[(*count)++] = p1.p; if ( errorSqr <= 2 ) return; BPointF mid; deCasteljau( &p1, &p2, &mid ); curvePoints( p1, mid, points, count, size ); curvePoints( mid, p2, points, count, size ); (*points)[*(count)++] = p2.p; } /** Do it :-). */ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_properties unique = mlt_frame_pop_service( frame ); int mode = mlt_properties_get_int( unique, "mode" ); // Get the image if ( mode == MODE_RGB ) *format = mlt_image_rgb24; int error = mlt_frame_get_image( frame, image, format, width, height, writable ); // Only process if we have no error and a valid colour space if ( !error ) { BPointF *bpoints; struct PointF *points; int bcount, length, count, size, i, j; bpoints = mlt_properties_get_data( unique, "points", &length ); bcount = length / sizeof( BPointF ); for ( i = 0; i < bcount; i++ ) { // map to image dimensions bpoints[i].h1.x *= *width; bpoints[i].p.x *= *width; bpoints[i].h2.x *= *width; bpoints[i].h1.y *= *height; bpoints[i].p.y *= *height; bpoints[i].h2.y *= *height; } count = 0; size = 1; points = mlt_pool_alloc( size * sizeof( struct PointF ) ); for ( i = 0; i < bcount; i++ ) { j = (i + 1) % bcount; curvePoints( bpoints[i], bpoints[j], &points, &count, &size ); } if ( count ) { length = *width * *height; uint8_t *map = mlt_pool_alloc( length ); int invert = mlt_properties_get_int( unique, "invert" ); fillMap( points, count, *width, *height, invert, map ); int feather = mlt_properties_get_int( unique, "feather" ); if ( feather && mode != MODE_RGB ) blur( map, *width, *height, feather, mlt_properties_get_int( unique, "feather_passes" ) ); int bpp; size = mlt_image_format_size( *format, *width, *height, &bpp ); uint8_t *p = *image; uint8_t *q = *image + size; i = 0; uint8_t *alpha; switch ( mode ) { case MODE_RGB: // *format == mlt_image_rgb24 while ( p != q ) { if ( !map[i++] ) p[0] = p[1] = p[2] = 0; p += 3; } break; case MODE_LUMA: switch ( *format ) { case mlt_image_rgb24: case mlt_image_rgb24a: case mlt_image_opengl: while ( p != q ) { p[0] = p[1] = p[2] = map[i++]; p += bpp; } break; case mlt_image_yuv422: while ( p != q ) { p[0] = map[i++]; p[1] = 128; p += 2; } break; case mlt_image_yuv420p: memcpy( p, map, length ); memset( p + length, 128, length / 2 ); break; default: break; } break; case MODE_ALPHA: switch ( *format ) { case mlt_image_rgb24a: case mlt_image_opengl: switch ( mlt_properties_get_int( unique, "alpha_operation" ) ) { case ALPHA_CLEAR: while ( p != q ) { p[3] = map[i++]; p += 4; } break; case ALPHA_MAX: while ( p != q ) { p[3] = MAX( p[3], map[i] ); p += 4; i++; } break; case ALPHA_MIN: while ( p != q ) { p[3] = MIN( p[3], map[i] ); p += 4; i++; } break; case ALPHA_ADD: while ( p != q ) { p[3] = MIN( p[3] + map[i], 255 ); p += 4; i++; } break; case ALPHA_SUB: while ( p != q ) { p[3] = MAX( p[3] - map[i], 0 ); p += 4; i++; } break; } break; default: alpha = mlt_frame_get_alpha_mask( frame ); switch ( mlt_properties_get_int( unique, "alpha_operation" ) ) { case ALPHA_CLEAR: memcpy( alpha, map, length ); break; case ALPHA_MAX: for ( ; i < length; i++, alpha++ ) *alpha = MAX( map[i], *alpha ); break; case ALPHA_MIN: for ( ; i < length; i++, alpha++ ) *alpha = MIN( map[i], *alpha ); break; case ALPHA_ADD: for ( ; i < length; i++, alpha++ ) *alpha = MIN( *alpha + map[i], 255 ); break; case ALPHA_SUB: for ( ; i < length; i++, alpha++ ) *alpha = MAX( *alpha - map[i], 0 ); break; } break; } break; } mlt_pool_release( map ); } mlt_pool_release( points ); } return error; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); int splineIsDirty = mlt_properties_get_int( properties, "_spline_is_dirty" ); char *modeStr = mlt_properties_get( properties, "mode" ); cJSON *root = mlt_properties_get_data( properties, "_spline_parsed", NULL ); if ( splineIsDirty || root == NULL ) { // we need to (re-)parse char *spline = mlt_properties_get( properties, "spline" ); root = cJSON_Parse( spline ); mlt_properties_set_data( properties, "_spline_parsed", root, 0, (mlt_destructor)cJSON_Delete, NULL ); mlt_properties_set_int( properties, "_spline_is_dirty", 0 ); } if ( root == NULL ) return frame; BPointF *points; int count, i; if ( root->type == cJSON_Array ) { /* * constant */ count = json2BCurves( root, &points ); } else if ( root->type == cJSON_Object ) { /* * keyframes */ mlt_position time, pos1, pos2; time = mlt_frame_get_position( frame ); cJSON *keyframe = root->child; cJSON *keyframeOld = keyframe; if ( !keyframe ) return frame; while ( atoi( keyframe->string ) < time && keyframe->next ) { keyframeOld = keyframe; keyframe = keyframe->next; } pos1 = atoi( keyframeOld->string ); pos2 = atoi( keyframe->string ); if ( pos1 >= pos2 || time >= pos2 ) { // keyframes in wrong order or before first / after last keyframe count = json2BCurves( keyframe, &points ); } else { /* * pos1 < time < pos2 */ BPointF *p1, *p2; int c1 = json2BCurves( keyframeOld, &p1 ); int c2 = json2BCurves( keyframe, &p2 ); // range 0-1 double position = ( time - pos1 ) / (double)( pos2 - pos1 + 1 ); count = MIN( c1, c2 ); // additional points are ignored points = mlt_pool_alloc( count * sizeof( BPointF ) ); for ( i = 0; i < count; i++ ) { lerp( &(p1[i].h1), &(p2[i].h1), &(points[i].h1), position ); lerp( &(p1[i].p), &(p2[i].p), &(points[i].p), position ); lerp( &(p1[i].h2), &(p2[i].h2), &(points[i].h2), position ); } mlt_pool_release( p1 ); mlt_pool_release( p2 ); } } else { return frame; } mlt_properties unique = mlt_frame_unique_properties( frame, MLT_FILTER_SERVICE( filter ) ); mlt_properties_set_data( unique, "points", points, count * sizeof( BPointF ), (mlt_destructor)mlt_pool_release, NULL ); mlt_properties_set_int( unique, "mode", stringValue( modeStr, MODESTR, 3 ) ); mlt_properties_set_int( unique, "alpha_operation", stringValue( mlt_properties_get( properties, "alpha_operation" ), ALPHAOPERATIONSTR, 5 ) ); mlt_properties_set_int( unique, "invert", mlt_properties_get_int( properties, "invert" ) ); mlt_properties_set_int( unique, "feather", mlt_properties_get_int( properties, "feather" ) ); mlt_properties_set_int( unique, "feather_passes", mlt_properties_get_int( properties, "feather_passes" ) ); mlt_frame_push_service( frame, unique ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_rotoscoping_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = mlt_filter_new( ); if ( filter ) { filter->process = filter_process; mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_properties_set( properties, "mode", "alpha" ); mlt_properties_set( properties, "alpha_operation", "clear" ); mlt_properties_set_int( properties, "invert", 0 ); mlt_properties_set_int( properties, "feather", 0 ); mlt_properties_set_int( properties, "feather_passes", 1 ); if ( arg ) mlt_properties_set( properties, "spline", arg ); mlt_events_listen( properties, filter, "property-changed", (mlt_listener)rotoPropertyChanged ); } return filter; } mlt-0.9.0/src/modules/rotoscoping/filter_rotoscoping.yml000066400000000000000000000051421215300731300235540ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: rotoscoping title: Rotoscoping copyright: Copyright (C) 2011 Till Theato version: 0.3 license: GPL language: en url: none creator: Till Theato tags: - Video description: Keyframable vector based rotoscoping bugs: - in some cases top most row in polygon is assigned to outside parameters: - identifier: mode title: Mode type: string description: How to visualize the area described by the spline readonly: no required: no default: alpha mutable: yes widget: dropdown values: - alpha - luma - rgb - identifier: alpha_operation title: Alpha Operation type: string description: | How to proceed with the current alpha mask (only if mode = alpha). clear = existing alpha mask is overwritten max = maximum: existing alpha mask, mask generated by this filter min = minimum: existing alpha mask, mask generated by this filter add = existing alpha mask + generated mask sub = existing alpha mask - generated mask readonly: no required: no default: clear mutable: yes widget: dropdown values: - clear - max - min - add - sub - identifier: invert title: Invert type: integer description: use area inside of spline (0) or the outside (1) readonly: no required: no minimum: 0 maximum: 1 default: 0 mutable: yes widget: checkbox - identifier: feather title: Feather type: integer description: amount of feathering (radius of "average" blur applied on mask) readonly: no required: no minimum: 0 maximum: 1000 # no real limit default: 0 mutable: yes widget: spinner - identifier: feather_passes title: Feathering passes type: integer description: number of blur (feathering) passes readonly: no required: no minimum: 1 maximum: 1000 # no real limit default: 1 mutable: yes widget: spinner - identifier: spline title: Spline type: string description: > The spline, a list of cubic Bézier curves, is described using JSON. The most basic parts are the coordinate tuples: [x, y]; x,y will be mapped from the range 0-1 to the image dimensions. Next layer are the Bézier points: [handle 1, point, handle 2] with handle 1, point, handle 2 being coordinate tuples The spline is a list of Bézier points. Optionally keyframes can be defined as a object of frame values, relative to the filter's in point, assigned to splines. readonly: no required: yes mutable: yes mlt-0.9.0/src/modules/rotoscoping/gpl000066400000000000000000000000001215300731300176070ustar00rootroot00000000000000mlt-0.9.0/src/modules/rtaudio/000077500000000000000000000000001215300731300162155ustar00rootroot00000000000000mlt-0.9.0/src/modules/rtaudio/Makefile000066400000000000000000000026121215300731300176560ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lpthread include ../../../config.mak TARGET = ../libmltrtaudio$(LIBSUF) OBJS = consumer_rtaudio.o \ RtAudio.o SRCS := $(OBJS:.o=.cpp) CXXFLAGS += $(CFLAGS) -Wno-deprecated -Wno-multichar -fno-rtti ifeq ($(targetos), Darwin) CXXFLAGS += -D__MACOSX_CORE__ LDFLAGS += -framework CoreAudio -framework CoreFoundation else ifeq ($(targetos), MinGW) CXXFLAGS += -D__WINDOWS_DS__ LDFLAGS += -lole32 -ldsound -lwinmm # For ASIO when ready to try that: #OBJS += asio.o asiodrivers.o asiolist.o iasiothiscallresolver.o #CXXFLAGS +=-D__WINDOWS_ASIO__ else ifeq ($(targetos), Linux) CXXFLAGS += -D__LINUX_ALSA__ CXXFLAGS += `pkg-config --cflags alsa` LDFLAGS += `pkg-config --libs alsa` else ifeq ($(targetos), NetBSD) CXXFLAGS += -D__LINUX_OSS__ LDFLAGS += -lossaudio else # FreeBSD CXXFLAGS += -D__LINUX_OSS__ endif all: $(TARGET) $(TARGET): $(OBJS) $(CXX) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CXX) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" #install -d "$(DESTDIR)$(mltdatadir)/rtaudio" #install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/rtaudio" uninstall: rm "$(DESTDIR)$(moduledir)/libmltrtaudio$(LIBSUF)" 2> /dev/null || true rm -rf "$(DESTDIR)$(mltdatadir)/rtaudio" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/rtaudio/RtAudio.cpp000066400000000000000000010621771215300731300203060ustar00rootroot00000000000000/************************************************************************/ /*! \class RtAudio \brief Realtime audio i/o C++ classes. RtAudio provides a common API (Application Programming Interface) for realtime audio input/output across Linux (native ALSA, Jack, and OSS), Macintosh OS X (CoreAudio and Jack), and Windows (DirectSound and ASIO) operating systems. RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/ RtAudio: realtime audio i/o C++ classes Copyright (c) 2001-2011 Gary P. Scavone 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. Any person wishing to distribute modifications to the Software is asked to send the modifications to the original developer so that they can be incorporated into the canonical version. This is, however, not a binding provision of this license. 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. */ /************************************************************************/ // RtAudio: Version 4.0.10 #include "RtAudio.h" #include #include #include #include // Static variable definitions. const unsigned int RtApi::MAX_SAMPLE_RATES = 14; const unsigned int RtApi::SAMPLE_RATES[] = { 4000, 5512, 8000, 9600, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000 }; #if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A) #define MUTEX_DESTROY(A) DeleteCriticalSection(A) #define MUTEX_LOCK(A) EnterCriticalSection(A) #define MUTEX_UNLOCK(A) LeaveCriticalSection(A) #elif defined(__LINUX_ALSA__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__) // pthread API #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL) #define MUTEX_DESTROY(A) pthread_mutex_destroy(A) #define MUTEX_LOCK(A) pthread_mutex_lock(A) #define MUTEX_UNLOCK(A) pthread_mutex_unlock(A) #else #define MUTEX_INITIALIZE(A) abs(*A) // dummy definitions #define MUTEX_DESTROY(A) abs(*A) // dummy definitions #endif // *************************************************** // // // RtAudio definitions. // // *************************************************** // void RtAudio :: getCompiledApi( std::vector &apis ) throw() { apis.clear(); // The order here will control the order of RtAudio's API search in // the constructor. #if defined(__UNIX_JACK__) apis.push_back( UNIX_JACK ); #endif #if defined(__LINUX_ALSA__) apis.push_back( LINUX_ALSA ); #endif #if defined(__LINUX_OSS__) apis.push_back( LINUX_OSS ); #endif #if defined(__WINDOWS_ASIO__) apis.push_back( WINDOWS_ASIO ); #endif #if defined(__WINDOWS_DS__) apis.push_back( WINDOWS_DS ); #endif #if defined(__MACOSX_CORE__) apis.push_back( MACOSX_CORE ); #endif #if defined(__RTAUDIO_DUMMY__) apis.push_back( RTAUDIO_DUMMY ); #endif } void RtAudio :: openRtApi( RtAudio::Api api ) { #if defined(__UNIX_JACK__) if ( api == UNIX_JACK ) rtapi_ = new RtApiJack(); #endif #if defined(__LINUX_ALSA__) if ( api == LINUX_ALSA ) rtapi_ = new RtApiAlsa(); #endif #if defined(__LINUX_OSS__) if ( api == LINUX_OSS ) rtapi_ = new RtApiOss(); #endif #if defined(__WINDOWS_ASIO__) if ( api == WINDOWS_ASIO ) rtapi_ = new RtApiAsio(); #endif #if defined(__WINDOWS_DS__) if ( api == WINDOWS_DS ) rtapi_ = new RtApiDs(); #endif #if defined(__MACOSX_CORE__) if ( api == MACOSX_CORE ) rtapi_ = new RtApiCore(); #endif #if defined(__RTAUDIO_DUMMY__) if ( api == RTAUDIO_DUMMY ) rtapi_ = new RtApiDummy(); #endif } RtAudio :: RtAudio( RtAudio::Api api ) throw() { rtapi_ = 0; if ( api != UNSPECIFIED ) { // Attempt to open the specified API. openRtApi( api ); if ( rtapi_ ) return; // No compiled support for specified API value. Issue a debug // warning and continue as if no API was specified. std::cerr << "\nRtAudio: no compiled support for specified API argument!\n" << std::endl; } // Iterate through the compiled APIs and return as soon as we find // one with at least one device or we reach the end of the list. std::vector< RtAudio::Api > apis; getCompiledApi( apis ); for ( unsigned int i=0; igetDeviceCount() ) break; } if ( rtapi_ ) return; // It should not be possible to get here because the preprocessor // definition __RTAUDIO_DUMMY__ is automatically defined if no // API-specific definitions are passed to the compiler. But just in // case something weird happens, we'll print out an error message. std::cerr << "\nRtAudio: no compiled API support found ... critical error!!\n\n"; } RtAudio :: ~RtAudio() throw() { delete rtapi_; } void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters, RtAudio::StreamParameters *inputParameters, RtAudioFormat format, unsigned int sampleRate, unsigned int *bufferFrames, RtAudioCallback callback, void *userData, RtAudio::StreamOptions *options ) { return rtapi_->openStream( outputParameters, inputParameters, format, sampleRate, bufferFrames, callback, userData, options ); } // *************************************************** // // // Public RtApi definitions (see end of file for // private or protected utility functions). // // *************************************************** // RtApi :: RtApi() { stream_.state = STREAM_CLOSED; stream_.mode = UNINITIALIZED; stream_.apiHandle = 0; stream_.userBuffer[0] = 0; stream_.userBuffer[1] = 0; MUTEX_INITIALIZE( &stream_.mutex ); showWarnings_ = true; } RtApi :: ~RtApi() { MUTEX_DESTROY( &stream_.mutex ); } void RtApi :: openStream( RtAudio::StreamParameters *oParams, RtAudio::StreamParameters *iParams, RtAudioFormat format, unsigned int sampleRate, unsigned int *bufferFrames, RtAudioCallback callback, void *userData, RtAudio::StreamOptions *options ) { if ( stream_.state != STREAM_CLOSED ) { errorText_ = "RtApi::openStream: a stream is already open!"; error( RtError::INVALID_USE ); } if ( oParams && oParams->nChannels < 1 ) { errorText_ = "RtApi::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one."; error( RtError::INVALID_USE ); } if ( iParams && iParams->nChannels < 1 ) { errorText_ = "RtApi::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one."; error( RtError::INVALID_USE ); } if ( oParams == NULL && iParams == NULL ) { errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!"; error( RtError::INVALID_USE ); } if ( formatBytes(format) == 0 ) { errorText_ = "RtApi::openStream: 'format' parameter value is undefined."; error( RtError::INVALID_USE ); } unsigned int nDevices = getDeviceCount(); unsigned int oChannels = 0; if ( oParams ) { oChannels = oParams->nChannels; if ( oParams->deviceId >= nDevices ) { errorText_ = "RtApi::openStream: output device parameter value is invalid."; error( RtError::INVALID_USE ); } } unsigned int iChannels = 0; if ( iParams ) { iChannels = iParams->nChannels; if ( iParams->deviceId >= nDevices ) { errorText_ = "RtApi::openStream: input device parameter value is invalid."; error( RtError::INVALID_USE ); } } clearStreamInfo(); bool result; if ( oChannels > 0 ) { result = probeDeviceOpen( oParams->deviceId, OUTPUT, oChannels, oParams->firstChannel, sampleRate, format, bufferFrames, options, oParams->deviceName ); if ( result == false ) error( RtError::SYSTEM_ERROR ); } if ( iChannels > 0 ) { result = probeDeviceOpen( iParams->deviceId, INPUT, iChannels, iParams->firstChannel, sampleRate, format, bufferFrames, options, iParams->deviceName ); if ( result == false ) { if ( oChannels > 0 ) closeStream(); error( RtError::SYSTEM_ERROR ); } } stream_.callbackInfo.callback = (void *) callback; stream_.callbackInfo.userData = userData; if ( options ) options->numberOfBuffers = stream_.nBuffers; stream_.state = STREAM_STOPPED; } unsigned int RtApi :: getDefaultInputDevice( void ) { // Should be implemented in subclasses if possible. return 0; } unsigned int RtApi :: getDefaultOutputDevice( void ) { // Should be implemented in subclasses if possible. return 0; } void RtApi :: closeStream( void ) { // MUST be implemented in subclasses! return; } bool RtApi :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options, const std::string &deviceName ) { // MUST be implemented in subclasses! return FAILURE; } void RtApi :: tickStreamTime( void ) { // Subclasses that do not provide their own implementation of // getStreamTime should call this function once per buffer I/O to // provide basic stream time support. stream_.streamTime += ( stream_.bufferSize * 1.0 / stream_.sampleRate ); #if defined( HAVE_GETTIMEOFDAY ) gettimeofday( &stream_.lastTickTimestamp, NULL ); #endif } long RtApi :: getStreamLatency( void ) { verifyStream(); long totalLatency = 0; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) totalLatency = stream_.latency[0]; if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) totalLatency += stream_.latency[1]; return totalLatency; } double RtApi :: getStreamTime( void ) { verifyStream(); #if defined( HAVE_GETTIMEOFDAY ) // Return a very accurate estimate of the stream time by // adding in the elapsed time since the last tick. struct timeval then; struct timeval now; if ( stream_.state != STREAM_RUNNING || stream_.streamTime == 0.0 ) return stream_.streamTime; gettimeofday( &now, NULL ); then = stream_.lastTickTimestamp; return stream_.streamTime + ((now.tv_sec + 0.000001 * now.tv_usec) - (then.tv_sec + 0.000001 * then.tv_usec)); #else return stream_.streamTime; #endif } unsigned int RtApi :: getStreamSampleRate( void ) { verifyStream(); return stream_.sampleRate; } // *************************************************** // // // OS/API-specific methods. // // *************************************************** // #if defined(__MACOSX_CORE__) // The OS X CoreAudio API is designed to use a separate callback // procedure for each of its audio devices. A single RtAudio duplex // stream using two different devices is supported here, though it // cannot be guaranteed to always behave correctly because we cannot // synchronize these two callbacks. // // A property listener is installed for over/underrun information. // However, no functionality is currently provided to allow property // listeners to trigger user handlers because it is unclear what could // be done if a critical stream parameter (buffer size, sample rate, // device disconnect) notification arrived. The listeners entail // quite a bit of extra code and most likely, a user program wouldn't // be prepared for the result anyway. However, we do provide a flag // to the client callback function to inform of an over/underrun. // A structure to hold various information related to the CoreAudio API // implementation. struct CoreHandle { AudioDeviceID id[2]; // device ids AudioDeviceIOProcID procId[2]; UInt32 iStream[2]; // device stream index (or first if using multiple) UInt32 nStreams[2]; // number of streams to use bool xrun[2]; char *deviceBuffer; pthread_cond_t condition; int drainCounter; // Tracks callback counts when draining bool internalDrain; // Indicates if stop is initiated from callback or not. CoreHandle() :deviceBuffer(0), drainCounter(0), internalDrain(false) { nStreams[0] = 1; nStreams[1] = 1; id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; } }; RtApiCore:: RtApiCore() { // This is a largely undocumented but absolutely necessary // requirement starting with OS-X 10.6. If not called, queries and // updates to various audio device properties are not handled // correctly. CFRunLoopRef theRunLoop = NULL; AudioObjectPropertyAddress property = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; OSStatus result = AudioObjectSetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop); if ( result != noErr ) { errorText_ = "RtApiCore::RtApiCore: error setting run loop property!"; error( RtError::WARNING ); } } RtApiCore :: ~RtApiCore() { // The subclass destructor gets called before the base class // destructor, so close an existing stream before deallocating // apiDeviceId memory. if ( stream_.state != STREAM_CLOSED ) closeStream(); } unsigned int RtApiCore :: getDeviceCount( void ) { // Find out how many audio devices there are, if any. UInt32 dataSize; AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; OSStatus result = AudioObjectGetPropertyDataSize( kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize ); if ( result != noErr ) { errorText_ = "RtApiCore::getDeviceCount: OS-X error getting device info!"; error( RtError::WARNING ); return 0; } return dataSize / sizeof( AudioDeviceID ); } unsigned int RtApiCore :: getDefaultInputDevice( void ) { unsigned int nDevices = getDeviceCount(); if ( nDevices <= 1 ) return 0; AudioDeviceID id; UInt32 dataSize = sizeof( AudioDeviceID ); AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &id ); if ( result != noErr ) { errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device."; error( RtError::WARNING ); return 0; } dataSize *= nDevices; AudioDeviceID deviceList[ nDevices ]; property.mSelector = kAudioHardwarePropertyDevices; result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList ); if ( result != noErr ) { errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device IDs."; error( RtError::WARNING ); return 0; } for ( unsigned int i=0; i= nDevices ) { errorText_ = "RtApiCore::getDeviceInfo: device ID is invalid!"; error( RtError::INVALID_USE ); } AudioDeviceID deviceList[ nDevices ]; UInt32 dataSize = sizeof( AudioDeviceID ) * nDevices; AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList ); if ( result != noErr ) { errorText_ = "RtApiCore::getDeviceInfo: OS-X system error getting device IDs."; error( RtError::WARNING ); return info; } AudioDeviceID id = deviceList[ device ]; // Get the device name. info.name.erase(); CFStringRef cfname; dataSize = sizeof( CFStringRef ); property.mSelector = kAudioObjectPropertyManufacturer; result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &cfname ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device manufacturer."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } //const char *mname = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() ); int length = CFStringGetLength(cfname); char *mname = (char *)malloc(length * 3 + 1); CFStringGetCString(cfname, mname, length * 3 + 1, CFStringGetSystemEncoding()); info.name.append( (const char *)mname, strlen(mname) ); info.name.append( ": " ); CFRelease( cfname ); free(mname); property.mSelector = kAudioObjectPropertyName; result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &cfname ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device name."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } //const char *name = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() ); length = CFStringGetLength(cfname); char *name = (char *)malloc(length * 3 + 1); CFStringGetCString(cfname, name, length * 3 + 1, CFStringGetSystemEncoding()); info.name.append( (const char *)name, strlen(name) ); CFRelease( cfname ); free(name); // Get the output stream "configuration". AudioBufferList *bufferList = nil; property.mSelector = kAudioDevicePropertyStreamConfiguration; property.mScope = kAudioDevicePropertyScopeOutput; // property.mElement = kAudioObjectPropertyElementWildcard; dataSize = 0; result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize ); if ( result != noErr || dataSize == 0 ) { errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration info for device (" << device << ")."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } // Allocate the AudioBufferList. bufferList = (AudioBufferList *) malloc( dataSize ); if ( bufferList == NULL ) { errorText_ = "RtApiCore::getDeviceInfo: memory error allocating output AudioBufferList."; error( RtError::WARNING ); return info; } result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList ); if ( result != noErr || dataSize == 0 ) { free( bufferList ); errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration for device (" << device << ")."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } // Get output channel information. unsigned int i, nStreams = bufferList->mNumberBuffers; for ( i=0; imBuffers[i].mNumberChannels; free( bufferList ); // Get the input stream "configuration". property.mScope = kAudioDevicePropertyScopeInput; result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize ); if ( result != noErr || dataSize == 0 ) { errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration info for device (" << device << ")."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } // Allocate the AudioBufferList. bufferList = (AudioBufferList *) malloc( dataSize ); if ( bufferList == NULL ) { errorText_ = "RtApiCore::getDeviceInfo: memory error allocating input AudioBufferList."; error( RtError::WARNING ); return info; } result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList ); if (result != noErr || dataSize == 0) { free( bufferList ); errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration for device (" << device << ")."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } // Get input channel information. nStreams = bufferList->mNumberBuffers; for ( i=0; imBuffers[i].mNumberChannels; free( bufferList ); // If device opens for both playback and capture, we determine the channels. if ( info.outputChannels > 0 && info.inputChannels > 0 ) info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels; // Probe the device sample rates. bool isInput = false; if ( info.outputChannels == 0 ) isInput = true; // Determine the supported sample rates. property.mSelector = kAudioDevicePropertyAvailableNominalSampleRates; if ( isInput == false ) property.mScope = kAudioDevicePropertyScopeOutput; result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize ); if ( result != kAudioHardwareNoError || dataSize == 0 ) { errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rate info."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } UInt32 nRanges = dataSize / sizeof( AudioValueRange ); AudioValueRange rangeList[ nRanges ]; result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &rangeList ); if ( result != kAudioHardwareNoError ) { errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rates."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } Float64 minimumRate = 100000000.0, maximumRate = 0.0; for ( UInt32 i=0; i maximumRate ) maximumRate = rangeList[i].mMaximum; } info.sampleRates.clear(); for ( unsigned int k=0; k= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate ) info.sampleRates.push_back( SAMPLE_RATES[k] ); } if ( info.sampleRates.size() == 0 ) { errorStream_ << "RtApiCore::probeDeviceInfo: No supported sample rates found for device (" << device << ")."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } // CoreAudio always uses 32-bit floating point data for PCM streams. // Thus, any other "physical" formats supported by the device are of // no interest to the client. info.nativeFormats = RTAUDIO_FLOAT32; if ( info.outputChannels > 0 ) if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true; if ( info.inputChannels > 0 ) if ( getDefaultInputDevice() == device ) info.isDefaultInput = true; info.probed = true; return info; } OSStatus callbackHandler( AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* infoPointer ) { CallbackInfo *info = (CallbackInfo *) infoPointer; RtApiCore *object = (RtApiCore *) info->object; if ( object->callbackEvent( inDevice, inInputData, outOutputData ) == false ) return kAudioHardwareUnspecifiedError; else return kAudioHardwareNoError; } OSStatus xrunListener( AudioObjectID inDevice, UInt32 nAddresses, const AudioObjectPropertyAddress properties[], void* handlePointer ) { CoreHandle *handle = (CoreHandle *) handlePointer; for ( UInt32 i=0; ixrun[1] = true; else handle->xrun[0] = true; } } return kAudioHardwareNoError; } OSStatus rateListener( AudioObjectID inDevice, UInt32 nAddresses, const AudioObjectPropertyAddress properties[], void* ratePointer ) { Float64 *rate = (Float64 *) ratePointer; UInt32 dataSize = sizeof( Float64 ); AudioObjectPropertyAddress property = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; AudioObjectGetPropertyData( inDevice, &property, 0, NULL, &dataSize, rate ); return kAudioHardwareNoError; } bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options, const std::string &deviceName ) { // Get device ID unsigned int nDevices = getDeviceCount(); if ( nDevices == 0 ) { // This should not happen because a check is made before this function is called. errorText_ = "RtApiCore::probeDeviceOpen: no devices found!"; return FAILURE; } if ( device >= nDevices ) { // This should not happen because a check is made before this function is called. errorText_ = "RtApiCore::probeDeviceOpen: device ID is invalid!"; return FAILURE; } AudioDeviceID deviceList[ nDevices ]; UInt32 dataSize = sizeof( AudioDeviceID ) * nDevices; AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList ); if ( result != noErr ) { errorText_ = "RtApiCore::probeDeviceOpen: OS-X system error getting device IDs."; return FAILURE; } AudioDeviceID id = deviceList[ device ]; // Setup for stream mode. bool isInput = false; if ( mode == INPUT ) { isInput = true; property.mScope = kAudioDevicePropertyScopeInput; } else property.mScope = kAudioDevicePropertyScopeOutput; // Get the stream "configuration". AudioBufferList *bufferList = nil; dataSize = 0; property.mSelector = kAudioDevicePropertyStreamConfiguration; result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize ); if ( result != noErr || dataSize == 0 ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream configuration info for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } // Allocate the AudioBufferList. bufferList = (AudioBufferList *) malloc( dataSize ); if ( bufferList == NULL ) { errorText_ = "RtApiCore::probeDeviceOpen: memory error allocating AudioBufferList."; return FAILURE; } result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList ); if (result != noErr || dataSize == 0) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream configuration for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } // Search for one or more streams that contain the desired number of // channels. CoreAudio devices can have an arbitrary number of // streams and each stream can have an arbitrary number of channels. // For each stream, a single buffer of interleaved samples is // provided. RtAudio prefers the use of one stream of interleaved // data or multiple consecutive single-channel streams. However, we // now support multiple consecutive multi-channel streams of // interleaved data as well. UInt32 iStream, offsetCounter = firstChannel; UInt32 nStreams = bufferList->mNumberBuffers; bool monoMode = false; bool foundStream = false; // First check that the device supports the requested number of // channels. UInt32 deviceChannels = 0; for ( iStream=0; iStreammBuffers[iStream].mNumberChannels; if ( deviceChannels < ( channels + firstChannel ) ) { free( bufferList ); errorStream_ << "RtApiCore::probeDeviceOpen: the device (" << device << ") does not support the requested channel count."; errorText_ = errorStream_.str(); return FAILURE; } // Look for a single stream meeting our needs. UInt32 firstStream, streamCount = 1, streamChannels = 0, channelOffset = 0; for ( iStream=0; iStreammBuffers[iStream].mNumberChannels; if ( streamChannels >= channels + offsetCounter ) { firstStream = iStream; channelOffset = offsetCounter; foundStream = true; break; } if ( streamChannels > offsetCounter ) break; offsetCounter -= streamChannels; } // If we didn't find a single stream above, then we should be able // to meet the channel specification with multiple streams. if ( foundStream == false ) { monoMode = true; offsetCounter = firstChannel; for ( iStream=0; iStreammBuffers[iStream].mNumberChannels; if ( streamChannels > offsetCounter ) break; offsetCounter -= streamChannels; } firstStream = iStream; channelOffset = offsetCounter; Int32 channelCounter = channels + offsetCounter - streamChannels; if ( streamChannels > 1 ) monoMode = false; while ( channelCounter > 0 ) { streamChannels = bufferList->mBuffers[++iStream].mNumberChannels; if ( streamChannels > 1 ) monoMode = false; channelCounter -= streamChannels; streamCount++; } } free( bufferList ); // Determine the buffer size. AudioValueRange bufferRange; dataSize = sizeof( AudioValueRange ); property.mSelector = kAudioDevicePropertyBufferFrameSizeRange; result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &bufferRange ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting buffer size range for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } if ( bufferRange.mMinimum > *bufferSize ) *bufferSize = (unsigned long) bufferRange.mMinimum; else if ( bufferRange.mMaximum < *bufferSize ) *bufferSize = (unsigned long) bufferRange.mMaximum; if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) *bufferSize = (unsigned long) bufferRange.mMinimum; // Set the buffer size. For multiple streams, I'm assuming we only // need to make this setting for the master channel. UInt32 theSize = (UInt32) *bufferSize; dataSize = sizeof( UInt32 ); property.mSelector = kAudioDevicePropertyBufferFrameSize; result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &theSize ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting the buffer size for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } // If attempting to setup a duplex stream, the bufferSize parameter // MUST be the same in both directions! *bufferSize = theSize; if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } stream_.bufferSize = *bufferSize; stream_.nBuffers = 1; // Try to set "hog" mode ... it's not clear to me this is working. if ( options && options->flags & RTAUDIO_HOG_DEVICE ) { pid_t hog_pid; dataSize = sizeof( hog_pid ); property.mSelector = kAudioDevicePropertyHogMode; result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &hog_pid ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting 'hog' state!"; errorText_ = errorStream_.str(); return FAILURE; } if ( hog_pid != getpid() ) { hog_pid = getpid(); result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &hog_pid ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting 'hog' state!"; errorText_ = errorStream_.str(); return FAILURE; } } } // Check and if necessary, change the sample rate for the device. Float64 nominalRate; dataSize = sizeof( Float64 ); property.mSelector = kAudioDevicePropertyNominalSampleRate; result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &nominalRate ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting current sample rate."; errorText_ = errorStream_.str(); return FAILURE; } // Only change the sample rate if off by more than 1 Hz. if ( fabs( nominalRate - (double)sampleRate ) > 1.0 ) { // Set a property listener for the sample rate change Float64 reportedRate = 0.0; AudioObjectPropertyAddress tmp = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; result = AudioObjectAddPropertyListener( id, &tmp, rateListener, (void *) &reportedRate ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate property listener for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } nominalRate = (Float64) sampleRate; result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &nominalRate ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } // Now wait until the reported nominal rate is what we just set. UInt32 microCounter = 0; while ( reportedRate != nominalRate ) { microCounter += 5000; if ( microCounter > 5000000 ) break; usleep( 5000 ); } // Remove the property listener. AudioObjectRemovePropertyListener( id, &tmp, rateListener, (void *) &reportedRate ); if ( microCounter > 5000000 ) { errorStream_ << "RtApiCore::probeDeviceOpen: timeout waiting for sample rate update for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } } // Now set the stream format for all streams. Also, check the // physical format of the device and change that if necessary. AudioStreamBasicDescription description; dataSize = sizeof( AudioStreamBasicDescription ); property.mSelector = kAudioStreamPropertyVirtualFormat; result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &description ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream format for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } // Set the sample rate and data format id. However, only make the // change if the sample rate is not within 1.0 of the desired // rate and the format is not linear pcm. bool updateFormat = false; if ( fabs( description.mSampleRate - (Float64)sampleRate ) > 1.0 ) { description.mSampleRate = (Float64) sampleRate; updateFormat = true; } if ( description.mFormatID != kAudioFormatLinearPCM ) { description.mFormatID = kAudioFormatLinearPCM; updateFormat = true; } if ( updateFormat ) { result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &description ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate or data format for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } } // Now check the physical format. property.mSelector = kAudioStreamPropertyPhysicalFormat; result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &description ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream physical format for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } //std::cout << "Current physical stream format:" << std::endl; //std::cout << " mBitsPerChan = " << description.mBitsPerChannel << std::endl; //std::cout << " aligned high = " << (description.mFormatFlags & kAudioFormatFlagIsAlignedHigh) << ", isPacked = " << (description.mFormatFlags & kAudioFormatFlagIsPacked) << std::endl; //std::cout << " bytesPerFrame = " << description.mBytesPerFrame << std::endl; //std::cout << " sample rate = " << description.mSampleRate << std::endl; if ( description.mFormatID != kAudioFormatLinearPCM || description.mBitsPerChannel < 16 ) { description.mFormatID = kAudioFormatLinearPCM; //description.mSampleRate = (Float64) sampleRate; AudioStreamBasicDescription testDescription = description; UInt32 formatFlags; // We'll try higher bit rates first and then work our way down. std::vector< std::pair > physicalFormats; formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsFloat) & ~kLinearPCMFormatFlagIsSignedInteger; physicalFormats.push_back( std::pair( 32, formatFlags ) ); formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat; physicalFormats.push_back( std::pair( 32, formatFlags ) ); physicalFormats.push_back( std::pair( 24, formatFlags ) ); // 24-bit packed formatFlags &= ~( kAudioFormatFlagIsPacked | kAudioFormatFlagIsAlignedHigh ); physicalFormats.push_back( std::pair( 24.2, formatFlags ) ); // 24-bit in 4 bytes, aligned low formatFlags |= kAudioFormatFlagIsAlignedHigh; physicalFormats.push_back( std::pair( 24.4, formatFlags ) ); // 24-bit in 4 bytes, aligned high formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat; physicalFormats.push_back( std::pair( 16, formatFlags ) ); physicalFormats.push_back( std::pair( 8, formatFlags ) ); bool setPhysicalFormat = false; for( unsigned int i=0; iflags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false; else stream_.userInterleaved = true; stream_.deviceInterleaved[mode] = true; if ( monoMode == true ) stream_.deviceInterleaved[mode] = false; // Set flags for buffer conversion. stream_.doConvertBuffer[mode] = false; if ( stream_.userFormat != stream_.deviceFormat[mode] ) stream_.doConvertBuffer[mode] = true; if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] ) stream_.doConvertBuffer[mode] = true; if ( streamCount == 1 ) { if ( stream_.nUserChannels[mode] > 1 && stream_.userInterleaved != stream_.deviceInterleaved[mode] ) stream_.doConvertBuffer[mode] = true; } else if ( monoMode && stream_.userInterleaved ) stream_.doConvertBuffer[mode] = true; // Allocate our CoreHandle structure for the stream. CoreHandle *handle = 0; if ( stream_.apiHandle == 0 ) { try { handle = new CoreHandle; } catch ( std::bad_alloc& ) { errorText_ = "RtApiCore::probeDeviceOpen: error allocating CoreHandle memory."; goto error; } if ( pthread_cond_init( &handle->condition, NULL ) ) { errorText_ = "RtApiCore::probeDeviceOpen: error initializing pthread condition variable."; goto error; } stream_.apiHandle = (void *) handle; } else handle = (CoreHandle *) stream_.apiHandle; handle->iStream[mode] = firstStream; handle->nStreams[mode] = streamCount; handle->id[mode] = id; // Allocate necessary internal buffers. unsigned long bufferBytes; bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); // stream_.userBuffer[mode] = (char *) calloc( 1, bufferBytes ); stream_.userBuffer[mode] = (char *) malloc( bufferBytes * sizeof(char) ); memset( stream_.userBuffer[mode], 0, bufferBytes * sizeof(char) ); if ( stream_.userBuffer[mode] == NULL ) { errorText_ = "RtApiCore::probeDeviceOpen: error allocating user buffer memory."; goto error; } // If possible, we will make use of the CoreAudio stream buffers as // "device buffers". However, we can't do this if using multiple // streams. if ( stream_.doConvertBuffer[mode] && handle->nStreams[mode] > 1 ) { bool makeBuffer = true; bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] ); if ( mode == INPUT ) { if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) { unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); if ( bufferBytes <= bytesOut ) makeBuffer = false; } } if ( makeBuffer ) { bufferBytes *= *bufferSize; if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); stream_.deviceBuffer = (char *) calloc( 1, bufferBytes ); if ( stream_.deviceBuffer == NULL ) { errorText_ = "RtApiCore::probeDeviceOpen: error allocating device buffer memory."; goto error; } } } stream_.sampleRate = sampleRate; stream_.device[mode] = device; stream_.state = STREAM_STOPPED; stream_.callbackInfo.object = (void *) this; // Setup the buffer conversion information structure. if ( stream_.doConvertBuffer[mode] ) { if ( streamCount > 1 ) setConvertInfo( mode, 0 ); else setConvertInfo( mode, channelOffset ); } if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] == device ) // Only one callback procedure per device. stream_.mode = DUPLEX; else { result = AudioDeviceCreateIOProcID( id, callbackHandler, (void *) &stream_.callbackInfo, &handle->procId[mode] ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error setting callback for device (" << device << ")."; errorText_ = errorStream_.str(); goto error; } if ( stream_.mode == OUTPUT && mode == INPUT ) stream_.mode = DUPLEX; else stream_.mode = mode; } // Setup the device property listener for over/underload. property.mSelector = kAudioDeviceProcessorOverload; result = AudioObjectAddPropertyListener( id, &property, xrunListener, (void *) handle ); return SUCCESS; error: if ( handle ) { pthread_cond_destroy( &handle->condition ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } return FAILURE; } void RtApiCore :: closeStream( void ) { if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiCore::closeStream(): no open stream to close!"; error( RtError::WARNING ); return; } CoreHandle *handle = (CoreHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { if ( stream_.state == STREAM_RUNNING ) AudioDeviceStop( handle->id[0], handle->procId[0] ); AudioDeviceDestroyIOProcID( handle->id[0], handle->procId[0] ); } if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) { if ( stream_.state == STREAM_RUNNING ) AudioDeviceStop( handle->id[1], handle->procId[1] ); AudioDeviceDestroyIOProcID( handle->id[1], handle->procId[1] ); } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } // Destroy pthread condition variable. pthread_cond_destroy( &handle->condition ); delete handle; stream_.apiHandle = 0; stream_.mode = UNINITIALIZED; stream_.state = STREAM_CLOSED; } void RtApiCore :: startStream( void ) { verifyStream(); if ( stream_.state == STREAM_RUNNING ) { errorText_ = "RtApiCore::startStream(): the stream is already running!"; error( RtError::WARNING ); return; } MUTEX_LOCK( &stream_.mutex ); OSStatus result = noErr; CoreHandle *handle = (CoreHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { result = AudioDeviceStart( handle->id[0], handle->procId[0] ); if ( result != noErr ) { errorStream_ << "RtApiCore::startStream: system error (" << getErrorCode( result ) << ") starting callback procedure on device (" << stream_.device[0] << ")."; errorText_ = errorStream_.str(); goto unlock; } } if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) { result = AudioDeviceStart( handle->id[1], handle->procId[1] ); if ( result != noErr ) { errorStream_ << "RtApiCore::startStream: system error starting input callback procedure on device (" << stream_.device[1] << ")."; errorText_ = errorStream_.str(); goto unlock; } } handle->drainCounter = 0; handle->internalDrain = false; stream_.state = STREAM_RUNNING; unlock: MUTEX_UNLOCK( &stream_.mutex ); if ( result == noErr ) return; error( RtError::SYSTEM_ERROR ); } void RtApiCore :: stopStream( void ) { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiCore::stopStream(): the stream is already stopped!"; error( RtError::WARNING ); return; } MUTEX_LOCK( &stream_.mutex ); if ( stream_.state == STREAM_STOPPED ) { MUTEX_UNLOCK( &stream_.mutex ); return; } OSStatus result = noErr; CoreHandle *handle = (CoreHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { if ( handle->drainCounter == 0 ) { handle->drainCounter = 2; pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled } MUTEX_UNLOCK( &stream_.mutex ); result = AudioDeviceStop( handle->id[0], callbackHandler ); MUTEX_LOCK( &stream_.mutex ); if ( result != noErr ) { errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping callback procedure on device (" << stream_.device[0] << ")."; errorText_ = errorStream_.str(); goto unlock; } } if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) { MUTEX_UNLOCK( &stream_.mutex ); result = AudioDeviceStop( handle->id[1], callbackHandler ); MUTEX_LOCK( &stream_.mutex ); if ( result != noErr ) { errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping input callback procedure on device (" << stream_.device[1] << ")."; errorText_ = errorStream_.str(); goto unlock; } } stream_.state = STREAM_STOPPED; unlock: MUTEX_UNLOCK( &stream_.mutex ); if ( result == noErr ) return; error( RtError::SYSTEM_ERROR ); } void RtApiCore :: abortStream( void ) { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiCore::abortStream(): the stream is already stopped!"; error( RtError::WARNING ); return; } CoreHandle *handle = (CoreHandle *) stream_.apiHandle; handle->drainCounter = 2; stopStream(); } bool RtApiCore :: callbackEvent( AudioDeviceID deviceId, const AudioBufferList *inBufferList, const AudioBufferList *outBufferList ) { if ( stream_.state == STREAM_STOPPED ) return SUCCESS; if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!"; error( RtError::WARNING ); return FAILURE; } CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo; CoreHandle *handle = (CoreHandle *) stream_.apiHandle; // Check if we were draining the stream and signal is finished. if ( handle->drainCounter > 3 ) { if ( handle->internalDrain == true ) stopStream(); else // external call to stopStream() pthread_cond_signal( &handle->condition ); return SUCCESS; } MUTEX_LOCK( &stream_.mutex ); // The state might change while waiting on a mutex. if ( stream_.state == STREAM_STOPPED ) { MUTEX_UNLOCK( &stream_.mutex ); return SUCCESS; } AudioDeviceID outputDevice = handle->id[0]; // Invoke user callback to get fresh output data UNLESS we are // draining stream or duplex mode AND the input/output devices are // different AND this function is called for the input device. if ( handle->drainCounter == 0 && ( stream_.mode != DUPLEX || deviceId == outputDevice ) ) { RtAudioCallback callback = (RtAudioCallback) info->callback; double streamTime = getStreamTime(); RtAudioStreamStatus status = 0; if ( stream_.mode != INPUT && handle->xrun[0] == true ) { status |= RTAUDIO_OUTPUT_UNDERFLOW; handle->xrun[0] = false; } if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) { status |= RTAUDIO_INPUT_OVERFLOW; handle->xrun[1] = false; } handle->drainCounter = callback( stream_.userBuffer[0], stream_.userBuffer[1], stream_.bufferSize, streamTime, status, info->userData ); if ( handle->drainCounter == 2 ) { MUTEX_UNLOCK( &stream_.mutex ); abortStream(); return SUCCESS; } else if ( handle->drainCounter == 1 ) handle->internalDrain = true; } if ( stream_.mode == OUTPUT || ( stream_.mode == DUPLEX && deviceId == outputDevice ) ) { if ( handle->drainCounter > 1 ) { // write zeros to the output stream if ( handle->nStreams[0] == 1 ) { memset( outBufferList->mBuffers[handle->iStream[0]].mData, 0, outBufferList->mBuffers[handle->iStream[0]].mDataByteSize ); } else { // fill multiple streams with zeros for ( unsigned int i=0; inStreams[0]; i++ ) { memset( outBufferList->mBuffers[handle->iStream[0]+i].mData, 0, outBufferList->mBuffers[handle->iStream[0]+i].mDataByteSize ); } } } else if ( handle->nStreams[0] == 1 ) { if ( stream_.doConvertBuffer[0] ) { // convert directly to CoreAudio stream buffer convertBuffer( (char *) outBufferList->mBuffers[handle->iStream[0]].mData, stream_.userBuffer[0], stream_.convertInfo[0] ); } else { // copy from user buffer memcpy( outBufferList->mBuffers[handle->iStream[0]].mData, stream_.userBuffer[0], outBufferList->mBuffers[handle->iStream[0]].mDataByteSize ); } } else { // fill multiple streams Float32 *inBuffer = (Float32 *) stream_.userBuffer[0]; if ( stream_.doConvertBuffer[0] ) { convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] ); inBuffer = (Float32 *) stream_.deviceBuffer; } if ( stream_.deviceInterleaved[0] == false ) { // mono mode UInt32 bufferBytes = outBufferList->mBuffers[handle->iStream[0]].mDataByteSize; for ( unsigned int i=0; imBuffers[handle->iStream[0]+i].mData, (void *)&inBuffer[i*stream_.bufferSize], bufferBytes ); } } else { // fill multiple multi-channel streams with interleaved data UInt32 streamChannels, channelsLeft, inJump, outJump, inOffset; Float32 *out, *in; bool inInterleaved = ( stream_.userInterleaved ) ? true : false; UInt32 inChannels = stream_.nUserChannels[0]; if ( stream_.doConvertBuffer[0] ) { inInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode inChannels = stream_.nDeviceChannels[0]; } if ( inInterleaved ) inOffset = 1; else inOffset = stream_.bufferSize; channelsLeft = inChannels; for ( unsigned int i=0; inStreams[0]; i++ ) { in = inBuffer; out = (Float32 *) outBufferList->mBuffers[handle->iStream[0]+i].mData; streamChannels = outBufferList->mBuffers[handle->iStream[0]+i].mNumberChannels; outJump = 0; // Account for possible channel offset in first stream if ( i == 0 && stream_.channelOffset[0] > 0 ) { streamChannels -= stream_.channelOffset[0]; outJump = stream_.channelOffset[0]; out += outJump; } // Account for possible unfilled channels at end of the last stream if ( streamChannels > channelsLeft ) { outJump = streamChannels - channelsLeft; streamChannels = channelsLeft; } // Determine input buffer offsets and skips if ( inInterleaved ) { inJump = inChannels; in += inChannels - channelsLeft; } else { inJump = 1; in += (inChannels - channelsLeft) * inOffset; } for ( unsigned int i=0; idrainCounter ) { handle->drainCounter++; goto unlock; } } AudioDeviceID inputDevice; inputDevice = handle->id[1]; if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && deviceId == inputDevice ) ) { if ( handle->nStreams[1] == 1 ) { if ( stream_.doConvertBuffer[1] ) { // convert directly from CoreAudio stream buffer convertBuffer( stream_.userBuffer[1], (char *) inBufferList->mBuffers[handle->iStream[1]].mData, stream_.convertInfo[1] ); } else { // copy to user buffer memcpy( stream_.userBuffer[1], inBufferList->mBuffers[handle->iStream[1]].mData, inBufferList->mBuffers[handle->iStream[1]].mDataByteSize ); } } else { // read from multiple streams Float32 *outBuffer = (Float32 *) stream_.userBuffer[1]; if ( stream_.doConvertBuffer[1] ) outBuffer = (Float32 *) stream_.deviceBuffer; if ( stream_.deviceInterleaved[1] == false ) { // mono mode UInt32 bufferBytes = inBufferList->mBuffers[handle->iStream[1]].mDataByteSize; for ( unsigned int i=0; imBuffers[handle->iStream[1]+i].mData, bufferBytes ); } } else { // read from multiple multi-channel streams UInt32 streamChannels, channelsLeft, inJump, outJump, outOffset; Float32 *out, *in; bool outInterleaved = ( stream_.userInterleaved ) ? true : false; UInt32 outChannels = stream_.nUserChannels[1]; if ( stream_.doConvertBuffer[1] ) { outInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode outChannels = stream_.nDeviceChannels[1]; } if ( outInterleaved ) outOffset = 1; else outOffset = stream_.bufferSize; channelsLeft = outChannels; for ( unsigned int i=0; inStreams[1]; i++ ) { out = outBuffer; in = (Float32 *) inBufferList->mBuffers[handle->iStream[1]+i].mData; streamChannels = inBufferList->mBuffers[handle->iStream[1]+i].mNumberChannels; inJump = 0; // Account for possible channel offset in first stream if ( i == 0 && stream_.channelOffset[1] > 0 ) { streamChannels -= stream_.channelOffset[1]; inJump = stream_.channelOffset[1]; in += inJump; } // Account for possible unread channels at end of the last stream if ( streamChannels > channelsLeft ) { inJump = streamChannels - channelsLeft; streamChannels = channelsLeft; } // Determine output buffer offsets and skips if ( outInterleaved ) { outJump = outChannels; out += outChannels - channelsLeft; } else { outJump = 1; out += (outChannels - channelsLeft) * outOffset; } for ( unsigned int i=0; i #include #include // A structure to hold various information related to the Jack API // implementation. struct JackHandle { jack_client_t *client; jack_port_t **ports[2]; std::string deviceName[2]; bool xrun[2]; pthread_cond_t condition; int drainCounter; // Tracks callback counts when draining bool internalDrain; // Indicates if stop is initiated from callback or not. JackHandle() :client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; } }; ThreadHandle threadId; void jackSilentError( const char * ) {}; RtApiJack :: RtApiJack() { // Nothing to do here. #if !defined(__RTAUDIO_DEBUG__) // Turn off Jack's internal error reporting. jack_set_error_function( &jackSilentError ); #endif } RtApiJack :: ~RtApiJack() { if ( stream_.state != STREAM_CLOSED ) closeStream(); } unsigned int RtApiJack :: getDeviceCount( void ) { // See if we can become a jack client. jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption; jack_status_t *status = NULL; jack_client_t *client = jack_client_open( "RtApiJackCount", options, status ); if ( client == 0 ) return 0; const char **ports; std::string port, previousPort; unsigned int nChannels = 0, nDevices = 0; ports = jack_get_ports( client, NULL, NULL, 0 ); if ( ports ) { // Parse the port names up to the first colon (:). size_t iColon = 0; do { port = (char *) ports[ nChannels ]; iColon = port.find(":"); if ( iColon != std::string::npos ) { port = port.substr( 0, iColon + 1 ); if ( port != previousPort ) { nDevices++; previousPort = port; } } } while ( ports[++nChannels] ); free( ports ); } jack_client_close( client ); return nDevices; } RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device ) { RtAudio::DeviceInfo info; info.probed = false; jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption jack_status_t *status = NULL; jack_client_t *client = jack_client_open( "RtApiJackInfo", options, status ); if ( client == 0 ) { errorText_ = "RtApiJack::getDeviceInfo: Jack server not found or connection error!"; error( RtError::WARNING ); return info; } const char **ports; std::string port, previousPort; unsigned int nPorts = 0, nDevices = 0; ports = jack_get_ports( client, NULL, NULL, 0 ); if ( ports ) { // Parse the port names up to the first colon (:). size_t iColon = 0; do { port = (char *) ports[ nPorts ]; iColon = port.find(":"); if ( iColon != std::string::npos ) { port = port.substr( 0, iColon ); if ( port != previousPort ) { if ( nDevices == device ) info.name = port; nDevices++; previousPort = port; } } } while ( ports[++nPorts] ); free( ports ); } if ( device >= nDevices ) { errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!"; error( RtError::INVALID_USE ); } // Get the current jack server sample rate. info.sampleRates.clear(); info.sampleRates.push_back( jack_get_sample_rate( client ) ); // Count the available ports containing the client name as device // channels. Jack "input ports" equal RtAudio output channels. unsigned int nChannels = 0; ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsInput ); if ( ports ) { while ( ports[ nChannels ] ) nChannels++; free( ports ); info.outputChannels = nChannels; } // Jack "output ports" equal RtAudio input channels. nChannels = 0; ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsOutput ); if ( ports ) { while ( ports[ nChannels ] ) nChannels++; free( ports ); info.inputChannels = nChannels; } if ( info.outputChannels == 0 && info.inputChannels == 0 ) { jack_client_close(client); errorText_ = "RtApiJack::getDeviceInfo: error determining Jack input/output channels!"; error( RtError::WARNING ); return info; } // If device opens for both playback and capture, we determine the channels. if ( info.outputChannels > 0 && info.inputChannels > 0 ) info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels; // Jack always uses 32-bit floats. info.nativeFormats = RTAUDIO_FLOAT32; // Jack doesn't provide default devices so we'll use the first available one. if ( device == 0 && info.outputChannels > 0 ) info.isDefaultOutput = true; if ( device == 0 && info.inputChannels > 0 ) info.isDefaultInput = true; jack_client_close(client); info.probed = true; return info; } int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer ) { CallbackInfo *info = (CallbackInfo *) infoPointer; RtApiJack *object = (RtApiJack *) info->object; if ( object->callbackEvent( (unsigned long) nframes ) == false ) return 1; return 0; } // This function will be called by a spawned thread when the Jack // server signals that it is shutting down. It is necessary to handle // it this way because the jackShutdown() function must return before // the jack_deactivate() function (in closeStream()) will return. extern "C" void *jackCloseStream( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiJack *object = (RtApiJack *) info->object; object->closeStream(); pthread_exit( NULL ); } void jackShutdown( void *infoPointer ) { CallbackInfo *info = (CallbackInfo *) infoPointer; RtApiJack *object = (RtApiJack *) info->object; // Check current stream state. If stopped, then we'll assume this // was called as a result of a call to RtApiJack::stopStream (the // deactivation of a client handle causes this function to be called). // If not, we'll assume the Jack server is shutting down or some // other problem occurred and we should close the stream. if ( object->isStreamRunning() == false ) return; pthread_create( &threadId, NULL, jackCloseStream, info ); std::cerr << "\nRtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!\n" << std::endl; } int jackXrun( void *infoPointer ) { JackHandle *handle = (JackHandle *) infoPointer; if ( handle->ports[0] ) handle->xrun[0] = true; if ( handle->ports[1] ) handle->xrun[1] = true; return 0; } bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options, const std::string &aDeviceName ) { JackHandle *handle = (JackHandle *) stream_.apiHandle; // Look for jack server and try to become a client (only do once per stream). jack_client_t *client = 0; if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) { jack_options_t jackoptions = (jack_options_t) ( JackNoStartServer ); //JackNullOption; jack_status_t *status = NULL; if ( options && !options->streamName.empty() ) client = jack_client_open( options->streamName.c_str(), jackoptions, status ); else client = jack_client_open( "RtApiJack", jackoptions, status ); if ( client == 0 ) { errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!"; error( RtError::WARNING ); return FAILURE; } } else { // The handle must have been created on an earlier pass. client = handle->client; } std::string deviceName = aDeviceName; const char **ports; if ( deviceName.size() == 0 ) { std::string port, previousPort, deviceName; unsigned int nPorts = 0, nDevices = 0; ports = jack_get_ports( client, NULL, NULL, 0 ); if ( ports ) { // Parse the port names up to the first colon (:). size_t iColon = 0; do { port = (char *) ports[ nPorts ]; iColon = port.find(":"); if ( iColon != std::string::npos ) { port = port.substr( 0, iColon ); if ( port != previousPort ) { if ( nDevices == device ) deviceName = port; nDevices++; previousPort = port; } } } while ( ports[++nPorts] ); free( ports ); } if ( device >= nDevices ) { errorText_ = "RtApiJack::probeDeviceOpen: device ID is invalid!"; return FAILURE; } } // Count the available ports containing the client name as device // channels. Jack "input ports" equal RtAudio output channels. unsigned int nChannels = 0; unsigned long flag = JackPortIsInput; if ( mode == INPUT ) flag = JackPortIsOutput; ports = jack_get_ports( client, deviceName.c_str(), NULL, flag ); if ( ports ) { while ( ports[ nChannels ] ) nChannels++; free( ports ); } // Compare the jack ports for specified client to the requested number of channels. if ( nChannels < (channels + firstChannel) ) { errorStream_ << "RtApiJack::probeDeviceOpen: requested number of channels (" << channels << ") + offset (" << firstChannel << ") not found for specified device (" << device << ":" << deviceName << ")."; errorText_ = errorStream_.str(); return FAILURE; } // Check the jack server sample rate. unsigned int jackRate = jack_get_sample_rate( client ); if ( sampleRate != jackRate ) { jack_client_close( client ); errorStream_ << "RtApiJack::probeDeviceOpen: the requested sample rate (" << sampleRate << ") is different than the JACK server rate (" << jackRate << ")."; errorText_ = errorStream_.str(); return FAILURE; } stream_.sampleRate = jackRate; // Get the latency of the JACK port. ports = jack_get_ports( client, deviceName.c_str(), NULL, flag ); if ( ports[ firstChannel ] ) stream_.latency[mode] = jack_port_get_latency( jack_port_by_name( client, ports[ firstChannel ] ) ); free( ports ); // The jack server always uses 32-bit floating-point data. stream_.deviceFormat[mode] = RTAUDIO_FLOAT32; stream_.userFormat = format; if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false; else stream_.userInterleaved = true; // Jack always uses non-interleaved buffers. stream_.deviceInterleaved[mode] = false; // Jack always provides host byte-ordered data. stream_.doByteSwap[mode] = false; // Get the buffer size. The buffer size and number of buffers // (periods) is set when the jack server is started. stream_.bufferSize = (int) jack_get_buffer_size( client ); *bufferSize = stream_.bufferSize; stream_.nDeviceChannels[mode] = channels; stream_.nUserChannels[mode] = channels; // Set flags for buffer conversion. stream_.doConvertBuffer[mode] = false; if ( stream_.userFormat != stream_.deviceFormat[mode] ) stream_.doConvertBuffer[mode] = true; if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] && stream_.nUserChannels[mode] > 1 ) stream_.doConvertBuffer[mode] = true; // Allocate our JackHandle structure for the stream. if ( handle == 0 ) { try { handle = new JackHandle; } catch ( std::bad_alloc& ) { errorText_ = "RtApiJack::probeDeviceOpen: error allocating JackHandle memory."; goto error; } if ( pthread_cond_init(&handle->condition, NULL) ) { errorText_ = "RtApiJack::probeDeviceOpen: error initializing pthread condition variable."; goto error; } stream_.apiHandle = (void *) handle; handle->client = client; } handle->deviceName[mode] = deviceName; // Allocate necessary internal buffers. unsigned long bufferBytes; bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); stream_.userBuffer[mode] = (char *) calloc( 1, bufferBytes ); if ( stream_.userBuffer[mode] == NULL ) { errorText_ = "RtApiJack::probeDeviceOpen: error allocating user buffer memory."; goto error; } if ( stream_.doConvertBuffer[mode] ) { bool makeBuffer = true; if ( mode == OUTPUT ) bufferBytes = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); else { // mode == INPUT bufferBytes = stream_.nDeviceChannels[1] * formatBytes( stream_.deviceFormat[1] ); if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) { unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]); if ( bufferBytes < bytesOut ) makeBuffer = false; } } if ( makeBuffer ) { bufferBytes *= *bufferSize; if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); stream_.deviceBuffer = (char *) calloc( 1, bufferBytes ); if ( stream_.deviceBuffer == NULL ) { errorText_ = "RtApiJack::probeDeviceOpen: error allocating device buffer memory."; goto error; } } } // Allocate memory for the Jack ports (channels) identifiers. handle->ports[mode] = (jack_port_t **) malloc ( sizeof (jack_port_t *) * channels ); if ( handle->ports[mode] == NULL ) { errorText_ = "RtApiJack::probeDeviceOpen: error allocating port memory."; goto error; } stream_.device[mode] = device; stream_.channelOffset[mode] = firstChannel; stream_.state = STREAM_STOPPED; stream_.callbackInfo.object = (void *) this; if ( stream_.mode == OUTPUT && mode == INPUT ) // We had already set up the stream for output. stream_.mode = DUPLEX; else { stream_.mode = mode; jack_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo ); jack_set_xrun_callback( handle->client, jackXrun, (void *) &handle ); jack_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo ); } // Register our ports. char label[64]; if ( mode == OUTPUT ) { for ( unsigned int i=0; iports[0][i] = jack_port_register( handle->client, (const char *)label, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ); } } else { for ( unsigned int i=0; iports[1][i] = jack_port_register( handle->client, (const char *)label, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ); } } // Setup the buffer conversion information structure. We don't use // buffers to do channel offsets, so we override that parameter // here. if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 ); return SUCCESS; error: if ( handle ) { pthread_cond_destroy( &handle->condition ); jack_client_close( handle->client ); if ( handle->ports[0] ) free( handle->ports[0] ); if ( handle->ports[1] ) free( handle->ports[1] ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } return FAILURE; } void RtApiJack :: closeStream( void ) { if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiJack::closeStream(): no open stream to close!"; error( RtError::WARNING ); return; } JackHandle *handle = (JackHandle *) stream_.apiHandle; if ( handle ) { if ( stream_.state == STREAM_RUNNING ) jack_deactivate( handle->client ); jack_client_close( handle->client ); } if ( handle ) { if ( handle->ports[0] ) free( handle->ports[0] ); if ( handle->ports[1] ) free( handle->ports[1] ); pthread_cond_destroy( &handle->condition ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } stream_.mode = UNINITIALIZED; stream_.state = STREAM_CLOSED; } void RtApiJack :: startStream( void ) { verifyStream(); if ( stream_.state == STREAM_RUNNING ) { errorText_ = "RtApiJack::startStream(): the stream is already running!"; error( RtError::WARNING ); return; } MUTEX_LOCK(&stream_.mutex); JackHandle *handle = (JackHandle *) stream_.apiHandle; int result = jack_activate( handle->client ); if ( result ) { errorText_ = "RtApiJack::startStream(): unable to activate JACK client!"; goto unlock; } const char **ports; // Get the list of available ports. if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { result = 1; ports = jack_get_ports( handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput); if ( ports == NULL) { errorText_ = "RtApiJack::startStream(): error determining available JACK input ports!"; goto unlock; } // Now make the port connections. Since RtAudio wasn't designed to // allow the user to select particular channels of a device, we'll // just open the first "nChannels" ports with offset. for ( unsigned int i=0; iclient, jack_port_name( handle->ports[0][i] ), ports[ stream_.channelOffset[0] + i ] ); if ( result ) { free( ports ); errorText_ = "RtApiJack::startStream(): error connecting output ports!"; goto unlock; } } free(ports); } if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { result = 1; ports = jack_get_ports( handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput ); if ( ports == NULL) { errorText_ = "RtApiJack::startStream(): error determining available JACK output ports!"; goto unlock; } // Now make the port connections. See note above. for ( unsigned int i=0; iclient, ports[ stream_.channelOffset[1] + i ], jack_port_name( handle->ports[1][i] ) ); if ( result ) { free( ports ); errorText_ = "RtApiJack::startStream(): error connecting input ports!"; goto unlock; } } free(ports); } handle->drainCounter = 0; handle->internalDrain = false; stream_.state = STREAM_RUNNING; unlock: MUTEX_UNLOCK(&stream_.mutex); if ( result == 0 ) return; error( RtError::SYSTEM_ERROR ); } void RtApiJack :: stopStream( void ) { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiJack::stopStream(): the stream is already stopped!"; error( RtError::WARNING ); return; } MUTEX_LOCK( &stream_.mutex ); if ( stream_.state == STREAM_STOPPED ) { MUTEX_UNLOCK( &stream_.mutex ); return; } JackHandle *handle = (JackHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { if ( handle->drainCounter == 0 ) { handle->drainCounter = 2; pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled } } jack_deactivate( handle->client ); stream_.state = STREAM_STOPPED; MUTEX_UNLOCK( &stream_.mutex ); } void RtApiJack :: abortStream( void ) { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiJack::abortStream(): the stream is already stopped!"; error( RtError::WARNING ); return; } JackHandle *handle = (JackHandle *) stream_.apiHandle; handle->drainCounter = 2; stopStream(); } // This function will be called by a spawned thread when the user // callback function signals that the stream should be stopped or // aborted. It is necessary to handle it this way because the // callbackEvent() function must return before the jack_deactivate() // function will return. extern "C" void *jackStopStream( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiJack *object = (RtApiJack *) info->object; object->stopStream(); pthread_exit( NULL ); } bool RtApiJack :: callbackEvent( unsigned long nframes ) { if ( stream_.state == STREAM_STOPPED ) return SUCCESS; if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!"; error( RtError::WARNING ); return FAILURE; } if ( stream_.bufferSize != nframes ) { errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!"; error( RtError::WARNING ); return FAILURE; } CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo; JackHandle *handle = (JackHandle *) stream_.apiHandle; // Check if we were draining the stream and signal is finished. if ( handle->drainCounter > 3 ) { if ( handle->internalDrain == true ) pthread_create( &threadId, NULL, jackStopStream, info ); else pthread_cond_signal( &handle->condition ); return SUCCESS; } MUTEX_LOCK( &stream_.mutex ); // The state might change while waiting on a mutex. if ( stream_.state == STREAM_STOPPED ) { MUTEX_UNLOCK( &stream_.mutex ); return SUCCESS; } // Invoke user callback first, to get fresh output data. if ( handle->drainCounter == 0 ) { RtAudioCallback callback = (RtAudioCallback) info->callback; double streamTime = getStreamTime(); RtAudioStreamStatus status = 0; if ( stream_.mode != INPUT && handle->xrun[0] == true ) { status |= RTAUDIO_OUTPUT_UNDERFLOW; handle->xrun[0] = false; } if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) { status |= RTAUDIO_INPUT_OVERFLOW; handle->xrun[1] = false; } handle->drainCounter = callback( stream_.userBuffer[0], stream_.userBuffer[1], stream_.bufferSize, streamTime, status, info->userData ); if ( handle->drainCounter == 2 ) { MUTEX_UNLOCK( &stream_.mutex ); ThreadHandle id; pthread_create( &id, NULL, jackStopStream, info ); return SUCCESS; } else if ( handle->drainCounter == 1 ) handle->internalDrain = true; } jack_default_audio_sample_t *jackbuffer; unsigned long bufferBytes = nframes * sizeof( jack_default_audio_sample_t ); if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { if ( handle->drainCounter > 1 ) { // write zeros to the output stream for ( unsigned int i=0; iports[0][i], (jack_nframes_t) nframes ); memset( jackbuffer, 0, bufferBytes ); } } else if ( stream_.doConvertBuffer[0] ) { convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] ); for ( unsigned int i=0; iports[0][i], (jack_nframes_t) nframes ); memcpy( jackbuffer, &stream_.deviceBuffer[i*bufferBytes], bufferBytes ); } } else { // no buffer conversion for ( unsigned int i=0; iports[0][i], (jack_nframes_t) nframes ); memcpy( jackbuffer, &stream_.userBuffer[0][i*bufferBytes], bufferBytes ); } } if ( handle->drainCounter ) { handle->drainCounter++; goto unlock; } } if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { if ( stream_.doConvertBuffer[1] ) { for ( unsigned int i=0; iports[1][i], (jack_nframes_t) nframes ); memcpy( &stream_.deviceBuffer[i*bufferBytes], jackbuffer, bufferBytes ); } convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] ); } else { // no buffer conversion for ( unsigned int i=0; iports[1][i], (jack_nframes_t) nframes ); memcpy( &stream_.userBuffer[1][i*bufferBytes], jackbuffer, bufferBytes ); } } } unlock: MUTEX_UNLOCK(&stream_.mutex); RtApi::tickStreamTime(); return SUCCESS; } //******************** End of __UNIX_JACK__ *********************// #endif #if defined(__WINDOWS_ASIO__) // ASIO API on Windows // The ASIO API is designed around a callback scheme, so this // implementation is similar to that used for OS-X CoreAudio and Linux // Jack. The primary constraint with ASIO is that it only allows // access to a single driver at a time. Thus, it is not possible to // have more than one simultaneous RtAudio stream. // // This implementation also requires a number of external ASIO files // and a few global variables. The ASIO callback scheme does not // allow for the passing of user data, so we must create a global // pointer to our callbackInfo structure. // // On unix systems, we make use of a pthread condition variable. // Since there is no equivalent in Windows, I hacked something based // on information found in // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html. #include "asiosys.h" #include "asio.h" #include "iasiothiscallresolver.h" #include "asiodrivers.h" #include AsioDrivers drivers; ASIOCallbacks asioCallbacks; ASIODriverInfo driverInfo; CallbackInfo *asioCallbackInfo; bool asioXRun; struct AsioHandle { int drainCounter; // Tracks callback counts when draining bool internalDrain; // Indicates if stop is initiated from callback or not. ASIOBufferInfo *bufferInfos; HANDLE condition; AsioHandle() :drainCounter(0), internalDrain(false), bufferInfos(0) {} }; // Function declarations (definitions at end of section) static const char* getAsioErrorString( ASIOError result ); void sampleRateChanged( ASIOSampleRate sRate ); long asioMessages( long selector, long value, void* message, double* opt ); RtApiAsio :: RtApiAsio() { // ASIO cannot run on a multi-threaded appartment. You can call // CoInitialize beforehand, but it must be for appartment threading // (in which case, CoInitilialize will return S_FALSE here). coInitialized_ = false; HRESULT hr = CoInitialize( NULL ); if ( FAILED(hr) ) { errorText_ = "RtApiAsio::ASIO requires a single-threaded appartment. Call CoInitializeEx(0,COINIT_APARTMENTTHREADED)"; error( RtError::WARNING ); } coInitialized_ = true; drivers.removeCurrentDriver(); driverInfo.asioVersion = 2; // See note in DirectSound implementation about GetDesktopWindow(). driverInfo.sysRef = GetForegroundWindow(); } RtApiAsio :: ~RtApiAsio() { if ( stream_.state != STREAM_CLOSED ) closeStream(); if ( coInitialized_ ) CoUninitialize(); } unsigned int RtApiAsio :: getDeviceCount( void ) { return (unsigned int) drivers.asioGetNumDev(); } RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device ) { RtAudio::DeviceInfo info; info.probed = false; // Get device ID unsigned int nDevices = getDeviceCount(); if ( nDevices == 0 ) { errorText_ = "RtApiAsio::getDeviceInfo: no devices found!"; error( RtError::INVALID_USE ); } if ( device >= nDevices ) { errorText_ = "RtApiAsio::getDeviceInfo: device ID is invalid!"; error( RtError::INVALID_USE ); } // If a stream is already open, we cannot probe other devices. Thus, use the saved results. if ( stream_.state != STREAM_CLOSED ) { if ( device >= devices_.size() ) { errorText_ = "RtApiAsio::getDeviceInfo: device ID was not present before stream was opened."; error( RtError::WARNING ); return info; } return devices_[ device ]; } char driverName[32]; ASIOError result = drivers.asioGetDriverName( (int) device, driverName, 32 ); if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::getDeviceInfo: unable to get driver name (" << getAsioErrorString( result ) << ")."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } info.name = driverName; if ( !drivers.loadDriver( driverName ) ) { errorStream_ << "RtApiAsio::getDeviceInfo: unable to load driver (" << driverName << ")."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } result = ASIOInit( &driverInfo ); if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ")."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } // Determine the device channel information. long inputChannels, outputChannels; result = ASIOGetChannels( &inputChannels, &outputChannels ); if ( result != ASE_OK ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ")."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } info.outputChannels = outputChannels; info.inputChannels = inputChannels; if ( info.outputChannels > 0 && info.inputChannels > 0 ) info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels; // Determine the supported sample rates. info.sampleRates.clear(); for ( unsigned int i=0; i 0 ) if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true; if ( info.inputChannels > 0 ) if ( getDefaultInputDevice() == device ) info.isDefaultInput = true; info.probed = true; drivers.removeCurrentDriver(); return info; } void bufferSwitch( long index, ASIOBool processNow ) { RtApiAsio *object = (RtApiAsio *) asioCallbackInfo->object; object->callbackEvent( index ); } void RtApiAsio :: saveDeviceInfo( void ) { devices_.clear(); unsigned int nDevices = getDeviceCount(); devices_.resize( nDevices ); for ( unsigned int i=0; isaveDeviceInfo(); if ( !drivers.loadDriver( driverName ) ) { errorStream_ << "RtApiAsio::probeDeviceOpen: unable to load driver (" << driverName << ")."; errorText_ = errorStream_.str(); return FAILURE; } result = ASIOInit( &driverInfo ); if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ")."; errorText_ = errorStream_.str(); return FAILURE; } } // Check the device channel count. long inputChannels, outputChannels; result = ASIOGetChannels( &inputChannels, &outputChannels ); if ( result != ASE_OK ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ")."; errorText_ = errorStream_.str(); return FAILURE; } if ( ( mode == OUTPUT && (channels+firstChannel) > (unsigned int) outputChannels) || ( mode == INPUT && (channels+firstChannel) > (unsigned int) inputChannels) ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested channel count (" << channels << ") + offset (" << firstChannel << ")."; errorText_ = errorStream_.str(); return FAILURE; } stream_.nDeviceChannels[mode] = channels; stream_.nUserChannels[mode] = channels; stream_.channelOffset[mode] = firstChannel; // Verify the sample rate is supported. result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate ); if ( result != ASE_OK ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested sample rate (" << sampleRate << ")."; errorText_ = errorStream_.str(); return FAILURE; } // Get the current sample rate ASIOSampleRate currentRate; result = ASIOGetSampleRate( ¤tRate ); if ( result != ASE_OK ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error getting sample rate."; errorText_ = errorStream_.str(); return FAILURE; } // Set the sample rate only if necessary if ( currentRate != sampleRate ) { result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate ); if ( result != ASE_OK ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error setting sample rate (" << sampleRate << ")."; errorText_ = errorStream_.str(); return FAILURE; } } // Determine the driver data type. ASIOChannelInfo channelInfo; channelInfo.channel = 0; if ( mode == OUTPUT ) channelInfo.isInput = false; else channelInfo.isInput = true; result = ASIOGetChannelInfo( &channelInfo ); if ( result != ASE_OK ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting data format."; errorText_ = errorStream_.str(); return FAILURE; } // Assuming WINDOWS host is always little-endian. stream_.doByteSwap[mode] = false; stream_.userFormat = format; stream_.deviceFormat[mode] = 0; if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB ) { stream_.deviceFormat[mode] = RTAUDIO_SINT16; if ( channelInfo.type == ASIOSTInt16MSB ) stream_.doByteSwap[mode] = true; } else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB ) { stream_.deviceFormat[mode] = RTAUDIO_SINT32; if ( channelInfo.type == ASIOSTInt32MSB ) stream_.doByteSwap[mode] = true; } else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB ) { stream_.deviceFormat[mode] = RTAUDIO_FLOAT32; if ( channelInfo.type == ASIOSTFloat32MSB ) stream_.doByteSwap[mode] = true; } else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB ) { stream_.deviceFormat[mode] = RTAUDIO_FLOAT64; if ( channelInfo.type == ASIOSTFloat64MSB ) stream_.doByteSwap[mode] = true; } if ( stream_.deviceFormat[mode] == 0 ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") data format not supported by RtAudio."; errorText_ = errorStream_.str(); return FAILURE; } // Set the buffer size. For a duplex stream, this will end up // setting the buffer size based on the input constraints, which // should be ok. long minSize, maxSize, preferSize, granularity; result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity ); if ( result != ASE_OK ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting buffer size."; errorText_ = errorStream_.str(); return FAILURE; } if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize; else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize; else if ( granularity == -1 ) { // Make sure bufferSize is a power of two. int log2_of_min_size = 0; int log2_of_max_size = 0; for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) { if ( minSize & ((long)1 << i) ) log2_of_min_size = i; if ( maxSize & ((long)1 << i) ) log2_of_max_size = i; } long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) ); int min_delta_num = log2_of_min_size; for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) { long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) ); if (current_delta < min_delta) { min_delta = current_delta; min_delta_num = i; } } *bufferSize = ( (unsigned int)1 << min_delta_num ); if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize; else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize; } else if ( granularity != 0 ) { // Set to an even multiple of granularity, rounding up. *bufferSize = (*bufferSize + granularity-1) / granularity * granularity; } if ( mode == INPUT && stream_.mode == OUTPUT && stream_.bufferSize != *bufferSize ) { drivers.removeCurrentDriver(); errorText_ = "RtApiAsio::probeDeviceOpen: input/output buffersize discrepancy!"; return FAILURE; } stream_.bufferSize = *bufferSize; stream_.nBuffers = 2; if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false; else stream_.userInterleaved = true; // ASIO always uses non-interleaved buffers. stream_.deviceInterleaved[mode] = false; // Allocate, if necessary, our AsioHandle structure for the stream. AsioHandle *handle = (AsioHandle *) stream_.apiHandle; if ( handle == 0 ) { try { handle = new AsioHandle; } catch ( std::bad_alloc& ) { //if ( handle == NULL ) { drivers.removeCurrentDriver(); errorText_ = "RtApiAsio::probeDeviceOpen: error allocating AsioHandle memory."; return FAILURE; } handle->bufferInfos = 0; // Create a manual-reset event. handle->condition = CreateEvent( NULL, // no security TRUE, // manual-reset FALSE, // non-signaled initially NULL ); // unnamed stream_.apiHandle = (void *) handle; } // Create the ASIO internal buffers. Since RtAudio sets up input // and output separately, we'll have to dispose of previously // created output buffers for a duplex stream. long inputLatency, outputLatency; if ( mode == INPUT && stream_.mode == OUTPUT ) { ASIODisposeBuffers(); if ( handle->bufferInfos ) free( handle->bufferInfos ); } // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure. bool buffersAllocated = false; unsigned int i, nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1]; handle->bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) ); if ( handle->bufferInfos == NULL ) { errorStream_ << "RtApiAsio::probeDeviceOpen: error allocating bufferInfo memory for driver (" << driverName << ")."; errorText_ = errorStream_.str(); goto error; } ASIOBufferInfo *infos; infos = handle->bufferInfos; for ( i=0; iisInput = ASIOFalse; infos->channelNum = i + stream_.channelOffset[0]; infos->buffers[0] = infos->buffers[1] = 0; } for ( i=0; iisInput = ASIOTrue; infos->channelNum = i + stream_.channelOffset[1]; infos->buffers[0] = infos->buffers[1] = 0; } // Set up the ASIO callback structure and create the ASIO data buffers. asioCallbacks.bufferSwitch = &bufferSwitch; asioCallbacks.sampleRateDidChange = &sampleRateChanged; asioCallbacks.asioMessage = &asioMessages; asioCallbacks.bufferSwitchTimeInfo = NULL; result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks ); if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") creating buffers."; errorText_ = errorStream_.str(); goto error; } buffersAllocated = true; // Set flags for buffer conversion. stream_.doConvertBuffer[mode] = false; if ( stream_.userFormat != stream_.deviceFormat[mode] ) stream_.doConvertBuffer[mode] = true; if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] && stream_.nUserChannels[mode] > 1 ) stream_.doConvertBuffer[mode] = true; // Allocate necessary internal buffers unsigned long bufferBytes; bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); stream_.userBuffer[mode] = (char *) calloc( 1, bufferBytes ); if ( stream_.userBuffer[mode] == NULL ) { errorText_ = "RtApiAsio::probeDeviceOpen: error allocating user buffer memory."; goto error; } if ( stream_.doConvertBuffer[mode] ) { bool makeBuffer = true; bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] ); if ( mode == INPUT ) { if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) { unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); if ( bufferBytes <= bytesOut ) makeBuffer = false; } } if ( makeBuffer ) { bufferBytes *= *bufferSize; if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); stream_.deviceBuffer = (char *) calloc( 1, bufferBytes ); if ( stream_.deviceBuffer == NULL ) { errorText_ = "RtApiAsio::probeDeviceOpen: error allocating device buffer memory."; goto error; } } } stream_.sampleRate = sampleRate; stream_.device[mode] = device; stream_.state = STREAM_STOPPED; asioCallbackInfo = &stream_.callbackInfo; stream_.callbackInfo.object = (void *) this; if ( stream_.mode == OUTPUT && mode == INPUT ) // We had already set up an output stream. stream_.mode = DUPLEX; else stream_.mode = mode; // Determine device latencies result = ASIOGetLatencies( &inputLatency, &outputLatency ); if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting latency."; errorText_ = errorStream_.str(); error( RtError::WARNING); // warn but don't fail } else { stream_.latency[0] = outputLatency; stream_.latency[1] = inputLatency; } // Setup the buffer conversion information structure. We don't use // buffers to do channel offsets, so we override that parameter // here. if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 ); return SUCCESS; error: if ( buffersAllocated ) ASIODisposeBuffers(); drivers.removeCurrentDriver(); if ( handle ) { CloseHandle( handle->condition ); if ( handle->bufferInfos ) free( handle->bufferInfos ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } return FAILURE; } void RtApiAsio :: closeStream() { if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiAsio::closeStream(): no open stream to close!"; error( RtError::WARNING ); return; } if ( stream_.state == STREAM_RUNNING ) { stream_.state = STREAM_STOPPED; ASIOStop(); } ASIODisposeBuffers(); drivers.removeCurrentDriver(); AsioHandle *handle = (AsioHandle *) stream_.apiHandle; if ( handle ) { CloseHandle( handle->condition ); if ( handle->bufferInfos ) free( handle->bufferInfos ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } stream_.mode = UNINITIALIZED; stream_.state = STREAM_CLOSED; } bool stopThreadCalled = false; void RtApiAsio :: startStream() { verifyStream(); if ( stream_.state == STREAM_RUNNING ) { errorText_ = "RtApiAsio::startStream(): the stream is already running!"; error( RtError::WARNING ); return; } //MUTEX_LOCK( &stream_.mutex ); AsioHandle *handle = (AsioHandle *) stream_.apiHandle; ASIOError result = ASIOStart(); if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::startStream: error (" << getAsioErrorString( result ) << ") starting device."; errorText_ = errorStream_.str(); goto unlock; } handle->drainCounter = 0; handle->internalDrain = false; ResetEvent( handle->condition ); stream_.state = STREAM_RUNNING; asioXRun = false; unlock: //MUTEX_UNLOCK( &stream_.mutex ); stopThreadCalled = false; if ( result == ASE_OK ) return; error( RtError::SYSTEM_ERROR ); } void RtApiAsio :: stopStream() { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiAsio::stopStream(): the stream is already stopped!"; error( RtError::WARNING ); return; } /* MUTEX_LOCK( &stream_.mutex ); if ( stream_.state == STREAM_STOPPED ) { MUTEX_UNLOCK( &stream_.mutex ); return; } */ AsioHandle *handle = (AsioHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { if ( handle->drainCounter == 0 ) { handle->drainCounter = 2; // MUTEX_UNLOCK( &stream_.mutex ); WaitForSingleObject( handle->condition, INFINITE ); // block until signaled //ResetEvent( handle->condition ); // MUTEX_LOCK( &stream_.mutex ); } } stream_.state = STREAM_STOPPED; ASIOError result = ASIOStop(); if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::stopStream: error (" << getAsioErrorString( result ) << ") stopping device."; errorText_ = errorStream_.str(); } // MUTEX_UNLOCK( &stream_.mutex ); if ( result == ASE_OK ) return; error( RtError::SYSTEM_ERROR ); } void RtApiAsio :: abortStream() { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiAsio::abortStream(): the stream is already stopped!"; error( RtError::WARNING ); return; } // The following lines were commented-out because some behavior was // noted where the device buffers need to be zeroed to avoid // continuing sound, even when the device buffers are completely // disposed. So now, calling abort is the same as calling stop. // AsioHandle *handle = (AsioHandle *) stream_.apiHandle; // handle->drainCounter = 2; stopStream(); } // This function will be called by a spawned thread when the user // callback function signals that the stream should be stopped or // aborted. It is necessary to handle it this way because the // callbackEvent() function must return before the ASIOStop() // function will return. extern "C" unsigned __stdcall asioStopStream( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiAsio *object = (RtApiAsio *) info->object; object->stopStream(); _endthreadex( 0 ); return 0; } bool RtApiAsio :: callbackEvent( long bufferIndex ) { if ( stream_.state == STREAM_STOPPED ) return SUCCESS; if ( stopThreadCalled ) return SUCCESS; if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiAsio::callbackEvent(): the stream is closed ... this shouldn't happen!"; error( RtError::WARNING ); return FAILURE; } CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo; AsioHandle *handle = (AsioHandle *) stream_.apiHandle; // Check if we were draining the stream and signal if finished. if ( handle->drainCounter > 3 ) { if ( handle->internalDrain == false ) SetEvent( handle->condition ); else { // spawn a thread to stop the stream unsigned threadId; stopThreadCalled = true; stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &asioStopStream, &stream_.callbackInfo, 0, &threadId ); } return SUCCESS; } /*MUTEX_LOCK( &stream_.mutex ); // The state might change while waiting on a mutex. if ( stream_.state == STREAM_STOPPED ) goto unlock; */ // Invoke user callback to get fresh output data UNLESS we are // draining stream. if ( handle->drainCounter == 0 ) { RtAudioCallback callback = (RtAudioCallback) info->callback; double streamTime = getStreamTime(); RtAudioStreamStatus status = 0; if ( stream_.mode != INPUT && asioXRun == true ) { status |= RTAUDIO_OUTPUT_UNDERFLOW; asioXRun = false; } if ( stream_.mode != OUTPUT && asioXRun == true ) { status |= RTAUDIO_INPUT_OVERFLOW; asioXRun = false; } handle->drainCounter = callback( stream_.userBuffer[0], stream_.userBuffer[1], stream_.bufferSize, streamTime, status, info->userData ); if ( handle->drainCounter == 2 ) { // MUTEX_UNLOCK( &stream_.mutex ); // abortStream(); unsigned threadId; stopThreadCalled = true; stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &asioStopStream, &stream_.callbackInfo, 0, &threadId ); return SUCCESS; } else if ( handle->drainCounter == 1 ) handle->internalDrain = true; } unsigned int nChannels, bufferBytes, i, j; nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1]; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { bufferBytes = stream_.bufferSize * formatBytes( stream_.deviceFormat[0] ); if ( handle->drainCounter > 1 ) { // write zeros to the output stream for ( i=0, j=0; ibufferInfos[i].isInput != ASIOTrue ) memset( handle->bufferInfos[i].buffers[bufferIndex], 0, bufferBytes ); } } else if ( stream_.doConvertBuffer[0] ) { convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] ); if ( stream_.doByteSwap[0] ) byteSwapBuffer( stream_.deviceBuffer, stream_.bufferSize * stream_.nDeviceChannels[0], stream_.deviceFormat[0] ); for ( i=0, j=0; ibufferInfos[i].isInput != ASIOTrue ) memcpy( handle->bufferInfos[i].buffers[bufferIndex], &stream_.deviceBuffer[j++*bufferBytes], bufferBytes ); } } else { if ( stream_.doByteSwap[0] ) byteSwapBuffer( stream_.userBuffer[0], stream_.bufferSize * stream_.nUserChannels[0], stream_.userFormat ); for ( i=0, j=0; ibufferInfos[i].isInput != ASIOTrue ) memcpy( handle->bufferInfos[i].buffers[bufferIndex], &stream_.userBuffer[0][bufferBytes*j++], bufferBytes ); } } if ( handle->drainCounter ) { handle->drainCounter++; goto unlock; } } if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { bufferBytes = stream_.bufferSize * formatBytes(stream_.deviceFormat[1]); if (stream_.doConvertBuffer[1]) { // Always interleave ASIO input data. for ( i=0, j=0; ibufferInfos[i].isInput == ASIOTrue ) memcpy( &stream_.deviceBuffer[j++*bufferBytes], handle->bufferInfos[i].buffers[bufferIndex], bufferBytes ); } if ( stream_.doByteSwap[1] ) byteSwapBuffer( stream_.deviceBuffer, stream_.bufferSize * stream_.nDeviceChannels[1], stream_.deviceFormat[1] ); convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] ); } else { for ( i=0, j=0; ibufferInfos[i].isInput == ASIOTrue ) { memcpy( &stream_.userBuffer[1][bufferBytes*j++], handle->bufferInfos[i].buffers[bufferIndex], bufferBytes ); } } if ( stream_.doByteSwap[1] ) byteSwapBuffer( stream_.userBuffer[1], stream_.bufferSize * stream_.nUserChannels[1], stream_.userFormat ); } } unlock: // The following call was suggested by Malte Clasen. While the API // documentation indicates it should not be required, some device // drivers apparently do not function correctly without it. ASIOOutputReady(); // MUTEX_UNLOCK( &stream_.mutex ); RtApi::tickStreamTime(); return SUCCESS; } void sampleRateChanged( ASIOSampleRate sRate ) { // The ASIO documentation says that this usually only happens during // external sync. Audio processing is not stopped by the driver, // actual sample rate might not have even changed, maybe only the // sample rate status of an AES/EBU or S/PDIF digital input at the // audio device. RtApi *object = (RtApi *) asioCallbackInfo->object; try { object->stopStream(); } catch ( RtError &exception ) { std::cerr << "\nRtApiAsio: sampleRateChanged() error (" << exception.getMessage() << ")!\n" << std::endl; return; } std::cerr << "\nRtApiAsio: driver reports sample rate changed to " << sRate << " ... stream stopped!!!\n" << std::endl; } long asioMessages( long selector, long value, void* message, double* opt ) { long ret = 0; switch( selector ) { case kAsioSelectorSupported: if ( value == kAsioResetRequest || value == kAsioEngineVersion || value == kAsioResyncRequest || value == kAsioLatenciesChanged // The following three were added for ASIO 2.0, you don't // necessarily have to support them. || value == kAsioSupportsTimeInfo || value == kAsioSupportsTimeCode || value == kAsioSupportsInputMonitor) ret = 1L; break; case kAsioResetRequest: // Defer the task and perform the reset of the driver during the // next "safe" situation. You cannot reset the driver right now, // as this code is called from the driver. Reset the driver is // done by completely destruct is. I.e. ASIOStop(), // ASIODisposeBuffers(), Destruction Afterwards you initialize the // driver again. std::cerr << "\nRtApiAsio: driver reset requested!!!" << std::endl; ret = 1L; break; case kAsioResyncRequest: // This informs the application that the driver encountered some // non-fatal data loss. It is used for synchronization purposes // of different media. Added mainly to work around the Win16Mutex // problems in Windows 95/98 with the Windows Multimedia system, // which could lose data because the Mutex was held too long by // another thread. However a driver can issue it in other // situations, too. // std::cerr << "\nRtApiAsio: driver resync requested!!!" << std::endl; asioXRun = true; ret = 1L; break; case kAsioLatenciesChanged: // This will inform the host application that the drivers were // latencies changed. Beware, it this does not mean that the // buffer sizes have changed! You might need to update internal // delay data. std::cerr << "\nRtApiAsio: driver latency may have changed!!!" << std::endl; ret = 1L; break; case kAsioEngineVersion: // Return the supported ASIO version of the host application. If // a host application does not implement this selector, ASIO 1.0 // is assumed by the driver. ret = 2L; break; case kAsioSupportsTimeInfo: // Informs the driver whether the // asioCallbacks.bufferSwitchTimeInfo() callback is supported. // For compatibility with ASIO 1.0 drivers the host application // should always support the "old" bufferSwitch method, too. ret = 0; break; case kAsioSupportsTimeCode: // Informs the driver whether application is interested in time // code info. If an application does not need to know about time // code, the driver has less work to do. ret = 0; break; } return ret; } static const char* getAsioErrorString( ASIOError result ) { struct Messages { ASIOError value; const char*message; }; static Messages m[] = { { ASE_NotPresent, "Hardware input or output is not present or available." }, { ASE_HWMalfunction, "Hardware is malfunctioning." }, { ASE_InvalidParameter, "Invalid input parameter." }, { ASE_InvalidMode, "Invalid mode." }, { ASE_SPNotAdvancing, "Sample position not advancing." }, { ASE_NoClock, "Sample clock or rate cannot be determined or is not present." }, { ASE_NoMemory, "Not enough memory to complete the request." } }; for ( unsigned int i = 0; i < sizeof(m)/sizeof(m[0]); ++i ) if ( m[i].value == result ) return m[i].message; return "Unknown error."; } //******************** End of __WINDOWS_ASIO__ *********************// #endif #if defined(__WINDOWS_DS__) // Windows DirectSound API // Modified by Robin Davies, October 2005 // - Improvements to DirectX pointer chasing. // - Bug fix for non-power-of-two Asio granularity used by Edirol PCR-A30. // - Auto-call CoInitialize for DSOUND and ASIO platforms. // Various revisions for RtAudio 4.0 by Gary Scavone, April 2007 // Changed device query structure for RtAudio 4.0.7, January 2010 #include #include #include #if defined(__MINGW32__) // missing from latest mingw winapi #define WAVE_FORMAT_96M08 0x00010000 /* 96 kHz, Mono, 8-bit */ #define WAVE_FORMAT_96S08 0x00020000 /* 96 kHz, Stereo, 8-bit */ #define WAVE_FORMAT_96M16 0x00040000 /* 96 kHz, Mono, 16-bit */ #define WAVE_FORMAT_96S16 0x00080000 /* 96 kHz, Stereo, 16-bit */ #ifdef NULL #undef NULL #endif #define NULL 0 #endif #define MINIMUM_DEVICE_BUFFER_SIZE 32768 #ifdef _MSC_VER // if Microsoft Visual C++ #pragma comment( lib, "winmm.lib" ) // then, auto-link winmm.lib. Otherwise, it has to be added manually. #endif static inline DWORD dsPointerBetween( DWORD pointer, DWORD laterPointer, DWORD earlierPointer, DWORD bufferSize ) { if ( pointer > bufferSize ) pointer -= bufferSize; if ( laterPointer < earlierPointer ) laterPointer += bufferSize; if ( pointer < earlierPointer ) pointer += bufferSize; return pointer >= earlierPointer && pointer < laterPointer; } // A structure to hold various information related to the DirectSound // API implementation. struct DsHandle { unsigned int drainCounter; // Tracks callback counts when draining bool internalDrain; // Indicates if stop is initiated from callback or not. void *id[2]; void *buffer[2]; bool xrun[2]; UINT bufferPointer[2]; DWORD dsBufferSize[2]; DWORD dsPointerLeadTime[2]; // the number of bytes ahead of the safe pointer to lead by. HANDLE condition; DsHandle() :drainCounter(0), internalDrain(false) { id[0] = 0; id[1] = 0; buffer[0] = 0; buffer[1] = 0; xrun[0] = false; xrun[1] = false; bufferPointer[0] = 0; bufferPointer[1] = 0; } }; // Declarations for utility functions, callbacks, and structures // specific to the DirectSound implementation. static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid, LPCTSTR description, LPCTSTR module, LPVOID lpContext ); static const char* getErrorString( int code ); extern "C" unsigned __stdcall callbackHandler( void *ptr ); struct DsDevice { LPGUID id[2]; bool validId[2]; bool found; std::string name; DsDevice() : found(false) { validId[0] = false; validId[1] = false; } }; std::vector< DsDevice > dsDevices; RtApiDs :: RtApiDs() { // Dsound will run both-threaded. If CoInitialize fails, then just // accept whatever the mainline chose for a threading model. coInitialized_ = false; HRESULT hr = CoInitialize( NULL ); if ( !FAILED( hr ) ) coInitialized_ = true; } RtApiDs :: ~RtApiDs() { if ( coInitialized_ ) CoUninitialize(); // balanced call. if ( stream_.state != STREAM_CLOSED ) closeStream(); } // The DirectSound default output is always the first device. unsigned int RtApiDs :: getDefaultOutputDevice( void ) { return 0; } // The DirectSound default input is always the first input device, // which is the first capture device enumerated. unsigned int RtApiDs :: getDefaultInputDevice( void ) { return 0; } unsigned int RtApiDs :: getDeviceCount( void ) { // Set query flag for previously found devices to false, so that we // can check for any devices that have disappeared. for ( unsigned int i=0; i indices; for ( unsigned int i=0; i= dsDevices.size() ) { errorText_ = "RtApiDs::getDeviceInfo: device ID is invalid!"; error( RtError::INVALID_USE ); } HRESULT result; if ( dsDevices[ device ].validId[0] == false ) goto probeInput; LPDIRECTSOUND output; DSCAPS outCaps; result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); error( RtError::WARNING ); goto probeInput; } outCaps.dwSize = sizeof( outCaps ); result = output->GetCaps( &outCaps ); if ( FAILED( result ) ) { output->Release(); errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting capabilities!"; errorText_ = errorStream_.str(); error( RtError::WARNING ); goto probeInput; } // Get output channel information. info.outputChannels = ( outCaps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1; // Get sample rate information. info.sampleRates.clear(); for ( unsigned int k=0; k= (unsigned int) outCaps.dwMinSecondarySampleRate && SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate ) info.sampleRates.push_back( SAMPLE_RATES[k] ); } // Get format information. if ( outCaps.dwFlags & DSCAPS_PRIMARY16BIT ) info.nativeFormats |= RTAUDIO_SINT16; if ( outCaps.dwFlags & DSCAPS_PRIMARY8BIT ) info.nativeFormats |= RTAUDIO_SINT8; output->Release(); if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true; if ( dsDevices[ device ].validId[1] == false ) { info.name = dsDevices[ device ].name; info.probed = true; return info; } probeInput: LPDIRECTSOUNDCAPTURE input; result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } DSCCAPS inCaps; inCaps.dwSize = sizeof( inCaps ); result = input->GetCaps( &inCaps ); if ( FAILED( result ) ) { input->Release(); errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting object capabilities (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } // Get input channel information. info.inputChannels = inCaps.dwChannels; // Get sample rate and format information. std::vector rates; if ( inCaps.dwChannels >= 2 ) { if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) info.nativeFormats |= RTAUDIO_SINT16; if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) info.nativeFormats |= RTAUDIO_SINT16; if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) info.nativeFormats |= RTAUDIO_SINT16; if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) info.nativeFormats |= RTAUDIO_SINT16; if ( inCaps.dwFormats & WAVE_FORMAT_1S08 ) info.nativeFormats |= RTAUDIO_SINT8; if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) info.nativeFormats |= RTAUDIO_SINT8; if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) info.nativeFormats |= RTAUDIO_SINT8; if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) info.nativeFormats |= RTAUDIO_SINT8; if ( info.nativeFormats & RTAUDIO_SINT16 ) { if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) rates.push_back( 11025 ); if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) rates.push_back( 22050 ); if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) rates.push_back( 44100 ); if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) rates.push_back( 96000 ); } else if ( info.nativeFormats & RTAUDIO_SINT8 ) { if ( inCaps.dwFormats & WAVE_FORMAT_1S08 ) rates.push_back( 11025 ); if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) rates.push_back( 22050 ); if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) rates.push_back( 44100 ); if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) rates.push_back( 96000 ); } } else if ( inCaps.dwChannels == 1 ) { if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) info.nativeFormats |= RTAUDIO_SINT16; if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) info.nativeFormats |= RTAUDIO_SINT16; if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) info.nativeFormats |= RTAUDIO_SINT16; if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) info.nativeFormats |= RTAUDIO_SINT16; if ( inCaps.dwFormats & WAVE_FORMAT_1M08 ) info.nativeFormats |= RTAUDIO_SINT8; if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) info.nativeFormats |= RTAUDIO_SINT8; if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) info.nativeFormats |= RTAUDIO_SINT8; if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) info.nativeFormats |= RTAUDIO_SINT8; if ( info.nativeFormats & RTAUDIO_SINT16 ) { if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) rates.push_back( 11025 ); if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) rates.push_back( 22050 ); if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) rates.push_back( 44100 ); if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) rates.push_back( 96000 ); } else if ( info.nativeFormats & RTAUDIO_SINT8 ) { if ( inCaps.dwFormats & WAVE_FORMAT_1M08 ) rates.push_back( 11025 ); if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) rates.push_back( 22050 ); if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) rates.push_back( 44100 ); if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) rates.push_back( 96000 ); } } else info.inputChannels = 0; // technically, this would be an error input->Release(); if ( info.inputChannels == 0 ) return info; // Copy the supported rates to the info structure but avoid duplication. bool found; for ( unsigned int i=0; i 0 && info.inputChannels > 0 ) info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels; if ( device == 0 ) info.isDefaultInput = true; // Copy name and return. info.name = dsDevices[ device ].name; info.probed = true; return info; } bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options, const std::string &deviceName ) { if ( channels + firstChannel > 2 ) { errorText_ = "RtApiDs::probeDeviceOpen: DirectSound does not support more than 2 channels per device."; return FAILURE; } unsigned int nDevices = dsDevices.size(); if ( nDevices == 0 ) { // This should not happen because a check is made before this function is called. errorText_ = "RtApiDs::probeDeviceOpen: no devices found!"; return FAILURE; } if ( device >= nDevices ) { // This should not happen because a check is made before this function is called. errorText_ = "RtApiDs::probeDeviceOpen: device ID is invalid!"; return FAILURE; } if ( mode == OUTPUT ) { if ( dsDevices[ device ].validId[0] == false ) { errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support output!"; errorText_ = errorStream_.str(); return FAILURE; } } else { // mode == INPUT if ( dsDevices[ device ].validId[1] == false ) { errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support input!"; errorText_ = errorStream_.str(); return FAILURE; } } // According to a note in PortAudio, using GetDesktopWindow() // instead of GetForegroundWindow() is supposed to avoid problems // that occur when the application's window is not the foreground // window. Also, if the application window closes before the // DirectSound buffer, DirectSound can crash. In the past, I had // problems when using GetDesktopWindow() but it seems fine now // (January 2010). I'll leave it commented here. // HWND hWnd = GetForegroundWindow(); HWND hWnd = GetDesktopWindow(); // Check the numberOfBuffers parameter and limit the lowest value to // two. This is a judgement call and a value of two is probably too // low for capture, but it should work for playback. int nBuffers = 0; if ( options ) nBuffers = options->numberOfBuffers; if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) nBuffers = 2; if ( nBuffers < 2 ) nBuffers = 3; // Check the lower range of the user-specified buffer size and set // (arbitrarily) to a lower bound of 32. if ( *bufferSize < 32 ) *bufferSize = 32; // Create the wave format structure. The data format setting will // be determined later. WAVEFORMATEX waveFormat; ZeroMemory( &waveFormat, sizeof(WAVEFORMATEX) ); waveFormat.wFormatTag = WAVE_FORMAT_PCM; waveFormat.nChannels = channels + firstChannel; waveFormat.nSamplesPerSec = (unsigned long) sampleRate; // Determine the device buffer size. By default, we'll use the value // defined above (32K), but we will grow it to make allowances for // very large software buffer sizes. DWORD dsBufferSize = MINIMUM_DEVICE_BUFFER_SIZE;; DWORD dsPointerLeadTime = 0; void *ohandle = 0, *bhandle = 0; HRESULT result; if ( mode == OUTPUT ) { LPDIRECTSOUND output; result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } DSCAPS outCaps; outCaps.dwSize = sizeof( outCaps ); result = output->GetCaps( &outCaps ); if ( FAILED( result ) ) { output->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting capabilities (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } // Check channel information. if ( channels + firstChannel == 2 && !( outCaps.dwFlags & DSCAPS_PRIMARYSTEREO ) ) { errorStream_ << "RtApiDs::getDeviceInfo: the output device (" << dsDevices[ device ].name << ") does not support stereo playback."; errorText_ = errorStream_.str(); return FAILURE; } // Check format information. Use 16-bit format unless not // supported or user requests 8-bit. if ( outCaps.dwFlags & DSCAPS_PRIMARY16BIT && !( format == RTAUDIO_SINT8 && outCaps.dwFlags & DSCAPS_PRIMARY8BIT ) ) { waveFormat.wBitsPerSample = 16; stream_.deviceFormat[mode] = RTAUDIO_SINT16; } else { waveFormat.wBitsPerSample = 8; stream_.deviceFormat[mode] = RTAUDIO_SINT8; } stream_.userFormat = format; // Update wave format structure and buffer information. waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8; waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels; // If the user wants an even bigger buffer, increase the device buffer size accordingly. while ( dsPointerLeadTime * 2U > dsBufferSize ) dsBufferSize *= 2; // Set cooperative level to DSSCL_EXCLUSIVE ... sound stops when window focus changes. // result = output->SetCooperativeLevel( hWnd, DSSCL_EXCLUSIVE ); // Set cooperative level to DSSCL_PRIORITY ... sound remains when window focus changes. result = output->SetCooperativeLevel( hWnd, DSSCL_PRIORITY ); if ( FAILED( result ) ) { output->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting cooperative level (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } // Even though we will write to the secondary buffer, we need to // access the primary buffer to set the correct output format // (since the default is 8-bit, 22 kHz!). Setup the DS primary // buffer description. DSBUFFERDESC bufferDescription; ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) ); bufferDescription.dwSize = sizeof( DSBUFFERDESC ); bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER; // Obtain the primary buffer LPDIRECTSOUNDBUFFER buffer; result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL ); if ( FAILED( result ) ) { output->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") accessing primary buffer (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } // Set the primary DS buffer sound format. result = buffer->SetFormat( &waveFormat ); if ( FAILED( result ) ) { output->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting primary buffer format (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } // Setup the secondary DS buffer description. ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) ); bufferDescription.dwSize = sizeof( DSBUFFERDESC ); bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCHARDWARE ); // Force hardware mixing bufferDescription.dwBufferBytes = dsBufferSize; bufferDescription.lpwfxFormat = &waveFormat; // Try to create the secondary DS buffer. If that doesn't work, // try to use software mixing. Otherwise, there's a problem. result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL ); if ( FAILED( result ) ) { bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE ); // Force software mixing result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL ); if ( FAILED( result ) ) { output->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating secondary buffer (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } } // Get the buffer size ... might be different from what we specified. DSBCAPS dsbcaps; dsbcaps.dwSize = sizeof( DSBCAPS ); result = buffer->GetCaps( &dsbcaps ); if ( FAILED( result ) ) { output->Release(); buffer->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } dsBufferSize = dsbcaps.dwBufferBytes; // Lock the DS buffer LPVOID audioPtr; DWORD dataLen; result = buffer->Lock( 0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0 ); if ( FAILED( result ) ) { output->Release(); buffer->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking buffer (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } // Zero the DS buffer ZeroMemory( audioPtr, dataLen ); // Unlock the DS buffer result = buffer->Unlock( audioPtr, dataLen, NULL, 0 ); if ( FAILED( result ) ) { output->Release(); buffer->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking buffer (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } ohandle = (void *) output; bhandle = (void *) buffer; } if ( mode == INPUT ) { LPDIRECTSOUNDCAPTURE input; result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } DSCCAPS inCaps; inCaps.dwSize = sizeof( inCaps ); result = input->GetCaps( &inCaps ); if ( FAILED( result ) ) { input->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting input capabilities (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } // Check channel information. if ( inCaps.dwChannels < channels + firstChannel ) { errorText_ = "RtApiDs::getDeviceInfo: the input device does not support requested input channels."; return FAILURE; } // Check format information. Use 16-bit format unless user // requests 8-bit. DWORD deviceFormats; if ( channels + firstChannel == 2 ) { deviceFormats = WAVE_FORMAT_1S08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_96S08; if ( format == RTAUDIO_SINT8 && inCaps.dwFormats & deviceFormats ) { waveFormat.wBitsPerSample = 8; stream_.deviceFormat[mode] = RTAUDIO_SINT8; } else { // assume 16-bit is supported waveFormat.wBitsPerSample = 16; stream_.deviceFormat[mode] = RTAUDIO_SINT16; } } else { // channel == 1 deviceFormats = WAVE_FORMAT_1M08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_4M08 | WAVE_FORMAT_96M08; if ( format == RTAUDIO_SINT8 && inCaps.dwFormats & deviceFormats ) { waveFormat.wBitsPerSample = 8; stream_.deviceFormat[mode] = RTAUDIO_SINT8; } else { // assume 16-bit is supported waveFormat.wBitsPerSample = 16; stream_.deviceFormat[mode] = RTAUDIO_SINT16; } } stream_.userFormat = format; // Update wave format structure and buffer information. waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8; waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels; // If the user wants an even bigger buffer, increase the device buffer size accordingly. while ( dsPointerLeadTime * 2U > dsBufferSize ) dsBufferSize *= 2; // Setup the secondary DS buffer description. DSCBUFFERDESC bufferDescription; ZeroMemory( &bufferDescription, sizeof( DSCBUFFERDESC ) ); bufferDescription.dwSize = sizeof( DSCBUFFERDESC ); bufferDescription.dwFlags = 0; bufferDescription.dwReserved = 0; bufferDescription.dwBufferBytes = dsBufferSize; bufferDescription.lpwfxFormat = &waveFormat; // Create the capture buffer. LPDIRECTSOUNDCAPTUREBUFFER buffer; result = input->CreateCaptureBuffer( &bufferDescription, &buffer, NULL ); if ( FAILED( result ) ) { input->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating input buffer (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } // Get the buffer size ... might be different from what we specified. DSCBCAPS dscbcaps; dscbcaps.dwSize = sizeof( DSCBCAPS ); result = buffer->GetCaps( &dscbcaps ); if ( FAILED( result ) ) { input->Release(); buffer->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } dsBufferSize = dscbcaps.dwBufferBytes; // NOTE: We could have a problem here if this is a duplex stream // and the play and capture hardware buffer sizes are different // (I'm actually not sure if that is a problem or not). // Currently, we are not verifying that. // Lock the capture buffer LPVOID audioPtr; DWORD dataLen; result = buffer->Lock( 0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0 ); if ( FAILED( result ) ) { input->Release(); buffer->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking input buffer (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } // Zero the buffer ZeroMemory( audioPtr, dataLen ); // Unlock the buffer result = buffer->Unlock( audioPtr, dataLen, NULL, 0 ); if ( FAILED( result ) ) { input->Release(); buffer->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking input buffer (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } ohandle = (void *) input; bhandle = (void *) buffer; } // Set various stream parameters DsHandle *handle = 0; stream_.nDeviceChannels[mode] = channels + firstChannel; stream_.nUserChannels[mode] = channels; stream_.bufferSize = *bufferSize; stream_.channelOffset[mode] = firstChannel; stream_.deviceInterleaved[mode] = true; if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false; else stream_.userInterleaved = true; // Set flag for buffer conversion stream_.doConvertBuffer[mode] = false; if (stream_.nUserChannels[mode] != stream_.nDeviceChannels[mode]) stream_.doConvertBuffer[mode] = true; if (stream_.userFormat != stream_.deviceFormat[mode]) stream_.doConvertBuffer[mode] = true; if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] && stream_.nUserChannels[mode] > 1 ) stream_.doConvertBuffer[mode] = true; // Allocate necessary internal buffers long bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); stream_.userBuffer[mode] = (char *) calloc( 1, bufferBytes ); if ( stream_.userBuffer[mode] == NULL ) { errorText_ = "RtApiDs::probeDeviceOpen: error allocating user buffer memory."; goto error; } if ( stream_.doConvertBuffer[mode] ) { bool makeBuffer = true; bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] ); if ( mode == INPUT ) { if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) { unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); if ( bufferBytes <= (long) bytesOut ) makeBuffer = false; } } if ( makeBuffer ) { bufferBytes *= *bufferSize; if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); stream_.deviceBuffer = (char *) calloc( 1, bufferBytes ); if ( stream_.deviceBuffer == NULL ) { errorText_ = "RtApiDs::probeDeviceOpen: error allocating device buffer memory."; goto error; } } } // Allocate our DsHandle structures for the stream. if ( stream_.apiHandle == 0 ) { try { handle = new DsHandle; } catch ( std::bad_alloc& ) { errorText_ = "RtApiDs::probeDeviceOpen: error allocating AsioHandle memory."; goto error; } // Create a manual-reset event. handle->condition = CreateEvent( NULL, // no security TRUE, // manual-reset FALSE, // non-signaled initially NULL ); // unnamed stream_.apiHandle = (void *) handle; } else handle = (DsHandle *) stream_.apiHandle; handle->id[mode] = ohandle; handle->buffer[mode] = bhandle; handle->dsBufferSize[mode] = dsBufferSize; handle->dsPointerLeadTime[mode] = dsPointerLeadTime; stream_.device[mode] = device; stream_.state = STREAM_STOPPED; if ( stream_.mode == OUTPUT && mode == INPUT ) // We had already set up an output stream. stream_.mode = DUPLEX; else stream_.mode = mode; stream_.nBuffers = nBuffers; stream_.sampleRate = sampleRate; // Setup the buffer conversion information structure. if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel ); // Setup the callback thread. if ( stream_.callbackInfo.isRunning == false ) { unsigned threadId; stream_.callbackInfo.isRunning = true; stream_.callbackInfo.object = (void *) this; stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &callbackHandler, &stream_.callbackInfo, 0, &threadId ); if ( stream_.callbackInfo.thread == 0 ) { errorText_ = "RtApiDs::probeDeviceOpen: error creating callback thread!"; goto error; } // Boost DS thread priority SetThreadPriority( (HANDLE) stream_.callbackInfo.thread, THREAD_PRIORITY_HIGHEST ); } return SUCCESS; error: if ( handle ) { if ( handle->buffer[0] ) { // the object pointer can be NULL and valid LPDIRECTSOUND object = (LPDIRECTSOUND) handle->id[0]; LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0]; if ( buffer ) buffer->Release(); object->Release(); } if ( handle->buffer[1] ) { LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handle->id[1]; LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1]; if ( buffer ) buffer->Release(); object->Release(); } CloseHandle( handle->condition ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } return FAILURE; } void RtApiDs :: closeStream() { if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiDs::closeStream(): no open stream to close!"; error( RtError::WARNING ); return; } // Stop the callback thread. stream_.callbackInfo.isRunning = false; WaitForSingleObject( (HANDLE) stream_.callbackInfo.thread, INFINITE ); CloseHandle( (HANDLE) stream_.callbackInfo.thread ); DsHandle *handle = (DsHandle *) stream_.apiHandle; if ( handle ) { if ( handle->buffer[0] ) { // the object pointer can be NULL and valid LPDIRECTSOUND object = (LPDIRECTSOUND) handle->id[0]; LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0]; if ( buffer ) { buffer->Stop(); buffer->Release(); } object->Release(); } if ( handle->buffer[1] ) { LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handle->id[1]; LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1]; if ( buffer ) { buffer->Stop(); buffer->Release(); } object->Release(); } CloseHandle( handle->condition ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } stream_.mode = UNINITIALIZED; stream_.state = STREAM_CLOSED; } void RtApiDs :: startStream() { verifyStream(); if ( stream_.state == STREAM_RUNNING ) { errorText_ = "RtApiDs::startStream(): the stream is already running!"; error( RtError::WARNING ); return; } //MUTEX_LOCK( &stream_.mutex ); DsHandle *handle = (DsHandle *) stream_.apiHandle; // Increase scheduler frequency on lesser windows (a side-effect of // increasing timer accuracy). On greater windows (Win2K or later), // this is already in effect. timeBeginPeriod( 1 ); buffersRolling = false; duplexPrerollBytes = 0; if ( stream_.mode == DUPLEX ) { // 0.5 seconds of silence in DUPLEX mode while the devices spin up and synchronize. duplexPrerollBytes = (int) ( 0.5 * stream_.sampleRate * formatBytes( stream_.deviceFormat[1] ) * stream_.nDeviceChannels[1] ); } HRESULT result = 0; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0]; result = buffer->Play( 0, 0, DSBPLAY_LOOPING ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::startStream: error (" << getErrorString( result ) << ") starting output buffer!"; errorText_ = errorStream_.str(); goto unlock; } } if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1]; result = buffer->Start( DSCBSTART_LOOPING ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::startStream: error (" << getErrorString( result ) << ") starting input buffer!"; errorText_ = errorStream_.str(); goto unlock; } } handle->drainCounter = 0; handle->internalDrain = false; ResetEvent( handle->condition ); stream_.state = STREAM_RUNNING; unlock: // MUTEX_UNLOCK( &stream_.mutex ); if ( FAILED( result ) ) error( RtError::SYSTEM_ERROR ); } void RtApiDs :: stopStream() { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiDs::stopStream(): the stream is already stopped!"; error( RtError::WARNING ); return; } /* MUTEX_LOCK( &stream_.mutex ); if ( stream_.state == STREAM_STOPPED ) { MUTEX_UNLOCK( &stream_.mutex ); return; } */ HRESULT result = 0; LPVOID audioPtr; DWORD dataLen; DsHandle *handle = (DsHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { if ( handle->drainCounter == 0 ) { handle->drainCounter = 2; // MUTEX_UNLOCK( &stream_.mutex ); WaitForSingleObject( handle->condition, INFINITE ); // block until signaled //ResetEvent( handle->condition ); // MUTEX_LOCK( &stream_.mutex ); } stream_.state = STREAM_STOPPED; // Stop the buffer and clear memory LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0]; result = buffer->Stop(); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping output buffer!"; errorText_ = errorStream_.str(); goto unlock; } // Lock the buffer and clear it so that if we start to play again, // we won't have old data playing. result = buffer->Lock( 0, handle->dsBufferSize[0], &audioPtr, &dataLen, NULL, NULL, 0 ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking output buffer!"; errorText_ = errorStream_.str(); goto unlock; } // Zero the DS buffer ZeroMemory( audioPtr, dataLen ); // Unlock the DS buffer result = buffer->Unlock( audioPtr, dataLen, NULL, 0 ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking output buffer!"; errorText_ = errorStream_.str(); goto unlock; } // If we start playing again, we must begin at beginning of buffer. handle->bufferPointer[0] = 0; } if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1]; audioPtr = NULL; dataLen = 0; stream_.state = STREAM_STOPPED; result = buffer->Stop(); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping input buffer!"; errorText_ = errorStream_.str(); goto unlock; } // Lock the buffer and clear it so that if we start to play again, // we won't have old data playing. result = buffer->Lock( 0, handle->dsBufferSize[1], &audioPtr, &dataLen, NULL, NULL, 0 ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking input buffer!"; errorText_ = errorStream_.str(); goto unlock; } // Zero the DS buffer ZeroMemory( audioPtr, dataLen ); // Unlock the DS buffer result = buffer->Unlock( audioPtr, dataLen, NULL, 0 ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking input buffer!"; errorText_ = errorStream_.str(); goto unlock; } // If we start recording again, we must begin at beginning of buffer. handle->bufferPointer[1] = 0; } unlock: timeEndPeriod( 1 ); // revert to normal scheduler frequency on lesser windows. // MUTEX_UNLOCK( &stream_.mutex ); if ( FAILED( result ) ) error( RtError::SYSTEM_ERROR ); } void RtApiDs :: abortStream() { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiDs::abortStream(): the stream is already stopped!"; error( RtError::WARNING ); return; } DsHandle *handle = (DsHandle *) stream_.apiHandle; handle->drainCounter = 2; stopStream(); } void RtApiDs :: callbackEvent() { if ( stream_.state == STREAM_STOPPED ) { Sleep( 50 ); // sleep 50 milliseconds return; } if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiDs::callbackEvent(): the stream is closed ... this shouldn't happen!"; error( RtError::WARNING ); return; } CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo; DsHandle *handle = (DsHandle *) stream_.apiHandle; // Check if we were draining the stream and signal is finished. if ( handle->drainCounter > stream_.nBuffers + 2 ) { if ( handle->internalDrain == false ) SetEvent( handle->condition ); else stopStream(); return; } /* MUTEX_LOCK( &stream_.mutex ); // The state might change while waiting on a mutex. if ( stream_.state == STREAM_STOPPED ) { MUTEX_UNLOCK( &stream_.mutex ); return; } */ // Invoke user callback to get fresh output data UNLESS we are // draining stream. if ( handle->drainCounter == 0 ) { RtAudioCallback callback = (RtAudioCallback) info->callback; double streamTime = getStreamTime(); RtAudioStreamStatus status = 0; if ( stream_.mode != INPUT && handle->xrun[0] == true ) { status |= RTAUDIO_OUTPUT_UNDERFLOW; handle->xrun[0] = false; } if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) { status |= RTAUDIO_INPUT_OVERFLOW; handle->xrun[1] = false; } handle->drainCounter = callback( stream_.userBuffer[0], stream_.userBuffer[1], stream_.bufferSize, streamTime, status, info->userData ); if ( handle->drainCounter == 2 ) { // MUTEX_UNLOCK( &stream_.mutex ); abortStream(); return; } else if ( handle->drainCounter == 1 ) handle->internalDrain = true; } HRESULT result; DWORD currentWritePointer, safeWritePointer; DWORD currentReadPointer, safeReadPointer; UINT nextWritePointer; LPVOID buffer1 = NULL; LPVOID buffer2 = NULL; DWORD bufferSize1 = 0; DWORD bufferSize2 = 0; char *buffer; long bufferBytes; if ( buffersRolling == false ) { if ( stream_.mode == DUPLEX ) { //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] ); // It takes a while for the devices to get rolling. As a result, // there's no guarantee that the capture and write device pointers // will move in lockstep. Wait here for both devices to start // rolling, and then set our buffer pointers accordingly. // e.g. Crystal Drivers: the capture buffer starts up 5700 to 9600 // bytes later than the write buffer. // Stub: a serious risk of having a pre-emptive scheduling round // take place between the two GetCurrentPosition calls... but I'm // really not sure how to solve the problem. Temporarily boost to // Realtime priority, maybe; but I'm not sure what priority the // DirectSound service threads run at. We *should* be roughly // within a ms or so of correct. LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0]; LPDIRECTSOUNDCAPTUREBUFFER dsCaptureBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1]; DWORD startSafeWritePointer, startSafeReadPointer; result = dsWriteBuffer->GetCurrentPosition( NULL, &startSafeWritePointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); } result = dsCaptureBuffer->GetCurrentPosition( NULL, &startSafeReadPointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); } while ( true ) { result = dsWriteBuffer->GetCurrentPosition( NULL, &safeWritePointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); } result = dsCaptureBuffer->GetCurrentPosition( NULL, &safeReadPointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); } if ( safeWritePointer != startSafeWritePointer && safeReadPointer != startSafeReadPointer ) break; Sleep( 1 ); } //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] ); handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0]; if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0]; handle->bufferPointer[1] = safeReadPointer; } else if ( stream_.mode == OUTPUT ) { // Set the proper nextWritePosition after initial startup. LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0]; result = dsWriteBuffer->GetCurrentPosition( ¤tWritePointer, &safeWritePointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); } handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0]; if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0]; } buffersRolling = true; } if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0]; if ( handle->drainCounter > 1 ) { // write zeros to the output stream bufferBytes = stream_.bufferSize * stream_.nUserChannels[0]; bufferBytes *= formatBytes( stream_.userFormat ); memset( stream_.userBuffer[0], 0, bufferBytes ); } // Setup parameters and do buffer conversion if necessary. if ( stream_.doConvertBuffer[0] ) { buffer = stream_.deviceBuffer; convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] ); bufferBytes = stream_.bufferSize * stream_.nDeviceChannels[0]; bufferBytes *= formatBytes( stream_.deviceFormat[0] ); } else { buffer = stream_.userBuffer[0]; bufferBytes = stream_.bufferSize * stream_.nUserChannels[0]; bufferBytes *= formatBytes( stream_.userFormat ); } // No byte swapping necessary in DirectSound implementation. // Ahhh ... windoze. 16-bit data is signed but 8-bit data is // unsigned. So, we need to convert our signed 8-bit data here to // unsigned. if ( stream_.deviceFormat[0] == RTAUDIO_SINT8 ) for ( int i=0; idsBufferSize[0]; nextWritePointer = handle->bufferPointer[0]; DWORD endWrite, leadPointer; while ( true ) { // Find out where the read and "safe write" pointers are. result = dsBuffer->GetCurrentPosition( ¤tWritePointer, &safeWritePointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); } // We will copy our output buffer into the region between // safeWritePointer and leadPointer. If leadPointer is not // beyond the next endWrite position, wait until it is. leadPointer = safeWritePointer + handle->dsPointerLeadTime[0]; //std::cout << "safeWritePointer = " << safeWritePointer << ", leadPointer = " << leadPointer << ", nextWritePointer = " << nextWritePointer << std::endl; if ( leadPointer > dsBufferSize ) leadPointer -= dsBufferSize; if ( leadPointer < nextWritePointer ) leadPointer += dsBufferSize; // unwrap offset endWrite = nextWritePointer + bufferBytes; // Check whether the entire write region is behind the play pointer. if ( leadPointer >= endWrite ) break; // If we are here, then we must wait until the leadPointer advances // beyond the end of our next write region. We use the // Sleep() function to suspend operation until that happens. double millis = ( endWrite - leadPointer ) * 1000.0; millis /= ( formatBytes( stream_.deviceFormat[0]) * stream_.nDeviceChannels[0] * stream_.sampleRate); if ( millis < 1.0 ) millis = 1.0; Sleep( (DWORD) millis ); } if ( dsPointerBetween( nextWritePointer, safeWritePointer, currentWritePointer, dsBufferSize ) || dsPointerBetween( endWrite, safeWritePointer, currentWritePointer, dsBufferSize ) ) { // We've strayed into the forbidden zone ... resync the read pointer. handle->xrun[0] = true; nextWritePointer = safeWritePointer + handle->dsPointerLeadTime[0] - bufferBytes; if ( nextWritePointer >= dsBufferSize ) nextWritePointer -= dsBufferSize; handle->bufferPointer[0] = nextWritePointer; endWrite = nextWritePointer + bufferBytes; } // Lock free space in the buffer result = dsBuffer->Lock( nextWritePointer, bufferBytes, &buffer1, &bufferSize1, &buffer2, &bufferSize2, 0 ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); } // Copy our buffer into the DS buffer CopyMemory( buffer1, buffer, bufferSize1 ); if ( buffer2 != NULL ) CopyMemory( buffer2, buffer+bufferSize1, bufferSize2 ); // Update our buffer offset and unlock sound buffer dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); } nextWritePointer = ( nextWritePointer + bufferSize1 + bufferSize2 ) % dsBufferSize; handle->bufferPointer[0] = nextWritePointer; if ( handle->drainCounter ) { handle->drainCounter++; goto unlock; } } if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { // Setup parameters. if ( stream_.doConvertBuffer[1] ) { buffer = stream_.deviceBuffer; bufferBytes = stream_.bufferSize * stream_.nDeviceChannels[1]; bufferBytes *= formatBytes( stream_.deviceFormat[1] ); } else { buffer = stream_.userBuffer[1]; bufferBytes = stream_.bufferSize * stream_.nUserChannels[1]; bufferBytes *= formatBytes( stream_.userFormat ); } LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1]; long nextReadPointer = handle->bufferPointer[1]; DWORD dsBufferSize = handle->dsBufferSize[1]; // Find out where the write and "safe read" pointers are. result = dsBuffer->GetCurrentPosition( ¤tReadPointer, &safeReadPointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); } if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset DWORD endRead = nextReadPointer + bufferBytes; // Handling depends on whether we are INPUT or DUPLEX. // If we're in INPUT mode then waiting is a good thing. If we're in DUPLEX mode, // then a wait here will drag the write pointers into the forbidden zone. // // In DUPLEX mode, rather than wait, we will back off the read pointer until // it's in a safe position. This causes dropouts, but it seems to be the only // practical way to sync up the read and write pointers reliably, given the // the very complex relationship between phase and increment of the read and write // pointers. // // In order to minimize audible dropouts in DUPLEX mode, we will // provide a pre-roll period of 0.5 seconds in which we return // zeros from the read buffer while the pointers sync up. if ( stream_.mode == DUPLEX ) { if ( safeReadPointer < endRead ) { if ( duplexPrerollBytes <= 0 ) { // Pre-roll time over. Be more agressive. int adjustment = endRead-safeReadPointer; handle->xrun[1] = true; // Two cases: // - large adjustments: we've probably run out of CPU cycles, so just resync exactly, // and perform fine adjustments later. // - small adjustments: back off by twice as much. if ( adjustment >= 2*bufferBytes ) nextReadPointer = safeReadPointer-2*bufferBytes; else nextReadPointer = safeReadPointer-bufferBytes-adjustment; if ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize; } else { // In pre=roll time. Just do it. nextReadPointer = safeReadPointer - bufferBytes; while ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize; } endRead = nextReadPointer + bufferBytes; } } else { // mode == INPUT while ( safeReadPointer < endRead ) { // See comments for playback. double millis = (endRead - safeReadPointer) * 1000.0; millis /= ( formatBytes(stream_.deviceFormat[1]) * stream_.nDeviceChannels[1] * stream_.sampleRate); if ( millis < 1.0 ) millis = 1.0; Sleep( (DWORD) millis ); // Wake up and find out where we are now. result = dsBuffer->GetCurrentPosition( ¤tReadPointer, &safeReadPointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); } if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset } } // Lock free space in the buffer result = dsBuffer->Lock( nextReadPointer, bufferBytes, &buffer1, &bufferSize1, &buffer2, &bufferSize2, 0 ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); } if ( duplexPrerollBytes <= 0 ) { // Copy our buffer into the DS buffer CopyMemory( buffer, buffer1, bufferSize1 ); if ( buffer2 != NULL ) CopyMemory( buffer+bufferSize1, buffer2, bufferSize2 ); } else { memset( buffer, 0, bufferSize1 ); if ( buffer2 != NULL ) memset( buffer + bufferSize1, 0, bufferSize2 ); duplexPrerollBytes -= bufferSize1 + bufferSize2; } // Update our buffer offset and unlock sound buffer nextReadPointer = ( nextReadPointer + bufferSize1 + bufferSize2 ) % dsBufferSize; dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); } handle->bufferPointer[1] = nextReadPointer; // No byte swapping necessary in DirectSound implementation. // If necessary, convert 8-bit data from unsigned to signed. if ( stream_.deviceFormat[1] == RTAUDIO_SINT8 ) for ( int j=0; jobject; bool* isRunning = &info->isRunning; while ( *isRunning == true ) { object->callbackEvent(); } _endthreadex( 0 ); return 0; } #include "tchar.h" std::string convertTChar( LPCTSTR name ) { #if defined( UNICODE ) || defined( _UNICODE ) int length = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL); std::string s( length, 0 ); length = WideCharToMultiByte(CP_UTF8, 0, name, wcslen(name), &s[0], length, NULL, NULL); #else std::string s( name ); #endif return s; } static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid, LPCTSTR description, LPCTSTR module, LPVOID lpContext ) { bool *isInput = (bool *) lpContext; HRESULT hr; bool validDevice = false; if ( *isInput == true ) { DSCCAPS caps; LPDIRECTSOUNDCAPTURE object; hr = DirectSoundCaptureCreate( lpguid, &object, NULL ); if ( hr != DS_OK ) return TRUE; caps.dwSize = sizeof(caps); hr = object->GetCaps( &caps ); if ( hr == DS_OK ) { if ( caps.dwChannels > 0 && caps.dwFormats > 0 ) validDevice = true; } object->Release(); } else { DSCAPS caps; LPDIRECTSOUND object; hr = DirectSoundCreate( lpguid, &object, NULL ); if ( hr != DS_OK ) return TRUE; caps.dwSize = sizeof(caps); hr = object->GetCaps( &caps ); if ( hr == DS_OK ) { if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO ) validDevice = true; } object->Release(); } // If good device, then save its name and guid. std::string name = convertTChar( description ); if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" ) name = "Default Device"; if ( validDevice ) { for ( unsigned int i=0; i #include // A structure to hold various information related to the ALSA API // implementation. struct AlsaHandle { snd_pcm_t *handles[2]; bool synchronized; bool xrun[2]; pthread_cond_t runnable_cv; bool runnable; AlsaHandle() :synchronized(false), runnable(false) { xrun[0] = false; xrun[1] = false; } }; extern "C" void *alsaCallbackHandler( void * ptr ); RtApiAlsa :: RtApiAlsa() { // Nothing to do here. } RtApiAlsa :: ~RtApiAlsa() { if ( stream_.state != STREAM_CLOSED ) closeStream(); } unsigned int RtApiAlsa :: getDeviceCount( void ) { unsigned nDevices = 0; int result, subdevice, card; char name[64]; snd_ctl_t *handle; // Count cards and devices card = -1; snd_card_next( &card ); while ( card >= 0 ) { sprintf( name, "hw:%d", card ); result = snd_ctl_open( &handle, name, 0 ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::getDeviceCount: control open, card = " << card << ", " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtError::WARNING ); goto nextcard; } subdevice = -1; while( 1 ) { result = snd_ctl_pcm_next_device( handle, &subdevice ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::getDeviceCount: control next device, card = " << card << ", " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtError::WARNING ); break; } if ( subdevice < 0 ) break; nDevices++; } nextcard: snd_ctl_close( handle ); snd_card_next( &card ); } return nDevices; } RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device ) { RtAudio::DeviceInfo info; info.probed = false; unsigned nDevices = 0; int result, subdevice, card; char name[64]; snd_ctl_t *chandle; // Count cards and devices card = -1; snd_card_next( &card ); while ( card >= 0 ) { sprintf( name, "hw:%d", card ); result = snd_ctl_open( &chandle, name, SND_CTL_NONBLOCK ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::getDeviceInfo: control open, card = " << card << ", " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtError::WARNING ); goto nextcard; } subdevice = -1; while( 1 ) { result = snd_ctl_pcm_next_device( chandle, &subdevice ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::getDeviceInfo: control next device, card = " << card << ", " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtError::WARNING ); break; } if ( subdevice < 0 ) break; if ( nDevices == device ) { sprintf( name, "hw:%d,%d", card, subdevice ); goto foundDevice; } nDevices++; } nextcard: snd_ctl_close( chandle ); snd_card_next( &card ); } if ( nDevices == 0 ) { errorText_ = "RtApiAlsa::getDeviceInfo: no devices found!"; error( RtError::INVALID_USE ); } if ( device >= nDevices ) { errorText_ = "RtApiAlsa::getDeviceInfo: device ID is invalid!"; error( RtError::INVALID_USE ); } foundDevice: // If a stream is already open, we cannot probe the stream devices. // Thus, use the saved results. if ( stream_.state != STREAM_CLOSED && ( stream_.device[0] == device || stream_.device[1] == device ) ) { if ( device >= devices_.size() ) { errorText_ = "RtApiAlsa::getDeviceInfo: device ID was not present before stream was opened."; error( RtError::WARNING ); return info; } return devices_[ device ]; } int openMode = SND_PCM_ASYNC; snd_pcm_stream_t stream; snd_pcm_info_t *pcminfo; snd_pcm_info_alloca( &pcminfo ); snd_pcm_t *phandle; snd_pcm_hw_params_t *params; snd_pcm_hw_params_alloca( ¶ms ); // First try for playback stream = SND_PCM_STREAM_PLAYBACK; snd_pcm_info_set_device( pcminfo, subdevice ); snd_pcm_info_set_subdevice( pcminfo, 0 ); snd_pcm_info_set_stream( pcminfo, stream ); result = snd_ctl_pcm_info( chandle, pcminfo ); if ( result < 0 ) { // Device probably doesn't support playback. goto captureProbe; } result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtError::WARNING ); goto captureProbe; } // The device is open ... fill the parameter structure. result = snd_pcm_hw_params_any( phandle, params ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtError::WARNING ); goto captureProbe; } // Get output channel information. unsigned int value; result = snd_pcm_hw_params_get_channels_max( params, &value ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") output channels, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtError::WARNING ); goto captureProbe; } info.outputChannels = value; snd_pcm_close( phandle ); captureProbe: // Now try for capture stream = SND_PCM_STREAM_CAPTURE; snd_pcm_info_set_stream( pcminfo, stream ); result = snd_ctl_pcm_info( chandle, pcminfo ); snd_ctl_close( chandle ); if ( result < 0 ) { // Device probably doesn't support capture. if ( info.outputChannels == 0 ) return info; goto probeParameters; } result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK); if ( result < 0 ) { errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtError::WARNING ); if ( info.outputChannels == 0 ) return info; goto probeParameters; } // The device is open ... fill the parameter structure. result = snd_pcm_hw_params_any( phandle, params ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtError::WARNING ); if ( info.outputChannels == 0 ) return info; goto probeParameters; } result = snd_pcm_hw_params_get_channels_max( params, &value ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") input channels, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtError::WARNING ); if ( info.outputChannels == 0 ) return info; goto probeParameters; } info.inputChannels = value; snd_pcm_close( phandle ); // If device opens for both playback and capture, we determine the channels. if ( info.outputChannels > 0 && info.inputChannels > 0 ) info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels; // ALSA doesn't provide default devices so we'll use the first available one. if ( device == 0 && info.outputChannels > 0 ) info.isDefaultOutput = true; if ( device == 0 && info.inputChannels > 0 ) info.isDefaultInput = true; probeParameters: // At this point, we just need to figure out the supported data // formats and sample rates. We'll proceed by opening the device in // the direction with the maximum number of channels, or playback if // they are equal. This might limit our sample rate options, but so // be it. if ( info.outputChannels >= info.inputChannels ) stream = SND_PCM_STREAM_PLAYBACK; else stream = SND_PCM_STREAM_CAPTURE; snd_pcm_info_set_stream( pcminfo, stream ); result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK); if ( result < 0 ) { errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } // The device is open ... fill the parameter structure. result = snd_pcm_hw_params_any( phandle, params ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } // Test our discrete set of sample rate values. info.sampleRates.clear(); for ( unsigned int i=0; i= 0 ) sprintf( name, "hw:%s,%d", cardname, subdevice ); info.name = name; // That's all ... close the device and return snd_pcm_close( phandle ); info.probed = true; return info; } void RtApiAlsa :: saveDeviceInfo( void ) { devices_.clear(); unsigned int nDevices = getDeviceCount(); devices_.resize( nDevices ); for ( unsigned int i=0; iflags & RTAUDIO_ALSA_USE_DEFAULT ) snprintf(name, sizeof(name), "%s", "default"); else if ( deviceName.size() > 0 ) snprintf(name, sizeof(name), "%s", deviceName.c_str()); else { // Count cards and devices card = -1; snd_card_next( &card ); while ( card >= 0 ) { sprintf( name, "hw:%d", card ); result = snd_ctl_open( &chandle, name, SND_CTL_NONBLOCK ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::probeDeviceOpen: control open, card = " << card << ", " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } subdevice = -1; while( 1 ) { result = snd_ctl_pcm_next_device( chandle, &subdevice ); if ( result < 0 ) break; if ( subdevice < 0 ) break; if ( nDevices == device ) { sprintf( name, "hw:%d,%d", card, subdevice ); snd_ctl_close( chandle ); goto foundDevice; } nDevices++; } snd_ctl_close( chandle ); snd_card_next( &card ); } if ( nDevices == 0 ) { // This should not happen because a check is made before this function is called. errorText_ = "RtApiAlsa::probeDeviceOpen: no devices found!"; return FAILURE; } if ( device >= nDevices ) { // This should not happen because a check is made before this function is called. errorText_ = "RtApiAlsa::probeDeviceOpen: device ID is invalid!"; return FAILURE; } } foundDevice: // The getDeviceInfo() function will not work for a device that is // already open. Thus, we'll probe the system before opening a // stream and save the results for use by getDeviceInfo(). // if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) // only do once // this->saveDeviceInfo(); snd_pcm_stream_t stream; if ( mode == OUTPUT ) stream = SND_PCM_STREAM_PLAYBACK; else stream = SND_PCM_STREAM_CAPTURE; snd_pcm_t *phandle; int openMode = SND_PCM_ASYNC; result = snd_pcm_open( &phandle, name, stream, openMode ); if ( result < 0 ) { if ( mode == OUTPUT ) errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device (" << name << ") won't open for output."; else errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device (" << name << ") won't open for input."; errorText_ = errorStream_.str(); return FAILURE; } // Fill the parameter structure. snd_pcm_hw_params_t *hw_params; snd_pcm_hw_params_alloca( &hw_params ); result = snd_pcm_hw_params_any( phandle, hw_params ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting pcm device (" << name << ") parameters, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } #if defined(__RTAUDIO_DEBUG__) fprintf( stderr, "\nRtApiAlsa: dump hardware params just after device open:\n\n" ); snd_pcm_hw_params_dump( hw_params, out ); #endif // Set access ... check user preference. if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) { stream_.userInterleaved = false; result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED ); if ( result < 0 ) { result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED ); stream_.deviceInterleaved[mode] = true; } else stream_.deviceInterleaved[mode] = false; } else { stream_.userInterleaved = true; result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED ); if ( result < 0 ) { result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED ); stream_.deviceInterleaved[mode] = false; } else stream_.deviceInterleaved[mode] = true; } if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting pcm device (" << name << ") access, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } // Determine how to set the device format. stream_.userFormat = format; snd_pcm_format_t deviceFormat = SND_PCM_FORMAT_UNKNOWN; if ( format == RTAUDIO_SINT8 ) deviceFormat = SND_PCM_FORMAT_S8; else if ( format == RTAUDIO_SINT16 ) deviceFormat = SND_PCM_FORMAT_S16; else if ( format == RTAUDIO_SINT24 ) deviceFormat = SND_PCM_FORMAT_S24; else if ( format == RTAUDIO_SINT32 ) deviceFormat = SND_PCM_FORMAT_S32; else if ( format == RTAUDIO_FLOAT32 ) deviceFormat = SND_PCM_FORMAT_FLOAT; else if ( format == RTAUDIO_FLOAT64 ) deviceFormat = SND_PCM_FORMAT_FLOAT64; if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat) == 0) { stream_.deviceFormat[mode] = format; goto setFormat; } // The user requested format is not natively supported by the device. deviceFormat = SND_PCM_FORMAT_FLOAT64; if ( snd_pcm_hw_params_test_format( phandle, hw_params, deviceFormat ) == 0 ) { stream_.deviceFormat[mode] = RTAUDIO_FLOAT64; goto setFormat; } deviceFormat = SND_PCM_FORMAT_FLOAT; if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) { stream_.deviceFormat[mode] = RTAUDIO_FLOAT32; goto setFormat; } deviceFormat = SND_PCM_FORMAT_S32; if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) { stream_.deviceFormat[mode] = RTAUDIO_SINT32; goto setFormat; } deviceFormat = SND_PCM_FORMAT_S24; if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) { stream_.deviceFormat[mode] = RTAUDIO_SINT24; goto setFormat; } deviceFormat = SND_PCM_FORMAT_S16; if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) { stream_.deviceFormat[mode] = RTAUDIO_SINT16; goto setFormat; } deviceFormat = SND_PCM_FORMAT_S8; if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) { stream_.deviceFormat[mode] = RTAUDIO_SINT8; goto setFormat; } // If we get here, no supported format was found. errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device " << device << " data format not supported by RtAudio."; errorText_ = errorStream_.str(); return FAILURE; setFormat: result = snd_pcm_hw_params_set_format( phandle, hw_params, deviceFormat ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting pcm device (" << name << ") data format, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } // Determine whether byte-swaping is necessary. stream_.doByteSwap[mode] = false; if ( deviceFormat != SND_PCM_FORMAT_S8 ) { result = snd_pcm_format_cpu_endian( deviceFormat ); if ( result == 0 ) stream_.doByteSwap[mode] = true; else if (result < 0) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting pcm device (" << name << ") endian-ness, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } } // Set the sample rate. result = snd_pcm_hw_params_set_rate_near( phandle, hw_params, (unsigned int*) &sampleRate, 0 ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting sample rate on device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } // Determine the number of channels for this device. We support a possible // minimum device channel number > than the value requested by the user. stream_.nUserChannels[mode] = channels; unsigned int value; result = snd_pcm_hw_params_get_channels_max( hw_params, &value ); unsigned int deviceChannels = value; if ( result < 0 || deviceChannels < channels + firstChannel ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: requested channel parameters not supported by device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } result = snd_pcm_hw_params_get_channels_min( hw_params, &value ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting minimum channels for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } deviceChannels = value; if ( deviceChannels < channels + firstChannel ) deviceChannels = channels + firstChannel; stream_.nDeviceChannels[mode] = deviceChannels; // Set the device channels. result = snd_pcm_hw_params_set_channels( phandle, hw_params, deviceChannels ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting channels for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } // Set the buffer (or period) size. int dir = 0; snd_pcm_uframes_t periodSize = *bufferSize; result = snd_pcm_hw_params_set_period_size_near( phandle, hw_params, &periodSize, &dir ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting period size for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } *bufferSize = periodSize; // Set the buffer number, which in ALSA is referred to as the "period". unsigned int periods = 0; if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) periods = 2; if ( options && options->numberOfBuffers > 0 ) periods = options->numberOfBuffers; if ( periods < 2 ) periods = 4; // a fairly safe default value result = snd_pcm_hw_params_set_periods_near( phandle, hw_params, &periods, &dir ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } // If attempting to setup a duplex stream, the bufferSize parameter // MUST be the same in both directions! if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) { errorStream_ << "RtApiAlsa::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << name << ")."; errorText_ = errorStream_.str(); return FAILURE; } stream_.bufferSize = *bufferSize; // Install the hardware configuration result = snd_pcm_hw_params( phandle, hw_params ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error installing hardware configuration on device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } #if defined(__RTAUDIO_DEBUG__) fprintf(stderr, "\nRtApiAlsa: dump hardware params after installation:\n\n"); snd_pcm_hw_params_dump( hw_params, out ); #endif // Set the software configuration to fill buffers with zeros and prevent device stopping on xruns. snd_pcm_sw_params_t *sw_params = NULL; snd_pcm_sw_params_alloca( &sw_params ); snd_pcm_sw_params_current( phandle, sw_params ); snd_pcm_sw_params_set_start_threshold( phandle, sw_params, *bufferSize ); snd_pcm_sw_params_set_stop_threshold( phandle, sw_params, ULONG_MAX ); snd_pcm_sw_params_set_silence_threshold( phandle, sw_params, 0 ); // The following two settings were suggested by Theo Veenker //snd_pcm_sw_params_set_avail_min( phandle, sw_params, *bufferSize ); //snd_pcm_sw_params_set_xfer_align( phandle, sw_params, 1 ); // here are two options for a fix //snd_pcm_sw_params_set_silence_size( phandle, sw_params, ULONG_MAX ); snd_pcm_uframes_t val; snd_pcm_sw_params_get_boundary( sw_params, &val ); snd_pcm_sw_params_set_silence_size( phandle, sw_params, val ); result = snd_pcm_sw_params( phandle, sw_params ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error installing software configuration on device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } #if defined(__RTAUDIO_DEBUG__) fprintf(stderr, "\nRtApiAlsa: dump software params after installation:\n\n"); snd_pcm_sw_params_dump( sw_params, out ); #endif // Set flags for buffer conversion stream_.doConvertBuffer[mode] = false; if ( stream_.userFormat != stream_.deviceFormat[mode] ) stream_.doConvertBuffer[mode] = true; if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] ) stream_.doConvertBuffer[mode] = true; if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] && stream_.nUserChannels[mode] > 1 ) stream_.doConvertBuffer[mode] = true; // Allocate the ApiHandle if necessary and then save. AlsaHandle *apiInfo = 0; if ( stream_.apiHandle == 0 ) { try { apiInfo = (AlsaHandle *) new AlsaHandle; } catch ( std::bad_alloc& ) { errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating AlsaHandle memory."; goto error; } if ( pthread_cond_init( &apiInfo->runnable_cv, NULL ) ) { errorText_ = "RtApiAlsa::probeDeviceOpen: error initializing pthread condition variable."; goto error; } stream_.apiHandle = (void *) apiInfo; apiInfo->handles[0] = 0; apiInfo->handles[1] = 0; } else { apiInfo = (AlsaHandle *) stream_.apiHandle; } apiInfo->handles[mode] = phandle; // Allocate necessary internal buffers. unsigned long bufferBytes; bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); stream_.userBuffer[mode] = (char *) calloc( 1, bufferBytes ); if ( stream_.userBuffer[mode] == NULL ) { errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating user buffer memory."; goto error; } if ( stream_.doConvertBuffer[mode] ) { bool makeBuffer = true; bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] ); if ( mode == INPUT ) { if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) { unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); if ( bufferBytes <= bytesOut ) makeBuffer = false; } } if ( makeBuffer ) { bufferBytes *= *bufferSize; if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); stream_.deviceBuffer = (char *) calloc( 1, bufferBytes ); if ( stream_.deviceBuffer == NULL ) { errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating device buffer memory."; goto error; } } } stream_.sampleRate = sampleRate; stream_.nBuffers = periods; stream_.device[mode] = device; stream_.state = STREAM_STOPPED; // Setup the buffer conversion information structure. if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel ); // Setup thread if necessary. if ( stream_.mode == OUTPUT && mode == INPUT ) { // We had already set up an output stream. stream_.mode = DUPLEX; // Link the streams if possible. apiInfo->synchronized = false; if ( snd_pcm_link( apiInfo->handles[0], apiInfo->handles[1] ) == 0 ) apiInfo->synchronized = true; else { errorText_ = "RtApiAlsa::probeDeviceOpen: unable to synchronize input and output devices."; error( RtError::WARNING ); } } else { stream_.mode = mode; // Setup callback thread. stream_.callbackInfo.object = (void *) this; // Set the thread attributes for joinable and realtime scheduling // priority (optional). The higher priority will only take affect // if the program is run as root or suid. Note, under Linux // processes with CAP_SYS_NICE privilege, a user can change // scheduling policy and priority (thus need not be root). See // POSIX "capabilities". pthread_attr_t attr; pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); #ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread) if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) { struct sched_param param; int priority = options->priority; int min = sched_get_priority_min( SCHED_RR ); int max = sched_get_priority_max( SCHED_RR ); if ( priority < min ) priority = min; else if ( priority > max ) priority = max; param.sched_priority = priority; pthread_attr_setschedparam( &attr, ¶m ); pthread_attr_setschedpolicy( &attr, SCHED_RR ); } else pthread_attr_setschedpolicy( &attr, SCHED_OTHER ); #else pthread_attr_setschedpolicy( &attr, SCHED_OTHER ); #endif stream_.callbackInfo.isRunning = true; result = pthread_create( &stream_.callbackInfo.thread, &attr, alsaCallbackHandler, &stream_.callbackInfo ); pthread_attr_destroy( &attr ); if ( result ) { stream_.callbackInfo.isRunning = false; errorText_ = "RtApiAlsa::error creating callback thread!"; goto error; } } return SUCCESS; error: if ( apiInfo ) { pthread_cond_destroy( &apiInfo->runnable_cv ); if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] ); if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] ); delete apiInfo; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } return FAILURE; } void RtApiAlsa :: closeStream() { if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiAlsa::closeStream(): no open stream to close!"; error( RtError::WARNING ); return; } AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle; stream_.callbackInfo.isRunning = false; MUTEX_LOCK( &stream_.mutex ); if ( stream_.state == STREAM_STOPPED ) { apiInfo->runnable = true; pthread_cond_signal( &apiInfo->runnable_cv ); } MUTEX_UNLOCK( &stream_.mutex ); pthread_join( stream_.callbackInfo.thread, NULL ); if ( stream_.state == STREAM_RUNNING ) { stream_.state = STREAM_STOPPED; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) snd_pcm_drop( apiInfo->handles[0] ); if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) snd_pcm_drop( apiInfo->handles[1] ); } if ( apiInfo ) { pthread_cond_destroy( &apiInfo->runnable_cv ); if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] ); if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] ); delete apiInfo; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } stream_.mode = UNINITIALIZED; stream_.state = STREAM_CLOSED; } void RtApiAlsa :: startStream() { // This method calls snd_pcm_prepare if the device isn't already in that state. verifyStream(); if ( stream_.state == STREAM_RUNNING ) { errorText_ = "RtApiAlsa::startStream(): the stream is already running!"; error( RtError::WARNING ); return; } MUTEX_LOCK( &stream_.mutex ); int result = 0; snd_pcm_state_t state; AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle; snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { state = snd_pcm_state( handle[0] ); if ( state != SND_PCM_STATE_PREPARED ) { result = snd_pcm_prepare( handle[0] ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::startStream: error preparing output pcm device, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); goto unlock; } } } if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) { state = snd_pcm_state( handle[1] ); if ( state != SND_PCM_STATE_PREPARED ) { result = snd_pcm_prepare( handle[1] ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::startStream: error preparing input pcm device, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); goto unlock; } } } stream_.state = STREAM_RUNNING; unlock: apiInfo->runnable = true; pthread_cond_signal( &apiInfo->runnable_cv ); MUTEX_UNLOCK( &stream_.mutex ); if ( result >= 0 ) return; error( RtError::SYSTEM_ERROR ); } void RtApiAlsa :: stopStream() { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiAlsa::stopStream(): the stream is already stopped!"; error( RtError::WARNING ); return; } stream_.state = STREAM_STOPPED; MUTEX_LOCK( &stream_.mutex ); //if ( stream_.state == STREAM_STOPPED ) { // MUTEX_UNLOCK( &stream_.mutex ); // return; //} int result = 0; AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle; snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { if ( apiInfo->synchronized ) result = snd_pcm_drop( handle[0] ); else result = snd_pcm_drain( handle[0] ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::stopStream: error draining output pcm device, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); goto unlock; } } if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) { result = snd_pcm_drop( handle[1] ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::stopStream: error stopping input pcm device, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); goto unlock; } } unlock: stream_.state = STREAM_STOPPED; MUTEX_UNLOCK( &stream_.mutex ); if ( result >= 0 ) return; error( RtError::SYSTEM_ERROR ); } void RtApiAlsa :: abortStream() { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiAlsa::abortStream(): the stream is already stopped!"; error( RtError::WARNING ); return; } stream_.state = STREAM_STOPPED; MUTEX_LOCK( &stream_.mutex ); //if ( stream_.state == STREAM_STOPPED ) { // MUTEX_UNLOCK( &stream_.mutex ); // return; //} int result = 0; AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle; snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { result = snd_pcm_drop( handle[0] ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::abortStream: error aborting output pcm device, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); goto unlock; } } if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) { result = snd_pcm_drop( handle[1] ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::abortStream: error aborting input pcm device, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); goto unlock; } } unlock: stream_.state = STREAM_STOPPED; MUTEX_UNLOCK( &stream_.mutex ); if ( result >= 0 ) return; error( RtError::SYSTEM_ERROR ); } void RtApiAlsa :: callbackEvent() { AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle; if ( stream_.state == STREAM_STOPPED ) { MUTEX_LOCK( &stream_.mutex ); while ( !apiInfo->runnable ) pthread_cond_wait( &apiInfo->runnable_cv, &stream_.mutex ); if ( stream_.state != STREAM_RUNNING ) { MUTEX_UNLOCK( &stream_.mutex ); return; } MUTEX_UNLOCK( &stream_.mutex ); } if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiAlsa::callbackEvent(): the stream is closed ... this shouldn't happen!"; error( RtError::WARNING ); return; } int doStopStream = 0; RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback; double streamTime = getStreamTime(); RtAudioStreamStatus status = 0; if ( stream_.mode != INPUT && apiInfo->xrun[0] == true ) { status |= RTAUDIO_OUTPUT_UNDERFLOW; apiInfo->xrun[0] = false; } if ( stream_.mode != OUTPUT && apiInfo->xrun[1] == true ) { status |= RTAUDIO_INPUT_OVERFLOW; apiInfo->xrun[1] = false; } doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1], stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData ); if ( doStopStream == 2 ) { abortStream(); return; } MUTEX_LOCK( &stream_.mutex ); // The state might change while waiting on a mutex. if ( stream_.state == STREAM_STOPPED ) goto unlock; int result; char *buffer; int channels; snd_pcm_t **handle; snd_pcm_sframes_t frames; RtAudioFormat format; handle = (snd_pcm_t **) apiInfo->handles; if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { // Setup parameters. if ( stream_.doConvertBuffer[1] ) { buffer = stream_.deviceBuffer; channels = stream_.nDeviceChannels[1]; format = stream_.deviceFormat[1]; } else { buffer = stream_.userBuffer[1]; channels = stream_.nUserChannels[1]; format = stream_.userFormat; } // Read samples from device in interleaved/non-interleaved format. if ( stream_.deviceInterleaved[1] ) result = snd_pcm_readi( handle[1], buffer, stream_.bufferSize ); else { void *bufs[channels]; size_t offset = stream_.bufferSize * formatBytes( format ); for ( int i=0; ixrun[1] = true; result = snd_pcm_prepare( handle[1] ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after overrun, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); } } else { errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); } } else { errorStream_ << "RtApiAlsa::callbackEvent: audio read error, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); } error( RtError::WARNING ); goto tryOutput; } // Do byte swapping if necessary. if ( stream_.doByteSwap[1] ) byteSwapBuffer( buffer, stream_.bufferSize * channels, format ); // Do buffer conversion if necessary. if ( stream_.doConvertBuffer[1] ) convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] ); // Check stream latency result = snd_pcm_delay( handle[1], &frames ); if ( result == 0 && frames > 0 ) stream_.latency[1] = frames; } tryOutput: if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { // Setup parameters and do buffer conversion if necessary. if ( stream_.doConvertBuffer[0] ) { buffer = stream_.deviceBuffer; convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] ); channels = stream_.nDeviceChannels[0]; format = stream_.deviceFormat[0]; } else { buffer = stream_.userBuffer[0]; channels = stream_.nUserChannels[0]; format = stream_.userFormat; } // Do byte swapping if necessary. if ( stream_.doByteSwap[0] ) byteSwapBuffer(buffer, stream_.bufferSize * channels, format); // Write samples to device in interleaved/non-interleaved format. if ( stream_.deviceInterleaved[0] ) result = snd_pcm_writei( handle[0], buffer, stream_.bufferSize ); else { void *bufs[channels]; size_t offset = stream_.bufferSize * formatBytes( format ); for ( int i=0; ixrun[0] = true; result = snd_pcm_prepare( handle[0] ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after underrun, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); } } else { errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); } } else { errorStream_ << "RtApiAlsa::callbackEvent: audio write error, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); } error( RtError::WARNING ); goto unlock; } // Check stream latency result = snd_pcm_delay( handle[0], &frames ); if ( result == 0 && frames > 0 ) stream_.latency[0] = frames; } unlock: MUTEX_UNLOCK( &stream_.mutex ); RtApi::tickStreamTime(); if ( doStopStream == 1 ) this->stopStream(); } extern "C" void *alsaCallbackHandler( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiAlsa *object = (RtApiAlsa *) info->object; bool *isRunning = &info->isRunning; while ( *isRunning == true ) { pthread_testcancel(); object->callbackEvent(); } pthread_exit( NULL ); } //******************** End of __LINUX_ALSA__ *********************// #endif #if defined(__LINUX_OSS__) #include #include #include #include #include #include #include extern "C" void *ossCallbackHandler(void * ptr); // A structure to hold various information related to the OSS API // implementation. struct OssHandle { int id[2]; // device ids bool xrun[2]; bool triggered; pthread_cond_t runnable; OssHandle() :triggered(false) { id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; } }; RtApiOss :: RtApiOss() { // Nothing to do here. } RtApiOss :: ~RtApiOss() { if ( stream_.state != STREAM_CLOSED ) closeStream(); } unsigned int RtApiOss :: getDeviceCount( void ) { int mixerfd = open( "/dev/mixer", O_RDWR, 0 ); if ( mixerfd == -1 ) { errorText_ = "RtApiOss::getDeviceCount: error opening '/dev/mixer'."; error( RtError::WARNING ); return 0; } oss_sysinfo sysinfo; if ( ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo ) == -1 ) { close( mixerfd ); errorText_ = "RtApiOss::getDeviceCount: error getting sysinfo, OSS version >= 4.0 is required."; error( RtError::WARNING ); return 0; } close( mixerfd ); return sysinfo.numaudios; } RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device ) { RtAudio::DeviceInfo info; info.probed = false; int mixerfd = open( "/dev/mixer", O_RDWR, 0 ); if ( mixerfd == -1 ) { errorText_ = "RtApiOss::getDeviceInfo: error opening '/dev/mixer'."; error( RtError::WARNING ); return info; } oss_sysinfo sysinfo; int result = ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo ); if ( result == -1 ) { close( mixerfd ); errorText_ = "RtApiOss::getDeviceInfo: error getting sysinfo, OSS version >= 4.0 is required."; error( RtError::WARNING ); return info; } unsigned nDevices = sysinfo.numaudios; if ( nDevices == 0 ) { close( mixerfd ); errorText_ = "RtApiOss::getDeviceInfo: no devices found!"; error( RtError::INVALID_USE ); } if ( device >= nDevices ) { close( mixerfd ); errorText_ = "RtApiOss::getDeviceInfo: device ID is invalid!"; error( RtError::INVALID_USE ); } oss_audioinfo ainfo; ainfo.dev = device; result = ioctl( mixerfd, SNDCTL_AUDIOINFO, &ainfo ); close( mixerfd ); if ( result == -1 ) { errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } // Probe channels if ( ainfo.caps & PCM_CAP_OUTPUT ) info.outputChannels = ainfo.max_channels; if ( ainfo.caps & PCM_CAP_INPUT ) info.inputChannels = ainfo.max_channels; if ( ainfo.caps & PCM_CAP_DUPLEX ) { if ( info.outputChannels > 0 && info.inputChannels > 0 && ainfo.caps & PCM_CAP_DUPLEX ) info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels; } // Probe data formats ... do for input unsigned long mask = ainfo.iformats; if ( mask & AFMT_S16_LE || mask & AFMT_S16_BE ) info.nativeFormats |= RTAUDIO_SINT16; if ( mask & AFMT_S8 ) info.nativeFormats |= RTAUDIO_SINT8; if ( mask & AFMT_S32_LE || mask & AFMT_S32_BE ) info.nativeFormats |= RTAUDIO_SINT32; if ( mask & AFMT_FLOAT ) info.nativeFormats |= RTAUDIO_FLOAT32; if ( mask & AFMT_S24_LE || mask & AFMT_S24_BE ) info.nativeFormats |= RTAUDIO_SINT24; // Check that we have at least one supported format if ( info.nativeFormats == 0 ) { errorStream_ << "RtApiOss::getDeviceInfo: device (" << ainfo.name << ") data format not supported by RtAudio."; errorText_ = errorStream_.str(); error( RtError::WARNING ); return info; } // Probe the supported sample rates. info.sampleRates.clear(); if ( ainfo.nrates ) { for ( unsigned int i=0; i= (int) SAMPLE_RATES[k] ) info.sampleRates.push_back( SAMPLE_RATES[k] ); } } if ( info.sampleRates.size() == 0 ) { errorStream_ << "RtApiOss::getDeviceInfo: no supported sample rates found for device (" << ainfo.name << ")."; errorText_ = errorStream_.str(); error( RtError::WARNING ); } else { info.probed = true; info.name = ainfo.name; } return info; } bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options, const std::string &deviceName ) { int mixerfd = open( "/dev/mixer", O_RDWR, 0 ); if ( mixerfd == -1 ) { errorText_ = "RtApiOss::probeDeviceOpen: error opening '/dev/mixer'."; return FAILURE; } oss_sysinfo sysinfo; int result = ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo ); if ( result == -1 ) { close( mixerfd ); errorText_ = "RtApiOss::probeDeviceOpen: error getting sysinfo, OSS version >= 4.0 is required."; return FAILURE; } unsigned nDevices = sysinfo.numaudios; if ( nDevices == 0 ) { // This should not happen because a check is made before this function is called. close( mixerfd ); errorText_ = "RtApiOss::probeDeviceOpen: no devices found!"; return FAILURE; } if ( device >= nDevices ) { // This should not happen because a check is made before this function is called. close( mixerfd ); errorText_ = "RtApiOss::probeDeviceOpen: device ID is invalid!"; return FAILURE; } oss_audioinfo ainfo; ainfo.dev = device; result = ioctl( mixerfd, SNDCTL_AUDIOINFO, &ainfo ); close( mixerfd ); if ( result == -1 ) { errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info."; errorText_ = errorStream_.str(); return FAILURE; } // Check if device supports input or output if ( ( mode == OUTPUT && !( ainfo.caps & PCM_CAP_OUTPUT ) ) || ( mode == INPUT && !( ainfo.caps & PCM_CAP_INPUT ) ) ) { if ( mode == OUTPUT ) errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support output."; else errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support input."; errorText_ = errorStream_.str(); return FAILURE; } int flags = 0; OssHandle *handle = (OssHandle *) stream_.apiHandle; if ( mode == OUTPUT ) flags |= O_WRONLY; else { // mode == INPUT if (stream_.mode == OUTPUT && stream_.device[0] == device) { // We just set the same device for playback ... close and reopen for duplex (OSS only). close( handle->id[0] ); handle->id[0] = 0; if ( !( ainfo.caps & PCM_CAP_DUPLEX ) ) { errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support duplex mode."; errorText_ = errorStream_.str(); return FAILURE; } // Check that the number previously set channels is the same. if ( stream_.nUserChannels[0] != channels ) { errorStream_ << "RtApiOss::probeDeviceOpen: input/output channels must be equal for OSS duplex device (" << ainfo.name << ")."; errorText_ = errorStream_.str(); return FAILURE; } flags |= O_RDWR; } else flags |= O_RDONLY; } // Set exclusive access if specified. if ( options && options->flags & RTAUDIO_HOG_DEVICE ) flags |= O_EXCL; // Try to open the device. int fd; fd = open( ainfo.devnode, flags, 0 ); if ( fd == -1 ) { if ( errno == EBUSY ) errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") is busy."; else errorStream_ << "RtApiOss::probeDeviceOpen: error opening device (" << ainfo.name << ")."; errorText_ = errorStream_.str(); return FAILURE; } // For duplex operation, specifically set this mode (this doesn't seem to work). /* if ( flags | O_RDWR ) { result = ioctl( fd, SNDCTL_DSP_SETDUPLEX, NULL ); if ( result == -1) { errorStream_ << "RtApiOss::probeDeviceOpen: error setting duplex mode for device (" << ainfo.name << ")."; errorText_ = errorStream_.str(); return FAILURE; } } */ // Check the device channel support. stream_.nUserChannels[mode] = channels; if ( ainfo.max_channels < (int)(channels + firstChannel) ) { close( fd ); errorStream_ << "RtApiOss::probeDeviceOpen: the device (" << ainfo.name << ") does not support requested channel parameters."; errorText_ = errorStream_.str(); return FAILURE; } // Set the number of channels. int deviceChannels = channels + firstChannel; result = ioctl( fd, SNDCTL_DSP_CHANNELS, &deviceChannels ); if ( result == -1 || deviceChannels < (int)(channels + firstChannel) ) { close( fd ); errorStream_ << "RtApiOss::probeDeviceOpen: error setting channel parameters on device (" << ainfo.name << ")."; errorText_ = errorStream_.str(); return FAILURE; } stream_.nDeviceChannels[mode] = deviceChannels; // Get the data format mask int mask; result = ioctl( fd, SNDCTL_DSP_GETFMTS, &mask ); if ( result == -1 ) { close( fd ); errorStream_ << "RtApiOss::probeDeviceOpen: error getting device (" << ainfo.name << ") data formats."; errorText_ = errorStream_.str(); return FAILURE; } // Determine how to set the device format. stream_.userFormat = format; int deviceFormat = -1; stream_.doByteSwap[mode] = false; if ( format == RTAUDIO_SINT8 ) { if ( mask & AFMT_S8 ) { deviceFormat = AFMT_S8; stream_.deviceFormat[mode] = RTAUDIO_SINT8; } } else if ( format == RTAUDIO_SINT16 ) { if ( mask & AFMT_S16_NE ) { deviceFormat = AFMT_S16_NE; stream_.deviceFormat[mode] = RTAUDIO_SINT16; } else if ( mask & AFMT_S16_OE ) { deviceFormat = AFMT_S16_OE; stream_.deviceFormat[mode] = RTAUDIO_SINT16; stream_.doByteSwap[mode] = true; } } else if ( format == RTAUDIO_SINT24 ) { if ( mask & AFMT_S24_NE ) { deviceFormat = AFMT_S24_NE; stream_.deviceFormat[mode] = RTAUDIO_SINT24; } else if ( mask & AFMT_S24_OE ) { deviceFormat = AFMT_S24_OE; stream_.deviceFormat[mode] = RTAUDIO_SINT24; stream_.doByteSwap[mode] = true; } } else if ( format == RTAUDIO_SINT32 ) { if ( mask & AFMT_S32_NE ) { deviceFormat = AFMT_S32_NE; stream_.deviceFormat[mode] = RTAUDIO_SINT32; } else if ( mask & AFMT_S32_OE ) { deviceFormat = AFMT_S32_OE; stream_.deviceFormat[mode] = RTAUDIO_SINT32; stream_.doByteSwap[mode] = true; } } if ( deviceFormat == -1 ) { // The user requested format is not natively supported by the device. if ( mask & AFMT_S16_NE ) { deviceFormat = AFMT_S16_NE; stream_.deviceFormat[mode] = RTAUDIO_SINT16; } else if ( mask & AFMT_S32_NE ) { deviceFormat = AFMT_S32_NE; stream_.deviceFormat[mode] = RTAUDIO_SINT32; } else if ( mask & AFMT_S24_NE ) { deviceFormat = AFMT_S24_NE; stream_.deviceFormat[mode] = RTAUDIO_SINT24; } else if ( mask & AFMT_S16_OE ) { deviceFormat = AFMT_S16_OE; stream_.deviceFormat[mode] = RTAUDIO_SINT16; stream_.doByteSwap[mode] = true; } else if ( mask & AFMT_S32_OE ) { deviceFormat = AFMT_S32_OE; stream_.deviceFormat[mode] = RTAUDIO_SINT32; stream_.doByteSwap[mode] = true; } else if ( mask & AFMT_S24_OE ) { deviceFormat = AFMT_S24_OE; stream_.deviceFormat[mode] = RTAUDIO_SINT24; stream_.doByteSwap[mode] = true; } else if ( mask & AFMT_S8) { deviceFormat = AFMT_S8; stream_.deviceFormat[mode] = RTAUDIO_SINT8; } } if ( stream_.deviceFormat[mode] == 0 ) { // This really shouldn't happen ... close( fd ); errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") data format not supported by RtAudio."; errorText_ = errorStream_.str(); return FAILURE; } // Set the data format. int temp = deviceFormat; result = ioctl( fd, SNDCTL_DSP_SETFMT, &deviceFormat ); if ( result == -1 || deviceFormat != temp ) { close( fd ); errorStream_ << "RtApiOss::probeDeviceOpen: error setting data format on device (" << ainfo.name << ")."; errorText_ = errorStream_.str(); return FAILURE; } // Attempt to set the buffer size. According to OSS, the minimum // number of buffers is two. The supposed minimum buffer size is 16 // bytes, so that will be our lower bound. The argument to this // call is in the form 0xMMMMSSSS (hex), where the buffer size (in // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM. // We'll check the actual value used near the end of the setup // procedure. int ossBufferBytes = *bufferSize * formatBytes( stream_.deviceFormat[mode] ) * deviceChannels; if ( ossBufferBytes < 16 ) ossBufferBytes = 16; int buffers = 0; if ( options ) buffers = options->numberOfBuffers; if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) buffers = 2; if ( buffers < 2 ) buffers = 3; temp = ((int) buffers << 16) + (int)( log10( (double)ossBufferBytes ) / log10( 2.0 ) ); result = ioctl( fd, SNDCTL_DSP_SETFRAGMENT, &temp ); if ( result == -1 ) { close( fd ); errorStream_ << "RtApiOss::probeDeviceOpen: error setting buffer size on device (" << ainfo.name << ")."; errorText_ = errorStream_.str(); return FAILURE; } stream_.nBuffers = buffers; // Save buffer size (in sample frames). *bufferSize = ossBufferBytes / ( formatBytes(stream_.deviceFormat[mode]) * deviceChannels ); stream_.bufferSize = *bufferSize; // Set the sample rate. int srate = sampleRate; result = ioctl( fd, SNDCTL_DSP_SPEED, &srate ); if ( result == -1 ) { close( fd ); errorStream_ << "RtApiOss::probeDeviceOpen: error setting sample rate (" << sampleRate << ") on device (" << ainfo.name << ")."; errorText_ = errorStream_.str(); return FAILURE; } // Verify the sample rate setup worked. if ( abs( srate - sampleRate ) > 100 ) { close( fd ); errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support sample rate (" << sampleRate << ")."; errorText_ = errorStream_.str(); return FAILURE; } stream_.sampleRate = sampleRate; if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] == device) { // We're doing duplex setup here. stream_.deviceFormat[0] = stream_.deviceFormat[1]; stream_.nDeviceChannels[0] = deviceChannels; } // Set interleaving parameters. stream_.userInterleaved = true; stream_.deviceInterleaved[mode] = true; if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false; // Set flags for buffer conversion stream_.doConvertBuffer[mode] = false; if ( stream_.userFormat != stream_.deviceFormat[mode] ) stream_.doConvertBuffer[mode] = true; if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] ) stream_.doConvertBuffer[mode] = true; if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] && stream_.nUserChannels[mode] > 1 ) stream_.doConvertBuffer[mode] = true; // Allocate the stream handles if necessary and then save. if ( stream_.apiHandle == 0 ) { try { handle = new OssHandle; } catch ( std::bad_alloc& ) { errorText_ = "RtApiOss::probeDeviceOpen: error allocating OssHandle memory."; goto error; } if ( pthread_cond_init( &handle->runnable, NULL ) ) { errorText_ = "RtApiOss::probeDeviceOpen: error initializing pthread condition variable."; goto error; } stream_.apiHandle = (void *) handle; } else { handle = (OssHandle *) stream_.apiHandle; } handle->id[mode] = fd; // Allocate necessary internal buffers. unsigned long bufferBytes; bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); stream_.userBuffer[mode] = (char *) calloc( 1, bufferBytes ); if ( stream_.userBuffer[mode] == NULL ) { errorText_ = "RtApiOss::probeDeviceOpen: error allocating user buffer memory."; goto error; } if ( stream_.doConvertBuffer[mode] ) { bool makeBuffer = true; bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] ); if ( mode == INPUT ) { if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) { unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); if ( bufferBytes <= bytesOut ) makeBuffer = false; } } if ( makeBuffer ) { bufferBytes *= *bufferSize; if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); stream_.deviceBuffer = (char *) calloc( 1, bufferBytes ); if ( stream_.deviceBuffer == NULL ) { errorText_ = "RtApiOss::probeDeviceOpen: error allocating device buffer memory."; goto error; } } } stream_.device[mode] = device; stream_.state = STREAM_STOPPED; // Setup the buffer conversion information structure. if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel ); // Setup thread if necessary. if ( stream_.mode == OUTPUT && mode == INPUT ) { // We had already set up an output stream. stream_.mode = DUPLEX; if ( stream_.device[0] == device ) handle->id[0] = fd; } else { stream_.mode = mode; // Setup callback thread. stream_.callbackInfo.object = (void *) this; // Set the thread attributes for joinable and realtime scheduling // priority. The higher priority will only take affect if the // program is run as root or suid. pthread_attr_t attr; pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); #ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread) if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) { struct sched_param param; int priority = options->priority; int min = sched_get_priority_min( SCHED_RR ); int max = sched_get_priority_max( SCHED_RR ); if ( priority < min ) priority = min; else if ( priority > max ) priority = max; param.sched_priority = priority; pthread_attr_setschedparam( &attr, ¶m ); pthread_attr_setschedpolicy( &attr, SCHED_RR ); } else pthread_attr_setschedpolicy( &attr, SCHED_OTHER ); #else pthread_attr_setschedpolicy( &attr, SCHED_OTHER ); #endif stream_.callbackInfo.isRunning = true; result = pthread_create( &stream_.callbackInfo.thread, &attr, ossCallbackHandler, &stream_.callbackInfo ); pthread_attr_destroy( &attr ); if ( result ) { stream_.callbackInfo.isRunning = false; errorText_ = "RtApiOss::error creating callback thread!"; goto error; } } return SUCCESS; error: if ( handle ) { pthread_cond_destroy( &handle->runnable ); if ( handle->id[0] ) close( handle->id[0] ); if ( handle->id[1] ) close( handle->id[1] ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } return FAILURE; } void RtApiOss :: closeStream() { if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiOss::closeStream(): no open stream to close!"; error( RtError::WARNING ); return; } OssHandle *handle = (OssHandle *) stream_.apiHandle; stream_.callbackInfo.isRunning = false; MUTEX_LOCK( &stream_.mutex ); if ( stream_.state == STREAM_STOPPED ) pthread_cond_signal( &handle->runnable ); MUTEX_UNLOCK( &stream_.mutex ); pthread_join( stream_.callbackInfo.thread, NULL ); if ( stream_.state == STREAM_RUNNING ) { if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 ); else ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 ); stream_.state = STREAM_STOPPED; } if ( handle ) { pthread_cond_destroy( &handle->runnable ); if ( handle->id[0] ) close( handle->id[0] ); if ( handle->id[1] ) close( handle->id[1] ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } stream_.mode = UNINITIALIZED; stream_.state = STREAM_CLOSED; } void RtApiOss :: startStream() { verifyStream(); if ( stream_.state == STREAM_RUNNING ) { errorText_ = "RtApiOss::startStream(): the stream is already running!"; error( RtError::WARNING ); return; } MUTEX_LOCK( &stream_.mutex ); stream_.state = STREAM_RUNNING; // No need to do anything else here ... OSS automatically starts // when fed samples. MUTEX_UNLOCK( &stream_.mutex ); OssHandle *handle = (OssHandle *) stream_.apiHandle; pthread_cond_signal( &handle->runnable ); } void RtApiOss :: stopStream() { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiOss::stopStream(): the stream is already stopped!"; error( RtError::WARNING ); return; } MUTEX_LOCK( &stream_.mutex ); // The state might change while waiting on a mutex. if ( stream_.state == STREAM_STOPPED ) { MUTEX_UNLOCK( &stream_.mutex ); return; } int result = 0; OssHandle *handle = (OssHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { // Flush the output with zeros a few times. char *buffer; int samples; RtAudioFormat format; if ( stream_.doConvertBuffer[0] ) { buffer = stream_.deviceBuffer; samples = stream_.bufferSize * stream_.nDeviceChannels[0]; format = stream_.deviceFormat[0]; } else { buffer = stream_.userBuffer[0]; samples = stream_.bufferSize * stream_.nUserChannels[0]; format = stream_.userFormat; } memset( buffer, 0, samples * formatBytes(format) ); for ( unsigned int i=0; iid[0], buffer, samples * formatBytes(format) ); if ( result == -1 ) { errorText_ = "RtApiOss::stopStream: audio write error."; error( RtError::WARNING ); } } result = ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 ); if ( result == -1 ) { errorStream_ << "RtApiOss::stopStream: system error stopping callback procedure on device (" << stream_.device[0] << ")."; errorText_ = errorStream_.str(); goto unlock; } handle->triggered = false; } if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && handle->id[0] != handle->id[1] ) ) { result = ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 ); if ( result == -1 ) { errorStream_ << "RtApiOss::stopStream: system error stopping input callback procedure on device (" << stream_.device[0] << ")."; errorText_ = errorStream_.str(); goto unlock; } } unlock: stream_.state = STREAM_STOPPED; MUTEX_UNLOCK( &stream_.mutex ); if ( result != -1 ) return; error( RtError::SYSTEM_ERROR ); } void RtApiOss :: abortStream() { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiOss::abortStream(): the stream is already stopped!"; error( RtError::WARNING ); return; } MUTEX_LOCK( &stream_.mutex ); // The state might change while waiting on a mutex. if ( stream_.state == STREAM_STOPPED ) { MUTEX_UNLOCK( &stream_.mutex ); return; } int result = 0; OssHandle *handle = (OssHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { result = ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 ); if ( result == -1 ) { errorStream_ << "RtApiOss::abortStream: system error stopping callback procedure on device (" << stream_.device[0] << ")."; errorText_ = errorStream_.str(); goto unlock; } handle->triggered = false; } if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && handle->id[0] != handle->id[1] ) ) { result = ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 ); if ( result == -1 ) { errorStream_ << "RtApiOss::abortStream: system error stopping input callback procedure on device (" << stream_.device[0] << ")."; errorText_ = errorStream_.str(); goto unlock; } } unlock: stream_.state = STREAM_STOPPED; MUTEX_UNLOCK( &stream_.mutex ); if ( result != -1 ) return; error( RtError::SYSTEM_ERROR ); } void RtApiOss :: callbackEvent() { OssHandle *handle = (OssHandle *) stream_.apiHandle; if ( stream_.state == STREAM_STOPPED ) { MUTEX_LOCK( &stream_.mutex ); pthread_cond_wait( &handle->runnable, &stream_.mutex ); if ( stream_.state != STREAM_RUNNING ) { MUTEX_UNLOCK( &stream_.mutex ); return; } MUTEX_UNLOCK( &stream_.mutex ); } if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiOss::callbackEvent(): the stream is closed ... this shouldn't happen!"; error( RtError::WARNING ); return; } // Invoke user callback to get fresh output data. int doStopStream = 0; RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback; double streamTime = getStreamTime(); RtAudioStreamStatus status = 0; if ( stream_.mode != INPUT && handle->xrun[0] == true ) { status |= RTAUDIO_OUTPUT_UNDERFLOW; handle->xrun[0] = false; } if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) { status |= RTAUDIO_INPUT_OVERFLOW; handle->xrun[1] = false; } doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1], stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData ); if ( doStopStream == 2 ) { this->abortStream(); return; } MUTEX_LOCK( &stream_.mutex ); // The state might change while waiting on a mutex. if ( stream_.state == STREAM_STOPPED ) goto unlock; int result; char *buffer; int samples; RtAudioFormat format; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { // Setup parameters and do buffer conversion if necessary. if ( stream_.doConvertBuffer[0] ) { buffer = stream_.deviceBuffer; convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] ); samples = stream_.bufferSize * stream_.nDeviceChannels[0]; format = stream_.deviceFormat[0]; } else { buffer = stream_.userBuffer[0]; samples = stream_.bufferSize * stream_.nUserChannels[0]; format = stream_.userFormat; } // Do byte swapping if necessary. if ( stream_.doByteSwap[0] ) byteSwapBuffer( buffer, samples, format ); if ( stream_.mode == DUPLEX && handle->triggered == false ) { int trig = 0; ioctl( handle->id[0], SNDCTL_DSP_SETTRIGGER, &trig ); result = write( handle->id[0], buffer, samples * formatBytes(format) ); trig = PCM_ENABLE_INPUT|PCM_ENABLE_OUTPUT; ioctl( handle->id[0], SNDCTL_DSP_SETTRIGGER, &trig ); handle->triggered = true; } else // Write samples to device. result = write( handle->id[0], buffer, samples * formatBytes(format) ); if ( result == -1 ) { // We'll assume this is an underrun, though there isn't a // specific means for determining that. handle->xrun[0] = true; errorText_ = "RtApiOss::callbackEvent: audio write error."; error( RtError::WARNING ); // Continue on to input section. } } if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { // Setup parameters. if ( stream_.doConvertBuffer[1] ) { buffer = stream_.deviceBuffer; samples = stream_.bufferSize * stream_.nDeviceChannels[1]; format = stream_.deviceFormat[1]; } else { buffer = stream_.userBuffer[1]; samples = stream_.bufferSize * stream_.nUserChannels[1]; format = stream_.userFormat; } // Read samples from device. result = read( handle->id[1], buffer, samples * formatBytes(format) ); if ( result == -1 ) { // We'll assume this is an overrun, though there isn't a // specific means for determining that. handle->xrun[1] = true; errorText_ = "RtApiOss::callbackEvent: audio read error."; error( RtError::WARNING ); goto unlock; } // Do byte swapping if necessary. if ( stream_.doByteSwap[1] ) byteSwapBuffer( buffer, samples, format ); // Do buffer conversion if necessary. if ( stream_.doConvertBuffer[1] ) convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] ); } unlock: MUTEX_UNLOCK( &stream_.mutex ); RtApi::tickStreamTime(); if ( doStopStream == 1 ) this->stopStream(); } extern "C" void *ossCallbackHandler( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiOss *object = (RtApiOss *) info->object; bool *isRunning = &info->isRunning; while ( *isRunning == true ) { pthread_testcancel(); object->callbackEvent(); } pthread_exit( NULL ); } //******************** End of __LINUX_OSS__ *********************// #endif // *************************************************** // // // Protected common (OS-independent) RtAudio methods. // // *************************************************** // // This method can be modified to control the behavior of error // message printing. void RtApi :: error( RtError::Type type ) { errorStream_.str(""); // clear the ostringstream if ( type == RtError::WARNING && showWarnings_ == true ) std::cerr << '\n' << errorText_ << "\n\n"; else if ( type != RtError::WARNING ) throw( RtError( errorText_, type ) ); } void RtApi :: verifyStream() { if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApi:: a stream is not open!"; error( RtError::INVALID_USE ); } } void RtApi :: clearStreamInfo() { stream_.mode = UNINITIALIZED; stream_.state = STREAM_CLOSED; stream_.sampleRate = 0; stream_.bufferSize = 0; stream_.nBuffers = 0; stream_.userFormat = 0; stream_.userInterleaved = true; stream_.streamTime = 0.0; stream_.apiHandle = 0; stream_.deviceBuffer = 0; stream_.callbackInfo.callback = 0; stream_.callbackInfo.userData = 0; stream_.callbackInfo.isRunning = false; for ( int i=0; i<2; i++ ) { stream_.device[i] = 11111; stream_.doConvertBuffer[i] = false; stream_.deviceInterleaved[i] = true; stream_.doByteSwap[i] = false; stream_.nUserChannels[i] = 0; stream_.nDeviceChannels[i] = 0; stream_.channelOffset[i] = 0; stream_.deviceFormat[i] = 0; stream_.latency[i] = 0; stream_.userBuffer[i] = 0; stream_.convertInfo[i].channels = 0; stream_.convertInfo[i].inJump = 0; stream_.convertInfo[i].outJump = 0; stream_.convertInfo[i].inFormat = 0; stream_.convertInfo[i].outFormat = 0; stream_.convertInfo[i].inOffset.clear(); stream_.convertInfo[i].outOffset.clear(); } } unsigned int RtApi :: formatBytes( RtAudioFormat format ) { if ( format == RTAUDIO_SINT16 ) return 2; else if ( format == RTAUDIO_SINT24 || format == RTAUDIO_SINT32 || format == RTAUDIO_FLOAT32 ) return 4; else if ( format == RTAUDIO_FLOAT64 ) return 8; else if ( format == RTAUDIO_SINT8 ) return 1; errorText_ = "RtApi::formatBytes: undefined format."; error( RtError::WARNING ); return 0; } void RtApi :: setConvertInfo( StreamMode mode, unsigned int firstChannel ) { if ( mode == INPUT ) { // convert device to user buffer stream_.convertInfo[mode].inJump = stream_.nDeviceChannels[1]; stream_.convertInfo[mode].outJump = stream_.nUserChannels[1]; stream_.convertInfo[mode].inFormat = stream_.deviceFormat[1]; stream_.convertInfo[mode].outFormat = stream_.userFormat; } else { // convert user to device buffer stream_.convertInfo[mode].inJump = stream_.nUserChannels[0]; stream_.convertInfo[mode].outJump = stream_.nDeviceChannels[0]; stream_.convertInfo[mode].inFormat = stream_.userFormat; stream_.convertInfo[mode].outFormat = stream_.deviceFormat[0]; } if ( stream_.convertInfo[mode].inJump < stream_.convertInfo[mode].outJump ) stream_.convertInfo[mode].channels = stream_.convertInfo[mode].inJump; else stream_.convertInfo[mode].channels = stream_.convertInfo[mode].outJump; // Set up the interleave/deinterleave offsets. if ( stream_.deviceInterleaved[mode] != stream_.userInterleaved ) { if ( ( mode == OUTPUT && stream_.deviceInterleaved[mode] ) || ( mode == INPUT && stream_.userInterleaved ) ) { for ( int k=0; k 0 ) { if ( stream_.deviceInterleaved[mode] ) { if ( mode == OUTPUT ) { for ( int k=0; k>= 8; } in += info.inJump; out += info.outJump; } } else if (info.inFormat == RTAUDIO_FLOAT32) { Float32 *in = (Float32 *)inBuffer; for (unsigned int i=0; i> 8) & 0x0000ffff); } in += info.inJump; out += info.outJump; } } else if (info.inFormat == RTAUDIO_SINT32) { Int32 *in = (Int32 *)inBuffer; for (unsigned int i=0; i> 16) & 0x0000ffff); } in += info.inJump; out += info.outJump; } } else if (info.inFormat == RTAUDIO_FLOAT32) { Float32 *in = (Float32 *)inBuffer; for (unsigned int i=0; i> 8) & 0x00ff); } in += info.inJump; out += info.outJump; } } else if (info.inFormat == RTAUDIO_SINT24) { Int32 *in = (Int32 *)inBuffer; for (unsigned int i=0; i> 16) & 0x000000ff); } in += info.inJump; out += info.outJump; } } else if (info.inFormat == RTAUDIO_SINT32) { Int32 *in = (Int32 *)inBuffer; for (unsigned int i=0; i> 24) & 0x000000ff); } in += info.inJump; out += info.outJump; } } else if (info.inFormat == RTAUDIO_FLOAT32) { Float32 *in = (Float32 *)inBuffer; for (unsigned int i=0; i>8) | (x<<8); } //static inline uint32_t bswap_32(uint32_t x) { return (bswap_16(x&0xffff)<<16) | (bswap_16(x>>16)); } //static inline uint64_t bswap_64(uint64_t x) { return (((unsigned long long)bswap_32(x&0xffffffffull))<<32) | (bswap_32(x>>32)); } void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format ) { register char val; register char *ptr; ptr = buffer; if ( format == RTAUDIO_SINT16 ) { for ( unsigned int i=0; i #include #include #include "RtError.h" /*! \typedef typedef unsigned long RtAudioFormat; \brief RtAudio data format type. Support for signed integers and floats. Audio data fed to/from an RtAudio stream is assumed to ALWAYS be in host byte order. The internal routines will automatically take care of any necessary byte-swapping between the host format and the soundcard. Thus, endian-ness is not a concern in the following format definitions. Note that 24-bit data is expected to be encapsulated in a 32-bit format. - \e RTAUDIO_SINT8: 8-bit signed integer. - \e RTAUDIO_SINT16: 16-bit signed integer. - \e RTAUDIO_SINT24: Lower 3 bytes of 32-bit signed integer. - \e RTAUDIO_SINT32: 32-bit signed integer. - \e RTAUDIO_FLOAT32: Normalized between plus/minus 1.0. - \e RTAUDIO_FLOAT64: Normalized between plus/minus 1.0. */ typedef unsigned long RtAudioFormat; static const RtAudioFormat RTAUDIO_SINT8 = 0x1; // 8-bit signed integer. static const RtAudioFormat RTAUDIO_SINT16 = 0x2; // 16-bit signed integer. static const RtAudioFormat RTAUDIO_SINT24 = 0x4; // Lower 3 bytes of 32-bit signed integer. static const RtAudioFormat RTAUDIO_SINT32 = 0x8; // 32-bit signed integer. static const RtAudioFormat RTAUDIO_FLOAT32 = 0x10; // Normalized between plus/minus 1.0. static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/minus 1.0. /*! \typedef typedef unsigned long RtAudioStreamFlags; \brief RtAudio stream option flags. The following flags can be OR'ed together to allow a client to make changes to the default stream behavior: - \e RTAUDIO_NONINTERLEAVED: Use non-interleaved buffers (default = interleaved). - \e RTAUDIO_MINIMIZE_LATENCY: Attempt to set stream parameters for lowest possible latency. - \e RTAUDIO_HOG_DEVICE: Attempt grab device for exclusive use. - \e RTAUDIO_ALSA_USE_DEFAULT: Use the "default" PCM device (ALSA only). By default, RtAudio streams pass and receive audio data from the client in an interleaved format. By passing the RTAUDIO_NONINTERLEAVED flag to the openStream() function, audio data will instead be presented in non-interleaved buffers. In this case, each buffer argument in the RtAudioCallback function will point to a single array of data, with \c nFrames samples for each channel concatenated back-to-back. For example, the first sample of data for the second channel would be located at index \c nFrames (assuming the \c buffer pointer was recast to the correct data type for the stream). Certain audio APIs offer a number of parameters that influence the I/O latency of a stream. By default, RtAudio will attempt to set these parameters internally for robust (glitch-free) performance (though some APIs, like Windows Direct Sound, make this difficult). By passing the RTAUDIO_MINIMIZE_LATENCY flag to the openStream() function, internal stream settings will be influenced in an attempt to minimize stream latency, though possibly at the expense of stream performance. If the RTAUDIO_HOG_DEVICE flag is set, RtAudio will attempt to open the input and/or output stream device(s) for exclusive use. Note that this is not possible with all supported audio APIs. If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt to select realtime scheduling (round-robin) for the callback thread. If the RTAUDIO_ALSA_USE_DEFAULT flag is set, RtAudio will attempt to open the "default" PCM device when using the ALSA API. Note that this will override any specified input or output device id. */ typedef unsigned int RtAudioStreamFlags; static const RtAudioStreamFlags RTAUDIO_NONINTERLEAVED = 0x1; // Use non-interleaved buffers (default = interleaved). static const RtAudioStreamFlags RTAUDIO_MINIMIZE_LATENCY = 0x2; // Attempt to set stream parameters for lowest possible latency. static const RtAudioStreamFlags RTAUDIO_HOG_DEVICE = 0x4; // Attempt grab device and prevent use by others. static const RtAudioStreamFlags RTAUDIO_SCHEDULE_REALTIME = 0x8; // Try to select realtime scheduling for callback thread. static const RtAudioStreamFlags RTAUDIO_ALSA_USE_DEFAULT = 0x10; // Use the "default" PCM device (ALSA only). /*! \typedef typedef unsigned long RtAudioStreamStatus; \brief RtAudio stream status (over- or underflow) flags. Notification of a stream over- or underflow is indicated by a non-zero stream \c status argument in the RtAudioCallback function. The stream status can be one of the following two options, depending on whether the stream is open for output and/or input: - \e RTAUDIO_INPUT_OVERFLOW: Input data was discarded because of an overflow condition at the driver. - \e RTAUDIO_OUTPUT_UNDERFLOW: The output buffer ran low, likely producing a break in the output sound. */ typedef unsigned int RtAudioStreamStatus; static const RtAudioStreamStatus RTAUDIO_INPUT_OVERFLOW = 0x1; // Input data was discarded because of an overflow condition at the driver. static const RtAudioStreamStatus RTAUDIO_OUTPUT_UNDERFLOW = 0x2; // The output buffer ran low, likely causing a gap in the output sound. //! RtAudio callback function prototype. /*! All RtAudio clients must create a function of type RtAudioCallback to read and/or write data from/to the audio stream. When the underlying audio system is ready for new input or output data, this function will be invoked. \param outputBuffer For output (or duplex) streams, the client should write \c nFrames of audio sample frames into this buffer. This argument should be recast to the datatype specified when the stream was opened. For input-only streams, this argument will be NULL. \param inputBuffer For input (or duplex) streams, this buffer will hold \c nFrames of input audio sample frames. This argument should be recast to the datatype specified when the stream was opened. For output-only streams, this argument will be NULL. \param nFrames The number of sample frames of input or output data in the buffers. The actual buffer size in bytes is dependent on the data type and number of channels in use. \param streamTime The number of seconds that have elapsed since the stream was started. \param status If non-zero, this argument indicates a data overflow or underflow condition for the stream. The particular condition can be determined by comparison with the RtAudioStreamStatus flags. \param userData A pointer to optional data provided by the client when opening the stream (default = NULL). To continue normal stream operation, the RtAudioCallback function should return a value of zero. To stop the stream and drain the output buffer, the function should return a value of one. To abort the stream immediately, the client should return a value of two. */ typedef int (*RtAudioCallback)( void *outputBuffer, void *inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void *userData ); // **************************************************************** // // // RtAudio class declaration. // // RtAudio is a "controller" used to select an available audio i/o // interface. It presents a common API for the user to call but all // functionality is implemented by the class RtApi and its // subclasses. RtAudio creates an instance of an RtApi subclass // based on the user's API choice. If no choice is made, RtAudio // attempts to make a "logical" API selection. // // **************************************************************** // class RtApi; class RtAudio { public: //! Audio API specifier arguments. enum Api { UNSPECIFIED, /*!< Search for a working compiled API. */ LINUX_ALSA, /*!< The Advanced Linux Sound Architecture API. */ LINUX_OSS, /*!< The Linux Open Sound System API. */ UNIX_JACK, /*!< The Jack Low-Latency Audio Server API. */ MACOSX_CORE, /*!< Macintosh OS-X Core Audio API. */ WINDOWS_ASIO, /*!< The Steinberg Audio Stream I/O API. */ WINDOWS_DS, /*!< The Microsoft Direct Sound API. */ RTAUDIO_DUMMY /*!< A compilable but non-functional API. */ }; //! The public device information structure for returning queried values. struct DeviceInfo { bool probed; /*!< true if the device capabilities were successfully probed. */ std::string name; /*!< Character string device identifier. */ unsigned int outputChannels; /*!< Maximum output channels supported by device. */ unsigned int inputChannels; /*!< Maximum input channels supported by device. */ unsigned int duplexChannels; /*!< Maximum simultaneous input/output channels supported by device. */ bool isDefaultOutput; /*!< true if this is the default output device. */ bool isDefaultInput; /*!< true if this is the default input device. */ std::vector sampleRates; /*!< Supported sample rates (queried from list of standard rates). */ RtAudioFormat nativeFormats; /*!< Bit mask of supported data formats. */ // Default constructor. DeviceInfo() :probed(false), outputChannels(0), inputChannels(0), duplexChannels(0), isDefaultOutput(false), isDefaultInput(false), nativeFormats(0) {} }; //! The structure for specifying input or ouput stream parameters. struct StreamParameters { unsigned int deviceId; /*!< Device index (0 to getDeviceCount() - 1). */ unsigned int nChannels; /*!< Number of channels. */ unsigned int firstChannel; /*!< First channel index on device (default = 0). */ std::string deviceName; /*!< Device name to use instead of using deviceId (ALSA, JACK). */ // Default constructor. StreamParameters() : deviceId(0), nChannels(0), firstChannel(0) {} }; //! The structure for specifying stream options. /*! The following flags can be OR'ed together to allow a client to make changes to the default stream behavior: - \e RTAUDIO_NONINTERLEAVED: Use non-interleaved buffers (default = interleaved). - \e RTAUDIO_MINIMIZE_LATENCY: Attempt to set stream parameters for lowest possible latency. - \e RTAUDIO_HOG_DEVICE: Attempt grab device for exclusive use. - \e RTAUDIO_SCHEDULE_REALTIME: Attempt to select realtime scheduling for callback thread. - \e RTAUDIO_ALSA_USE_DEFAULT: Use the "default" PCM device (ALSA only). By default, RtAudio streams pass and receive audio data from the client in an interleaved format. By passing the RTAUDIO_NONINTERLEAVED flag to the openStream() function, audio data will instead be presented in non-interleaved buffers. In this case, each buffer argument in the RtAudioCallback function will point to a single array of data, with \c nFrames samples for each channel concatenated back-to-back. For example, the first sample of data for the second channel would be located at index \c nFrames (assuming the \c buffer pointer was recast to the correct data type for the stream). Certain audio APIs offer a number of parameters that influence the I/O latency of a stream. By default, RtAudio will attempt to set these parameters internally for robust (glitch-free) performance (though some APIs, like Windows Direct Sound, make this difficult). By passing the RTAUDIO_MINIMIZE_LATENCY flag to the openStream() function, internal stream settings will be influenced in an attempt to minimize stream latency, though possibly at the expense of stream performance. If the RTAUDIO_HOG_DEVICE flag is set, RtAudio will attempt to open the input and/or output stream device(s) for exclusive use. Note that this is not possible with all supported audio APIs. If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt to select realtime scheduling (round-robin) for the callback thread. The \c priority parameter will only be used if the RTAUDIO_SCHEDULE_REALTIME flag is set. It defines the thread's realtime priority. If the RTAUDIO_ALSA_USE_DEFAULT flag is set, RtAudio will attempt to open the "default" PCM device when using the ALSA API. Note that this will override any specified input or output device id. The \c numberOfBuffers parameter can be used to control stream latency in the Windows DirectSound, Linux OSS, and Linux Alsa APIs only. A value of two is usually the smallest allowed. Larger numbers can potentially result in more robust stream performance, though likely at the cost of stream latency. The value set by the user is replaced during execution of the RtAudio::openStream() function by the value actually used by the system. The \c streamName parameter can be used to set the client name when using the Jack API. By default, the client name is set to RtApiJack. However, if you wish to create multiple instances of RtAudio with Jack, each instance must have a unique client name. */ struct StreamOptions { RtAudioStreamFlags flags; /*!< A bit-mask of stream flags (RTAUDIO_NONINTERLEAVED, RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE, RTAUDIO_ALSA_USE_DEFAULT). */ unsigned int numberOfBuffers; /*!< Number of stream buffers. */ std::string streamName; /*!< A stream name (currently used only in Jack). */ int priority; /*!< Scheduling priority of callback thread (only used with flag RTAUDIO_SCHEDULE_REALTIME). */ // Default constructor. StreamOptions() : flags(0), numberOfBuffers(0), priority(0) {} }; //! A static function to determine the available compiled audio APIs. /*! The values returned in the std::vector can be compared against the enumerated list values. Note that there can be more than one API compiled for certain operating systems. */ static void getCompiledApi( std::vector &apis ) throw(); //! The class constructor. /*! The constructor performs minor initialization tasks. No exceptions can be thrown. If no API argument is specified and multiple API support has been compiled, the default order of use is JACK, ALSA, OSS (Linux systems) and ASIO, DS (Windows systems). */ RtAudio( RtAudio::Api api=UNSPECIFIED ) throw(); //! The destructor. /*! If a stream is running or open, it will be stopped and closed automatically. */ ~RtAudio() throw(); //! Returns the audio API specifier for the current instance of RtAudio. RtAudio::Api getCurrentApi( void ) throw(); //! A public function that queries for the number of audio devices available. /*! This function performs a system query of available devices each time it is called, thus supporting devices connected \e after instantiation. If a system error occurs during processing, a warning will be issued. */ unsigned int getDeviceCount( void ) throw(); //! Return an RtAudio::DeviceInfo structure for a specified device number. /*! Any device integer between 0 and getDeviceCount() - 1 is valid. If an invalid argument is provided, an RtError (type = INVALID_USE) will be thrown. If a device is busy or otherwise unavailable, the structure member "probed" will have a value of "false" and all other members are undefined. If the specified device is the current default input or output device, the corresponding "isDefault" member will have a value of "true". */ RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); //! A function that returns the index of the default output device. /*! If the underlying audio API does not provide a "default device", or if no devices are available, the return value will be 0. Note that this is a valid device identifier and it is the client's responsibility to verify that a device is available before attempting to open a stream. */ unsigned int getDefaultOutputDevice( void ) throw(); //! A function that returns the index of the default input device. /*! If the underlying audio API does not provide a "default device", or if no devices are available, the return value will be 0. Note that this is a valid device identifier and it is the client's responsibility to verify that a device is available before attempting to open a stream. */ unsigned int getDefaultInputDevice( void ) throw(); //! A public function for opening a stream with the specified parameters. /*! An RtError (type = SYSTEM_ERROR) is thrown if a stream cannot be opened with the specified parameters or an error occurs during processing. An RtError (type = INVALID_USE) is thrown if any invalid device ID or channel number parameters are specified. \param outputParameters Specifies output stream parameters to use when opening a stream, including a device ID, number of channels, and starting channel number. For input-only streams, this argument should be NULL. The device ID is an index value between 0 and getDeviceCount() - 1. \param inputParameters Specifies input stream parameters to use when opening a stream, including a device ID, number of channels, and starting channel number. For output-only streams, this argument should be NULL. The device ID is an index value between 0 and getDeviceCount() - 1. \param format An RtAudioFormat specifying the desired sample data format. \param sampleRate The desired sample rate (sample frames per second). \param *bufferFrames A pointer to a value indicating the desired internal buffer size in sample frames. The actual value used by the device is returned via the same pointer. A value of zero can be specified, in which case the lowest allowable value is determined. \param callback A client-defined function that will be invoked when input data is available and/or output data is needed. \param userData An optional pointer to data that can be accessed from within the callback function. \param options An optional pointer to a structure containing various global stream options, including a list of OR'ed RtAudioStreamFlags and a suggested number of stream buffers that can be used to control stream latency. More buffers typically result in more robust performance, though at a cost of greater latency. If a value of zero is specified, a system-specific median value is chosen. If the RTAUDIO_MINIMIZE_LATENCY flag bit is set, the lowest allowable value is used. The actual value used is returned via the structure argument. The parameter is API dependent. */ void openStream( RtAudio::StreamParameters *outputParameters, RtAudio::StreamParameters *inputParameters, RtAudioFormat format, unsigned int sampleRate, unsigned int *bufferFrames, RtAudioCallback callback, void *userData = NULL, RtAudio::StreamOptions *options = NULL ); //! A function that closes a stream and frees any associated stream memory. /*! If a stream is not open, this function issues a warning and returns (no exception is thrown). */ void closeStream( void ) throw(); //! A function that starts a stream. /*! An RtError (type = SYSTEM_ERROR) is thrown if an error occurs during processing. An RtError (type = INVALID_USE) is thrown if a stream is not open. A warning is issued if the stream is already running. */ void startStream( void ); //! Stop a stream, allowing any samples remaining in the output queue to be played. /*! An RtError (type = SYSTEM_ERROR) is thrown if an error occurs during processing. An RtError (type = INVALID_USE) is thrown if a stream is not open. A warning is issued if the stream is already stopped. */ void stopStream( void ); //! Stop a stream, discarding any samples remaining in the input/output queue. /*! An RtError (type = SYSTEM_ERROR) is thrown if an error occurs during processing. An RtError (type = INVALID_USE) is thrown if a stream is not open. A warning is issued if the stream is already stopped. */ void abortStream( void ); //! Returns true if a stream is open and false if not. bool isStreamOpen( void ) const throw(); //! Returns true if the stream is running and false if it is stopped or not open. bool isStreamRunning( void ) const throw(); //! Returns the number of elapsed seconds since the stream was started. /*! If a stream is not open, an RtError (type = INVALID_USE) will be thrown. */ double getStreamTime( void ); //! Returns the internal stream latency in sample frames. /*! The stream latency refers to delay in audio input and/or output caused by internal buffering by the audio system and/or hardware. For duplex streams, the returned value will represent the sum of the input and output latencies. If a stream is not open, an RtError (type = INVALID_USE) will be thrown. If the API does not report latency, the return value will be zero. */ long getStreamLatency( void ); //! Returns actual sample rate in use by the stream. /*! On some systems, the sample rate used may be slightly different than that specified in the stream parameters. If a stream is not open, an RtError (type = INVALID_USE) will be thrown. */ unsigned int getStreamSampleRate( void ); //! Specify whether warning messages should be printed to stderr. void showWarnings( bool value = true ) throw(); protected: void openRtApi( RtAudio::Api api ); RtApi *rtapi_; }; // Operating system dependent thread functionality. #if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) #include #include typedef unsigned long ThreadHandle; typedef CRITICAL_SECTION StreamMutex; #elif defined(__LINUX_ALSA__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__) // Using pthread library for various flavors of unix. #include typedef pthread_t ThreadHandle; typedef pthread_mutex_t StreamMutex; #else // Setup for "dummy" behavior #define __RTAUDIO_DUMMY__ typedef int ThreadHandle; typedef int StreamMutex; #endif // This global structure type is used to pass callback information // between the private RtAudio stream structure and global callback // handling functions. struct CallbackInfo { void *object; // Used as a "this" pointer. ThreadHandle thread; void *callback; void *userData; void *apiInfo; // void pointer for API specific callback information bool isRunning; // Default constructor. CallbackInfo() :object(0), thread(0), callback(0), userData(0), apiInfo(0), isRunning(false) {} }; // **************************************************************** // // // RtApi class declaration. // // Subclasses of RtApi contain all API- and OS-specific code necessary // to fully implement the RtAudio API. // // Note that RtApi is an abstract base class and cannot be // explicitly instantiated. The class RtAudio will create an // instance of an RtApi subclass (RtApiOss, RtApiAlsa, // RtApiJack, RtApiCore, RtApiAl, RtApiDs, or RtApiAsio). // // **************************************************************** // #if defined( HAVE_GETTIMEOFDAY ) #include #endif #include class RtApi { public: RtApi(); virtual ~RtApi(); virtual RtAudio::Api getCurrentApi( void ) = 0; virtual unsigned int getDeviceCount( void ) = 0; virtual RtAudio::DeviceInfo getDeviceInfo( unsigned int device ) = 0; virtual unsigned int getDefaultInputDevice( void ); virtual unsigned int getDefaultOutputDevice( void ); void openStream( RtAudio::StreamParameters *outputParameters, RtAudio::StreamParameters *inputParameters, RtAudioFormat format, unsigned int sampleRate, unsigned int *bufferFrames, RtAudioCallback callback, void *userData, RtAudio::StreamOptions *options ); virtual void closeStream( void ); virtual void startStream( void ) = 0; virtual void stopStream( void ) = 0; virtual void abortStream( void ) = 0; long getStreamLatency( void ); unsigned int getStreamSampleRate( void ); virtual double getStreamTime( void ); bool isStreamOpen( void ) const { return stream_.state != STREAM_CLOSED; }; bool isStreamRunning( void ) const { return stream_.state == STREAM_RUNNING; }; void showWarnings( bool value ) { showWarnings_ = value; }; protected: static const unsigned int MAX_SAMPLE_RATES; static const unsigned int SAMPLE_RATES[]; enum { FAILURE, SUCCESS }; enum StreamState { STREAM_STOPPED, STREAM_RUNNING, STREAM_CLOSED = -50 }; enum StreamMode { OUTPUT, INPUT, DUPLEX, UNINITIALIZED = -75 }; // A protected structure used for buffer conversion. struct ConvertInfo { int channels; int inJump, outJump; RtAudioFormat inFormat, outFormat; std::vector inOffset; std::vector outOffset; }; // A protected structure for audio streams. struct RtApiStream { unsigned int device[2]; // Playback and record, respectively. void *apiHandle; // void pointer for API specific stream handle information StreamMode mode; // OUTPUT, INPUT, or DUPLEX. StreamState state; // STOPPED, RUNNING, or CLOSED char *userBuffer[2]; // Playback and record, respectively. char *deviceBuffer; bool doConvertBuffer[2]; // Playback and record, respectively. bool userInterleaved; bool deviceInterleaved[2]; // Playback and record, respectively. bool doByteSwap[2]; // Playback and record, respectively. unsigned int sampleRate; unsigned int bufferSize; unsigned int nBuffers; unsigned int nUserChannels[2]; // Playback and record, respectively. unsigned int nDeviceChannels[2]; // Playback and record channels, respectively. unsigned int channelOffset[2]; // Playback and record, respectively. unsigned long latency[2]; // Playback and record, respectively. RtAudioFormat userFormat; RtAudioFormat deviceFormat[2]; // Playback and record, respectively. StreamMutex mutex; CallbackInfo callbackInfo; ConvertInfo convertInfo[2]; double streamTime; // Number of elapsed seconds since the stream started. #if defined(HAVE_GETTIMEOFDAY) struct timeval lastTickTimestamp; #endif RtApiStream() :apiHandle(0), mode(OUTPUT), state(STREAM_STOPPED), deviceBuffer(0), userInterleaved(0), sampleRate(0), bufferSize(0), nBuffers(0), streamTime(0) { device[0] = 11111; device[1] = 11111; memset( &channelOffset, 0, sizeof( channelOffset ) ); memset( &deviceFormat, 0, sizeof( deviceFormat ) ); memset( &deviceInterleaved, 0, sizeof( deviceInterleaved ) ); memset( &doByteSwap, 0, sizeof( doByteSwap ) ); memset( &doConvertBuffer, 0, sizeof( doConvertBuffer ) ); memset( &latency, 0, sizeof( latency ) ); memset( &nDeviceChannels, 0, sizeof( nDeviceChannels ) ); memset( &nUserChannels, 0, sizeof( nUserChannels ) ); memset( &userBuffer, 0, sizeof( userBuffer ) ); memset( &userFormat, 0, sizeof( userFormat ) ); } }; typedef signed short Int16; typedef signed int Int32; typedef float Float32; typedef double Float64; std::ostringstream errorStream_; std::string errorText_; bool showWarnings_; RtApiStream stream_; /*! Protected, api-specific method that attempts to open a device with the given parameters. This function MUST be implemented by all subclasses. If an error is encountered during the probe, a "warning" message is reported and FAILURE is returned. A successful probe is indicated by a return value of SUCCESS. */ virtual bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options, const std::string &deviceName ); //! A protected function used to increment the stream time. void tickStreamTime( void ); //! Protected common method to clear an RtApiStream structure. void clearStreamInfo(); /*! Protected common method that throws an RtError (type = INVALID_USE) if a stream is not open. */ void verifyStream( void ); //! Protected common error method to allow global control over error handling. void error( RtError::Type type ); /*! Protected method used to perform format, channel number, and/or interleaving conversions between the user and device buffers. */ void convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info ); //! Protected common method used to perform byte-swapping on buffers. void byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format ); //! Protected common method that returns the number of bytes for a given format. unsigned int formatBytes( RtAudioFormat format ); //! Protected common method that sets up the parameters for buffer conversion. void setConvertInfo( StreamMode mode, unsigned int firstChannel ); }; // **************************************************************** // // // Inline RtAudio definitions. // // **************************************************************** // inline RtAudio::Api RtAudio :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); } inline unsigned int RtAudio :: getDeviceCount( void ) throw() { return rtapi_->getDeviceCount(); } inline RtAudio::DeviceInfo RtAudio :: getDeviceInfo( unsigned int device ) { return rtapi_->getDeviceInfo( device ); } inline unsigned int RtAudio :: getDefaultInputDevice( void ) throw() { return rtapi_->getDefaultInputDevice(); } inline unsigned int RtAudio :: getDefaultOutputDevice( void ) throw() { return rtapi_->getDefaultOutputDevice(); } inline void RtAudio :: closeStream( void ) throw() { return rtapi_->closeStream(); } inline void RtAudio :: startStream( void ) { return rtapi_->startStream(); } inline void RtAudio :: stopStream( void ) { return rtapi_->stopStream(); } inline void RtAudio :: abortStream( void ) { return rtapi_->abortStream(); } inline bool RtAudio :: isStreamOpen( void ) const throw() { return rtapi_->isStreamOpen(); } inline bool RtAudio :: isStreamRunning( void ) const throw() { return rtapi_->isStreamRunning(); } inline long RtAudio :: getStreamLatency( void ) { return rtapi_->getStreamLatency(); } inline unsigned int RtAudio :: getStreamSampleRate( void ) { return rtapi_->getStreamSampleRate(); }; inline double RtAudio :: getStreamTime( void ) { return rtapi_->getStreamTime(); } inline void RtAudio :: showWarnings( bool value ) throw() { rtapi_->showWarnings( value ); } // RtApi Subclass prototypes. #if defined(__MACOSX_CORE__) #include class RtApiCore: public RtApi { public: RtApiCore(); ~RtApiCore(); RtAudio::Api getCurrentApi( void ) { return RtAudio::MACOSX_CORE; }; unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); unsigned int getDefaultOutputDevice( void ); unsigned int getDefaultInputDevice( void ); void closeStream( void ); void startStream( void ); void stopStream( void ); void abortStream( void ); long getStreamLatency( void ); // This function is intended for internal use only. It must be // public because it is called by the internal callback handler, // which is not a member of RtAudio. External use of this function // will most likely produce highly undesireable results! bool callbackEvent( AudioDeviceID deviceId, const AudioBufferList *inBufferList, const AudioBufferList *outBufferList ); private: bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options, const std::string &deviceName ); static const char* getErrorCode( OSStatus code ); }; #endif #if defined(__UNIX_JACK__) class RtApiJack: public RtApi { public: RtApiJack(); ~RtApiJack(); RtAudio::Api getCurrentApi( void ) { return RtAudio::UNIX_JACK; }; unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); void startStream( void ); void stopStream( void ); void abortStream( void ); long getStreamLatency( void ); // This function is intended for internal use only. It must be // public because it is called by the internal callback handler, // which is not a member of RtAudio. External use of this function // will most likely produce highly undesireable results! bool callbackEvent( unsigned long nframes ); private: bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options, const std::string &deviceName ); }; #endif #if defined(__WINDOWS_ASIO__) class RtApiAsio: public RtApi { public: RtApiAsio(); ~RtApiAsio(); RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_ASIO; }; unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); void startStream( void ); void stopStream( void ); void abortStream( void ); long getStreamLatency( void ); // This function is intended for internal use only. It must be // public because it is called by the internal callback handler, // which is not a member of RtAudio. External use of this function // will most likely produce highly undesireable results! bool callbackEvent( long bufferIndex ); private: std::vector devices_; void saveDeviceInfo( void ); bool coInitialized_; bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options, const std::string &deviceName ); }; #endif #if defined(__WINDOWS_DS__) class RtApiDs: public RtApi { public: RtApiDs(); ~RtApiDs(); RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_DS; }; unsigned int getDeviceCount( void ); unsigned int getDefaultOutputDevice( void ); unsigned int getDefaultInputDevice( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); void startStream( void ); void stopStream( void ); void abortStream( void ); long getStreamLatency( void ); // This function is intended for internal use only. It must be // public because it is called by the internal callback handler, // which is not a member of RtAudio. External use of this function // will most likely produce highly undesireable results! void callbackEvent( void ); private: bool coInitialized_; bool buffersRolling; long duplexPrerollBytes; bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options, const std::string &deviceName ); }; #endif #if defined(__LINUX_ALSA__) class RtApiAlsa: public RtApi { public: RtApiAlsa(); ~RtApiAlsa(); RtAudio::Api getCurrentApi() { return RtAudio::LINUX_ALSA; }; unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); void startStream( void ); void stopStream( void ); void abortStream( void ); // This function is intended for internal use only. It must be // public because it is called by the internal callback handler, // which is not a member of RtAudio. External use of this function // will most likely produce highly undesireable results! void callbackEvent( void ); private: std::vector devices_; void saveDeviceInfo( void ); bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options, const std::string &deviceName ); }; #endif #if defined(__LINUX_OSS__) class RtApiOss: public RtApi { public: RtApiOss(); ~RtApiOss(); RtAudio::Api getCurrentApi() { return RtAudio::LINUX_OSS; }; unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); void startStream( void ); void stopStream( void ); void abortStream( void ); // This function is intended for internal use only. It must be // public because it is called by the internal callback handler, // which is not a member of RtAudio. External use of this function // will most likely produce highly undesireable results! void callbackEvent( void ); private: bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options, const std::string &deviceName ); }; #endif #if defined(__RTAUDIO_DUMMY__) class RtApiDummy: public RtApi { public: RtApiDummy() { errorText_ = "RtApiDummy: This class provides no functionality."; error( RtError::WARNING ); }; RtAudio::Api getCurrentApi( void ) { return RtAudio::RTAUDIO_DUMMY; }; unsigned int getDeviceCount( void ) { return 0; }; RtAudio::DeviceInfo getDeviceInfo( unsigned int device ) { RtAudio::DeviceInfo info; return info; }; void closeStream( void ) {}; void startStream( void ) {}; void stopStream( void ) {}; void abortStream( void ) {}; private: bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options, const std::string &deviceName ) { return false; }; }; #endif #endif // Indentation settings for Vim and Emacs // // Local Variables: // c-basic-offset: 2 // indent-tabs-mode: nil // End: // // vim: et sts=2 sw=2 mlt-0.9.0/src/modules/rtaudio/RtError.h000066400000000000000000000041301215300731300177630ustar00rootroot00000000000000/************************************************************************/ /*! \class RtError \brief Exception handling class for RtAudio & RtMidi. The RtError class is quite simple but it does allow errors to be "caught" by RtError::Type. See the RtAudio and RtMidi documentation to know which methods can throw an RtError. */ /************************************************************************/ #ifndef RTERROR_H #define RTERROR_H #include #include #include class RtError : public std::exception { public: //! Defined RtError types. enum Type { WARNING, /*!< A non-critical error. */ DEBUG_WARNING, /*!< A non-critical error which might be useful for debugging. */ UNSPECIFIED, /*!< The default, unspecified error type. */ NO_DEVICES_FOUND, /*!< No devices found on system. */ INVALID_DEVICE, /*!< An invalid device ID was specified. */ MEMORY_ERROR, /*!< An error occured during memory allocation. */ INVALID_PARAMETER, /*!< An invalid parameter was specified to a function. */ INVALID_USE, /*!< The function was called incorrectly. */ DRIVER_ERROR, /*!< A system driver error occured. */ SYSTEM_ERROR, /*!< A system error occured. */ THREAD_ERROR /*!< A thread error occured. */ }; //! The constructor. RtError( const std::string& message, Type type = RtError::UNSPECIFIED ) throw() : message_(message), type_(type) {} //! The destructor. virtual ~RtError( void ) throw() {} //! Prints thrown error message to stderr. virtual void printMessage( void ) const throw() { std::cerr << '\n' << message_ << "\n\n"; } //! Returns the thrown error message type. virtual const Type& getType(void) const throw() { return type_; } //! Returns the thrown error message string. virtual const std::string& getMessage(void) const throw() { return message_; } //! Returns the thrown error message as a c-style string. virtual const char* what( void ) const throw() { return message_.c_str(); } protected: std::string message_; Type type_; }; #endif mlt-0.9.0/src/modules/rtaudio/configure000077500000000000000000000003611215300731300201240ustar00rootroot00000000000000#!/bin/sh if [ "$help" != "1" ] then if [ "$targetos" != "Darwin" ] && [ "$targetos" != "MinGW" ] && [ "$targetos" != "Linux" ] then echo "- only builds on Linux, OS X, or Windows: disabling" touch ../disable-rtaudio exit 0 fi fi mlt-0.9.0/src/modules/rtaudio/consumer_rtaudio.cpp000066400000000000000000000457351215300731300223210ustar00rootroot00000000000000/* * consumer_rtaudio.c -- output through RtAudio audio wrapper * Copyright (C) 2011 Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 consumer library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include "RtAudio.h" static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer consumer, char *name ); static int rtaudio_callback( void *outputBuffer, void *inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void *userData ); static void *consumer_thread_proxy( void *arg ); static void *video_thread_proxy( void *arg ); class RtAudioConsumer { public: struct mlt_consumer_s consumer; RtAudio rt; int device_id; mlt_deque queue; pthread_t thread; int joined; int running; uint8_t audio_buffer[4096 * 10]; int audio_avail; pthread_mutex_t audio_mutex; pthread_cond_t audio_cond; pthread_mutex_t video_mutex; pthread_cond_t video_cond; int playing; pthread_cond_t refresh_cond; pthread_mutex_t refresh_mutex; int refresh_count; bool is_purge; mlt_consumer getConsumer() { return &consumer; } RtAudioConsumer() : device_id(-1) , queue(NULL) , joined(0) , running(0) , audio_avail(0) , playing(0) , refresh_count(0) , is_purge(false) { memset( &consumer, 0, sizeof( consumer ) ); } ~RtAudioConsumer() { // Close the queue mlt_deque_close( queue ); // Destroy mutexes pthread_mutex_destroy( &audio_mutex ); pthread_cond_destroy( &audio_cond ); pthread_mutex_destroy( &video_mutex ); pthread_cond_destroy( &video_cond ); pthread_mutex_destroy( &refresh_mutex ); pthread_cond_destroy( &refresh_cond ); if ( rt.isStreamOpen() ) rt.closeStream(); } bool open( const char* arg ) { if ( rt.getDeviceCount() < 1 ) { mlt_log_warning( getConsumer(), "no audio devices found\n" ); return false; } #ifndef __LINUX_ALSA__ device_id = rt.getDefaultOutputDevice(); #endif if ( arg && strcmp( arg, "" ) && strcmp( arg, "default" ) ) { // Get device ID by name unsigned int n = rt.getDeviceCount(); RtAudio::DeviceInfo info; unsigned int i; for ( i = 0; i < n; i++ ) { info = rt.getDeviceInfo( i ); mlt_log_verbose( NULL, "RtAudio device %d = %s\n", i, info.name.c_str() ); if ( info.probed && info.name == arg ) { device_id = i; break; } } // Name selection failed, try arg as numeric if ( i == n ) device_id = (int) strtol( arg, NULL, 0 ); } // Create the queue queue = mlt_deque_init( ); // get a handle on properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( &consumer ); // Set the default volume mlt_properties_set_double( properties, "volume", 1.0 ); // This is the initialisation of the consumer pthread_mutex_init( &audio_mutex, NULL ); pthread_cond_init( &audio_cond, NULL); pthread_mutex_init( &video_mutex, NULL ); pthread_cond_init( &video_cond, NULL); // Default scaler (for now we'll use nearest) mlt_properties_set( properties, "rescale", "nearest" ); mlt_properties_set( properties, "deinterlace_method", "onefield" ); // Default buffer for low latency mlt_properties_set_int( properties, "buffer", 1 ); // Default audio buffer mlt_properties_set_int( properties, "audio_buffer", 1024 ); // Set the resource to the device name arg mlt_properties_set( properties, "resource", arg ); // Ensure we don't join on a non-running object joined = 1; // Initialize the refresh handler pthread_cond_init( &refresh_cond, NULL ); pthread_mutex_init( &refresh_mutex, NULL ); mlt_events_listen( properties, this, "property-changed", ( mlt_listener )consumer_refresh_cb ); return true; } int start() { if ( !running ) { stop(); running = 1; joined = 0; pthread_create( &thread, NULL, consumer_thread_proxy, this ); } return 0; } int stop() { if ( running && !joined ) { // Kill the thread and clean up joined = 1; running = 0; // Unlatch the consumer thread pthread_mutex_lock( &refresh_mutex ); pthread_cond_broadcast( &refresh_cond ); pthread_mutex_unlock( &refresh_mutex ); // Cleanup the main thread pthread_join( thread, NULL ); // Unlatch the video thread pthread_mutex_lock( &video_mutex ); pthread_cond_broadcast( &video_cond ); pthread_mutex_unlock( &video_mutex ); // Unlatch the audio callback pthread_mutex_lock( &audio_mutex ); pthread_cond_broadcast( &audio_cond ); pthread_mutex_unlock( &audio_mutex ); if ( rt.isStreamOpen() ) try { // Stop the stream rt.stopStream(); } catch ( RtError& e ) { mlt_log_error( getConsumer(), "%s\n", e.getMessage().c_str() ); } } return 0; } void purge() { if ( running ) { pthread_mutex_lock( &video_mutex ); mlt_frame frame = MLT_FRAME( mlt_deque_peek_back( queue ) ); // When playing rewind or fast forward then we need to keep one // frame in the queue to prevent playback stalling. double speed = frame? mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame), "_speed" ) : 0; int n = ( speed == 0.0 || speed == 1.0 ) ? 0 : 1; while ( mlt_deque_count( queue ) > n ) mlt_frame_close( MLT_FRAME( mlt_deque_pop_back( queue ) ) ); is_purge = true; pthread_cond_broadcast( &video_cond ); pthread_mutex_unlock( &video_mutex ); } } void consumer_thread() { // Get the properties mlt_properties consumer_props = MLT_CONSUMER_PROPERTIES( getConsumer() ); // Video thread pthread_t thread; // internal intialization int init_audio = 1; int init_video = 1; mlt_frame frame = NULL; mlt_properties properties = NULL; int duration = 0; int64_t playtime = 0; struct timespec tm = { 0, 100000 }; // int last_position = -1; pthread_mutex_lock( &refresh_mutex ); refresh_count = 0; pthread_mutex_unlock( &refresh_mutex ); // Loop until told not to while ( running ) { // Get a frame from the attached producer frame = mlt_consumer_rt_frame( getConsumer() ); // Ensure that we have a frame if ( frame ) { // Get the frame properties properties = MLT_FRAME_PROPERTIES( frame ); // Get the speed of the frame double speed = mlt_properties_get_double( properties, "_speed" ); // Get refresh request for the current frame int refresh = mlt_properties_get_int( consumer_props, "refresh" ); // Clear refresh mlt_events_block( consumer_props, consumer_props ); mlt_properties_set_int( consumer_props, "refresh", 0 ); mlt_events_unblock( consumer_props, consumer_props ); // Play audio init_audio = play_audio( frame, init_audio, &duration ); // Determine the start time now if ( playing && init_video ) { // Create the video thread pthread_create( &thread, NULL, video_thread_proxy, this ); // Video doesn't need to be initialised any more init_video = 0; } // Set playtime for this frame mlt_properties_set_int( properties, "playtime", playtime ); while ( running && speed != 0 && mlt_deque_count( queue ) > 15 ) nanosleep( &tm, NULL ); // Push this frame to the back of the queue if ( running && speed ) { pthread_mutex_lock( &video_mutex ); if ( is_purge && speed == 1.0 ) { mlt_frame_close( frame ); is_purge = false; } else { mlt_deque_push_back( queue, frame ); pthread_cond_broadcast( &video_cond ); } pthread_mutex_unlock( &video_mutex ); // Calculate the next playtime playtime += ( duration * 1000 ); } else if ( running ) { pthread_mutex_lock( &refresh_mutex ); if ( refresh == 0 && refresh_count <= 0 ) { play_video( frame ); pthread_cond_wait( &refresh_cond, &refresh_mutex ); } mlt_frame_close( frame ); refresh_count --; pthread_mutex_unlock( &refresh_mutex ); } else { mlt_frame_close( frame ); frame = NULL; } // Optimisation to reduce latency if ( frame && speed == 1.0 ) { // TODO: disabled due to misbehavior on parallel-consumer // if ( last_position != -1 && last_position + 1 != mlt_frame_get_position( frame ) ) // mlt_consumer_purge( consumer ); // last_position = mlt_frame_get_position( frame ); } else { mlt_consumer_purge( getConsumer() ); // last_position = -1; } } } // Kill the video thread if ( init_video == 0 ) { pthread_mutex_lock( &video_mutex ); pthread_cond_broadcast( &video_cond ); pthread_mutex_unlock( &video_mutex ); pthread_join( thread, NULL ); } while( mlt_deque_count( queue ) ) mlt_frame_close( (mlt_frame) mlt_deque_pop_back( queue ) ); audio_avail = 0; } int callback( int16_t *outbuf, int16_t *inbuf, unsigned int samples, double streamTime, RtAudioStreamStatus status ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() ); double volume = mlt_properties_get_double( properties, "volume" ); int channels = mlt_properties_get_int( properties, "channels" ); int len = mlt_audio_format_size( mlt_audio_s16, samples, channels ); pthread_mutex_lock( &audio_mutex ); // Block until audio received while ( running && len > audio_avail ) pthread_cond_wait( &audio_cond, &audio_mutex ); if ( audio_avail >= len ) { // Place in the audio buffer memcpy( outbuf, audio_buffer, len ); // Remove len from the audio available audio_avail -= len; // Remove the samples memmove( audio_buffer, audio_buffer + len, audio_avail ); } else { // Just to be safe, wipe the stream first memset( outbuf, 0, len ); // Copy what we have memcpy( outbuf, audio_buffer, audio_avail ); // No audio left audio_avail = 0; } if ( volume != 1.0 ) { int16_t *p = outbuf; int i = samples * channels + 1; while ( --i ) *p++ *= volume; } // We're definitely playing now playing = 1; pthread_cond_broadcast( &audio_cond ); pthread_mutex_unlock( &audio_mutex ); return 0; } int play_audio( mlt_frame frame, int init_audio, int *duration ) { // Get the properties of this consumer mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() ); mlt_audio_format afmt = mlt_audio_s16; // Set the preferred params of the test card signal int channels = mlt_properties_get_int( properties, "channels" ); int frequency = mlt_properties_get_int( properties, "frequency" ); int scrub = mlt_properties_get_int( properties, "scrub_audio" ); static int counter = 0; int samples = mlt_sample_calculator( mlt_properties_get_double( properties, "fps" ), frequency, counter++ ); int16_t *pcm; mlt_frame_get_audio( frame, (void**) &pcm, &afmt, &frequency, &channels, &samples ); *duration = ( ( samples * 1000 ) / frequency ); if ( mlt_properties_get_int( properties, "audio_off" ) ) { playing = 1; return init_audio; } if ( init_audio == 1 ) { RtAudio::StreamParameters parameters; parameters.deviceId = device_id; parameters.nChannels = channels; parameters.firstChannel = 0; RtAudio::StreamOptions options; unsigned int bufferFrames = mlt_properties_get_int( properties, "audio_buffer" ); if ( device_id == -1 ) { options.flags = RTAUDIO_ALSA_USE_DEFAULT; parameters.deviceId = 0; } if ( mlt_properties_get( properties, "resource" ) ) parameters.deviceName = mlt_properties_get( properties, "resource" ); try { if ( rt.isStreamOpen() ) { rt.closeStream(); } rt.openStream( ¶meters, NULL, RTAUDIO_SINT16, frequency, &bufferFrames, &rtaudio_callback, this, &options ); rt.startStream(); init_audio = 0; playing = 1; } catch ( RtError& e ) { mlt_log_error( getConsumer(), "%s\n", e.getMessage().c_str() ); init_audio = 2; } } if ( init_audio == 0 ) { mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); size_t bytes = ( samples * channels * 2 ); pthread_mutex_lock( &audio_mutex ); while ( running && bytes > ( sizeof( audio_buffer) - audio_avail ) ) pthread_cond_wait( &audio_cond, &audio_mutex ); if ( running ) { if ( scrub || mlt_properties_get_double( properties, "_speed" ) == 1 ) memcpy( &audio_buffer[ audio_avail ], pcm, bytes ); else memset( &audio_buffer[ audio_avail ], 0, bytes ); audio_avail += bytes; } pthread_cond_broadcast( &audio_cond ); pthread_mutex_unlock( &audio_mutex ); } return init_audio; } int play_video( mlt_frame frame ) { // Get the properties of this consumer mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() ); if ( running && !mlt_consumer_is_stopped( getConsumer() ) ) mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); return 0; } void video_thread() { // Obtain time of thread start struct timeval now; int64_t start = 0; int64_t elapsed = 0; struct timespec tm; mlt_frame next = NULL; mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() ); double speed = 0; // Get real time flag int real_time = mlt_properties_get_int( properties, "real_time" ); // Get the current time gettimeofday( &now, NULL ); // Determine start time start = ( int64_t )now.tv_sec * 1000000 + now.tv_usec; while ( running ) { // Pop the next frame pthread_mutex_lock( &video_mutex ); next = (mlt_frame) mlt_deque_pop_front( queue ); while ( next == NULL && running ) { pthread_cond_wait( &video_cond, &video_mutex ); next = (mlt_frame) mlt_deque_pop_front( queue ); } pthread_mutex_unlock( &video_mutex ); if ( !running || next == NULL ) break; // Get the properties properties = MLT_FRAME_PROPERTIES( next ); // Get the speed of the frame speed = mlt_properties_get_double( properties, "_speed" ); // Get the current time gettimeofday( &now, NULL ); // Get the elapsed time elapsed = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec ) - start; // See if we have to delay the display of the current frame if ( mlt_properties_get_int( properties, "rendered" ) == 1 && running ) { // Obtain the scheduled playout time int64_t scheduled = mlt_properties_get_int( properties, "playtime" ); // Determine the difference between the elapsed time and the scheduled playout time int64_t difference = scheduled - elapsed; // Smooth playback a bit if ( real_time && ( difference > 20000 && speed == 1.0 ) ) { tm.tv_sec = difference / 1000000; tm.tv_nsec = ( difference % 1000000 ) * 500; nanosleep( &tm, NULL ); } // Show current frame if not too old if ( !real_time || ( difference > -10000 || speed != 1.0 || mlt_deque_count( queue ) < 2 ) ) play_video( next ); // If the queue is empty, recalculate start to allow build up again if ( real_time && ( mlt_deque_count( queue ) == 0 && speed == 1.0 ) ) { gettimeofday( &now, NULL ); start = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec ) - scheduled + 20000; } } // This frame can now be closed mlt_frame_close( next ); next = NULL; } if ( next != NULL ) mlt_frame_close( next ); mlt_consumer_stopped( getConsumer() ); } }; static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer consumer, char *name ) { if ( !strcmp( name, "refresh" ) ) { RtAudioConsumer* rtaudio = (RtAudioConsumer*) consumer->child; pthread_mutex_lock( &rtaudio->refresh_mutex ); rtaudio->refresh_count = rtaudio->refresh_count <= 0 ? 1 : rtaudio->refresh_count + 1; pthread_cond_broadcast( &rtaudio->refresh_cond ); pthread_mutex_unlock( &rtaudio->refresh_mutex ); } } static int rtaudio_callback( void *outputBuffer, void *inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void *userData ) { RtAudioConsumer* rtaudio = (RtAudioConsumer*) userData; return rtaudio->callback( (int16_t*) outputBuffer, (int16_t*) inputBuffer, nFrames, streamTime, status ); } static void *consumer_thread_proxy( void *arg ) { RtAudioConsumer* rtaudio = (RtAudioConsumer*) arg; rtaudio->consumer_thread(); return NULL; } static void *video_thread_proxy( void *arg ) { RtAudioConsumer* rtaudio = (RtAudioConsumer*) arg; rtaudio->video_thread(); return NULL; } /** Start the consumer. */ static int start( mlt_consumer consumer ) { RtAudioConsumer* rtaudio = (RtAudioConsumer*) consumer->child; return rtaudio->start(); } /** Stop the consumer. */ static int stop( mlt_consumer consumer ) { RtAudioConsumer* rtaudio = (RtAudioConsumer*) consumer->child; return rtaudio->stop(); } /** Determine if the consumer is stopped. */ static int is_stopped( mlt_consumer consumer ) { RtAudioConsumer* rtaudio = (RtAudioConsumer*) consumer->child; return !rtaudio->running; } static void purge( mlt_consumer consumer ) { RtAudioConsumer* rtaudio = (RtAudioConsumer*) consumer->child; rtaudio->purge(); } /** Close the consumer. */ static void close( mlt_consumer consumer ) { // Stop the consumer mlt_consumer_stop( consumer ); // Close the parent consumer->close = NULL; mlt_consumer_close( consumer ); // Free the memory delete (RtAudioConsumer*) consumer->child; } extern "C" { mlt_consumer consumer_rtaudio_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Allocate the consumer RtAudioConsumer* rtaudio = new RtAudioConsumer(); mlt_consumer consumer = NULL; // If allocated if ( rtaudio && !mlt_consumer_init( rtaudio->getConsumer(), rtaudio, profile ) ) { // If initialises without error if ( rtaudio->open( arg? arg : getenv( "AUDIODEV" ) ) ) { // Setup callbacks consumer = rtaudio->getConsumer(); consumer->close = close; consumer->start = start; consumer->stop = stop; consumer->is_stopped = is_stopped; consumer->purge = purge; } else { mlt_consumer_close( rtaudio->getConsumer() ); delete rtaudio; } } // Return consumer return consumer; } static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; const char *service_type = "consumer"; snprintf( file, PATH_MAX, "%s/rtaudio/%s_%s.yml", mlt_environment( "MLT_DATA" ), service_type, id ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( consumer_type, "rtaudio", consumer_rtaudio_init ); MLT_REGISTER_METADATA( consumer_type, "rtaudio", metadata, NULL ); } } // extern C mlt-0.9.0/src/modules/rtaudio/consumer_rtaudio.yml000066400000000000000000000022451215300731300223250ustar00rootroot00000000000000schema_version: 0.1 type: consumer identifier: rtaudio title: RtAudio description: > RtAudio provides native, realtime audio output across Linux, Macintosh OS X, Windows, and some BSD operating systems. url: http://www.music.mcgill.ca/~gary/rtaudio/ version: 1 copyright: Dan Dennedy creator: Dan Dennedy creator: Gary P. Scavone license: LGPLv2.1 language: en tags: - Audio parameters: - identifier: resource title: Device description: An optional device name, number, or ID to use. type: string required: no - identifier: audio_buffer title: Audio buffer type: integer minimum: 256 maximum: 8192 default: 1024 unit: samples - identifier: volume title: Volume type: float minimum: 0.0 default: 1.0 mutable: yes - identifier: refresh description: > Applications should set this to update the video frame when paused. type: integer minimum: 0 maximum: 1 - identifier: scrub_audio title: Audio scrubbing type: integer description: If enabled, sound is played even when the speed is not normal. mutable: yes minimum: 0 maximum: 1 default: 0 widget: checkbox mlt-0.9.0/src/modules/sdl/000077500000000000000000000000001215300731300153305ustar00rootroot00000000000000mlt-0.9.0/src/modules/sdl/Makefile000066400000000000000000000021511215300731300167670ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lpthread -lm include ../../../config.mak include config.mak TARGET = ../libmltsdl$(LIBSUF) OBJS = factory.o \ consumer_sdl.o \ consumer_sdl_audio.o \ consumer_sdl_preview.o \ consumer_sdl_still.o ifeq ($(targetos),Darwin) CFLAGS += -ObjC LDFLAGS += -lobjc -framework Foundation else ifneq ($(targetos), MinGW) LDFLAGS += -lX11 endif CFLAGS += `sdl-config --cflags` LDFLAGS += `sdl-config --libs` ifeq ($(WITH_SDL_IMAGE),1) OBJS += producer_sdl_image.o CFLAGS += -DWITH_SDL_IMAGE LDFLAGS += -lSDL_image endif SRCS := $(OBJS:.o=.c) ifeq ($(targetos),Darwin) OBJS += consumer_sdl_osx.o SRCS += consumer_sdl_osx.m consumer_sdl_osx.h endif all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/sdl" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/sdl" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/sdl/configure000077500000000000000000000005701215300731300172410ustar00rootroot00000000000000#!/bin/sh if [ "$help" != "1" ] then sdl-config --version > /dev/null 2>&1 disable_sdl=$? if [ "$disable_sdl" = "0" ] then echo > config.mak image=`sdl-config --prefix`/include/SDL/SDL_image.h if [ -f "$image" ] then echo "WITH_SDL_IMAGE=1" >> config.mak fi else echo "- sdl development libs not found: disabling" touch ../disable-sdl fi exit 0 fi mlt-0.9.0/src/modules/sdl/consumer_sdl.c000066400000000000000000000655041215300731300202030ustar00rootroot00000000000000/* * consumer_sdl.c -- A Simple DirectMedia Layer consumer * Copyright (C) 2003-2004, 2010 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "consumer_sdl_osx.h" extern pthread_mutex_t mlt_sdl_mutex; /** This classes definition. */ typedef struct consumer_sdl_s *consumer_sdl; struct consumer_sdl_s { struct mlt_consumer_s parent; mlt_properties properties; mlt_deque queue; pthread_t thread; int joined; int running; uint8_t audio_buffer[ 4096 * 10 ]; int audio_avail; pthread_mutex_t audio_mutex; pthread_cond_t audio_cond; pthread_mutex_t video_mutex; pthread_cond_t video_cond; int window_width; int window_height; int previous_width; int previous_height; int width; int height; int playing; int sdl_flags; SDL_Overlay *sdl_overlay; SDL_Rect rect; uint8_t *buffer; int bpp; int is_purge; }; /** Forward references to static functions. */ static int consumer_start( mlt_consumer parent ); static int consumer_stop( mlt_consumer parent ); static int consumer_is_stopped( mlt_consumer parent ); static void consumer_purge( mlt_consumer parent ); static void consumer_close( mlt_consumer parent ); static void *consumer_thread( void * ); static int consumer_get_dimensions( int *width, int *height ); static void consumer_sdl_event( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ); /** This is what will be called by the factory - anything can be passed in via the argument, but keep it simple. */ mlt_consumer consumer_sdl_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create the consumer object consumer_sdl self = calloc( 1, sizeof( struct consumer_sdl_s ) ); // If no malloc'd and consumer init ok if ( self != NULL && mlt_consumer_init( &self->parent, self, profile ) == 0 ) { // Create the queue self->queue = mlt_deque_init( ); // Get the parent consumer object mlt_consumer parent = &self->parent; // We have stuff to clean up, so override the close method parent->close = consumer_close; // get a handle on properties mlt_service service = MLT_CONSUMER_SERVICE( parent ); self->properties = MLT_SERVICE_PROPERTIES( service ); // Set the default volume mlt_properties_set_double( self->properties, "volume", 1.0 ); // This is the initialisation of the consumer pthread_mutex_init( &self->audio_mutex, NULL ); pthread_cond_init( &self->audio_cond, NULL); pthread_mutex_init( &self->video_mutex, NULL ); pthread_cond_init( &self->video_cond, NULL); // Default scaler (for now we'll use nearest) mlt_properties_set( self->properties, "rescale", "nearest" ); mlt_properties_set( self->properties, "deinterlace_method", "onefield" ); mlt_properties_set_int( self->properties, "top_field_first", -1 ); // Default buffer for low latency mlt_properties_set_int( self->properties, "buffer", 1 ); // Default audio buffer mlt_properties_set_int( self->properties, "audio_buffer", 2048 ); // Ensure we don't join on a non-running object self->joined = 1; // process actual param if ( arg && sscanf( arg, "%dx%d", &self->width, &self->height ) ) { mlt_properties_set_int( self->properties, "_arg_size", 1 ); } else { self->width = mlt_properties_get_int( self->properties, "width" ); self->height = mlt_properties_get_int( self->properties, "height" ); } // Set the sdl flags self->sdl_flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_DOUBLEBUF; #if !defined(__DARWIN__) self->sdl_flags |= SDL_RESIZABLE; #endif // Allow thread to be started/stopped parent->start = consumer_start; parent->stop = consumer_stop; parent->is_stopped = consumer_is_stopped; parent->purge = consumer_purge; // Register specific events mlt_events_register( self->properties, "consumer-sdl-event", ( mlt_transmitter )consumer_sdl_event ); // Return the consumer produced return parent; } // malloc or consumer init failed free( self ); // Indicate failure return NULL; } static void consumer_sdl_event( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) { if ( listener != NULL ) listener( owner, self, ( SDL_Event * )args[ 0 ] ); } int consumer_start( mlt_consumer parent ) { consumer_sdl self = parent->child; if ( !self->running ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( parent ); int video_off = mlt_properties_get_int( properties, "video_off" ); int preview_off = mlt_properties_get_int( properties, "preview_off" ); int display_off = video_off | preview_off; int audio_off = mlt_properties_get_int( properties, "audio_off" ); int sdl_started = mlt_properties_get_int( properties, "sdl_started" ); char *output_display = mlt_properties_get( properties, "output_display" ); char *window_id = mlt_properties_get( properties, "window_id" ); char *audio_driver = mlt_properties_get( properties, "audio_driver" ); char *video_driver = mlt_properties_get( properties, "video_driver" ); char *audio_device = mlt_properties_get( properties, "audio_device" ); consumer_stop( parent ); self->running = 1; self->joined = 0; if ( output_display != NULL ) setenv( "DISPLAY", output_display, 1 ); if ( window_id != NULL ) setenv( "SDL_WINDOWID", window_id, 1 ); if ( video_driver != NULL ) setenv( "SDL_VIDEODRIVER", video_driver, 1 ); if ( audio_driver != NULL ) setenv( "SDL_AUDIODRIVER", audio_driver, 1 ); if ( audio_device != NULL ) setenv( "AUDIODEV", audio_device, 1 ); if ( ! mlt_properties_get_int( self->properties, "_arg_size" ) ) { if ( mlt_properties_get_int( self->properties, "width" ) > 0 ) self->width = mlt_properties_get_int( self->properties, "width" ); if ( mlt_properties_get_int( self->properties, "height" ) > 0 ) self->height = mlt_properties_get_int( self->properties, "height" ); } self->bpp = mlt_properties_get_int( self->properties, "bpp" ); if ( sdl_started == 0 && display_off == 0 ) { pthread_mutex_lock( &mlt_sdl_mutex ); int ret = SDL_Init( SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE ); pthread_mutex_unlock( &mlt_sdl_mutex ); if ( ret < 0 ) { mlt_log_error( MLT_CONSUMER_SERVICE(parent), "Failed to initialize SDL: %s\n", SDL_GetError() ); return -1; } SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL ); SDL_EnableUNICODE( 1 ); } if ( audio_off == 0 ) SDL_InitSubSystem( SDL_INIT_AUDIO ); // Default window size if ( mlt_properties_get_int( self->properties, "_arg_size" ) ) { self->window_width = self->width; self->window_height = self->height; } else { double display_ratio = mlt_properties_get_double( self->properties, "display_ratio" ); self->window_width = ( double )self->height * display_ratio + 0.5; self->window_height = self->height; } pthread_mutex_lock( &mlt_sdl_mutex ); if ( !SDL_GetVideoSurface() && display_off == 0 ) { if ( mlt_properties_get_int( self->properties, "fullscreen" ) ) { const SDL_VideoInfo *vi; pthread_mutex_lock( &mlt_sdl_mutex ); vi = SDL_GetVideoInfo(); pthread_mutex_unlock( &mlt_sdl_mutex ); self->window_width = vi->current_w; self->window_height = vi->current_h; self->sdl_flags |= SDL_FULLSCREEN; SDL_ShowCursor( SDL_DISABLE ); } SDL_SetVideoMode( self->window_width, self->window_height, 0, self->sdl_flags ); } pthread_mutex_unlock( &mlt_sdl_mutex ); pthread_create( &self->thread, NULL, consumer_thread, self ); } return 0; } int consumer_stop( mlt_consumer parent ) { // Get the actual object consumer_sdl self = parent->child; if ( self->joined == 0 ) { // Kill the thread and clean up self->joined = 1; self->running = 0; #ifndef WIN32 if ( self->thread ) #endif pthread_join( self->thread, NULL ); // internal cleanup if ( self->sdl_overlay != NULL ) SDL_FreeYUVOverlay( self->sdl_overlay ); self->sdl_overlay = NULL; if ( !mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "audio_off" ) ) { pthread_mutex_lock( &self->audio_mutex ); pthread_cond_broadcast( &self->audio_cond ); pthread_mutex_unlock( &self->audio_mutex ); SDL_QuitSubSystem( SDL_INIT_AUDIO ); } if ( mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "sdl_started" ) == 0 ) { pthread_mutex_lock( &mlt_sdl_mutex ); SDL_Quit( ); pthread_mutex_unlock( &mlt_sdl_mutex ); } } return 0; } int consumer_is_stopped( mlt_consumer parent ) { consumer_sdl self = parent->child; return !self->running; } void consumer_purge( mlt_consumer parent ) { consumer_sdl self = parent->child; if ( self->running ) { pthread_mutex_lock( &self->video_mutex ); while ( mlt_deque_count( self->queue ) ) mlt_frame_close( mlt_deque_pop_back( self->queue ) ); self->is_purge = 1; pthread_cond_broadcast( &self->video_cond ); pthread_mutex_unlock( &self->video_mutex ); } } static int sdl_lock_display( ) { pthread_mutex_lock( &mlt_sdl_mutex ); SDL_Surface *screen = SDL_GetVideoSurface( ); int result = screen != NULL && ( !SDL_MUSTLOCK( screen ) || SDL_LockSurface( screen ) >= 0 ); pthread_mutex_unlock( &mlt_sdl_mutex ); return result; } static void sdl_unlock_display( ) { pthread_mutex_lock( &mlt_sdl_mutex ); SDL_Surface *screen = SDL_GetVideoSurface( ); if ( screen != NULL && SDL_MUSTLOCK( screen ) ) SDL_UnlockSurface( screen ); pthread_mutex_unlock( &mlt_sdl_mutex ); } static void sdl_fill_audio( void *udata, uint8_t *stream, int len ) { consumer_sdl self = udata; // Get the volume double volume = mlt_properties_get_double( self->properties, "volume" ); pthread_mutex_lock( &self->audio_mutex ); // Block until audio received while ( self->running && len > self->audio_avail ) pthread_cond_wait( &self->audio_cond, &self->audio_mutex ); if ( self->audio_avail >= len ) { // Place in the audio buffer if ( volume != 1.0 ) SDL_MixAudio( stream, self->audio_buffer, len, ( int )( ( float )SDL_MIX_MAXVOLUME * volume ) ); else memcpy( stream, self->audio_buffer, len ); // Remove len from the audio available self->audio_avail -= len; // Remove the samples memmove( self->audio_buffer, self->audio_buffer + len, self->audio_avail ); } else { // Just to be safe, wipe the stream first memset( stream, 0, len ); // Mix the audio SDL_MixAudio( stream, self->audio_buffer, len, ( int )( ( float )SDL_MIX_MAXVOLUME * volume ) ); // No audio left self->audio_avail = 0; } // We're definitely playing now self->playing = 1; pthread_cond_broadcast( &self->audio_cond ); pthread_mutex_unlock( &self->audio_mutex ); } static int consumer_play_audio( consumer_sdl self, mlt_frame frame, int init_audio, int *duration ) { // Get the properties of self consumer mlt_properties properties = self->properties; mlt_audio_format afmt = mlt_audio_s16; // Set the preferred params of the test card signal int channels = mlt_properties_get_int( properties, "channels" ); int dest_channels = channels; int frequency = mlt_properties_get_int( properties, "frequency" ); static int counter = 0; int samples = mlt_sample_calculator( mlt_properties_get_double( self->properties, "fps" ), frequency, counter++ ); int16_t *pcm; int bytes; mlt_frame_get_audio( frame, (void**) &pcm, &afmt, &frequency, &channels, &samples ); *duration = ( ( samples * 1000 ) / frequency ); pcm += mlt_properties_get_int( properties, "audio_offset" ); if ( mlt_properties_get_int( properties, "audio_off" ) ) { self->playing = 1; init_audio = 1; return init_audio; } if ( init_audio == 1 ) { SDL_AudioSpec request; SDL_AudioSpec got; int audio_buffer = mlt_properties_get_int( properties, "audio_buffer" ); // specify audio format memset( &request, 0, sizeof( SDL_AudioSpec ) ); self->playing = 0; request.freq = frequency; request.format = AUDIO_S16SYS; request.channels = dest_channels; request.samples = audio_buffer; request.callback = sdl_fill_audio; request.userdata = (void *)self; if ( SDL_OpenAudio( &request, &got ) != 0 ) { mlt_log_error( MLT_CONSUMER_SERVICE( self ), "SDL failed to open audio: %s\n", SDL_GetError() ); init_audio = 2; } else if ( got.size != 0 ) { SDL_PauseAudio( 0 ); init_audio = 0; } } if ( init_audio == 0 ) { mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); bytes = samples * dest_channels * sizeof(*pcm); pthread_mutex_lock( &self->audio_mutex ); while ( self->running && bytes > ( sizeof( self->audio_buffer) - self->audio_avail ) ) pthread_cond_wait( &self->audio_cond, &self->audio_mutex ); if ( self->running ) { if ( mlt_properties_get_double( properties, "_speed" ) == 1 ) { if ( channels == dest_channels ) { memcpy( &self->audio_buffer[ self->audio_avail ], pcm, bytes ); } else { int16_t *dest = (int16_t*) &self->audio_buffer[ self->audio_avail ]; int i = samples + 1; while ( --i ) { memcpy( dest, pcm, dest_channels * sizeof(*pcm) ); pcm += channels; dest += dest_channels; } } } else { memset( &self->audio_buffer[ self->audio_avail ], 0, bytes ); } self->audio_avail += bytes; } pthread_cond_broadcast( &self->audio_cond ); pthread_mutex_unlock( &self->audio_mutex ); } else { self->playing = 1; } return init_audio; } static int consumer_play_video( consumer_sdl self, mlt_frame frame ) { // Get the properties of this consumer mlt_properties properties = self->properties; mlt_image_format vfmt = mlt_image_yuv422; int width = self->width, height = self->height; uint8_t *image; int changed = 0; int video_off = mlt_properties_get_int( properties, "video_off" ); int preview_off = mlt_properties_get_int( properties, "preview_off" ); mlt_image_format preview_format = mlt_properties_get_int( properties, "preview_format" ); int display_off = video_off | preview_off; if ( self->running && display_off == 0 ) { // Get the image, width and height mlt_frame_get_image( frame, &image, &vfmt, &width, &height, 0 ); void *pool = mlt_cocoa_autorelease_init(); // Handle events if ( SDL_GetVideoSurface() ) { SDL_Event event; sdl_lock_display( ); pthread_mutex_lock( &mlt_sdl_mutex ); changed = consumer_get_dimensions( &self->window_width, &self->window_height ); pthread_mutex_unlock( &mlt_sdl_mutex ); sdl_unlock_display( ); while ( SDL_PollEvent( &event ) ) { mlt_events_fire( self->properties, "consumer-sdl-event", &event, NULL ); switch( event.type ) { case SDL_VIDEORESIZE: self->window_width = event.resize.w; self->window_height = event.resize.h; changed = 1; break; case SDL_QUIT: self->running = 0; break; case SDL_KEYDOWN: { mlt_producer producer = mlt_properties_get_data( properties, "transport_producer", NULL ); char keyboard[ 2 ] = " "; void (*callback)( mlt_producer, char * ) = mlt_properties_get_data( properties, "transport_callback", NULL ); if ( callback != NULL && producer != NULL && event.key.keysym.unicode < 0x80 && event.key.keysym.unicode > 0 ) { keyboard[ 0 ] = ( char )event.key.keysym.unicode; callback( producer, keyboard ); } } break; } } } sdl_lock_display(); if ( width != self->width || height != self->height ) { if ( self->sdl_overlay != NULL ) SDL_FreeYUVOverlay( self->sdl_overlay ); self->sdl_overlay = NULL; } if ( self->running && ( !SDL_GetVideoSurface() || changed ) ) { // Force an overlay recreation if ( self->sdl_overlay != NULL ) SDL_FreeYUVOverlay( self->sdl_overlay ); self->sdl_overlay = NULL; // open SDL window with video overlay, if possible pthread_mutex_lock( &mlt_sdl_mutex ); SDL_Surface *screen = SDL_SetVideoMode( self->window_width, self->window_height, self->bpp, self->sdl_flags ); if ( consumer_get_dimensions( &self->window_width, &self->window_height ) ) screen = SDL_SetVideoMode( self->window_width, self->window_height, self->bpp, self->sdl_flags ); pthread_mutex_unlock( &mlt_sdl_mutex ); if ( screen ) { uint32_t color = mlt_properties_get_int( self->properties, "window_background" ); SDL_FillRect( screen, NULL, color >> 8 ); SDL_Flip( screen ); } } if ( self->running ) { // Determine window's new display aspect ratio double this_aspect = ( double )self->window_width / self->window_height; // Get the display aspect ratio double display_ratio = mlt_properties_get_double( properties, "display_ratio" ); // Determine frame's display aspect ratio double frame_aspect = mlt_frame_get_aspect_ratio( frame ) * width / height; // Store the width and height received self->width = width; self->height = height; // If using hardware scaler if ( mlt_properties_get( properties, "rescale" ) != NULL && !strcmp( mlt_properties_get( properties, "rescale" ), "none" ) ) { // Use hardware scaler to normalise display aspect ratio self->rect.w = frame_aspect / this_aspect * self->window_width; self->rect.h = self->window_height; if ( self->rect.w > self->window_width ) { self->rect.w = self->window_width; self->rect.h = this_aspect / frame_aspect * self->window_height; } } // Special case optimisation to negate odd effect of sample aspect ratio // not corresponding exactly with image resolution. else if ( (int)( this_aspect * 1000 ) == (int)( display_ratio * 1000 ) ) { self->rect.w = self->window_width; self->rect.h = self->window_height; } // Use hardware scaler to normalise sample aspect ratio else if ( self->window_height * display_ratio > self->window_width ) { self->rect.w = self->window_width; self->rect.h = self->window_width / display_ratio; } else { self->rect.w = self->window_height * display_ratio; self->rect.h = self->window_height; } self->rect.x = ( self->window_width - self->rect.w ) / 2; self->rect.y = ( self->window_height - self->rect.h ) / 2; self->rect.x -= self->rect.x % 2; mlt_properties_set_int( self->properties, "rect_x", self->rect.x ); mlt_properties_set_int( self->properties, "rect_y", self->rect.y ); mlt_properties_set_int( self->properties, "rect_w", self->rect.w ); mlt_properties_set_int( self->properties, "rect_h", self->rect.h ); SDL_SetClipRect( SDL_GetVideoSurface(), &self->rect ); } if ( self->running && SDL_GetVideoSurface() && self->sdl_overlay == NULL ) { SDL_SetClipRect( SDL_GetVideoSurface(), &self->rect ); self->sdl_overlay = SDL_CreateYUVOverlay( width, height, SDL_YUY2_OVERLAY, SDL_GetVideoSurface() ); } if ( self->running && SDL_GetVideoSurface() && self->sdl_overlay != NULL ) { self->buffer = self->sdl_overlay->pixels[ 0 ]; if ( SDL_LockYUVOverlay( self->sdl_overlay ) >= 0 ) { if ( image != NULL ) memcpy( self->buffer, image, width * height * 2 ); SDL_UnlockYUVOverlay( self->sdl_overlay ); SDL_DisplayYUVOverlay( self->sdl_overlay, &SDL_GetVideoSurface()->clip_rect ); } } sdl_unlock_display(); mlt_cocoa_autorelease_close( pool ); mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); } else if ( self->running ) { vfmt = preview_format == mlt_image_none ? mlt_image_rgb24a : preview_format; if ( !video_off ) mlt_frame_get_image( frame, &image, &vfmt, &width, &height, 0 ); mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); } return 0; } static void *video_thread( void *arg ) { // Identify the arg consumer_sdl self = arg; // Obtain time of thread start struct timeval now; int64_t start = 0; int64_t elapsed = 0; struct timespec tm; mlt_frame next = NULL; mlt_properties properties = NULL; double speed = 0; // Get real time flag int real_time = mlt_properties_get_int( self->properties, "real_time" ); // Get the current time gettimeofday( &now, NULL ); // Determine start time start = ( int64_t )now.tv_sec * 1000000 + now.tv_usec; while ( self->running ) { // Pop the next frame pthread_mutex_lock( &self->video_mutex ); next = mlt_deque_pop_front( self->queue ); while ( next == NULL && self->running ) { pthread_cond_wait( &self->video_cond, &self->video_mutex ); next = mlt_deque_pop_front( self->queue ); } pthread_mutex_unlock( &self->video_mutex ); if ( !self->running || next == NULL ) break; // Get the properties properties = MLT_FRAME_PROPERTIES( next ); // Get the speed of the frame speed = mlt_properties_get_double( properties, "_speed" ); // Get the current time gettimeofday( &now, NULL ); // Get the elapsed time elapsed = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec ) - start; // See if we have to delay the display of the current frame if ( mlt_properties_get_int( properties, "rendered" ) == 1 && self->running ) { // Obtain the scheduled playout time int64_t scheduled = mlt_properties_get_int( properties, "playtime" ); // Determine the difference between the elapsed time and the scheduled playout time int64_t difference = scheduled - elapsed; // Smooth playback a bit if ( real_time && ( difference > 20000 && speed == 1.0 ) ) { tm.tv_sec = difference / 1000000; tm.tv_nsec = ( difference % 1000000 ) * 500; nanosleep( &tm, NULL ); } // Show current frame if not too old if ( !real_time || ( difference > -10000 || speed != 1.0 || mlt_deque_count( self->queue ) < 2 ) ) consumer_play_video( self, next ); // If the queue is empty, recalculate start to allow build up again if ( real_time && ( mlt_deque_count( self->queue ) == 0 && speed == 1.0 ) ) { gettimeofday( &now, NULL ); start = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec ) - scheduled + 20000; } } else { static int dropped = 0; mlt_log_info( MLT_CONSUMER_SERVICE(&self->parent), "dropped video frame %d\n", ++dropped ); } // This frame can now be closed mlt_frame_close( next ); next = NULL; } if ( next != NULL ) mlt_frame_close( next ); mlt_consumer_stopped( &self->parent ); return NULL; } /** Threaded wrapper for pipe. */ static void *consumer_thread( void *arg ) { // Identify the arg consumer_sdl self = arg; // Get the consumer mlt_consumer consumer = &self->parent; // Convenience functionality int terminate_on_pause = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( consumer ), "terminate_on_pause" ); int terminated = 0; // Video thread pthread_t thread; // internal intialization int init_audio = 1; int init_video = 1; mlt_frame frame = NULL; int duration = 0; int64_t playtime = 0; struct timespec tm = { 0, 100000 }; // Loop until told not to while( self->running ) { // Get a frame from the attached producer frame = !terminated? mlt_consumer_rt_frame( consumer ) : NULL; // Check for termination if ( terminate_on_pause && frame ) terminated = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0; // Ensure that we have a frame if ( frame ) { // Play audio init_audio = consumer_play_audio( self, frame, init_audio, &duration ); // Determine the start time now if ( self->playing && init_video ) { // Create the video thread pthread_create( &thread, NULL, video_thread, self ); // Video doesn't need to be initialised any more init_video = 0; } // Set playtime for this frame mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "playtime", playtime ); while ( self->running && mlt_deque_count( self->queue ) > 15 ) nanosleep( &tm, NULL ); // Push this frame to the back of the queue pthread_mutex_lock( &self->video_mutex ); if ( self->is_purge ) { mlt_frame_close( frame ); frame = NULL; self->is_purge = 0; } else { mlt_deque_push_back( self->queue, frame ); pthread_cond_broadcast( &self->video_cond ); } pthread_mutex_unlock( &self->video_mutex ); // Calculate the next playtime playtime += ( duration * 1000 ); } else if ( terminated ) { if ( init_video || mlt_deque_count( self->queue ) == 0 ) break; else nanosleep( &tm, NULL ); } } self->running = 0; // Unblock sdl_preview if ( mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( consumer ), "put_mode" ) == 1 ) { frame = mlt_consumer_get_frame( consumer ); if ( frame ) mlt_frame_close( frame ); frame = NULL; } // Kill the video thread if ( init_video == 0 ) { pthread_mutex_lock( &self->video_mutex ); pthread_cond_broadcast( &self->video_cond ); pthread_mutex_unlock( &self->video_mutex ); pthread_join( thread, NULL ); } while( mlt_deque_count( self->queue ) ) mlt_frame_close( mlt_deque_pop_back( self->queue ) ); self->audio_avail = 0; return NULL; } static int consumer_get_dimensions( int *width, int *height ) { int changed = 0; // SDL windows manager structure SDL_SysWMinfo wm; // Specify the SDL Version SDL_VERSION( &wm.version ); // Lock the display //sdl_lock_display(); #ifndef __DARWIN__ // Get the wm structure if ( SDL_GetWMInfo( &wm ) == 1 ) { #ifndef WIN32 // Check that we have the X11 wm if ( wm.subsystem == SDL_SYSWM_X11 ) { // Get the SDL window Window window = wm.info.x11.window; // Get the display session Display *display = wm.info.x11.display; // Get the window attributes XWindowAttributes attr; XGetWindowAttributes( display, window, &attr ); // Determine whether window has changed changed = *width != attr.width || *height != attr.height; // Return width and height *width = attr.width; *height = attr.height; } #endif } #endif // Unlock the display //sdl_unlock_display(); return changed; } /** Callback to allow override of the close method. */ static void consumer_close( mlt_consumer parent ) { // Get the actual object consumer_sdl self = parent->child; // Stop the consumer ///mlt_consumer_stop( parent ); // Now clean up the rest mlt_consumer_close( parent ); // Close the queue mlt_deque_close( self->queue ); // Destroy mutexes pthread_mutex_destroy( &self->audio_mutex ); pthread_cond_destroy( &self->audio_cond ); // Finally clean up this free( self ); } mlt-0.9.0/src/modules/sdl/consumer_sdl.yml000066400000000000000000000021021215300731300205430ustar00rootroot00000000000000schema_version: 0.1 type: consumer identifier: sdl title: SDL Fast YUV version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Audio - Video description: > Simple DirectMedia Layer audio and video output module. parameters: - identifier: argument title: Video Standard type: string description: The size of the window as WxH pixels. required: no - identifier: volume title: Volume type: float description: Audio level factor. mutable: yes - identifier: video_off title: Video off type: integer description: If 1, disable video output mutable: yes minimum: 0 maximum: 1 default: 0 widget: checkbox - identifier: audio_off title: Audio off type: integer description: If 1, disable audio output mutable: yes minimum: 0 maximum: 1 default: 0 widget: checkbox - identifier: audio_buffer title: Audio buffer type: integer description: Size of the sdl audio buffer. mutable: yes default: 2048 minimum: 128 mlt-0.9.0/src/modules/sdl/consumer_sdl_audio.c000066400000000000000000000430141215300731300213540ustar00rootroot00000000000000/* * consumer_sdl_audio.c -- A Simple DirectMedia Layer audio-only consumer * Copyright (C) 2009-2012 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include extern pthread_mutex_t mlt_sdl_mutex; /** This classes definition. */ typedef struct consumer_sdl_s *consumer_sdl; struct consumer_sdl_s { struct mlt_consumer_s parent; mlt_properties properties; mlt_deque queue; pthread_t thread; int joined; int running; uint8_t audio_buffer[ 4096 * 10 ]; int audio_avail; pthread_mutex_t audio_mutex; pthread_cond_t audio_cond; pthread_mutex_t video_mutex; pthread_cond_t video_cond; int playing; pthread_cond_t refresh_cond; pthread_mutex_t refresh_mutex; int refresh_count; int is_purge; }; /** Forward references to static functions. */ static int consumer_start( mlt_consumer parent ); static int consumer_stop( mlt_consumer parent ); static int consumer_is_stopped( mlt_consumer parent ); static void consumer_purge( mlt_consumer parent ); static void consumer_close( mlt_consumer parent ); static void *consumer_thread( void * ); static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer self, char *name ); /** This is what will be called by the factory - anything can be passed in via the argument, but keep it simple. */ mlt_consumer consumer_sdl_audio_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create the consumer object consumer_sdl self = calloc( 1, sizeof( struct consumer_sdl_s ) ); // If no malloc'd and consumer init ok if ( self != NULL && mlt_consumer_init( &self->parent, self, profile ) == 0 ) { // Create the queue self->queue = mlt_deque_init( ); // Get the parent consumer object mlt_consumer parent = &self->parent; // We have stuff to clean up, so override the close method parent->close = consumer_close; // get a handle on properties mlt_service service = MLT_CONSUMER_SERVICE( parent ); self->properties = MLT_SERVICE_PROPERTIES( service ); // Set the default volume mlt_properties_set_double( self->properties, "volume", 1.0 ); // This is the initialisation of the consumer pthread_mutex_init( &self->audio_mutex, NULL ); pthread_cond_init( &self->audio_cond, NULL); pthread_mutex_init( &self->video_mutex, NULL ); pthread_cond_init( &self->video_cond, NULL); // Default scaler (for now we'll use nearest) mlt_properties_set( self->properties, "rescale", "nearest" ); mlt_properties_set( self->properties, "deinterlace_method", "onefield" ); mlt_properties_set_int( self->properties, "top_field_first", -1 ); // Default buffer for low latency mlt_properties_set_int( self->properties, "buffer", 1 ); // Default audio buffer mlt_properties_set_int( self->properties, "audio_buffer", 2048 ); // Ensure we don't join on a non-running object self->joined = 1; // Allow thread to be started/stopped parent->start = consumer_start; parent->stop = consumer_stop; parent->is_stopped = consumer_is_stopped; parent->purge = consumer_purge; // Initialize the refresh handler pthread_cond_init( &self->refresh_cond, NULL ); pthread_mutex_init( &self->refresh_mutex, NULL ); mlt_events_listen( MLT_CONSUMER_PROPERTIES( parent ), self, "property-changed", ( mlt_listener )consumer_refresh_cb ); // Return the consumer produced return parent; } // malloc or consumer init failed free( self ); // Indicate failure return NULL; } static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer parent, char *name ) { if ( !strcmp( name, "refresh" ) ) { consumer_sdl self = parent->child; pthread_mutex_lock( &self->refresh_mutex ); if ( self->refresh_count < 2 ) self->refresh_count = self->refresh_count <= 0 ? 1 : self->refresh_count + 1; pthread_cond_broadcast( &self->refresh_cond ); pthread_mutex_unlock( &self->refresh_mutex ); } } int consumer_start( mlt_consumer parent ) { consumer_sdl self = parent->child; if ( !self->running ) { consumer_stop( parent ); pthread_mutex_lock( &mlt_sdl_mutex ); int ret = SDL_Init( SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE ); pthread_mutex_unlock( &mlt_sdl_mutex ); if ( ret < 0 ) { mlt_log_error( MLT_CONSUMER_SERVICE(parent), "Failed to initialize SDL: %s\n", SDL_GetError() ); return -1; } self->running = 1; self->joined = 0; pthread_create( &self->thread, NULL, consumer_thread, self ); } return 0; } int consumer_stop( mlt_consumer parent ) { // Get the actual object consumer_sdl self = parent->child; if ( self->running && !self->joined ) { // Kill the thread and clean up self->joined = 1; self->running = 0; // Unlatch the consumer thread pthread_mutex_lock( &self->refresh_mutex ); pthread_cond_broadcast( &self->refresh_cond ); pthread_mutex_unlock( &self->refresh_mutex ); // Cleanup the main thread #ifndef WIN32 if ( self->thread ) #endif pthread_join( self->thread, NULL ); // Unlatch the video thread pthread_mutex_lock( &self->video_mutex ); pthread_cond_broadcast( &self->video_cond ); pthread_mutex_unlock( &self->video_mutex ); // Unlatch the audio callback pthread_mutex_lock( &self->audio_mutex ); pthread_cond_broadcast( &self->audio_cond ); pthread_mutex_unlock( &self->audio_mutex ); SDL_QuitSubSystem( SDL_INIT_AUDIO ); } return 0; } int consumer_is_stopped( mlt_consumer parent ) { consumer_sdl self = parent->child; return !self->running; } void consumer_purge( mlt_consumer parent ) { consumer_sdl self = parent->child; if ( self->running ) { pthread_mutex_lock( &self->video_mutex ); mlt_frame frame = MLT_FRAME( mlt_deque_peek_back( self->queue ) ); // When playing rewind or fast forward then we need to keep one // frame in the queue to prevent playback stalling. double speed = frame? mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame), "_speed" ) : 0; int n = ( speed == 0.0 || speed == 1.0 ) ? 0 : 1; while ( mlt_deque_count( self->queue ) > n ) mlt_frame_close( mlt_deque_pop_back( self->queue ) ); self->is_purge = 1; pthread_cond_broadcast( &self->video_cond ); pthread_mutex_unlock( &self->video_mutex ); } } static void sdl_fill_audio( void *udata, uint8_t *stream, int len ) { consumer_sdl self = udata; // Get the volume double volume = mlt_properties_get_double( self->properties, "volume" ); pthread_mutex_lock( &self->audio_mutex ); // Block until audio received #ifdef __DARWIN__ while ( self->running && len > self->audio_avail ) pthread_cond_wait( &self->audio_cond, &self->audio_mutex ); #endif if ( self->audio_avail >= len ) { // Place in the audio buffer if ( volume != 1.0 ) SDL_MixAudio( stream, self->audio_buffer, len, ( int )( ( float )SDL_MIX_MAXVOLUME * volume ) ); else memcpy( stream, self->audio_buffer, len ); // Remove len from the audio available self->audio_avail -= len; // Remove the samples memmove( self->audio_buffer, self->audio_buffer + len, self->audio_avail ); } else { // Just to be safe, wipe the stream first memset( stream, 0, len ); // Mix the audio SDL_MixAudio( stream, self->audio_buffer, self->audio_avail, ( int )( ( float )SDL_MIX_MAXVOLUME * volume ) ); // No audio left self->audio_avail = 0; } // We're definitely playing now self->playing = 1; pthread_cond_broadcast( &self->audio_cond ); pthread_mutex_unlock( &self->audio_mutex ); } static int consumer_play_audio( consumer_sdl self, mlt_frame frame, int init_audio, int *duration ) { // Get the properties of this consumer mlt_properties properties = self->properties; mlt_audio_format afmt = mlt_audio_s16; // Set the preferred params of the test card signal int channels = mlt_properties_get_int( properties, "channels" ); int frequency = mlt_properties_get_int( properties, "frequency" ); int scrub = mlt_properties_get_int( properties, "scrub_audio" ); static int counter = 0; int samples = mlt_sample_calculator( mlt_properties_get_double( self->properties, "fps" ), frequency, counter++ ); int16_t *pcm; int bytes; mlt_frame_get_audio( frame, (void**) &pcm, &afmt, &frequency, &channels, &samples ); *duration = ( ( samples * 1000 ) / frequency ); if ( mlt_properties_get_int( properties, "audio_off" ) ) { self->playing = 1; init_audio = 1; return init_audio; } if ( init_audio == 1 ) { SDL_AudioSpec request; SDL_AudioSpec got; int audio_buffer = mlt_properties_get_int( properties, "audio_buffer" ); // specify audio format memset( &request, 0, sizeof( SDL_AudioSpec ) ); self->playing = 0; request.freq = frequency; request.format = AUDIO_S16SYS; request.channels = channels; request.samples = audio_buffer; request.callback = sdl_fill_audio; request.userdata = (void *)self; if ( SDL_OpenAudio( &request, &got ) != 0 ) { mlt_log_error( MLT_CONSUMER_SERVICE( self ), "SDL failed to open audio: %s\n", SDL_GetError() ); init_audio = 2; } else if ( got.size != 0 ) { SDL_PauseAudio( 0 ); init_audio = 0; } } if ( init_audio == 0 ) { mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); bytes = ( samples * channels * 2 ); pthread_mutex_lock( &self->audio_mutex ); while ( self->running && bytes > ( sizeof( self->audio_buffer) - self->audio_avail ) ) pthread_cond_wait( &self->audio_cond, &self->audio_mutex ); if ( self->running ) { if ( scrub || mlt_properties_get_double( properties, "_speed" ) == 1 ) memcpy( &self->audio_buffer[ self->audio_avail ], pcm, bytes ); else memset( &self->audio_buffer[ self->audio_avail ], 0, bytes ); self->audio_avail += bytes; } pthread_cond_broadcast( &self->audio_cond ); pthread_mutex_unlock( &self->audio_mutex ); } else { self->playing = 1; } return init_audio; } static int consumer_play_video( consumer_sdl self, mlt_frame frame ) { // Get the properties of this consumer mlt_properties properties = self->properties; if ( self->running && !mlt_consumer_is_stopped( &self->parent ) ) mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); return 0; } static void *video_thread( void *arg ) { // Identify the arg consumer_sdl self = arg; // Obtain time of thread start struct timeval now; int64_t start = 0; int64_t elapsed = 0; struct timespec tm; mlt_frame next = NULL; mlt_properties properties = NULL; double speed = 0; // Get real time flag int real_time = mlt_properties_get_int( self->properties, "real_time" ); // Get the current time gettimeofday( &now, NULL ); // Determine start time start = ( int64_t )now.tv_sec * 1000000 + now.tv_usec; while ( self->running ) { // Pop the next frame pthread_mutex_lock( &self->video_mutex ); next = mlt_deque_pop_front( self->queue ); while ( next == NULL && self->running ) { pthread_cond_wait( &self->video_cond, &self->video_mutex ); next = mlt_deque_pop_front( self->queue ); } pthread_mutex_unlock( &self->video_mutex ); if ( !self->running || next == NULL ) break; // Get the properties properties = MLT_FRAME_PROPERTIES( next ); // Get the speed of the frame speed = mlt_properties_get_double( properties, "_speed" ); // Get the current time gettimeofday( &now, NULL ); // Get the elapsed time elapsed = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec ) - start; // See if we have to delay the display of the current frame if ( mlt_properties_get_int( properties, "rendered" ) == 1 && self->running ) { // Obtain the scheduled playout time int64_t scheduled = mlt_properties_get_int( properties, "playtime" ); // Determine the difference between the elapsed time and the scheduled playout time int64_t difference = scheduled - elapsed; // Smooth playback a bit if ( real_time && ( difference > 20000 && speed == 1.0 ) ) { tm.tv_sec = difference / 1000000; tm.tv_nsec = ( difference % 1000000 ) * 500; nanosleep( &tm, NULL ); } // Show current frame if not too old if ( !real_time || ( difference > -10000 || speed != 1.0 || mlt_deque_count( self->queue ) < 2 ) ) consumer_play_video( self, next ); // If the queue is empty, recalculate start to allow build up again if ( real_time && ( mlt_deque_count( self->queue ) == 0 && speed == 1.0 ) ) { gettimeofday( &now, NULL ); start = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec ) - scheduled + 20000; } } // This frame can now be closed mlt_frame_close( next ); next = NULL; } if ( next != NULL ) mlt_frame_close( next ); mlt_consumer_stopped( &self->parent ); return NULL; } /** Threaded wrapper for pipe. */ static void *consumer_thread( void *arg ) { // Identify the arg consumer_sdl self = arg; // Get the consumer mlt_consumer consumer = &self->parent; // Get the properties mlt_properties consumer_props = MLT_CONSUMER_PROPERTIES( consumer ); // Video thread pthread_t thread; // internal intialization int init_audio = 1; int init_video = 1; mlt_frame frame = NULL; mlt_properties properties = NULL; int duration = 0; int64_t playtime = 0; struct timespec tm = { 0, 100000 }; // int last_position = -1; pthread_mutex_lock( &self->refresh_mutex ); self->refresh_count = 0; pthread_mutex_unlock( &self->refresh_mutex ); // Loop until told not to while( self->running ) { // Get a frame from the attached producer frame = mlt_consumer_rt_frame( consumer ); // Ensure that we have a frame if ( frame ) { // Get the frame properties properties = MLT_FRAME_PROPERTIES( frame ); // Get the speed of the frame double speed = mlt_properties_get_double( properties, "_speed" ); // Get refresh request for the current frame int refresh = mlt_properties_get_int( consumer_props, "refresh" ); // Clear refresh mlt_events_block( consumer_props, consumer_props ); mlt_properties_set_int( consumer_props, "refresh", 0 ); mlt_events_unblock( consumer_props, consumer_props ); // Play audio init_audio = consumer_play_audio( self, frame, init_audio, &duration ); // Determine the start time now if ( self->playing && init_video ) { // Create the video thread pthread_create( &thread, NULL, video_thread, self ); // Video doesn't need to be initialised any more init_video = 0; } // Set playtime for this frame mlt_properties_set_int( properties, "playtime", playtime ); while ( self->running && speed != 0 && mlt_deque_count( self->queue ) > 15 ) nanosleep( &tm, NULL ); // Push this frame to the back of the queue if ( self->running && speed ) { pthread_mutex_lock( &self->video_mutex ); if ( self->is_purge && speed == 1.0 ) { mlt_frame_close( frame ); self->is_purge = 0; } else { mlt_deque_push_back( self->queue, frame ); pthread_cond_broadcast( &self->video_cond ); } pthread_mutex_unlock( &self->video_mutex ); // Calculate the next playtime playtime += ( duration * 1000 ); } else if ( self->running ) { pthread_mutex_lock( &self->refresh_mutex ); if ( ( refresh == 0 && self->refresh_count <= 0 ) || self->refresh_count > 1 ) { consumer_play_video( self, frame ); pthread_cond_wait( &self->refresh_cond, &self->refresh_mutex ); } mlt_frame_close( frame ); self->refresh_count --; pthread_mutex_unlock( &self->refresh_mutex ); } else { mlt_frame_close( frame ); frame = NULL; } // Optimisation to reduce latency if ( frame && speed == 1.0 ) { // TODO: disabled due to misbehavior on parallel-consumer // if ( last_position != -1 && last_position + 1 != mlt_frame_get_position( frame ) ) // mlt_consumer_purge( consumer ); // last_position = mlt_frame_get_position( frame ); } else { mlt_consumer_purge( consumer ); // last_position = -1; } } } // Kill the video thread if ( init_video == 0 ) { pthread_mutex_lock( &self->video_mutex ); pthread_cond_broadcast( &self->video_cond ); pthread_mutex_unlock( &self->video_mutex ); pthread_join( thread, NULL ); } while( mlt_deque_count( self->queue ) ) mlt_frame_close( mlt_deque_pop_back( self->queue ) ); self->audio_avail = 0; return NULL; } /** Callback to allow override of the close method. */ static void consumer_close( mlt_consumer parent ) { // Get the actual object consumer_sdl self = parent->child; // Stop the consumer mlt_consumer_stop( parent ); // Now clean up the rest mlt_consumer_close( parent ); // Close the queue mlt_deque_close( self->queue ); // Destroy mutexes pthread_mutex_destroy( &self->audio_mutex ); pthread_cond_destroy( &self->audio_cond ); pthread_mutex_destroy( &self->video_mutex ); pthread_cond_destroy( &self->video_cond ); pthread_mutex_destroy( &self->refresh_mutex ); pthread_cond_destroy( &self->refresh_cond ); // Finally clean up this free( self ); } mlt-0.9.0/src/modules/sdl/consumer_sdl_audio.yml000066400000000000000000000017371215300731300217410ustar00rootroot00000000000000schema_version: 0.1 type: consumer identifier: sdl_audio title: SDL Audio Only version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Audio description: > Simple DirectMedia Layer audio only output module. parameters: - identifier: volume title: Volume type: float description: Audio level factor. mutable: yes - identifier: audio_off title: Audio off type: integer description: If 1, disable audio output mutable: yes minimum: 0 maximum: 1 default: 0 widget: checkbox - identifier: audio_buffer title: Audio buffer type: integer description: Size of the sdl audio buffer. mutable: yes default: 2048 minimum: 128 - identifier: scrub_audio title: Audio scrubbing type: integer description: If enabled, sound is played even when the speed is not normal. mutable: yes minimum: 0 maximum: 1 default: 0 widget: checkbox mlt-0.9.0/src/modules/sdl/consumer_sdl_osx.h000066400000000000000000000022441215300731300210710ustar00rootroot00000000000000/* * consumer_sdl_osx.m -- An OS X compatibility shim for SDL * Copyright (C) 2010 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _CONSUMER_SDL_OSX_H_ #define _CONSUMER_SDL_OSX_H_ #ifdef __DARWIN__ void* mlt_cocoa_autorelease_init(); void mlt_cocoa_autorelease_close( void* ); #else static inline void *mlt_cocoa_autorelease_init() { return NULL; } static inline void mlt_cocoa_autorelease_close(void* p) { } #endif #endif mlt-0.9.0/src/modules/sdl/consumer_sdl_osx.m000066400000000000000000000056671215300731300211120ustar00rootroot00000000000000/* * consumer_sdl_osx.m -- An OS X compatibility shim for SDL * Copyright (C) 2010 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #import void* mlt_cocoa_autorelease_init() { return [[NSAutoreleasePool alloc] init]; } void mlt_cocoa_autorelease_close( void* p ) { NSAutoreleasePool* pool = ( NSAutoreleasePool* ) p; [pool release]; } #if 0 /* The code below is not used at this time - could not get it to work, but * it is based on code from gruntster on the avidemux project team. */ #import static NSWindow* nsWindow = nil; static NSQuickDrawView* nsView = nil; void sdl_cocoa_init(void* parent, int x, int y, int width, int height) { NSRect contentRect; contentRect = NSMakeRect(x, y, width, height); if (!nsWindow) { // initWithWindowRef always returns the same result for the same WindowRef nsWindow = [[NSWindow alloc] initWithWindowRef:(WindowRef)parent]; [nsWindow setContentView:[[[NSView alloc] initWithFrame:contentRect] autorelease]]; } if (!nsView) { nsView = [[NSQuickDrawView alloc] initWithFrame:contentRect]; [[nsWindow contentView] addSubview:nsView]; [nsView release]; [nsWindow orderOut:nil]; // very important, otherwise window won't be placed correctly on repeat showings [nsWindow orderFront:nil]; } else { [nsView setFrame:contentRect]; [[nsWindow contentView] setFrame:contentRect]; } // finally, set SDL environment variables with all this nonsense char SDL_windowhack[20]; sprintf(SDL_windowhack, "%d", (int)nsWindow); setenv("SDL_NSWindowPointer", SDL_windowhack, 1); sprintf(SDL_windowhack,"%d", (int)nsView); setenv("SDL_NSQuickDrawViewPointer", SDL_windowhack, 1); } void sdl_cocoa_close(void) { if (nsWindow) { // Reference count cannot fall below 2 because SDL releases the window when closing // and again when reinitialising (even though this is our own window...). if ([nsWindow retainCount] > 2) [nsWindow release]; // SDL takes care of all the destroying...a little too much, so make sure our Carbon // window is still displayed (via its Cocoa wrapper) [nsWindow makeKeyAndOrderFront:nil]; } } #endif mlt-0.9.0/src/modules/sdl/consumer_sdl_osx_hack.h000066400000000000000000000020701215300731300220540ustar00rootroot00000000000000/* * Purpose: A dummy thread object to inform Cocoa that it needs to be thread safe. * Author: Zachary Drew * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #import @interface DummyThread : NSObject - init; - (void)startThread:(id)arg; @end @implementation DummyThread - init { [super init]; return self; } - (void)startThread:(id)arg { return; } @end mlt-0.9.0/src/modules/sdl/consumer_sdl_preview.c000066400000000000000000000415751215300731300217460ustar00rootroot00000000000000/* * consumer_sdl_preview.c -- A Simple DirectMedia Layer consumer * Copyright (C) 2004-2005, 2010 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include extern pthread_mutex_t mlt_sdl_mutex; typedef struct consumer_sdl_s *consumer_sdl; struct consumer_sdl_s { struct mlt_consumer_s parent; mlt_consumer active; int ignore_change; mlt_consumer play; mlt_consumer still; pthread_t thread; int joined; int running; int sdl_flags; double last_speed; mlt_position last_position; pthread_cond_t refresh_cond; pthread_mutex_t refresh_mutex; int refresh_count; }; /** Forward references to static functions. */ static int consumer_start( mlt_consumer parent ); static int consumer_stop( mlt_consumer parent ); static int consumer_is_stopped( mlt_consumer parent ); static void consumer_purge( mlt_consumer parent ); static void consumer_close( mlt_consumer parent ); static void *consumer_thread( void * ); static void consumer_frame_show_cb( mlt_consumer sdl, mlt_consumer self, mlt_frame frame ); static void consumer_sdl_event_cb( mlt_consumer sdl, mlt_consumer self, SDL_Event *event ); static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer self, char *name ); mlt_consumer consumer_sdl_preview_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { consumer_sdl self = calloc( 1, sizeof( struct consumer_sdl_s ) ); if ( self != NULL && mlt_consumer_init( &self->parent, self, profile ) == 0 ) { // Get the parent consumer object mlt_consumer parent = &self->parent; // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( parent ); // Get the width and height int width = mlt_properties_get_int( properties, "width" ); int height = mlt_properties_get_int( properties, "height" ); // Process actual param if ( arg == NULL || sscanf( arg, "%dx%d", &width, &height ) == 2 ) { mlt_properties_set_int( properties, "width", width ); mlt_properties_set_int( properties, "height", height ); } // Create child consumers self->play = mlt_factory_consumer( profile, "sdl", arg ); self->still = mlt_factory_consumer( profile, "sdl_still", arg ); mlt_properties_set( properties, "rescale", "nearest" ); mlt_properties_set( properties, "deinterlace_method", "onefield" ); mlt_properties_set_int( properties, "prefill", 1 ); mlt_properties_set_int( properties, "top_field_first", -1 ); parent->close = consumer_close; parent->start = consumer_start; parent->stop = consumer_stop; parent->is_stopped = consumer_is_stopped; parent->purge = consumer_purge; self->joined = 1; mlt_events_listen( MLT_CONSUMER_PROPERTIES( self->play ), self, "consumer-frame-show", ( mlt_listener )consumer_frame_show_cb ); mlt_events_listen( MLT_CONSUMER_PROPERTIES( self->still ), self, "consumer-frame-show", ( mlt_listener )consumer_frame_show_cb ); mlt_events_listen( MLT_CONSUMER_PROPERTIES( self->play ), self, "consumer-sdl-event", ( mlt_listener )consumer_sdl_event_cb ); mlt_events_listen( MLT_CONSUMER_PROPERTIES( self->still ), self, "consumer-sdl-event", ( mlt_listener )consumer_sdl_event_cb ); pthread_cond_init( &self->refresh_cond, NULL ); pthread_mutex_init( &self->refresh_mutex, NULL ); mlt_events_listen( MLT_CONSUMER_PROPERTIES( parent ), self, "property-changed", ( mlt_listener )consumer_refresh_cb ); mlt_events_register( properties, "consumer-sdl-paused", NULL ); return parent; } free( self ); return NULL; } void consumer_frame_show_cb( mlt_consumer sdl, mlt_consumer parent, mlt_frame frame ) { consumer_sdl self = parent->child; self->last_speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ); self->last_position = mlt_frame_get_position( frame ); mlt_events_fire( MLT_CONSUMER_PROPERTIES( parent ), "consumer-frame-show", frame, NULL ); } static void consumer_sdl_event_cb( mlt_consumer sdl, mlt_consumer parent, SDL_Event *event ) { mlt_events_fire( MLT_CONSUMER_PROPERTIES( parent ), "consumer-sdl-event", event, NULL ); } static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer parent, char *name ) { if ( !strcmp( name, "refresh" ) ) { consumer_sdl self = parent->child; pthread_mutex_lock( &self->refresh_mutex ); self->refresh_count = self->refresh_count <= 0 ? 1 : self->refresh_count + 1; pthread_cond_broadcast( &self->refresh_cond ); pthread_mutex_unlock( &self->refresh_mutex ); } } static int consumer_start( mlt_consumer parent ) { consumer_sdl self = parent->child; if ( !self->running ) { // properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( parent ); mlt_properties play = MLT_CONSUMER_PROPERTIES( self->play ); mlt_properties still = MLT_CONSUMER_PROPERTIES( self->still ); char *window_id = mlt_properties_get( properties, "window_id" ); char *audio_driver = mlt_properties_get( properties, "audio_driver" ); char *video_driver = mlt_properties_get( properties, "video_driver" ); char *audio_device = mlt_properties_get( properties, "audio_device" ); char *output_display = mlt_properties_get( properties, "output_display" ); int progressive = mlt_properties_get_int( properties, "progressive" ) | mlt_properties_get_int( properties, "deinterlace" ); consumer_stop( parent ); self->running = 1; self->joined = 0; self->last_speed = 1; if ( output_display != NULL ) setenv( "DISPLAY", output_display, 1 ); if ( window_id != NULL ) setenv( "SDL_WINDOWID", window_id, 1 ); if ( video_driver != NULL ) setenv( "SDL_VIDEODRIVER", video_driver, 1 ); if ( audio_driver != NULL ) setenv( "SDL_AUDIODRIVER", audio_driver, 1 ); if ( audio_device != NULL ) setenv( "AUDIODEV", audio_device, 1 ); pthread_mutex_lock( &mlt_sdl_mutex ); int ret = SDL_Init( SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE ); pthread_mutex_unlock( &mlt_sdl_mutex ); if ( ret < 0 ) { fprintf( stderr, "Failed to initialize SDL: %s\n", SDL_GetError() ); return -1; } SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL ); SDL_EnableUNICODE( 1 ); // Pass properties down mlt_properties_set_data( play, "transport_producer", mlt_properties_get_data( properties, "transport_producer", NULL ), 0, NULL, NULL ); mlt_properties_set_data( still, "transport_producer", mlt_properties_get_data( properties, "transport_producer", NULL ), 0, NULL, NULL ); mlt_properties_set_data( play, "transport_callback", mlt_properties_get_data( properties, "transport_callback", NULL ), 0, NULL, NULL ); mlt_properties_set_data( still, "transport_callback", mlt_properties_get_data( properties, "transport_callback", NULL ), 0, NULL, NULL ); mlt_properties_set_int( play, "progressive", progressive ); mlt_properties_set_int( still, "progressive", progressive ); mlt_properties_pass_list( play, properties, "deinterlace_method,resize,rescale,width,height,aspect_ratio,display_ratio,preview_off,preview_format,window_background" ",top_field_first,volume,real_time,buffer,prefill,audio_off,frequency,drop_max" ); mlt_properties_pass_list( still, properties, "deinterlace_method,resize,rescale,width,height,aspect_ratio,display_ratio,preview_off,preview_format,window_background" ",top_field_first"); mlt_properties_pass( play, properties, "play." ); mlt_properties_pass( still, properties, "still." ); mlt_properties_set_data( play, "app_lock", mlt_properties_get_data( properties, "app_lock", NULL ), 0, NULL, NULL ); mlt_properties_set_data( still, "app_lock", mlt_properties_get_data( properties, "app_lock", NULL ), 0, NULL, NULL ); mlt_properties_set_data( play, "app_unlock", mlt_properties_get_data( properties, "app_unlock", NULL ), 0, NULL, NULL ); mlt_properties_set_data( still, "app_unlock", mlt_properties_get_data( properties, "app_unlock", NULL ), 0, NULL, NULL ); mlt_properties_set_int( play, "put_mode", 1 ); mlt_properties_set_int( still, "put_mode", 1 ); mlt_properties_set_int( play, "terminate_on_pause", 1 ); // Start the still producer just to initialise the gui mlt_consumer_start( self->still ); self->active = self->still; // Inform child consumers that we control the sdl mlt_properties_set_int( play, "sdl_started", 1 ); mlt_properties_set_int( still, "sdl_started", 1 ); pthread_create( &self->thread, NULL, consumer_thread, self ); } return 0; } static int consumer_stop( mlt_consumer parent ) { // Get the actual object consumer_sdl self = parent->child; if ( self->joined == 0 ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( parent ); int app_locked = mlt_properties_get_int( properties, "app_locked" ); void ( *lock )( void ) = mlt_properties_get_data( properties, "app_lock", NULL ); void ( *unlock )( void ) = mlt_properties_get_data( properties, "app_unlock", NULL ); if ( app_locked && unlock ) unlock( ); // Kill the thread and clean up self->running = 0; pthread_mutex_lock( &self->refresh_mutex ); pthread_cond_broadcast( &self->refresh_cond ); pthread_mutex_unlock( &self->refresh_mutex ); #ifndef WIN32 if ( self->thread ) #endif pthread_join( self->thread, NULL ); self->joined = 1; if ( app_locked && lock ) lock( ); pthread_mutex_lock( &mlt_sdl_mutex ); SDL_Quit( ); pthread_mutex_unlock( &mlt_sdl_mutex ); } return 0; } static int consumer_is_stopped( mlt_consumer parent ) { consumer_sdl self = parent->child; return !self->running; } void consumer_purge( mlt_consumer parent ) { consumer_sdl self = parent->child; if ( self->running ) mlt_consumer_purge( self->play ); } static void *consumer_thread( void *arg ) { // Identify the arg consumer_sdl self = arg; // Get the consumer mlt_consumer consumer = &self->parent; // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // internal intialization mlt_frame frame = NULL; int last_position = -1; int eos = 0; int eos_threshold = 20; if ( self->play ) eos_threshold = eos_threshold + mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( self->play ), "buffer" ); // Determine if the application is dealing with the preview int preview_off = mlt_properties_get_int( properties, "preview_off" ); pthread_mutex_lock( &self->refresh_mutex ); self->refresh_count = 0; pthread_mutex_unlock( &self->refresh_mutex ); // Loop until told not to while( self->running ) { // Get a frame from the attached producer frame = mlt_consumer_get_frame( consumer ); // Ensure that we have a frame if ( self->running && frame != NULL ) { // Get the speed of the frame double speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ); // Lock during the operation mlt_service_lock( MLT_CONSUMER_SERVICE( consumer ) ); // Get refresh request for the current frame int refresh = mlt_properties_get_int( properties, "refresh" ); // Decrement refresh and clear changed mlt_events_block( properties, properties ); mlt_properties_set_int( properties, "refresh", 0 ); mlt_events_unblock( properties, properties ); // Unlock after the operation mlt_service_unlock( MLT_CONSUMER_SERVICE( consumer ) ); // Set the changed property on this frame for the benefit of still mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "refresh", refresh ); // Make sure the recipient knows that this frame isn't really rendered mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 0 ); // Optimisation to reduce latency if ( speed == 1.0 ) { if ( last_position != -1 && last_position + 1 != mlt_frame_get_position( frame ) ) mlt_consumer_purge( self->play ); last_position = mlt_frame_get_position( frame ); } else { //mlt_consumer_purge( self->play ); last_position = -1; } // If we aren't playing normally, then use the still if ( speed != 1 ) { mlt_producer producer = MLT_PRODUCER( mlt_service_get_producer( MLT_CONSUMER_SERVICE( consumer ) ) ); mlt_position duration = producer? mlt_producer_get_playtime( producer ) : -1; int pause = 0; #ifndef SKIP_WAIT_EOS if ( self->active == self->play ) { // Do not interrupt the play consumer near the end if ( duration - self->last_position > eos_threshold ) { // Get a new frame at the sought position mlt_frame_close( frame ); if ( producer ) mlt_producer_seek( producer, self->last_position ); frame = mlt_consumer_get_frame( consumer ); pause = 1; } else { // Send frame with speed 0 to stop it if ( frame && !mlt_consumer_is_stopped( self->play ) ) { mlt_consumer_put_frame( self->play, frame ); frame = NULL; eos = 1; } // Check for end of stream if ( mlt_consumer_is_stopped( self->play ) ) { // Stream has ended mlt_log_verbose( MLT_CONSUMER_SERVICE( consumer ), "END OF STREAM\n" ); pause = 1; eos = 0; // reset eos indicator } else { // Prevent a tight busy loop struct timespec tm = { 0, 100000L }; // 100 usec nanosleep( &tm, NULL ); } } } #else pause = self->active == self->play; #endif if ( pause ) { // Start the still consumer if ( !mlt_consumer_is_stopped( self->play ) ) mlt_consumer_stop( self->play ); self->last_speed = speed; self->active = self->still; self->ignore_change = 0; mlt_consumer_start( self->still ); } // Send the frame to the active child if ( frame && !eos ) { mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "refresh", 1 ); if ( self->active ) mlt_consumer_put_frame( self->active, frame ); } if ( pause && speed == 0.0 ) { mlt_events_fire( properties, "consumer-sdl-paused", NULL ); } } // Allow a little grace time before switching consumers on speed changes else if ( self->ignore_change -- > 0 && self->active != NULL && !mlt_consumer_is_stopped( self->active ) ) { mlt_consumer_put_frame( self->active, frame ); } // Otherwise use the normal player else { if ( !mlt_consumer_is_stopped( self->still ) ) mlt_consumer_stop( self->still ); if ( mlt_consumer_is_stopped( self->play ) ) { self->last_speed = speed; self->active = self->play; self->ignore_change = 0; mlt_consumer_start( self->play ); } if ( self->play ) mlt_consumer_put_frame( self->play, frame ); } // Copy the rectangle info from the active consumer if ( self->running && preview_off == 0 && self->active ) { mlt_properties active = MLT_CONSUMER_PROPERTIES( self->active ); mlt_service_lock( MLT_CONSUMER_SERVICE( consumer ) ); mlt_properties_set_int( properties, "rect_x", mlt_properties_get_int( active, "rect_x" ) ); mlt_properties_set_int( properties, "rect_y", mlt_properties_get_int( active, "rect_y" ) ); mlt_properties_set_int( properties, "rect_w", mlt_properties_get_int( active, "rect_w" ) ); mlt_properties_set_int( properties, "rect_h", mlt_properties_get_int( active, "rect_h" ) ); mlt_service_unlock( MLT_CONSUMER_SERVICE( consumer ) ); } if ( self->active == self->still ) { pthread_mutex_lock( &self->refresh_mutex ); if ( self->running && speed == 0 && self->refresh_count <= 0 ) { mlt_events_fire( properties, "consumer-sdl-paused", NULL ); pthread_cond_wait( &self->refresh_cond, &self->refresh_mutex ); } self->refresh_count --; pthread_mutex_unlock( &self->refresh_mutex ); } } else { if ( frame ) mlt_frame_close( frame ); mlt_consumer_put_frame( self->active, NULL ); self->running = 0; } } if ( self->play ) mlt_consumer_stop( self->play ); if ( self->still ) mlt_consumer_stop( self->still ); return NULL; } /** Callback to allow override of the close method. */ static void consumer_close( mlt_consumer parent ) { // Get the actual object consumer_sdl self = parent->child; // Stop the consumer mlt_consumer_stop( parent ); // Close the child consumers mlt_consumer_close( self->play ); mlt_consumer_close( self->still ); // Now clean up the rest mlt_consumer_close( parent ); // Finally clean up self free( self ); } mlt-0.9.0/src/modules/sdl/consumer_sdl_preview.yml000066400000000000000000000003011215300731300223030ustar00rootroot00000000000000schema_version: 0.1 type: consumer identifier: sdl title: SDL version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Audio - Video mlt-0.9.0/src/modules/sdl/consumer_sdl_still.c000066400000000000000000000450621215300731300214070ustar00rootroot00000000000000/* * consumer_sdl_still.c -- A Simple DirectMedia Layer consumer * Copyright (C) 2003-2004, 2010 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "consumer_sdl_osx.h" extern pthread_mutex_t mlt_sdl_mutex; /** This classes definition. */ typedef struct consumer_sdl_s *consumer_sdl; struct consumer_sdl_s { struct mlt_consumer_s parent; mlt_properties properties; pthread_t thread; int joined; int running; int window_width; int window_height; int width; int height; int playing; int sdl_flags; SDL_Rect rect; uint8_t *buffer; int last_position; mlt_producer last_producer; }; /** Forward references to static functions. */ static int consumer_start( mlt_consumer parent ); static int consumer_stop( mlt_consumer parent ); static int consumer_is_stopped( mlt_consumer parent ); static void consumer_close( mlt_consumer parent ); static void *consumer_thread( void * ); static int consumer_get_dimensions( int *width, int *height ); static void consumer_sdl_event( mlt_listener listener, mlt_properties owner, mlt_service this, void **args ); /** This is what will be called by the factory - anything can be passed in via the argument, but keep it simple. */ mlt_consumer consumer_sdl_still_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create the consumer object consumer_sdl this = calloc( 1, sizeof( struct consumer_sdl_s ) ); // If no malloc'd and consumer init ok if ( this != NULL && mlt_consumer_init( &this->parent, this, profile ) == 0 ) { // Get the parent consumer object mlt_consumer parent = &this->parent; // get a handle on properties mlt_service service = MLT_CONSUMER_SERVICE( parent ); this->properties = MLT_SERVICE_PROPERTIES( service ); // We have stuff to clean up, so override the close method parent->close = consumer_close; // Default scaler (for now we'll use nearest) mlt_properties_set( this->properties, "rescale", "nearest" ); // We're always going to run this in non-realtime mode mlt_properties_set( this->properties, "real_time", "0" ); // Ensure we don't join on a non-running object this->joined = 1; // process actual param if ( arg == NULL || sscanf( arg, "%dx%d", &this->width, &this->height ) != 2 ) { this->width = mlt_properties_get_int( this->properties, "width" ); this->height = mlt_properties_get_int( this->properties, "height" ); } else { mlt_properties_set_int( this->properties, "width", this->width ); mlt_properties_set_int( this->properties, "height", this->height ); } // Set the sdl flags this->sdl_flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_RESIZABLE | SDL_DOUBLEBUF; // Allow thread to be started/stopped parent->start = consumer_start; parent->stop = consumer_stop; parent->is_stopped = consumer_is_stopped; // Register specific events mlt_events_register( this->properties, "consumer-sdl-event", ( mlt_transmitter )consumer_sdl_event ); // Return the consumer produced return parent; } // malloc or consumer init failed free( this ); // Indicate failure return NULL; } static void consumer_sdl_event( mlt_listener listener, mlt_properties owner, mlt_service this, void **args ) { if ( listener != NULL ) listener( owner, this, ( SDL_Event * )args[ 0 ] ); } static int consumer_start( mlt_consumer parent ) { consumer_sdl this = parent->child; if ( !this->running ) { int preview_off = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "preview_off" ); int sdl_started = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "sdl_started" ); consumer_stop( parent ); this->last_position = -1; this->running = 1; this->joined = 0; // Allow the user to force resizing to window size this->width = mlt_properties_get_int( this->properties, "width" ); this->height = mlt_properties_get_int( this->properties, "height" ); // Default window size double display_ratio = mlt_properties_get_double( this->properties, "display_ratio" ); this->window_width = ( double )this->height * display_ratio + 0.5; this->window_height = this->height; if ( sdl_started == 0 && preview_off == 0 ) { pthread_mutex_lock( &mlt_sdl_mutex ); int ret = SDL_Init( SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE ); pthread_mutex_unlock( &mlt_sdl_mutex ); if ( ret < 0 ) { fprintf( stderr, "Failed to initialize SDL: %s\n", SDL_GetError() ); return -1; } SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL ); SDL_EnableUNICODE( 1 ); } pthread_mutex_lock( &mlt_sdl_mutex ); if ( !SDL_GetVideoSurface() && preview_off == 0 ) SDL_SetVideoMode( this->window_width, this->window_height, 0, this->sdl_flags ); pthread_mutex_unlock( &mlt_sdl_mutex ); pthread_create( &this->thread, NULL, consumer_thread, this ); } return 0; } static int consumer_stop( mlt_consumer parent ) { // Get the actual object consumer_sdl this = parent->child; if ( this->joined == 0 ) { int preview_off = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "preview_off" ); int sdl_started = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "sdl_started" ); // Kill the thread and clean up this->running = 0; pthread_join( this->thread, NULL ); this->joined = 1; if ( sdl_started == 0 && preview_off == 0 ) { pthread_mutex_lock( &mlt_sdl_mutex ); SDL_Quit( ); pthread_mutex_unlock( &mlt_sdl_mutex ); } } return 0; } static int consumer_is_stopped( mlt_consumer parent ) { consumer_sdl this = parent->child; return !this->running; } static int sdl_lock_display( ) { pthread_mutex_lock( &mlt_sdl_mutex ); SDL_Surface *screen = SDL_GetVideoSurface( ); int result = screen != NULL && ( !SDL_MUSTLOCK( screen ) || SDL_LockSurface( screen ) >= 0 ); pthread_mutex_unlock( &mlt_sdl_mutex ); return result; } static void sdl_unlock_display( ) { pthread_mutex_lock( &mlt_sdl_mutex ); SDL_Surface *screen = SDL_GetVideoSurface( ); if ( screen != NULL && SDL_MUSTLOCK( screen ) ) SDL_UnlockSurface( screen ); pthread_mutex_unlock( &mlt_sdl_mutex ); } static inline void display_1( SDL_Surface *screen, SDL_Rect rect, uint8_t *image, int width, int height ) { // Generate the affine transform scaling values if ( rect.w == 0 || rect.h == 0 ) return; int scale_width = ( width << 16 ) / rect.w; int scale_height = ( height << 16 ) / rect.h; int stride = width * 4; int x, y, row_index; uint8_t *q, *row; // Constants defined for clarity and optimisation int scanlength = screen->pitch; uint8_t *start = ( uint8_t * )screen->pixels + rect.y * scanlength + rect.x; uint8_t *p; // Iterate through the screen using a very basic scaling algorithm for ( y = 0; y < rect.h; y ++ ) { p = start; row_index = ( 32768 + scale_height * y ) >> 16; row = image + stride * row_index; for ( x = 0; x < rect.w; x ++ ) { q = row + ( ( ( 32768 + scale_width * x ) >> 16 ) * 4 ); *p ++ = SDL_MapRGB( screen->format, *q, *( q + 1 ), *( q + 2 ) ); } start += scanlength; } } static inline void display_2( SDL_Surface *screen, SDL_Rect rect, uint8_t *image, int width, int height ) { // Generate the affine transform scaling values if ( rect.w == 0 || rect.h == 0 ) return; int scale_width = ( width << 16 ) / rect.w; int scale_height = ( height << 16 ) / rect.h; int stride = width * 4; int x, y, row_index; uint8_t *q, *row; // Constants defined for clarity and optimisation int scanlength = screen->pitch / 2; uint16_t *start = ( uint16_t * )screen->pixels + rect.y * scanlength + rect.x; uint16_t *p; // Iterate through the screen using a very basic scaling algorithm for ( y = 0; y < rect.h; y ++ ) { p = start; row_index = ( 32768 + scale_height * y ) >> 16; row = image + stride * row_index; for ( x = 0; x < rect.w; x ++ ) { q = row + ( ( ( 32768 + scale_width * x ) >> 16 ) * 4 ); *p ++ = SDL_MapRGB( screen->format, *q, *( q + 1 ), *( q + 2 ) ); } start += scanlength; } } static inline void display_3( SDL_Surface *screen, SDL_Rect rect, uint8_t *image, int width, int height ) { // Generate the affine transform scaling values if ( rect.w == 0 || rect.h == 0 ) return; int scale_width = ( width << 16 ) / rect.w; int scale_height = ( height << 16 ) / rect.h; int stride = width * 4; int x, y, row_index; uint8_t *q, *row; // Constants defined for clarity and optimisation int scanlength = screen->pitch; uint8_t *start = ( uint8_t * )screen->pixels + rect.y * scanlength + rect.x; uint8_t *p; uint32_t pixel; // Iterate through the screen using a very basic scaling algorithm for ( y = 0; y < rect.h; y ++ ) { p = start; row_index = ( 32768 + scale_height * y ) >> 16; row = image + stride * row_index; for ( x = 0; x < rect.w; x ++ ) { q = row + ( ( ( 32768 + scale_width * x ) >> 16 ) * 4 ); pixel = SDL_MapRGB( screen->format, *q, *( q + 1 ), *( q + 2 ) ); *p ++ = (pixel & 0xFF0000) >> 16; *p ++ = (pixel & 0x00FF00) >> 8; *p ++ = (pixel & 0x0000FF); } start += scanlength; } } static inline void display_4( SDL_Surface *screen, SDL_Rect rect, uint8_t *image, int width, int height ) { // Generate the affine transform scaling values if ( rect.w == 0 || rect.h == 0 ) return; int scale_width = ( width << 16 ) / rect.w; int scale_height = ( height << 16 ) / rect.h; int stride = width * 4; int x, y, row_index; uint8_t *q, *row; // Constants defined for clarity and optimisation int scanlength = screen->pitch / 4; uint32_t *start = ( uint32_t * )screen->pixels + rect.y * scanlength + rect.x; uint32_t *p; // Iterate through the screen using a very basic scaling algorithm for ( y = 0; y < rect.h; y ++ ) { p = start; row_index = ( 32768 + scale_height * y ) >> 16; row = image + stride * row_index; for ( x = 0; x < rect.w; x ++ ) { q = row + ( ( ( 32768 + scale_width * x ) >> 16 ) * 4 ); *p ++ = SDL_MapRGB( screen->format, *q, *( q + 1 ), *( q + 2 ) ); } start += scanlength; } } static int consumer_play_video( consumer_sdl this, mlt_frame frame ) { // Get the properties of this consumer mlt_properties properties = this->properties; mlt_image_format vfmt = mlt_image_rgb24a; int height = this->height; int width = this->width; uint8_t *image = NULL; int changed = 0; double display_ratio = mlt_properties_get_double( this->properties, "display_ratio" ); void ( *lock )( void ) = mlt_properties_get_data( properties, "app_lock", NULL ); void ( *unlock )( void ) = mlt_properties_get_data( properties, "app_unlock", NULL ); if ( lock != NULL ) lock( ); void *pool = mlt_cocoa_autorelease_init(); sdl_lock_display(); // Handle events if ( SDL_GetVideoSurface() ) { SDL_Event event; pthread_mutex_lock( &mlt_sdl_mutex ); changed = consumer_get_dimensions( &this->window_width, &this->window_height ); pthread_mutex_unlock( &mlt_sdl_mutex ); while ( SDL_PollEvent( &event ) ) { mlt_events_fire( this->properties, "consumer-sdl-event", &event, NULL ); switch( event.type ) { case SDL_VIDEORESIZE: this->window_width = event.resize.w; this->window_height = event.resize.h; changed = 1; break; case SDL_QUIT: this->running = 0; break; case SDL_KEYDOWN: { mlt_producer producer = mlt_properties_get_data( properties, "transport_producer", NULL ); char keyboard[ 2 ] = " "; void (*callback)( mlt_producer, char * ) = mlt_properties_get_data( properties, "transport_callback", NULL ); if ( callback != NULL && producer != NULL && event.key.keysym.unicode < 0x80 && event.key.keysym.unicode > 0 ) { keyboard[ 0 ] = ( char )event.key.keysym.unicode; callback( producer, keyboard ); } } break; } } } if ( !SDL_GetVideoSurface() || changed ) { // open SDL window pthread_mutex_lock( &mlt_sdl_mutex ); SDL_Surface *screen = SDL_SetVideoMode( this->window_width, this->window_height, 0, this->sdl_flags ); if ( consumer_get_dimensions( &this->window_width, &this->window_height ) ) screen = SDL_SetVideoMode( this->window_width, this->window_height, 0, this->sdl_flags ); if ( screen ) { uint32_t color = mlt_properties_get_int( this->properties, "window_background" ); SDL_FillRect( screen, NULL, color >> 8 ); changed = 1; } pthread_mutex_unlock( &mlt_sdl_mutex ); } mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "test_audio", 1 ); if ( changed == 0 && this->last_position == mlt_frame_get_position( frame ) && this->last_producer == mlt_frame_get_original_producer( frame ) && !mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "refresh" ) ) { sdl_unlock_display( ); mlt_cocoa_autorelease_close( pool ); if ( unlock != NULL ) unlock( ); struct timespec tm = { 0, 100000 }; nanosleep( &tm, NULL ); return 0; } // Update last frame shown info this->last_position = mlt_frame_get_position( frame ); this->last_producer = mlt_frame_get_original_producer( frame ); // Get the image, width and height mlt_frame_get_image( frame, &image, &vfmt, &width, &height, 0 ); if ( image != NULL ) { char *rescale = mlt_properties_get( properties, "rescale" ); if ( rescale != NULL && strcmp( rescale, "none" ) ) { double this_aspect = display_ratio / ( ( double )this->window_width / ( double )this->window_height ); this->rect.w = this_aspect * this->window_width; this->rect.h = this->window_height; if ( this->rect.w > this->window_width ) { this->rect.w = this->window_width; this->rect.h = ( 1.0 / this_aspect ) * this->window_height; } } else { double frame_aspect = mlt_frame_get_aspect_ratio( frame ) * width / height; this->rect.w = frame_aspect * this->window_height; this->rect.h = this->window_height; if ( this->rect.w > this->window_width ) { this->rect.w = this->window_width; this->rect.h = ( 1.0 / frame_aspect ) * this->window_width; } } this->rect.x = ( this->window_width - this->rect.w ) / 2; this->rect.y = ( this->window_height - this->rect.h ) / 2; mlt_properties_set_int( this->properties, "rect_x", this->rect.x ); mlt_properties_set_int( this->properties, "rect_y", this->rect.y ); mlt_properties_set_int( this->properties, "rect_w", this->rect.w ); mlt_properties_set_int( this->properties, "rect_h", this->rect.h ); } pthread_mutex_lock( &mlt_sdl_mutex ); SDL_Surface *screen = SDL_GetVideoSurface( ); if ( !mlt_consumer_is_stopped( &this->parent ) && screen && screen->pixels ) { switch( screen->format->BytesPerPixel ) { case 1: display_1( screen, this->rect, image, width, height ); break; case 2: display_2( screen, this->rect, image, width, height ); break; case 3: display_3( screen, this->rect, image, width, height ); break; case 4: display_4( screen, this->rect, image, width, height ); break; default: fprintf( stderr, "Unsupported video depth %d\n", screen->format->BytesPerPixel ); break; } // Flip it into sight SDL_Flip( screen ); } pthread_mutex_unlock( &mlt_sdl_mutex ); sdl_unlock_display(); mlt_cocoa_autorelease_close( pool ); if ( unlock != NULL ) unlock( ); mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); return 1; } /** Threaded wrapper for pipe. */ static void *consumer_thread( void *arg ) { // Identify the arg consumer_sdl this = arg; // Get the consumer mlt_consumer consumer = &this->parent; mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_frame frame = NULL; // Allow the hosting app to provide the preview int preview_off = mlt_properties_get_int( properties, "preview_off" ); // Loop until told not to while( this->running ) { // Get a frame from the attached producer frame = mlt_consumer_rt_frame( consumer ); // Ensure that we have a frame if ( this->running && frame != NULL ) { if ( preview_off == 0 ) { consumer_play_video( this, frame ); } else { mlt_image_format vfmt = mlt_image_rgb24a; int height = this->height; int width = this->width; uint8_t *image = NULL; mlt_image_format preview_format = mlt_properties_get_int( properties, "preview_format" ); // Check if a specific colour space has been requested if ( preview_off && preview_format != mlt_image_none ) vfmt = preview_format; mlt_frame_get_image( frame, &image, &vfmt, &width, &height, 0 ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "format", vfmt ); mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); } mlt_frame_close( frame ); } else { if ( frame ) mlt_frame_close( frame ); this->running = 0; } } return NULL; } static int consumer_get_dimensions( int *width, int *height ) { int changed = 0; // SDL windows manager structure SDL_SysWMinfo wm; // Specify the SDL Version SDL_VERSION( &wm.version ); #ifndef __DARWIN__ // Get the wm structure if ( SDL_GetWMInfo( &wm ) == 1 ) { #ifndef WIN32 // Check that we have the X11 wm if ( wm.subsystem == SDL_SYSWM_X11 ) { // Get the SDL window Window window = wm.info.x11.window; // Get the display session Display *display = wm.info.x11.display; // Get the window attributes XWindowAttributes attr; XGetWindowAttributes( display, window, &attr ); // Determine whether window has changed changed = *width != attr.width || *height != attr.height; // Return width and height *width = attr.width; *height = attr.height; } #endif } #endif return changed; } /** Callback to allow override of the close method. */ static void consumer_close( mlt_consumer parent ) { // Get the actual object consumer_sdl this = parent->child; // Stop the consumer mlt_consumer_stop( parent ); // Now clean up the rest mlt_consumer_close( parent ); // Finally clean up this free( this ); } mlt-0.9.0/src/modules/sdl/consumer_sdl_still.yml000066400000000000000000000003011215300731300217510ustar00rootroot00000000000000schema_version: 0.1 type: consumer identifier: sdl_still title: SDL RGB version: 1 copyright: Ushodaya Enterprises Limited creator: Charles Yates license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/sdl/factory.c000066400000000000000000000051461215300731300171510ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include extern mlt_consumer consumer_sdl_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_consumer consumer_sdl_audio_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_consumer consumer_sdl_still_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_consumer consumer_sdl_preview_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); #ifdef WITH_SDL_IMAGE extern mlt_producer producer_sdl_image_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); #endif static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/sdl/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( consumer_type, "sdl", consumer_sdl_init ); MLT_REGISTER( consumer_type, "sdl_audio", consumer_sdl_audio_init ); MLT_REGISTER( consumer_type, "sdl_preview", consumer_sdl_preview_init ); MLT_REGISTER( consumer_type, "sdl_still", consumer_sdl_still_init ); #ifdef WITH_SDL_IMAGE MLT_REGISTER( producer_type, "sdl_image", producer_sdl_image_init ); MLT_REGISTER_METADATA( producer_type, "sdl_image", metadata, "consumer_sdl_image.yml" ); #endif MLT_REGISTER_METADATA( consumer_type, "sdl", metadata, "consumer_sdl.yml" ); MLT_REGISTER_METADATA( consumer_type, "sdl_audio", metadata, "consumer_sdl_audio.yml" ); MLT_REGISTER_METADATA( consumer_type, "sdl_preview", metadata, "consumer_sdl_preview.yml" ); MLT_REGISTER_METADATA( consumer_type, "sdl_still", metadata, "consumer_sdl_still.yml" ); } mlt-0.9.0/src/modules/sdl/producer_sdl_image.c000066400000000000000000000170031215300731300213240ustar00rootroot00000000000000/* * producer_sdl_image.c -- Image loader which wraps SDL_image * Copyright (C) 2005 Visual Media FX * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include static int producer_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); SDL_Surface *surface = mlt_properties_get_data( properties, "surface", NULL ); SDL_Surface *converted = NULL; *width = surface->w; *height = surface->h; int image_size = *width * *height * 3; if ( surface->format->BitsPerPixel != 32 && surface->format->BitsPerPixel != 24 ) { SDL_PixelFormat fmt; fmt.BitsPerPixel = 24; fmt.BytesPerPixel = 3; fmt.Rshift = 16; fmt.Gshift = 8; fmt.Bshift = 0; fmt.Rmask = 0xff << 16; fmt.Gmask = 0xff << 8; fmt.Bmask = 0xff; converted = SDL_ConvertSurface( surface, &fmt, 0 ); } switch( surface->format->BitsPerPixel ) { case 32: *format = mlt_image_rgb24a; image_size = *width * *height * 4; *image = mlt_pool_alloc( image_size ); memcpy( *image, surface->pixels, image_size ); break; default: *format = mlt_image_rgb24; *image = mlt_pool_alloc( image_size ); memcpy( *image, surface->pixels, image_size ); break; } if ( converted ) SDL_FreeSurface( converted ); // Update the frame mlt_frame_set_image( frame, *image, image_size, mlt_pool_release ); return 0; } static int filter_files( const struct dirent *de ) { return de->d_name[ 0 ] != '.'; } static mlt_properties parse_file_names( char *resource ) { mlt_properties properties = mlt_properties_new( ); if ( strstr( resource, "/.all." ) != NULL ) { char *dir_name = strdup( resource ); char *extension = strrchr( resource, '.' ); *( strstr( dir_name, "/.all." ) + 1 ) = '\0'; char fullname[ 1024 ]; strcpy( fullname, dir_name ); struct dirent **de = NULL; int n = scandir( fullname, &de, filter_files, alphasort ); int i; struct stat info; for (i = 0; i < n; i++ ) { snprintf( fullname, 1023, "%s%s", dir_name, de[i]->d_name ); if ( strstr( fullname, extension ) && lstat( fullname, &info ) == 0 && ( S_ISREG( info.st_mode ) || info.st_mode | S_IXUSR ) ) { char temp[ 20 ]; sprintf( temp, "%d", i ); mlt_properties_set( properties, temp, fullname ); } free( de[ i ] ); } free( de ); free( dir_name ); } else { mlt_properties_set( properties, "0", resource ); } return properties; } static SDL_Surface *load_image( mlt_producer producer ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); char *resource = mlt_properties_get( properties, "resource" ); char *last_resource = mlt_properties_get( properties, "_last_resource" ); int image_idx = 0; char *this_resource = NULL; double ttl = mlt_properties_get_int( properties, "ttl" ); mlt_position position = mlt_producer_position( producer ); SDL_Surface *surface = mlt_properties_get_data( properties, "_surface", NULL ); mlt_properties filenames = mlt_properties_get_data( properties, "_filenames", NULL ); if ( filenames == NULL ) { filenames = parse_file_names( resource ); mlt_properties_set_data( properties, "_filenames", filenames, 0, ( mlt_destructor )mlt_properties_close, 0 ); mlt_properties_set_data( properties, "_surface", surface, 0, ( mlt_destructor )SDL_FreeSurface, 0 ); } if ( mlt_properties_count( filenames ) ) { image_idx = ( int )floor( ( double )position / ttl ) % mlt_properties_count( filenames ); this_resource = mlt_properties_get_value( filenames, image_idx ); if ( surface == NULL || last_resource == NULL || strcmp( last_resource, this_resource ) ) { surface = IMG_Load( this_resource ); if ( surface != NULL ) { surface->refcount ++; mlt_properties_set_data( properties, "_surface", surface, 0, ( mlt_destructor )SDL_FreeSurface, 0 ); mlt_properties_set( properties, "_last_resource", this_resource ); mlt_properties_set_int( properties, "meta.media.width", surface->w ); mlt_properties_set_int( properties, "meta.media.height", surface->h ); } } else if ( surface != NULL ) { surface->refcount ++; } } return surface; } static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); if ( *frame != NULL ) { // Create the surface for the current image SDL_Surface *surface = load_image( producer ); if ( surface != NULL ) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Obtain properties of producer mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Set producer-specific frame properties mlt_properties_set_int( properties, "progressive", 1 ); mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_props, "aspect_ratio" ) ); mlt_properties_set_data( properties, "surface", surface, 0, ( mlt_destructor )SDL_FreeSurface, NULL ); // Push the get_image method mlt_frame_push_get_image( *frame, producer_get_image ); } } // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; } static void producer_close( mlt_producer producer ) { producer->close = NULL; mlt_producer_close( producer ); free( producer ); } mlt_producer producer_sdl_image_init( mlt_profile profile, mlt_service_type type, const char *id, char *file ) { mlt_producer producer = calloc( 1, sizeof( struct mlt_producer_s ) ); if ( producer != NULL && mlt_producer_init( producer, NULL ) == 0 ) { // Get the properties interface mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); // Callback registration producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )producer_close; // Set the default properties mlt_properties_set( properties, "resource", file ); mlt_properties_set( properties, "_resource", "" ); mlt_properties_set_double( properties, "aspect_ratio", 1 ); mlt_properties_set_int( properties, "ttl", 25 ); mlt_properties_set_int( properties, "progressive", 1 ); // Validate the resource SDL_Surface *surface = NULL; if ( file && ( surface = load_image( producer ) ) ) { SDL_FreeSurface( surface ); mlt_properties_set_data( properties, "_surface", NULL, 0, NULL, NULL ); } else { producer_close( producer ); producer = NULL; } return producer; } free( producer ); return NULL; } mlt-0.9.0/src/modules/sdl/producer_sdl_image.yml000066400000000000000000000003121215300731300216760ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: sdl_image title: SDL Image version: 1 copyright: Visual Media FX ? creator: Charles Yates license: LGPLv2.1 language: en notes: DEPRECATED tags: - Video mlt-0.9.0/src/modules/sox/000077500000000000000000000000001215300731300153575ustar00rootroot00000000000000mlt-0.9.0/src/modules/sox/Makefile000066400000000000000000000014511215300731300170200ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lm include ../../../config.mak include config.mak TARGET = ../libmltsox$(LIBSUF) OBJS = factory.o \ filter_sox.o SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/sox" install -m 644 filter_sox.yml "$(DESTDIR)$(mltdatadir)/sox" install -m 644 filter_sox_effect.yml "$(DESTDIR)$(mltdatadir)/sox" uninstall: rm "$(DESTDIR)$(moduledir)/libmltsox$(LIBSUF)" 2> /dev/null || true rm -rf "$(DESTDIR)$(mltdatadir)/sox" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/sox/configure000077500000000000000000000036571215300731300173010ustar00rootroot00000000000000#!/bin/sh if [ "$help" != "1" ] then # Determine how to lookup dependencies of executable for OS targetos=$(uname -s) case $targetos in Darwin) LDD="otool -L" ;; Linux|FreeBSD|NetBSD) LDD="ldd" ;; *) ;; esac pkg-config sox if [ $? -eq 0 ] then disable_sox=0 echo "CFLAGS += $(pkg-config --cflags sox)" > config.mak echo "LDFLAGS += $(pkg-config --libs sox)" >> config.mak [ $(pkg-config --modversion sox | cut -d. -f1) -gt 13 ] && echo "CFLAGS += -DSOX14" >> config.mak else which libst-config > /dev/null 2>&1 if [ $? -eq 0 ] then disable_sox=0 # determine if we need libsndfile $LDD $(which sox) | grep libsndfile > /dev/null [ $? -eq 0 ] && libsndfile="-lsndfile" # determine if we need libsamplerate $LDD $(which sox) | grep libsamplerate > /dev/null [ $? -eq 0 ] && libsamplerate="-lsamplerate" echo "CFLAGS += $(libst-config --cflags) -I../.." > config.mak echo "LDFLAGS += -lst $(libst-config --libs) $libsndfile $libsamplerate" >> config.mak else sox --version 2> /dev/null | grep 'v14.' > /dev/null disable_sox=$? if [ $disable_sox -eq 0 ] then LIBDIR=lib bits=$(uname -m) case $bits in x86_64) [ -d /usr/lib/lib64 ] && export LIBDIR=lib64 || export LIBDIR=lib ;; *) export LIBDIR=lib ;; esac sox=$(which sox) # chop sox soxdir=$(dirname $sox) # chop bin soxdir=$(dirname $soxdir) # determine if we need libsamplerate $LDD "$sox" | grep libsamplerate > /dev/null [ $? -eq 0 ] && libsamplerate="-lsamplerate" # determine if we need libsfx $LDD $(which sox) | grep libsfx > /dev/null [ $? -eq 0 ] && libsfx="-lsfx" echo "CFLAGS += -DSOX14 -I$soxdir/include" > config.mak echo "LDFLAGS += -L$soxdir/$LIBDIR -lsox $libsfx $libsamplerate" >> config.mak fi fi fi if [ "$disable_sox" != "0" ] then echo "- sox not found: disabling" touch ../disable-sox fi exit 0 fi mlt-0.9.0/src/modules/sox/factory.c000066400000000000000000000054461215300731300172030ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #ifdef SOX14 #include #endif extern mlt_filter filter_sox_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; mlt_properties result = NULL; // Load the yaml file snprintf( file, PATH_MAX, "%s/sox/filter_%s.yml", mlt_environment( "MLT_DATA" ), strcmp( id, "sox" ) ? "sox_effect" : "sox" ); result = mlt_properties_parse_yaml( file ); #ifdef SOX14 if ( result && ( type == filter_type ) && strcmp( id, "sox" ) ) { // Annotate the yaml properties with sox effect usage. mlt_properties params = mlt_properties_get_data( result, "parameters", NULL ); const sox_effect_handler_t *e; int i; for ( i = 0; sox_effect_fns[i]; i++ ) { e = sox_effect_fns[i](); if ( e && e->name && !strcmp( e->name, id + 4 ) ) { mlt_properties p = mlt_properties_get_data( params, "0", NULL ); mlt_properties_set( result, "identifier", e->name ); mlt_properties_set( result, "title", e->name ); mlt_properties_set( p, "type", "string" ); mlt_properties_set( p, "title", "Options" ); if ( e->usage ) mlt_properties_set( p, "format", e->usage ); break; } } } #endif return result; } MLT_REPOSITORY { MLT_REGISTER( filter_type, "sox", filter_sox_init ); MLT_REGISTER_METADATA( filter_type, "sox", metadata, NULL ); #ifdef SOX14 int i; const sox_effect_handler_t *e; char name[64] = "sox."; for ( i = 0; sox_effect_fns[i]; i++ ) { e = sox_effect_fns[i](); if ( e && e->name && !( e->flags & SOX_EFF_DEPRECATED ) #if (SOX_LIB_VERSION_CODE >= SOX_LIB_VERSION(14,3,0)) && !( e->flags & SOX_EFF_INTERNAL ) #endif ) { strcpy( name + 4, e->name ); MLT_REGISTER( filter_type, name, filter_sox_init ); MLT_REGISTER_METADATA( filter_type, name, metadata, NULL ); } } #endif } mlt-0.9.0/src/modules/sox/filter_sox.c000066400000000000000000000356451215300731300177160ustar00rootroot00000000000000/* * filter_sox.c -- apply any number of SOX effects using libst * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include // TODO: does not support multiple effects with SoX v14.1.0+ #ifdef SOX14 # include # define ST_EOF SOX_EOF # define ST_SUCCESS SOX_SUCCESS # define st_sample_t sox_sample_t # define eff_t sox_effect_t* # define ST_LIB_VERSION_CODE SOX_LIB_VERSION_CODE # define ST_LIB_VERSION SOX_LIB_VERSION # if (ST_LIB_VERSION_CODE >= ST_LIB_VERSION(14,2,0)) # define st_size_t size_t # else # define st_size_t sox_size_t # endif # define ST_SIGNED_WORD_TO_SAMPLE(d,clips) SOX_SIGNED_16BIT_TO_SAMPLE(d,clips) # if (ST_LIB_VERSION_CODE >= ST_LIB_VERSION(14,1,0)) # define ST_SSIZE_MIN SOX_SAMPLE_MIN # else # define ST_SSIZE_MIN SOX_SSIZE_MIN # endif # define ST_SAMPLE_TO_SIGNED_WORD(d,clips) SOX_SAMPLE_TO_SIGNED_16BIT(d,clips) #else # include #endif #define BUFFER_LEN 8192 #define AMPLITUDE_NORM 0.2511886431509580 /* -12dBFS */ #define AMPLITUDE_MIN 0.00001 /** Compute the mean of a set of doubles skipping unset values flagged as -1 */ static inline double mean( double *buf, int count ) { double mean = 0; int i; int j = 0; for ( i = 0; i < count; i++ ) { if ( buf[ i ] != -1.0 ) { mean += buf[ i ]; j ++; } } if ( j > 0 ) mean /= j; return mean; } #if (ST_LIB_VERSION_CODE >= ST_LIB_VERSION(14,1,0)) static void delete_effect( eff_t effp ) { free( effp->priv ); free( (void*)effp->in_encoding ); free( effp ); } #endif /** Create an effect state instance for a channels */ static int create_effect( mlt_filter this, char *value, int count, int channel, int frequency ) { mlt_tokeniser tokeniser = mlt_tokeniser_init(); char id[ 256 ]; int error = 1; // Tokenise the effect specification mlt_tokeniser_parse_new( tokeniser, value, " " ); if ( tokeniser->count < 1 ) { mlt_tokeniser_close( tokeniser ); return error; } // Locate the effect mlt_destructor effect_destructor = mlt_pool_release; #ifdef SOX14 //fprintf(stderr, "%s: effect %s count %d\n", __FUNCTION__, tokeniser->tokens[0], tokeniser->count ); #if (ST_LIB_VERSION_CODE >= ST_LIB_VERSION(14,1,0)) sox_effect_handler_t const *eff_handle = sox_find_effect( tokeniser->tokens[0] ); if (eff_handle == NULL ) return error; eff_t eff = sox_create_effect( eff_handle ); effect_destructor = ( mlt_destructor ) delete_effect; sox_encodinginfo_t *enc = calloc( 1, sizeof( sox_encodinginfo_t ) ); enc->encoding = SOX_ENCODING_SIGN2; enc->bits_per_sample = 16; eff->in_encoding = eff->out_encoding = enc; #else eff_t eff = mlt_pool_alloc( sizeof( sox_effect_t ) ); sox_create_effect( eff, sox_find_effect( tokeniser->tokens[0] ) ); #endif int opt_count = tokeniser->count - 1; #else eff_t eff = mlt_pool_alloc( sizeof( struct st_effect ) ); int opt_count = st_geteffect_opt( eff, tokeniser->count, tokeniser->tokens ); #endif // If valid effect if ( opt_count != ST_EOF ) { // Supply the effect parameters #ifdef SOX14 #if (ST_LIB_VERSION_CODE >= ST_LIB_VERSION(14,2,0)) if ( sox_effect_options( eff, opt_count, &tokeniser->tokens[ tokeniser->count > 1 ? 1 : 0 ] ) == ST_SUCCESS ) #else if ( ( * eff->handler.getopts )( eff, opt_count, &tokeniser->tokens[ tokeniser->count > 1 ? 1 : 0 ] ) == ST_SUCCESS ) #endif #else if ( ( * eff->h->getopts )( eff, opt_count, &tokeniser->tokens[ tokeniser->count - opt_count ] ) == ST_SUCCESS ) #endif { // Set the sox signal parameters #if (ST_LIB_VERSION_CODE >= ST_LIB_VERSION(14,1,0)) eff->in_signal.rate = frequency; eff->out_signal.rate = frequency; eff->in_signal.channels = 1; eff->out_signal.channels = 1; eff->in_signal.precision = 16; eff->out_signal.precision = 16; eff->in_signal.length = 0; eff->out_signal.length = 0; #else eff->ininfo.rate = frequency; eff->outinfo.rate = frequency; eff->ininfo.channels = 1; eff->outinfo.channels = 1; #endif // Start the effect #ifdef SOX14 if ( ( * eff->handler.start )( eff ) == ST_SUCCESS ) #else if ( ( * eff->h->start )( eff ) == ST_SUCCESS ) #endif { // Construct id sprintf( id, "_effect_%d_%d", count, channel ); // Save the effect state mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), id, eff, 0, effect_destructor, NULL ); error = 0; } } } // Some error occurred so delete the temp effect state if ( error == 1 ) effect_destructor( eff ); mlt_tokeniser_close( tokeniser ); return error; } /** Get the audio. */ static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { #if (ST_LIB_VERSION_CODE >= ST_LIB_VERSION(14,3,0)) SOX_SAMPLE_LOCALS; #endif // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); // Get the properties st_sample_t *input_buffer;// = mlt_properties_get_data( filter_properties, "input_buffer", NULL ); st_sample_t *output_buffer = mlt_properties_get_data( filter_properties, "output_buffer", NULL ); int i; // channel int count = mlt_properties_get_int( filter_properties, "_effect_count" ); int analysis = mlt_properties_get( filter_properties, "effect" ) && !strcmp( mlt_properties_get( filter_properties, "effect" ), "analysis" ); // Get the producer's audio *format = mlt_audio_s32; mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); // Even though some effects are multi-channel aware, it is not reliable // We must maintain a separate effect state for each channel for ( i = 0; i < *channels; i++ ) { char id[ 256 ]; sprintf( id, "_effect_0_%d", i ); // Get an existing effect state eff_t e = mlt_properties_get_data( filter_properties, id, NULL ); // Validate the existing effect state #if (ST_LIB_VERSION_CODE >= ST_LIB_VERSION(14,1,0)) if ( e != NULL && ( e->in_signal.rate != *frequency || e->out_signal.rate != *frequency ) ) #else if ( e != NULL && ( e->ininfo.rate != *frequency || e->outinfo.rate != *frequency ) ) #endif e = NULL; // (Re)Create the effect state if ( e == NULL ) { int j = 0; // Reset the count count = 0; // Loop over all properties for ( j = 0; j < mlt_properties_count( filter_properties ); j ++ ) { // Get the name of this property char *name = mlt_properties_get_name( filter_properties, j ); // If the name does not contain a . and matches effect if ( !strncmp( name, "effect", 6 ) ) { // Get the effect specification char *value = mlt_properties_get_value( filter_properties, j ); // Create an instance if ( create_effect( filter, value, count, i, *frequency ) == 0 ) count ++; } } // Save the number of filters mlt_properties_set_int( filter_properties, "_effect_count", count ); } if ( *samples > 0 && ( count > 0 || analysis ) ) { input_buffer = (st_sample_t*) *buffer + i * *samples; st_sample_t *p = input_buffer; st_size_t isamp = *samples; st_size_t osamp = *samples; int j = *samples + 1; char *normalise = mlt_properties_get( filter_properties, "normalise" ); double normalised_gain = 1.0; if ( analysis ) { // Run analysis to compute a gain level to normalize the audio across entire filter duration double max_power = mlt_properties_get_double( filter_properties, "_max_power" ); double peak = mlt_properties_get_double( filter_properties, "_max_peak" ); double use_peak = mlt_properties_get_int( filter_properties, "use_peak" ); double power = 0; int n = *samples + 1; // Compute power level of samples in this channel of this frame while ( --n ) { double s = fabs( *p++ ); // Track peak if ( s > peak ) { peak = s; mlt_properties_set_double( filter_properties, "_max_peak", peak ); } power += s * s; } power /= *samples; // Track maximum power if ( power > max_power ) { max_power = power; mlt_properties_set_double( filter_properties, "_max_power", max_power ); } // Complete analysis the last channel of the last frame. if ( i + 1 == *channels && mlt_filter_get_position( filter, frame ) + 1 == mlt_filter_get_length2( filter, frame ) ) { double rms = sqrt( max_power / ST_SSIZE_MIN / ST_SSIZE_MIN ); char effect[32]; // Convert RMS or peak to gain if ( use_peak ) normalised_gain = ST_SSIZE_MIN / -peak; else normalised_gain = AMPLITUDE_NORM / rms; // Set properties for serialization snprintf( effect, sizeof(effect), "vol %f", normalised_gain ); effect[31] = 0; mlt_properties_set( filter_properties, "effect", effect ); mlt_properties_set( filter_properties, "analyze", NULL ); // Show output comparable to normalize --no-adjust --fractions mlt_properties_set_double( filter_properties, "level", rms ); mlt_properties_set_double( filter_properties, "gain", normalised_gain ); mlt_properties_set_double( filter_properties, "peak", -peak / ST_SSIZE_MIN ); } // restore some variables p = input_buffer; } if ( normalise ) { int window = mlt_properties_get_int( filter_properties, "window" ); double *smooth_buffer = mlt_properties_get_data( filter_properties, "smooth_buffer", NULL ); double max_gain = mlt_properties_get_double( filter_properties, "max_gain" ); double rms = 0; // Default the maximum gain factor to 20dBFS if ( max_gain == 0 ) max_gain = 10.0; // Compute rms amplitude while( --j ) { rms += ( double )*p * ( double )*p; p ++; } rms = sqrt( rms / *samples / ST_SSIZE_MIN / ST_SSIZE_MIN ); // The smoothing buffer prevents radical shifts in the gain level if ( window > 0 && smooth_buffer != NULL ) { int smooth_index = mlt_properties_get_int( filter_properties, "_smooth_index" ); smooth_buffer[ smooth_index ] = rms; // Ignore very small values that adversely affect the mean if ( rms > AMPLITUDE_MIN ) mlt_properties_set_int( filter_properties, "_smooth_index", ( smooth_index + 1 ) % window ); // Smoothing is really just a mean over the past N values normalised_gain = AMPLITUDE_NORM / mean( smooth_buffer, window ); } else if ( rms > 0 ) { // Determine gain to apply as current amplitude normalised_gain = AMPLITUDE_NORM / rms; } //printf("filter_sox: rms %.3f gain %.3f\n", rms, normalised_gain ); // Govern the maximum gain if ( normalised_gain > max_gain ) normalised_gain = max_gain; } // For each effect for ( j = 0; j < count; j++ ) { sprintf( id, "_effect_%d_%d", j, i ); e = mlt_properties_get_data( filter_properties, id, NULL ); // We better have this guy if ( e != NULL ) { float saved_gain = 1.0; // XXX: hack to apply the normalised gain level to the vol effect #ifdef SOX14 if ( normalise && strcmp( e->handler.name, "vol" ) == 0 ) #else if ( normalise && strcmp( e->name, "vol" ) == 0 ) #endif { float *f = ( float * )( e->priv ); saved_gain = *f; *f = saved_gain * normalised_gain; } // Apply the effect #ifdef SOX14 if ( ( * e->handler.flow )( e, input_buffer, output_buffer, &isamp, &osamp ) != ST_SUCCESS ) #else if ( ( * e->h->flow )( e, input_buffer, output_buffer, &isamp, &osamp ) != ST_SUCCESS ) #endif { mlt_log_warning( MLT_FILTER_SERVICE(filter), "effect processing failed\n" ); } // XXX: hack to restore the original vol gain to prevent accumulation #ifdef SOX14 if ( normalise && strcmp( e->handler.name, "vol" ) == 0 ) #else if ( normalise && strcmp( e->name, "vol" ) == 0 ) #endif { float *f = ( float * )( e->priv ); *f = saved_gain; } } } // Write back memcpy( input_buffer, output_buffer, *samples * sizeof(st_sample_t) ); } } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); return 0; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { if ( mlt_frame_is_test_audio( frame ) == 0 ) { // Add the filter to the frame mlt_frame_push_audio( frame, this ); mlt_frame_push_audio( frame, filter_get_audio ); // Parse the window property and allocate smoothing buffer if needed mlt_properties properties = MLT_FILTER_PROPERTIES( this ); int window = mlt_properties_get_int( properties, "window" ); if ( mlt_properties_get( properties, "smooth_buffer" ) == NULL && window > 1 ) { // Create a smoothing buffer for the calculated "max power" of frame of audio used in normalisation double *smooth_buffer = (double*) calloc( window, sizeof( double ) ); int i; for ( i = 0; i < window; i++ ) smooth_buffer[ i ] = -1.0; mlt_properties_set_data( properties, "smooth_buffer", smooth_buffer, 0, free, NULL ); } } return frame; } /** Constructor for the filter. */ mlt_filter filter_sox_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { void *input_buffer = mlt_pool_alloc( BUFFER_LEN ); void *output_buffer = mlt_pool_alloc( BUFFER_LEN ); mlt_properties properties = MLT_FILTER_PROPERTIES( this ); this->process = filter_process; if ( !strncmp( id, "sox.", 4 ) ) { char *s = malloc( strlen( id ) + ( arg? strlen( arg ) + 2 : 1 ) ); strcpy( s, id + 4 ); if ( arg ) { strcat( s, " " ); strcat( s, arg ); } mlt_properties_set( properties, "effect", s ); free( s ); } else if ( arg ) mlt_properties_set( properties, "effect", arg ); mlt_properties_set_data( properties, "input_buffer", input_buffer, BUFFER_LEN, mlt_pool_release, NULL ); mlt_properties_set_data( properties, "output_buffer", output_buffer, BUFFER_LEN, mlt_pool_release, NULL ); mlt_properties_set_int( properties, "window", 75 ); mlt_properties_set( properties, "version", sox_version() ); } return this; } // What to do when a libst internal failure occurs void cleanup(void){} mlt-0.9.0/src/modules/sox/filter_sox.yml000066400000000000000000000041311215300731300202570ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: sox title: SoX version: 2 copyright: Copyright (C) 2003-2011 Ushodaya Enterprises Limited license: LGPL language: en url: http://sox.sourceforge.net/ creator: Dan Dennedy tags: - Audio description: Process audio using a SoX effect. bugs: - Some effects are stereo only, but MLT processes each channel separately. - Some effects have a temporal side-effect that do not work well. parameters: - identifier: argument title: Effect name and options type: string format: effect [options] description: > If the effect name is "analysis" then it does not run any effect. Instead, it analyzes the audio to determine a normalized gain level. The results are put into the level, peak, and gain properties as well as this effect property as the parameter to the vol effect. - identifier: level title: Signal power level (RMS) type: float readonly: yes - identifier: peak title: Peak signal level type: float readonly: yes - identifier: gain title: Gain to normalize type: float readonly: yes - identifier: use_peak title: Use peak description: > Use peak signal level instead of RMS (root mean square) power level to compute gain for normalization. type: integer minimum: 0 maximum: 1 default: 0 widget: checkbox - identifier: normalise title: Dynamic normalization description: > This computes the gain for normalization dynamically per frame, but it uses a sliding smoothing window to prevent the gain from fluctuating wildly. Currently, this must be used in combination with some SoX effect. type: integer minimum: 0 maximum: 1 default: 0 widget: checkbox - identifier: window title: Smoothing window size type: integer minimum: 0 default: 75 unit: frames widget: spinner - identifier: max_gain title: Maximum gain description: > With dynamic normalization, this puts a maximum limit on the amount of gain. type: float minimum: 0 maximum: 20 default: 10 mlt-0.9.0/src/modules/sox/filter_sox_effect.yml000066400000000000000000000010451215300731300215740ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: sox title: sox version: 1 copyright: Copyright (C) 2003-2011 Ushodaya Enterprises Limited license: LGPL language: en url: http://sox.sourceforge.net/ creator: Dan Dennedy tags: - Audio description: Process audio using a SoX effect. bugs: - Some effects are stereo only, but MLT processes each channel separately. - Some effects have a temporal side-effect that do not work well. parameters: - identifier: argument title: Effect name and options type: string format: effect [options] mlt-0.9.0/src/modules/swfdec/000077500000000000000000000000001215300731300160215ustar00rootroot00000000000000mlt-0.9.0/src/modules/swfdec/Makefile000066400000000000000000000012501215300731300174570ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lm include ../../../config.mak include config.mak TARGET = ../libmltswfdec$(LIBSUF) OBJS = producer_swfdec.o ifeq ($(targetos), MinGW) LDFLAGS += -Wl,enable-auto-import -lz endif SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/swfdec" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/swfdec" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/swfdec/configure000077500000000000000000000015501215300731300177310ustar00rootroot00000000000000#!/bin/sh if [ "$help" != "1" ] then pkg-config swfdec-0.9 2> /dev/null disable_swfdec=$? echo > config.mak if [ "$disable_swfdec" = "0" ] then echo "CFLAGS += $(pkg-config --cflags swfdec-0.9)" >> config.mak echo "LDFLAGS += $(pkg-config --libs swfdec-0.9)" >> config.mak else pkg-config swfdec-0.8 2> /dev/null disable_swfdec=$? if [ "$disable_swfdec" = "0" ] then echo "CFLAGS += $(pkg-config --cflags swfdec-0.8)" >> config.mak echo "LDFLAGS += $(pkg-config --libs swfdec-0.8)" >> config.mak else pkg-config swfdec-0.7 2> /dev/null disable_swfdec=$? if [ "$disable_swfdec" = "0" ] then echo "CFLAGS += $(pkg-config --cflags swfdec-0.7)" >> config.mak echo "LDFLAGS += $(pkg-config --libs swfdec-0.7)" >> config.mak else echo "- swfdec not found: disabling" touch ../disable-swfdec exit 0 fi fi fi fi mlt-0.9.0/src/modules/swfdec/producer_swfdec.c000066400000000000000000000216031215300731300213450ustar00rootroot00000000000000/* * producer_swfdec.c -- swfdec producer for Flash files * Copyright (C) 2010 Dan Dennedy * * swfdec library 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 (at your option) any later version. * * swfdec library 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 swfdec library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include typedef struct { struct mlt_producer_s parent; SwfdecPlayer *player; SwfdecURL *url; cairo_surface_t *surface; cairo_t *cairo; mlt_position last_position; guint width; guint height; } *producer_swfdec; void swfdec_open( producer_swfdec swfdec, mlt_profile profile ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( &swfdec->parent ); // Setup the swfdec player swfdec->player = swfdec_player_new( NULL ); if ( mlt_properties_get( properties, "variables") ) swfdec_player_set_variables( swfdec->player, mlt_properties_get( properties, "variables" ) ); swfdec_player_set_url( swfdec->player, swfdec->url ); swfdec_player_set_maximum_runtime( swfdec->player, 10000 ); // Setup size swfdec_player_get_default_size( swfdec->player, &swfdec->width, &swfdec->height ); if ( swfdec->width == 0 || swfdec->height == 0 ) { swfdec_player_set_size( swfdec->player, profile->width, profile->height ); swfdec->width = profile->width; swfdec->height = profile->height; } // Setup scaling double scale = 1.0; if ( swfdec->width > 2 * swfdec->height ) scale = 0.5 * profile->width / swfdec->height; else if ( swfdec->height > 2 * swfdec->width ) scale = 0.5 * profile->height / swfdec->width; else scale = (double) profile->width / MAX( swfdec->width, swfdec->height ); swfdec->width = ceil( scale * swfdec->width ); swfdec->height = ceil( scale * swfdec->height ); // Compute the centering translation double x = swfdec->width > profile->width ? (swfdec->width - profile->width) / 2 : 0; double y = swfdec->height > profile->height ? (swfdec->height - profile->height) / 2 : 0; // Setup cairo swfdec->surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, MIN(profile->width, swfdec->width), MIN(profile->height, swfdec->height) ); swfdec->cairo = cairo_create( swfdec->surface ); cairo_translate( swfdec->cairo, -x, -y ); cairo_scale( swfdec->cairo, scale, scale ); } void swfdec_close( producer_swfdec swfdec ) { if ( swfdec->cairo ) cairo_destroy( swfdec->cairo ); swfdec->cairo = NULL; if ( swfdec->player ) g_object_unref( swfdec->player ); swfdec->player = NULL; if ( swfdec->surface ) cairo_surface_destroy( swfdec->surface ); swfdec->surface = NULL; } // Cairo uses 32 bit native endian ARGB static void bgra_to_rgba( uint8_t *src, uint8_t* dst, int width, int height ) { int n = width * height + 1; while ( --n ) { *dst++ = src[2]; *dst++ = src[1]; *dst++ = src[0]; *dst++ = src[3]; src += 4; } } static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { producer_swfdec swfdec = mlt_frame_pop_service( frame ); mlt_service service = MLT_PRODUCER_SERVICE( &swfdec->parent ); mlt_profile profile = mlt_service_profile( service ); mlt_service_lock( service ); if ( !swfdec->player ) swfdec_open( swfdec, profile ); // Set width and height *width = swfdec->width; *height = swfdec->height; *format = mlt_image_rgb24a; *buffer = mlt_pool_alloc( *width * ( *height + 1 ) * 4 ); mlt_frame_set_image( frame, *buffer, *width * ( *height + 1 ) * 4, mlt_pool_release ); // Seek mlt_position pos = mlt_frame_original_position( frame ); if ( pos > swfdec->last_position ) { gulong msec = 1000UL * ( pos - swfdec->last_position ) * profile->frame_rate_den / profile->frame_rate_num; while ( msec > 0 ) msec -= swfdec_player_advance( swfdec->player, msec ); } else if ( pos < swfdec->last_position ) { swfdec_close( swfdec ); swfdec_open( swfdec, mlt_service_profile( service ) ); gulong msec = 1000UL * pos * profile->frame_rate_den / profile->frame_rate_num; while ( msec > 0 ) msec -= swfdec_player_advance( swfdec->player, msec ); } swfdec->last_position = pos; // Render cairo_save( swfdec->cairo ); //cairo_set_source_rgba( swfdec->cairo, r, g, b, a ); cairo_set_operator( swfdec->cairo, CAIRO_OPERATOR_CLEAR ); cairo_paint( swfdec->cairo ); cairo_restore( swfdec->cairo ); swfdec_player_render( swfdec->player, swfdec->cairo ); // Get image from surface uint8_t *image = cairo_image_surface_get_data( swfdec->surface ); mlt_service_unlock( service ); // Convert to RGBA bgra_to_rgba( image, *buffer, swfdec->width, swfdec->height ); return 0; } static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Access the private data producer_swfdec swfdec = producer->child; // Create an empty frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); // Get the frames properties mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Update other info on the frame mlt_properties_set_int( properties, "test_image", 0 ); mlt_properties_set_int( properties, "width", swfdec->width ); mlt_properties_set_int( properties, "height", swfdec->height ); mlt_properties_set_int( properties, "progressive", 1 ); mlt_properties_set_double( properties, "aspect_ratio", 1.0 ); // Push the get_image method on to the stack mlt_frame_push_service( *frame, swfdec ); mlt_frame_push_get_image( *frame, get_image ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; } static void producer_close( mlt_producer parent ) { // Obtain swfdec producer_swfdec swfdec = parent->child; // Close the file swfdec_close( swfdec ); if ( swfdec->url ) swfdec_url_free( swfdec->url ); // Close the parent parent->close = NULL; mlt_producer_close( parent ); // Free the memory free( swfdec ); } mlt_producer producer_swfdec_init( mlt_profile profile, mlt_service_type type, const char *id, char *filename ) { if ( !filename ) return NULL; producer_swfdec swfdec = calloc( 1, sizeof( *swfdec ) ); mlt_producer producer = NULL; if ( swfdec && mlt_producer_init( &swfdec->parent, swfdec ) == 0 ) { // Initialize swfdec and try to open the file swfdec->url = swfdec_url_new_from_input( filename ); if ( swfdec->url ) { // Set the return value producer = &swfdec->parent; // Set the resource property (required for all producers) mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_properties_set( properties, "resource", filename ); // Set the callbacks producer->close = (mlt_destructor) producer_close; producer->get_frame = get_frame; // Set the meta media attributes swfdec->width = profile->width; swfdec->height = profile->height; mlt_properties_set_int( properties, "meta.media.nb_streams", 1 ); mlt_properties_set( properties, "meta.media.0.stream.type", "video" ); mlt_properties_set( properties, "meta.media.0.codec.name", "swf" ); mlt_properties_set( properties, "meta.media.0.codec.long_name", "Adobe Flash" ); mlt_properties_set( properties, "meta.media.0.codec.pix_fmt", "bgra" ); mlt_properties_set_int( properties, "meta.media.width", profile->width ); mlt_properties_set_int( properties, "meta.media.height", profile->height ); mlt_properties_set_double( properties, "meta.media.sample_aspect_num", 1.0 ); mlt_properties_set_double( properties, "meta.media.sample_aspect_den", 1.0 ); mlt_properties_set_int( properties, "meta.media.frame_rate_num", profile->frame_rate_num ); mlt_properties_set_int( properties, "meta.media.frame_rate_den", profile->frame_rate_den ); mlt_properties_set_int( properties, "meta.media.progressive", 1 ); } else { g_object_unref( swfdec->player ); mlt_producer_close( &swfdec->parent ); free( swfdec ); } } else { free( swfdec ); } return producer; } static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/swfdec/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { swfdec_init(); MLT_REGISTER( producer_type, "swfdec", producer_swfdec_init ); MLT_REGISTER_METADATA( producer_type, "swfdec", metadata, "producer_swfdec.yml" ); } mlt-0.9.0/src/modules/swfdec/producer_swfdec.yml000066400000000000000000000002511215300731300217200ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: swfdec title: Flash version: 1 copyright: Dan Dennedy creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/videostab/000077500000000000000000000000001215300731300165265ustar00rootroot00000000000000mlt-0.9.0/src/modules/videostab/Makefile000066400000000000000000000017651215300731300201770ustar00rootroot00000000000000include ../../../config.mak CFLAGS += -I../.. ifdef SSE2_FLAGS CFLAGS += -msse2 endif LDFLAGS += -L../../framework -lmlt -lm TARGET = ../libmltvideostab$(LIBSUF) OBJS = factory.o \ filter_videostab.o filter_videostab2.o \ stabilize.o transform.o transform_image.o tlist.o\ stab/klt/convolve.o stab/klt/klt.o stab/klt/pyramid.o stab/klt/trackFeatures.o \ stab/klt/error.o stab/klt/klt_util.o stab/klt/selectGoodFeatures.o \ stab/estimate.o stab/resample.o stab/utils.o stab/vector.o SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d $(DESTDIR)$(mltdatadir)/videostab install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/videostab" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/videostab/factory.c000066400000000000000000000032731215300731300203460ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (c) 2011 Marco Gittler * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include extern mlt_filter filter_videostab_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_videostab2_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties videostab_metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/videostab/filter_%s.yml", mlt_environment( "MLT_DATA" ), id ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( filter_type, "videostab", filter_videostab_init ); MLT_REGISTER_METADATA( filter_type, "videostab", videostab_metadata, NULL ); MLT_REGISTER( filter_type, "videostab2", filter_videostab2_init ); MLT_REGISTER_METADATA( filter_type, "videostab2", videostab_metadata, NULL ); } mlt-0.9.0/src/modules/videostab/filter_videostab.c000066400000000000000000000141071215300731300222220ustar00rootroot00000000000000/* * filter_imagestab.c -- video stabilization with code from http://vstab.sourceforge.net/ * Copyright (c) 2011 Marco Gittler * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include "stab/vector.h" #include "stab/utils.h" #include "stab/estimate.h" #include "stab/resample.h" typedef struct { mlt_filter parent; int initialized; int* lanc_kernels; es_ctx *es; vc *pos_i; vc *pos_h; vc *pos_y; rs_ctx *rs; } *videostab; static void serialize_vectors( videostab self, mlt_position length ) { mlt_geometry g = mlt_geometry_init(); if ( g ) { struct mlt_geometry_item_s item; int i; // Initialize geometry item item.key = item.f[0] = item.f[1] = 1; item.f[2] = item.f[3] = item.f[4] = 0; for ( i = 0; i < length; i++ ) { // Set the geometry item item.frame = i; item.x = self->pos_h[i].x; item.y = self->pos_h[i].y; // Add the geometry item mlt_geometry_insert( g, &item ); } // Put the analysis results in a property mlt_geometry_set_length( g, length ); mlt_properties_set_data( MLT_FILTER_PROPERTIES( self->parent ), "vectors", g, 0, (mlt_destructor) mlt_geometry_close, (mlt_serialiser) mlt_geometry_serialise ); } } static void deserialize_vectors( videostab self, char *vectors, mlt_position length ) { mlt_geometry g = mlt_geometry_init(); // Parse the property as a geometry if ( g && !mlt_geometry_parse( g, vectors, length, -1, -1 ) ) { struct mlt_geometry_item_s item; int i; // Copy the geometry items to a vc array for interp() for ( i = 0; i < length; i++ ) { mlt_geometry_fetch( g, &item, i ); self->pos_h[i].x = item.x; self->pos_h[i].y = item.y; } } else { mlt_log_warning( MLT_FILTER_SERVICE(self->parent), "failed to parse vectors\n" ); } // We are done with this mlt_geometry if ( g ) mlt_geometry_close( g ); } static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = mlt_frame_pop_service( frame ); *format = mlt_image_rgb24; mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "consumer_deinterlace", 1 ); int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); if ( !error && *image ) { videostab self = filter->child; mlt_position length = mlt_filter_get_length2( filter, frame ); int h = *height; int w = *width; // Service locks are for concurrency control mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); if ( !self->initialized ) { // Initialize our context self->initialized = 1; self->es = es_init( w, h ); self->pos_i = (vc*) malloc( length * sizeof(vc) ); self->pos_h = (vc*) malloc( length * sizeof(vc) ); self->pos_y = (vc*) malloc( h * sizeof(vc) ); self->rs = rs_init( w, h ); } char *vectors = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "vectors" ); if ( !vectors ) { // Analyse int pos = (int) mlt_filter_get_position( filter, frame ); self->pos_i[pos] = vc_add( pos == 0 ? vc_zero() : self->pos_i[pos - 1], es_estimate( self->es, *image ) ); // On last frame if ( pos == length - 1 ) { mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE(filter) ); double fps = mlt_profile_fps( profile ); // Filter and store the results hipass( self->pos_i, self->pos_h, length, fps ); serialize_vectors( self, length ); } } else { // Apply if ( self->initialized != 2 ) { // Load analysis results from property self->initialized = 2; deserialize_vectors( self, vectors, length ); } if ( self->initialized == 2 ) { // Stabilize float shutter_angle = mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame) , "shutterangle" ); float pos = mlt_filter_get_position( filter, frame ); int i; for (i = 0; i < h; i ++) self->pos_y[i] = interp( self->lanc_kernels,self->pos_h, length, pos + (i - h / 2.0) * shutter_angle / (h * 360.0) ); rs_resample( self->lanc_kernels,self->rs, *image, self->pos_y ); } } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); } return error; } static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } void filter_close( mlt_filter parent ) { videostab self = parent->child; if ( self->es ) es_free( self->es ); if ( self->pos_i ) free( self->pos_i ); if ( self->pos_h ) free( self->pos_h ); if ( self->pos_y ) free( self->pos_y ); if ( self->rs ) rs_free( self->rs ); if ( self->lanc_kernels) free_lanc_kernels(self->lanc_kernels); free( self ); parent->close = NULL; parent->child = NULL; } mlt_filter filter_videostab_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { videostab self = calloc( 1, sizeof(*self) ); if ( self ) { mlt_filter parent = mlt_filter_new(); if ( !parent ) { free( self ); return NULL; } parent->child = self; parent->close = filter_close; parent->process = filter_process; self->parent = parent; mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "shutterangle", "0" ); // 0 - 180 , default 0 self->lanc_kernels=prepare_lanc_kernels(); return parent; } return NULL; } mlt-0.9.0/src/modules/videostab/filter_videostab.yml000066400000000000000000000023511215300731300225770ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: videostab title: Videostab copyright: Copyright (C) 2011 Marco Gittler creator: Marco Gittler < contributor: - Dan Dennedy version: 0.1 license: GPL language: en url: http://vstab.sourceforge.net/ creator: Marco Gittler tags: - Video description: Stabilize Video (for wiggly video) notes: > This filter requires two passes. The first pass performs analysis and stores the result in the vectors property. The second pass applies the vectors to the image. To use with melt, use 'melt ... -consumer xml:output.mlt all=1' for the first pass. For the second pass, use output.mlt as the input. parameters: - identifier: shutterangle title: Shutterangle type: integer description: Angle that Images could be maximum rotated readonly: no required: no minimum: 0 maximum: 180 default: 0 mutable: yes widget: spinner - identifier: vectors title: Vectors type: geometry description: > A set of X/Y coordinates by which to adjust the image. When this is not supplied, the filter computes the vectors and stores them in this property when the last frame has been processed. mlt-0.9.0/src/modules/videostab/filter_videostab2.c000066400000000000000000000233031215300731300223020ustar00rootroot00000000000000/* * filter_imagestab.c -- video stabilization with code from http://vstab.sourceforge.net/ * Copyright (c) 2011 Marco Gittler * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include "stabilize.h" #include "transform_image.h" typedef struct { StabData* stab; TransformData* trans; int initialized; void* parent; } videostab2_data; static void serialize_vectors( videostab2_data* self, mlt_position length ) { mlt_geometry g = mlt_geometry_init(); if ( g ) { struct mlt_geometry_item_s item; mlt_position i; // Initialize geometry item item.key = item.f[0] = item.f[1] = item.f[2] = item.f[3] = 1; item.f[4] = 0; tlist* transform_data =self->stab->transs; for ( i = 0; i < length; i++ ) { // Set the geometry item item.frame = i; if (transform_data){ if ( transform_data->data){ Transform* t=transform_data->data; item.x=t->x; item.y=t->y; item.w=t->alpha; item.h=t->zoom; transform_data=transform_data->next; } } // Add the geometry item mlt_geometry_insert( g, &item ); } // Put the analysis results in a property mlt_geometry_set_length( g, length ); mlt_properties_set_data( MLT_FILTER_PROPERTIES( (mlt_filter) self->parent ), "vectors", g, 0, (mlt_destructor) mlt_geometry_close, (mlt_serialiser) mlt_geometry_serialise ); } } // scale zoom implements the factor that the vetcors must be scaled since the vector is calulated for real with, now we need it for (scaled)width Transform* deserialize_vectors( char *vectors, mlt_position length ,float scale_zoom ) { mlt_geometry g = mlt_geometry_init(); Transform* tx=NULL; // Parse the property as a geometry if ( g && !mlt_geometry_parse( g, vectors, length, -1, -1 ) ) { struct mlt_geometry_item_s item; int i; tx=calloc(1,sizeof(Transform)*length); // Copy the geometry items to a vc array for interp() for ( i = 0; i < length; i++ ) { mlt_geometry_fetch( g, &item, i ); Transform t; t.x=scale_zoom*item.x; t.y=scale_zoom*item.y; t.alpha=item.w; t.zoom=scale_zoom*item.h; t.extra=0; tx[i]=t; } } else { //mlt_log_warning( NULL, "failed to parse vectors\n" ); } // We are done with this mlt_geometry if ( g ) mlt_geometry_close( g ); return tx; } static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = mlt_frame_pop_service( frame ); char *vectors = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "vectors" ); *format = mlt_image_yuv422; if (vectors) *format= mlt_image_rgb24; mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "consumer_deinterlace", 1 ); int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); if ( !error && *image ) { videostab2_data* data = filter->child; if ( data==NULL ) { // big error, abort return 1; } mlt_position length = mlt_filter_get_length2( filter, frame ); int h = *height; int w = *width; // Service locks are for concurrency control mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); if ( !vectors) { if ( !data->initialized ) { // Initialize our context data->initialized = 1; data->stab->width=w; data->stab->height=h; if (*format==mlt_image_yuv420p) data->stab->framesize=w*h* 3/2;//( mlt_image_format_size ( *format, w,h , 0) ; // 3/2 =1 too small if (*format==mlt_image_yuv422) data->stab->framesize=w*h; data->stab->shakiness = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "shakiness" ); data->stab->accuracy = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "accuracy" ); data->stab->stepsize = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "stepsize" ); data->stab->algo = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "algo" ); data->stab->show = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "show" ); data->stab->contrast_threshold = mlt_properties_get_double( MLT_FILTER_PROPERTIES(filter) , "mincontrast" ); stabilize_configure(data->stab); } // Analyse mlt_position pos = mlt_filter_get_position( filter, frame ); stabilize_filter_video ( data->stab , *image, *format ); // On last frame if ( pos == length - 1 ) { serialize_vectors( data , length ); } } else { if ( data->initialized!=1 ) { char *interps = mlt_properties_get( MLT_FRAME_PROPERTIES( frame ), "rescale.interp" ); if ( data->initialized != 2 ) { // Load analysis results from property data->initialized = 2; int interp = 2; float scale_zoom=1.0; if ( *width != mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "meta.media.width" ) ) scale_zoom = (float) *width / (float) mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "meta.media.width" ); if ( strcmp( interps, "nearest" ) == 0 || strcmp( interps, "neighbor" ) == 0 ) interp = 0; else if ( strcmp( interps, "tiles" ) == 0 || strcmp( interps, "fast_bilinear" ) == 0 ) interp = 1; else if ( strcmp( interps, "bilinear" ) == 0 ) interp = 2; else if ( strcmp( interps, "bicubic" ) == 0 ) interp = 3; else if ( strcmp( interps, "bicublin" ) == 0 ) interp = 4; data->trans->interpoltype = interp; data->trans->smoothing = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "smoothing" ); data->trans->maxshift = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "maxshift" ); data->trans->maxangle = mlt_properties_get_double( MLT_FILTER_PROPERTIES(filter), "maxangle" ); data->trans->crop = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "crop" ); data->trans->invert = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "invert" ); data->trans->relative = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "relative" ); data->trans->zoom = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "zoom" ); data->trans->optzoom = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "optzoom" ); data->trans->sharpen = mlt_properties_get_double( MLT_FILTER_PROPERTIES(filter), "sharpen" ); transform_configure(data->trans,w,h,*format ,*image, deserialize_vectors( vectors, length , scale_zoom ),length); } if ( data->initialized == 2 ) { // Stabilize float pos = mlt_filter_get_position( filter, frame ); data->trans->current_trans=pos; transform_filter_video(data->trans, *image, *format ); } } } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); } return error; } static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } static void filter_close( mlt_filter parent ) { videostab2_data* data = parent->child; if (data){ if (data->stab) stabilize_stop(data->stab); if (data->trans){ if (data->trans->src) free(data->trans->src); free (data->trans); } free( data ); } parent->close = NULL; parent->child = NULL; } mlt_filter filter_videostab2_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { videostab2_data* data= calloc( 1, sizeof(videostab2_data)); if ( data ) { data->stab = calloc( 1, sizeof(StabData) ); if ( !data->stab ) { free( data ); return NULL; } data->trans = calloc( 1, sizeof (TransformData) ) ; if ( !data->trans ) { free( data->stab ); free( data ); return NULL; } mlt_filter parent = mlt_filter_new(); if ( !parent ) { free( data->trans ); free( data->stab ); free( data ); return NULL; } parent->child = data; parent->close = filter_close; parent->process = filter_process; data->parent = parent; //properties for stabilize mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "shakiness", "4" ); mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "accuracy", "4" ); mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "stepsize", "6" ); mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "algo", "1" ); mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "mincontrast", "0.3" ); mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "show", "0" ); //properties for transform mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "smoothing", "10" ); mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "maxshift", "-1" ); mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "maxangle", "-1" ); mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "crop", "0" ); mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "invert", "0" ); mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "relative", "1" ); mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "zoom", "0" ); mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "optzoom", "1" ); mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "sharpen", "0.8" ); return parent; } return NULL; } mlt-0.9.0/src/modules/videostab/filter_videostab2.yml000066400000000000000000000105471215300731300226670ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: videostab2 title: Videostab2 copyright: Copyright (C) 2011 Marco Gittler creator: Marco Gittler version: 0.1 license: GPL language: en url: ttp://public.hronopik.de/vid.stab/features.php?lang=en tags: - Video description: Stabilize Video (for wiggly/rolling video) notes: > This filter requires two passes. The first pass performs analysis and stores the result in the vectors property. The second pass applies the vectors to the image. To use with melt, use 'melt ... -consumer xml:output.mlt all=1' for the first pass. For the second pass, use output.mlt as the input. parameters: - identifier: vectors title: Vectors type: geometry description: > A set of X/Y coordinates by which to adjust the image. When this is not supplied, the filter computes the vectors and stores them in this property when the last frame has been processed. - identifier: shakiness title: Shakiness type: integer description: How shaky is the Video readonly: no required: no minimum: 1 maximum: 10 default: 4 mutable: yes widget: spinner - identifier: accuracy title: Accuracy type: integer description: Accuracy of Shakiness detection readonly: no required: no minimum: 1 maximum: 15 default: 4 mutable: yes widget: spinner - identifier: stepsize title: Stepsize type: integer description: Stepsize of Detection process minimum around readonly: no required: no minimum: 0 maximum: 100 default: 6 mutable: yes widget: spinner - identifier: algo title: Algo type: integer description: 0 = Bruteforce, 1 = small measurement fields readonly: no required: no minimum: 0 maximum: 1 default: 1 mutable: yes widget: spinner - identifier: mincontrast title: MinContrast type: float description: Below this Contrast Field is discarded readonly: no required: no minimum: 0 maximum: 1 default: 0.3 mutable: yes widget: spinner - identifier: show title: Show type: integer description: 0 = draw nothing, 1,2 show fields and transforms readonly: no required: no minimum: 0 maximum: 2 default: 0 mutable: yes widget: spinner - identifier: smoothing title: Smoothing type: integer description: number of frames for lowpass filtering ( ( num * 2 + 1) frames ) readonly: no required: no minimum: 0 maximum: 100 default: 10 mutable: yes widget: spinner - identifier: maxshift title: Maxshift type: integer description: max number of pixels to shift readonly: no required: no minimum: -1 maximum: 1000 default: -1 mutable: yes widget: spinner - identifier: maxangle title: Maxangle type: float description: max angle to rotate (in rad) readonly: no required: no minimum: -1 maximum: 3.142 default: -1 mutable: yes widget: spinner - identifier: crop title: Crop type: integer description: 0 = keep border, 1 = black background readonly: no required: no minimum: 0 maximum: 1 default: 0 mutable: yes widget: spinner - identifier: invert title: Invert type: integer description: Invert transform readonly: no required: no minimum: 0 maximum: 1 default: 0 mutable: yes widget: spinner - identifier: relative title: Relative Transform type: integer description: 0 = absolute transform, 1= relative readonly: no required: no minimum: 0 maximum: 1 default: 1 mutable: yes widget: spinner - identifier: zoom title: Zoom type: integer description: additional zoom during transform readonly: no required: no minimum: -500 maximum: 500 default: 0 mutable: yes widget: spinner - identifier: optzoom title: Optimal Zoom type: integer description: use optimal zoom (calulated from transforms) readonly: no required: no minimum: 0 maximum: 1 default: 1 mutable: yes widget: spinner - identifier: sharpen title: Sharpen Image type: float description: sharpen transformed image readonly: no required: no minimum: 0 maximum: 10 default: 0.8 mutable: yes widget: spinner mlt-0.9.0/src/modules/videostab/gpl000066400000000000000000000000001215300731300172210ustar00rootroot00000000000000mlt-0.9.0/src/modules/videostab/stab/000077500000000000000000000000001215300731300174575ustar00rootroot00000000000000mlt-0.9.0/src/modules/videostab/stab/estimate.c000066400000000000000000000062541215300731300214450ustar00rootroot00000000000000/* * Video stabilizer * * Copyright (c) 2008 Lenny * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #if !defined(__DARWIN__) && !defined(__FreeBSD__) && !defined(WIN32) && !defined(__NetBSD__) #include #endif #include "estimate.h" #include "vector.h" #include "utils.h" #if !defined(MAXFLOAT) #define MAXFLOAT HUGE_VAL #endif es_ctx *es_init(int nc, int nr) { es_ctx *es = (es_ctx *)malloc(sizeof(es_ctx)); es->tc = KLTCreateTrackingContext(); es->tc->sequentialMode = TRUE; es->tc->min_eigenvalue = 8; es->tc->verbose = FALSE; KLTChangeTCPyramid(es->tc, 31); KLTUpdateTCBorder(es->tc); es->fr[0] = (KLT_PixelType *)malloc(nc * nr * sizeof(KLT_PixelType)); es->fr[1] = (KLT_PixelType *)malloc(nc * nr * sizeof(KLT_PixelType)); es->fl = KLTCreateFeatureList(64); es->dv = (vc *)malloc(64 * sizeof(vc)); es->nv = 0; es->nc = nc; es->nr = nr; es->ff = FALSE; return es; } vc es_estimate(es_ctx *es, unsigned char *fr) { KLT_PixelType *t; int is, id; t = es->fr[0]; es->fr[0] = es->fr[1]; es->fr[1] = t; for (is = 0, id = 0; id < es->nc * es->nr; is += 3, id ++) es->fr[1][id] = (fr[is + 0] * 30 + fr[is + 1] * 59 + fr[is + 2] * 11) / 100; if (es->ff == FALSE) { es->ff = TRUE; } else { vc bv = vc_set(0.0, 0.0); float be = MAXFLOAT; int i, i2; KLTSelectGoodFeatures( es->tc, es->fr[0], es->nc, es->nr, es->fl ); for (i = 0; i < es->fl->nFeatures; i ++) es->dv[i] = vc_set(es->fl->feature[i]->x, es->fl->feature[i]->y); KLTTrackFeatures( es->tc, es->fr[0], es->fr[1], es->nc, es->nr, es->fl ); es->nv = 0; for (i = 0; i < es->fl->nFeatures; i ++) { if (es->fl->feature[i]->val == KLT_TRACKED) { es->dv[es->nv] = vc_set( es->fl->feature[i]->x - es->dv[i].x, es->fl->feature[i]->y - es->dv[i].y ); es->nv ++; } } for (i = 0; i < es->nv; i ++) { float ce = 0.0; for (i2 = 0; i2 < es->nv; i2 ++) ce += vc_len(vc_sub(es->dv[i2], es->dv[i])); if (ce < be) { bv = es->dv[i]; be = ce; } } return bv; } return vc_zero(); } void es_free(es_ctx *es) { free(es->dv); free(es->fr[0]); free(es->fr[1]); KLTFreeFeatureList(es->fl); KLTFreeTrackingContext(es->tc); free(es); } mlt-0.9.0/src/modules/videostab/stab/estimate.h000066400000000000000000000005361215300731300214470ustar00rootroot00000000000000#ifndef ESTIMATE_H #define ESTIMATE_H #include "klt/klt.h" #include "vector.h" typedef struct { KLT_TrackingContext tc; KLT_PixelType *fr[2]; KLT_FeatureList fl; vc *dv; int nv; int nc, nr; int ff; } es_ctx; es_ctx *es_init(int, int); vc es_estimate(es_ctx *, unsigned char *); void es_free(es_ctx *); #endif mlt-0.9.0/src/modules/videostab/stab/klt/000077500000000000000000000000001215300731300202515ustar00rootroot00000000000000mlt-0.9.0/src/modules/videostab/stab/klt/base.h000066400000000000000000000012661215300731300213410ustar00rootroot00000000000000/********************************************************************* * base.h *********************************************************************/ #ifndef _BASE_H_ #define _BASE_H_ #ifndef uchar #define uchar unsigned char #endif #ifndef schar #define schar signed char #endif #ifndef uint #define uint unsigned int #endif #ifndef ushort #define ushort unsigned short #endif #ifndef ulong #define ulong unsigned long #endif #ifndef max #define max(a,b) ((a) > (b) ? (a) : (b)) #endif #ifndef min #define min(a,b) ((a) < (b) ? (a) : (b)) #endif #define max3(a,b,c) ((a) > (b) ? max((a),(c)) : max((b),(c))) #define min3(a,b,c) ((a) < (b) ? min((a),(c)) : min((b),(c))) #endif mlt-0.9.0/src/modules/videostab/stab/klt/convolve.c000066400000000000000000000154221215300731300222540ustar00rootroot00000000000000/********************************************************************* * convolve.c *********************************************************************/ /* Standard includes */ #include #include /* malloc(), realloc() */ /* Our includes */ #include "base.h" #include "error.h" #include "convolve.h" #include "klt_util.h" /* printing */ #define MAX_KERNEL_WIDTH 71 typedef struct { int width; float data[MAX_KERNEL_WIDTH]; } ConvolutionKernel; /* Kernels */ ConvolutionKernel gauss_kernel; ConvolutionKernel gaussderiv_kernel; float sigma_last = -10.0; /********************************************************************* * _KLTToFloatImage * * Given a pointer to image data (probably unsigned chars), copy * data to a float image. */ void _KLTToFloatImage( KLT_PixelType *img, int ncols, int nrows, _KLT_FloatImage floatimg) { KLT_PixelType *ptrend = img + ncols*nrows; float *ptrout = floatimg->data; floatimg->ncols = ncols; floatimg->nrows = nrows; while (img < ptrend) *ptrout++ = (float) *img++; } /********************************************************************* * _computeKernels */ void _computeKernels( float sigma, ConvolutionKernel *gauss, ConvolutionKernel *gaussderiv) { const float factor = 0.01f; /* for truncating tail */ int i; /* Compute kernels, and automatically determine widths */ { const int hw = MAX_KERNEL_WIDTH / 2; float max_gauss = 1.0f, max_gaussderiv = (float) (sigma*exp(-0.5f)); /* Compute gauss and deriv */ for (i = -hw ; i <= hw ; i++) { gauss->data[i+hw] = (float) exp(-i*i / (2*sigma*sigma)); gaussderiv->data[i+hw] = -i * gauss->data[i+hw]; } /* Compute widths */ gauss->width = MAX_KERNEL_WIDTH; for (i = -hw ; fabs(gauss->data[i+hw] / max_gauss) < factor ; i++, gauss->width -= 2); gaussderiv->width = MAX_KERNEL_WIDTH; for (i = -hw ; fabs(gaussderiv->data[i+hw] / max_gaussderiv) < factor ; i++, gaussderiv->width -= 2); if (gauss->width == MAX_KERNEL_WIDTH || gaussderiv->width == MAX_KERNEL_WIDTH) KLTError("(_computeKernels) MAX_KERNEL_WIDTH %d is too small for " "a sigma of %f", MAX_KERNEL_WIDTH, sigma); } /* Shift if width less than MAX_KERNEL_WIDTH */ for (i = 0 ; i < gauss->width ; i++) gauss->data[i] = gauss->data[i+(MAX_KERNEL_WIDTH-gauss->width)/2]; for (i = 0 ; i < gaussderiv->width ; i++) gaussderiv->data[i] = gaussderiv->data[i+(MAX_KERNEL_WIDTH-gaussderiv->width)/2]; /* Normalize gauss and deriv */ { const int hw = gaussderiv->width / 2; float den; den = 0.0; for (i = 0 ; i < gauss->width ; i++) den += gauss->data[i]; for (i = 0 ; i < gauss->width ; i++) gauss->data[i] /= den; den = 0.0; for (i = -hw ; i <= hw ; i++) den -= i*gaussderiv->data[i+hw]; for (i = -hw ; i <= hw ; i++) gaussderiv->data[i+hw] /= den; } sigma_last = sigma; } /********************************************************************* * _KLTGetKernelWidths * */ void _KLTGetKernelWidths( float sigma, int *gauss_width, int *gaussderiv_width) { _computeKernels(sigma, &gauss_kernel, &gaussderiv_kernel); *gauss_width = gauss_kernel.width; *gaussderiv_width = gaussderiv_kernel.width; } /********************************************************************* * _convolveImageHoriz */ void _convolveImageHoriz( _KLT_FloatImage imgin, ConvolutionKernel kernel, _KLT_FloatImage imgout) { float *ptrrow = imgin->data; /* Points to row's first pixel */ float *ptrout = imgout->data, /* Points to next output pixel */ *ppp; float sum; int radius = kernel.width / 2; int ncols = imgin->ncols, nrows = imgin->nrows; int i, j, k; /* For each row, do ... */ for (j = 0 ; j < nrows ; j++) { /* Zero leftmost columns */ for (i = 0 ; i < radius ; i++) *ptrout++ = 0.0; /* Convolve middle columns with kernel */ for ( ; i < ncols - radius ; i++) { ppp = ptrrow + i - radius; sum = 0.0; for (k = kernel.width-1 ; k >= 0 ; k--) sum += *ppp++ * kernel.data[k]; *ptrout++ = sum; } /* Zero rightmost columns */ for ( ; i < ncols ; i++) *ptrout++ = 0.0; ptrrow += ncols; } } /********************************************************************* * _convolveImageVert */ void _convolveImageVert( _KLT_FloatImage imgin, ConvolutionKernel kernel, _KLT_FloatImage imgout) { float *ptrcol = imgin->data; /* Points to row's first pixel */ float *ptrout = imgout->data, /* Points to next output pixel */ *ppp; float sum; int radius = kernel.width / 2; int ncols = imgin->ncols, nrows = imgin->nrows; int i, j, k; /* For each column, do ... */ for (i = 0 ; i < ncols ; i++) { /* Zero topmost rows */ for (j = 0 ; j < radius ; j++) { *ptrout = 0.0; ptrout += ncols; } /* Convolve middle rows with kernel */ for ( ; j < nrows - radius ; j++) { ppp = ptrcol + ncols * (j - radius); sum = 0.0; for (k = kernel.width-1 ; k >= 0 ; k--) { sum += *ppp * kernel.data[k]; ppp += ncols; } *ptrout = sum; ptrout += ncols; } /* Zero bottommost rows */ for ( ; j < nrows ; j++) { *ptrout = 0.0; ptrout += ncols; } ptrcol++; ptrout -= nrows * ncols - 1; } } /********************************************************************* * _convolveSeparate */ void _convolveSeparate( _KLT_FloatImage imgin, ConvolutionKernel horiz_kernel, ConvolutionKernel vert_kernel, _KLT_FloatImage imgout) { /* Create temporary image */ _KLT_FloatImage tmpimg; tmpimg = _KLTCreateFloatImage(imgin->ncols, imgin->nrows); /* Do convolution */ _convolveImageHoriz(imgin, horiz_kernel, tmpimg); _convolveImageVert(tmpimg, vert_kernel, imgout); /* Free memory */ _KLTFreeFloatImage(tmpimg); } /********************************************************************* * _KLTComputeGradients */ void _KLTComputeGradients( _KLT_FloatImage img, float sigma, _KLT_FloatImage gradx, _KLT_FloatImage grady) { /* Compute kernels, if necessary */ if (fabs(sigma - sigma_last) > 0.05) _computeKernels(sigma, &gauss_kernel, &gaussderiv_kernel); _convolveSeparate(img, gaussderiv_kernel, gauss_kernel, gradx); _convolveSeparate(img, gauss_kernel, gaussderiv_kernel, grady); } /********************************************************************* * _KLTComputeSmoothedImage */ void _KLTComputeSmoothedImage( _KLT_FloatImage img, float sigma, _KLT_FloatImage smooth) { /* Compute kernel, if necessary; gauss_deriv is not used */ if (fabs(sigma - sigma_last) > 0.05) _computeKernels(sigma, &gauss_kernel, &gaussderiv_kernel); _convolveSeparate(img, gauss_kernel, gauss_kernel, smooth); } mlt-0.9.0/src/modules/videostab/stab/klt/convolve.h000066400000000000000000000012111215300731300222500ustar00rootroot00000000000000/********************************************************************* * convolve.h *********************************************************************/ #ifndef _CONVOLVE_H_ #define _CONVOLVE_H_ #include "klt.h" #include "klt_util.h" void _KLTToFloatImage( KLT_PixelType *img, int ncols, int nrows, _KLT_FloatImage floatimg); void _KLTComputeGradients( _KLT_FloatImage img, float sigma, _KLT_FloatImage gradx, _KLT_FloatImage grady); void _KLTGetKernelWidths( float sigma, int *gauss_width, int *gaussderiv_width); void _KLTComputeSmoothedImage( _KLT_FloatImage img, float sigma, _KLT_FloatImage smooth); #endif mlt-0.9.0/src/modules/videostab/stab/klt/error.c000066400000000000000000000020301215300731300215410ustar00rootroot00000000000000/********************************************************************* * error.c * * Error and warning messages, and system commands. *********************************************************************/ /* Standard includes */ #include #include #include #include /********************************************************************* * KLTError * * Prints an error message and dies. * * INPUTS * exactly like printf */ void KLTError(char *fmt, ...) { va_list args; va_start(args, fmt); mlt_log_error(NULL, "KLT Error: "); mlt_log_error(NULL, fmt, args); mlt_log_error(NULL, "\n"); va_end(args); } /********************************************************************* * KLTWarning * * Prints a warning message. * * INPUTS * exactly like printf */ void KLTWarning(char *fmt, ...) { va_list args; va_start(args, fmt); fprintf(stderr, "KLT Warning: "); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); fflush(stderr); va_end(args); } mlt-0.9.0/src/modules/videostab/stab/klt/error.h000066400000000000000000000004611215300731300215540ustar00rootroot00000000000000/********************************************************************* * error.h *********************************************************************/ #ifndef _ERROR_H_ #define _ERROR_H_ #include #include void KLTError(char *fmt, ...); void KLTWarning(char *fmt, ...); #endif mlt-0.9.0/src/modules/videostab/stab/klt/klt.c000066400000000000000000000240321215300731300212100ustar00rootroot00000000000000/********************************************************************* * klt.c * * Kanade-Lucas-Tomasi tracker *********************************************************************/ /* Standard includes */ #include /* logf() */ #include /* malloc() */ /* Our includes */ #include "base.h" #include "convolve.h" #include "error.h" #include "klt.h" #include "pyramid.h" /********************************************************************* * KLTCreateTrackingContext * */ KLT_TrackingContext KLTCreateTrackingContext() { KLT_TrackingContext tc = NULL; /* Allocate memory */ tc = (KLT_TrackingContext) calloc(1, sizeof(KLT_TrackingContextRec)); /* Set values to default values */ tc->mindist = 10; tc->window_width = 7; tc->window_height = 7; tc->sequentialMode = FALSE; tc->smoothBeforeSelecting = TRUE; tc->min_eigenvalue = 1; tc->min_determinant = 0.01; tc->max_iterations = 10; tc->min_displacement = 0.1; tc->max_residue = 10.0; tc->grad_sigma = 1.0; tc->smooth_sigma_fact = 0.1; tc->pyramid_sigma_fact = 0.9; tc->step_factor = 1.0; tc->nSkippedPixels = 0; tc->pyramid_last = NULL; tc->pyramid_last_gradx = NULL; tc->pyramid_last_grady = NULL; tc->verbose = TRUE; /* Change nPyramidLevels and subsampling */ KLTChangeTCPyramid(tc, 31); /* Update border, which is dependent upon */ /* smooth_sigma_fact, pyramid_sigma_fact, window_size, and subsampling */ KLTUpdateTCBorder(tc); return(tc); } /********************************************************************* * KLTCreateFeatureList * */ KLT_FeatureList KLTCreateFeatureList( int nFeatures) { KLT_FeatureList fl; KLT_Feature first; int nbytes = sizeof(KLT_FeatureListRec) + nFeatures * sizeof(KLT_Feature) + nFeatures * sizeof(KLT_FeatureRec); int i; /* Allocate memory for feature list */ fl = (KLT_FeatureList) malloc(nbytes); /* Set parameters */ fl->nFeatures = nFeatures; /* Set pointers */ fl->feature = (KLT_Feature *) (fl + 1); first = (KLT_Feature) (fl->feature + nFeatures); for (i = 0 ; i < nFeatures ; i++) fl->feature[i] = first + i; /* Return feature list */ return(fl); } /********************************************************************* * KLTPrintTrackingContext */ void KLTPrintTrackingContext( KLT_TrackingContext tc) { fprintf(stderr, "\n\nTracking context:\n\n"); fprintf(stderr, "\tmindist = %d\n", tc->mindist); fprintf(stderr, "\twindow_width = %d\n", tc->window_width); fprintf(stderr, "\twindow_height = %d\n", tc->window_height); fprintf(stderr, "\tsequentialMode = %s\n", tc->sequentialMode ? "TRUE" : "FALSE"); fprintf(stderr, "\tsmoothBeforeSelecting = %s\n", tc->smoothBeforeSelecting ? "TRUE" : "FALSE"); fprintf(stderr, "\tmin_eigenvalue = %d\n", tc->min_eigenvalue); fprintf(stderr, "\tmin_determinant = %f\n", tc->min_determinant); fprintf(stderr, "\tmin_displacement = %f\n", tc->min_displacement); fprintf(stderr, "\tmax_iterations = %d\n", tc->max_iterations); fprintf(stderr, "\tmax_residue = %f\n", tc->max_residue); fprintf(stderr, "\tgrad_sigma = %f\n", tc->grad_sigma); fprintf(stderr, "\tsmooth_sigma_fact = %f\n", tc->smooth_sigma_fact); fprintf(stderr, "\tpyramid_sigma_fact = %f\n", tc->pyramid_sigma_fact); fprintf(stderr, "\tnSkippedPixels = %d\n", tc->nSkippedPixels); fprintf(stderr, "\tborderx = %d\n", tc->borderx); fprintf(stderr, "\tbordery = %d\n", tc->bordery); fprintf(stderr, "\tnPyramidLevels = %d\n", tc->nPyramidLevels); fprintf(stderr, "\tsubsampling = %d\n", tc->subsampling); fprintf(stderr, "\n\tpyramid_last = %s\n", (tc->pyramid_last!=NULL) ? "points to old image" : "NULL"); fprintf(stderr, "\tpyramid_last_gradx = %s\n", (tc->pyramid_last_gradx!=NULL) ? "points to old image" : "NULL"); fprintf(stderr, "\tpyramid_last_grady = %s\n", (tc->pyramid_last_grady!=NULL) ? "points to old image" : "NULL"); fprintf(stderr, "\n\n"); } /********************************************************************* * KLTChangeTCPyramid * */ void KLTChangeTCPyramid( KLT_TrackingContext tc, int search_range) { float window_halfwidth; float subsampling; /* Check window size (and correct if necessary) */ if (tc->window_width % 2 != 1) { tc->window_width = tc->window_width+1; KLTWarning("(KLTChangeTCPyramid) Window width must be odd. " "Changing to %d.\n", tc->window_width); } if (tc->window_height % 2 != 1) { tc->window_height = tc->window_height+1; KLTWarning("(KLTChangeTCPyramid) Window height must be odd. " "Changing to %d.\n", tc->window_height); } if (tc->window_width < 3) { tc->window_width = 3; KLTWarning("(KLTChangeTCPyramid) Window width must be at least three. \n" "Changing to %d.\n", tc->window_width); } if (tc->window_height < 3) { tc->window_height = 3; KLTWarning("(KLTChangeTCPyramid) Window height must be at least three. \n" "Changing to %d.\n", tc->window_height); } window_halfwidth = min(tc->window_width,tc->window_height)/2.0f; subsampling = ((float) search_range) / window_halfwidth; if (subsampling < 1.0) { /* 1.0 = 0+1 */ tc->nPyramidLevels = 1; } else if (subsampling <= 3.0) { /* 3.0 = 2+1 */ tc->nPyramidLevels = 2; tc->subsampling = 2; } else if (subsampling <= 5.0) { /* 5.0 = 4+1 */ tc->nPyramidLevels = 2; tc->subsampling = 4; } else if (subsampling <= 9.0) { /* 9.0 = 8+1 */ tc->nPyramidLevels = 2; tc->subsampling = 8; } else { /* The following lines are derived from the formula: search_range = window_halfwidth * \sum_{i=0}^{nPyramidLevels-1} 8^i, which is the same as: search_range = window_halfwidth * (8^nPyramidLevels - 1)/(8 - 1). Then, the value is rounded up to the nearest integer. */ float val = (float) (log(7.0*subsampling+1.0)/log(8.0)); tc->nPyramidLevels = (int) (val + 0.99); tc->subsampling = 8; } } /********************************************************************* * NOTE: Manually must ensure consistency with _KLTComputePyramid() */ float _pyramidSigma( KLT_TrackingContext tc) { return (tc->pyramid_sigma_fact * tc->subsampling); } /********************************************************************* * Updates border, which is dependent upon * smooth_sigma_fact, pyramid_sigma_fact, window_size, and subsampling */ void KLTUpdateTCBorder( KLT_TrackingContext tc) { float val; int pyramid_gauss_hw; int smooth_gauss_hw; int gauss_width, gaussderiv_width; int num_levels = tc->nPyramidLevels; int n_invalid_pixels; int window_hw; int ss = tc->subsampling; int ss_power; int border; int i; /* Check window size (and correct if necessary) */ if (tc->window_width % 2 != 1) { tc->window_width = tc->window_width+1; KLTWarning("(KLTUpdateTCBorder) Window width must be odd. " "Changing to %d.\n", tc->window_width); } if (tc->window_height % 2 != 1) { tc->window_height = tc->window_height+1; KLTWarning("(KLTUpdateTCBorder) Window height must be odd. " "Changing to %d.\n", tc->window_height); } if (tc->window_width < 3) { tc->window_width = 3; KLTWarning("(KLTUpdateTCBorder) Window width must be at least three. \n" "Changing to %d.\n", tc->window_width); } if (tc->window_height < 3) { tc->window_height = 3; KLTWarning("(KLTUpdateTCBorder) Window height must be at least three. \n" "Changing to %d.\n", tc->window_height); } window_hw = max(tc->window_width, tc->window_height)/2; /* Find widths of convolution windows */ _KLTGetKernelWidths(_KLTComputeSmoothSigma(tc), &gauss_width, &gaussderiv_width); smooth_gauss_hw = gauss_width/2; _KLTGetKernelWidths(_pyramidSigma(tc), &gauss_width, &gaussderiv_width); pyramid_gauss_hw = gauss_width/2; /* Compute the # of invalid pixels at each level of the pyramid. n_invalid_pixels is computed with respect to the ith level of the pyramid. So, e.g., if n_invalid_pixels = 5 after the first iteration, then there are 5 invalid pixels in level 1, which translated means 5*subsampling invalid pixels in the original level 0. */ n_invalid_pixels = smooth_gauss_hw; for (i = 1 ; i < num_levels ; i++) { val = ((float) n_invalid_pixels + pyramid_gauss_hw) / ss; n_invalid_pixels = (int) (val + 0.99); /* Round up */ } /* ss_power = ss^(num_levels-1) */ ss_power = 1; for (i = 1 ; i < num_levels ; i++) ss_power *= ss; /* Compute border by translating invalid pixels back into */ /* original image */ border = (n_invalid_pixels + window_hw) * ss_power; tc->borderx = border; tc->bordery = border; } /********************************************************************* * KLTFreeTrackingContext * KLTFreeFeatureList * KLTFreeFeatureHistory * KLTFreeFeatureTable */ void KLTFreeTrackingContext( KLT_TrackingContext tc) { if (tc->pyramid_last) _KLTFreePyramid((_KLT_Pyramid) tc->pyramid_last); if (tc->pyramid_last_gradx) _KLTFreePyramid((_KLT_Pyramid) tc->pyramid_last_gradx); if (tc->pyramid_last_grady) _KLTFreePyramid((_KLT_Pyramid) tc->pyramid_last_grady); free(tc); } void KLTFreeFeatureList(KLT_FeatureList fl) { free(fl); } /********************************************************************* * KLTStopSequentialMode */ void KLTStopSequentialMode( KLT_TrackingContext tc) { tc->sequentialMode = FALSE; _KLTFreePyramid((_KLT_Pyramid) tc->pyramid_last); _KLTFreePyramid((_KLT_Pyramid) tc->pyramid_last_gradx); _KLTFreePyramid((_KLT_Pyramid) tc->pyramid_last_grady); tc->pyramid_last = NULL; tc->pyramid_last_gradx = NULL; tc->pyramid_last_grady = NULL; } /********************************************************************* * KLTCountRemainingFeatures */ int KLTCountRemainingFeatures( KLT_FeatureList fl) { int count = 0; int i; for (i = 0 ; i < fl->nFeatures ; i++) if (fl->feature[i]->val >= 0) count++; return count; } mlt-0.9.0/src/modules/videostab/stab/klt/klt.h000066400000000000000000000071441215300731300212220ustar00rootroot00000000000000/********************************************************************* * klt.h * * Kanade-Lucas-Tomasi tracker *********************************************************************/ #ifndef _KLT_H_ #define _KLT_H_ typedef float KLT_locType; typedef unsigned char KLT_PixelType; #define KLT_BOOL int #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #ifndef NULL #define NULL 0 #endif #define KLT_TRACKED 0 #define KLT_NOT_FOUND -1 #define KLT_SMALL_DET -2 #define KLT_MAX_ITERATIONS -3 #define KLT_OOB -4 #define KLT_LARGE_RESIDUE -5 #include "klt_util.h" /* for affine mapping */ /******************* * Structures */ typedef struct { /* Available to user */ int mindist; /* min distance b/w features */ int window_width, window_height; KLT_BOOL sequentialMode; /* whether to save most recent image to save time */ /* can set to TRUE manually, but don't set to */ /* FALSE manually */ KLT_BOOL smoothBeforeSelecting; /* whether to smooth image before */ /* selecting features */ /* Available, but hopefully can ignore */ int min_eigenvalue; /* smallest eigenvalue allowed for selecting */ float min_determinant; /* th for determining lost */ float min_displacement; /* th for stopping tracking when pixel changes little */ int max_iterations; /* th for stopping tracking when too many iterations */ float max_residue; /* th for stopping tracking when residue is large */ float grad_sigma; float smooth_sigma_fact; float pyramid_sigma_fact; float step_factor; /* size of Newton steps; 2.0 comes from equations, 1.0 seems to avoid overshooting */ int nSkippedPixels; /* # of pixels skipped when finding features */ int borderx; /* border in which features will not be found */ int bordery; int nPyramidLevels; /* computed from search_ranges */ int subsampling; /* " */ /* User must not touch these */ void *pyramid_last; void *pyramid_last_gradx; void *pyramid_last_grady; int verbose; } KLT_TrackingContextRec, *KLT_TrackingContext; typedef struct { KLT_locType x; KLT_locType y; int val; } KLT_FeatureRec, *KLT_Feature; typedef struct { int nFeatures; KLT_Feature *feature; } KLT_FeatureListRec, *KLT_FeatureList; typedef struct { int nFrames; KLT_Feature *feature; } KLT_FeatureHistoryRec, *KLT_FeatureHistory; typedef struct { int nFrames; int nFeatures; KLT_Feature **feature; } KLT_FeatureTableRec, *KLT_FeatureTable; /******************* * Functions */ /* Create */ KLT_TrackingContext KLTCreateTrackingContext(); KLT_FeatureList KLTCreateFeatureList(int); /* Free */ void KLTFreeTrackingContext(KLT_TrackingContext); void KLTFreeFeatureList(KLT_FeatureList); /* Processing */ void KLTSelectGoodFeatures( KLT_TrackingContext tc, KLT_PixelType *img, int ncols, int nrows, KLT_FeatureList fl); void KLTTrackFeatures( KLT_TrackingContext tc, KLT_PixelType *img1, KLT_PixelType *img2, int ncols, int nrows, KLT_FeatureList fl); void KLTReplaceLostFeatures( KLT_TrackingContext tc, KLT_PixelType *img, int ncols, int nrows, KLT_FeatureList fl); /* Utilities */ int KLTCountRemainingFeatures( KLT_FeatureList fl); void KLTPrintTrackingContext( KLT_TrackingContext tc); void KLTChangeTCPyramid( KLT_TrackingContext tc, int search_range); void KLTUpdateTCBorder( KLT_TrackingContext tc); void KLTStopSequentialMode( KLT_TrackingContext tc); float _KLTComputeSmoothSigma( KLT_TrackingContext tc); #endif mlt-0.9.0/src/modules/videostab/stab/klt/klt_util.c000066400000000000000000000021631215300731300222460ustar00rootroot00000000000000/********************************************************************* * klt_util.c *********************************************************************/ /* Standard includes */ #include #include /* Our includes */ #include "base.h" #include "error.h" #include "klt.h" #include "klt_util.h" /*********************************************************************/ float _KLTComputeSmoothSigma( KLT_TrackingContext tc) { return (tc->smooth_sigma_fact * max(tc->window_width, tc->window_height)); } /********************************************************************* * _KLTCreateFloatImage */ _KLT_FloatImage _KLTCreateFloatImage(int ncols, int nrows) { int nbytes = sizeof(_KLT_FloatImageRec) + ncols * nrows * sizeof(float); _KLT_FloatImage floatimg; floatimg = (_KLT_FloatImage)malloc(nbytes); floatimg->ncols = ncols; floatimg->nrows = nrows; floatimg->data = (float *)(floatimg + 1); return(floatimg); } /********************************************************************* * _KLTFreeFloatImage */ void _KLTFreeFloatImage( _KLT_FloatImage floatimg) { free(floatimg); } mlt-0.9.0/src/modules/videostab/stab/klt/klt_util.h000066400000000000000000000010171215300731300222500ustar00rootroot00000000000000/********************************************************************* * klt_util.h *********************************************************************/ #ifndef _KLT_UTIL_H_ #define _KLT_UTIL_H_ typedef struct { int ncols; int nrows; float *data; } _KLT_FloatImageRec, *_KLT_FloatImage; _KLT_FloatImage _KLTCreateFloatImage( int ncols, int nrows); void _KLTFreeFloatImage( _KLT_FloatImage); void _KLTPrintSubFloatImage( _KLT_FloatImage floatimg, int x0, int y0, int width, int height); #endif mlt-0.9.0/src/modules/videostab/stab/klt/pyramid.c000066400000000000000000000063731215300731300220730ustar00rootroot00000000000000/********************************************************************* * pyramid.c * *********************************************************************/ /* Standard includes */ #include /* malloc() ? */ #include /* memset() ? */ #include /* */ /* Our includes */ #include "base.h" #include "error.h" #include "convolve.h" /* for computing pyramid */ #include "pyramid.h" /********************************************************************* * */ _KLT_Pyramid _KLTCreatePyramid( int ncols, int nrows, int subsampling, int nlevels) { _KLT_Pyramid pyramid; int nbytes = sizeof(_KLT_PyramidRec) + nlevels * sizeof(_KLT_FloatImage *) + nlevels * sizeof(int) + nlevels * sizeof(int); int i; if (subsampling != 2 && subsampling != 4 && subsampling != 8 && subsampling != 16 && subsampling != 32) KLTError("(_KLTCreatePyramid) Pyramid's subsampling must " "be either 2, 4, 8, 16, or 32"); /* Allocate memory for structure and set parameters */ pyramid = (_KLT_Pyramid)malloc(nbytes); /* Set parameters */ pyramid->subsampling = subsampling; pyramid->nLevels = nlevels; pyramid->img = (_KLT_FloatImage *) (pyramid + 1); pyramid->ncols = (int *) (pyramid->img + nlevels); pyramid->nrows = (int *) (pyramid->ncols + nlevels); /* Allocate memory for each level of pyramid and assign pointers */ for (i = 0 ; i < nlevels ; i++) { pyramid->img[i] = _KLTCreateFloatImage(ncols, nrows); pyramid->ncols[i] = ncols; pyramid->nrows[i] = nrows; ncols /= subsampling; nrows /= subsampling; } return pyramid; } /********************************************************************* * */ void _KLTFreePyramid( _KLT_Pyramid pyramid) { int i; /* Free images */ for (i = 0 ; i < pyramid->nLevels ; i++) _KLTFreeFloatImage(pyramid->img[i]); /* Free structure */ free(pyramid); } /********************************************************************* * */ void _KLTComputePyramid( _KLT_FloatImage img, _KLT_Pyramid pyramid, float sigma_fact) { _KLT_FloatImage currimg, tmpimg; int ncols = img->ncols, nrows = img->nrows; int subsampling = pyramid->subsampling; int subhalf = subsampling / 2; float sigma = subsampling * sigma_fact; /* empirically determined */ int oldncols; int i, x, y; if (subsampling != 2 && subsampling != 4 && subsampling != 8 && subsampling != 16 && subsampling != 32) KLTError("(_KLTComputePyramid) Pyramid's subsampling must " "be either 2, 4, 8, 16, or 32"); /* Copy original image to level 0 of pyramid */ memcpy(pyramid->img[0]->data, img->data, ncols*nrows*sizeof(float)); currimg = img; for (i = 1 ; i < pyramid->nLevels ; i++) { tmpimg = _KLTCreateFloatImage(ncols, nrows); _KLTComputeSmoothedImage(currimg, sigma, tmpimg); /* Subsample */ oldncols = ncols; ncols /= subsampling; nrows /= subsampling; for (y = 0 ; y < nrows ; y++) for (x = 0 ; x < ncols ; x++) pyramid->img[i]->data[y*ncols+x] = tmpimg->data[(subsampling*y+subhalf)*oldncols + (subsampling*x+subhalf)]; /* Reassign current image */ currimg = pyramid->img[i]; _KLTFreeFloatImage(tmpimg); } } mlt-0.9.0/src/modules/videostab/stab/klt/pyramid.h000066400000000000000000000011351215300731300220670ustar00rootroot00000000000000/********************************************************************* * pyramid.h *********************************************************************/ #ifndef _PYRAMID_H_ #define _PYRAMID_H_ #include "klt_util.h" typedef struct { int subsampling; int nLevels; _KLT_FloatImage *img; int *ncols, *nrows; } _KLT_PyramidRec, *_KLT_Pyramid; _KLT_Pyramid _KLTCreatePyramid( int ncols, int nrows, int subsampling, int nlevels); void _KLTComputePyramid( _KLT_FloatImage floatimg, _KLT_Pyramid pyramid, float sigma_fact); void _KLTFreePyramid( _KLT_Pyramid pyramid); #endif mlt-0.9.0/src/modules/videostab/stab/klt/selectGoodFeatures.c000066400000000000000000000306341215300731300242120ustar00rootroot00000000000000/********************************************************************* * selectGoodFeatures.c * *********************************************************************/ /* Standard includes */ #include /* malloc(), qsort() */ #include /* fflush() */ #include /* memset() */ #include /* sqrt() */ /* Our includes */ #include "base.h" #include "error.h" #include "convolve.h" #include "klt.h" #include "klt_util.h" #include "pyramid.h" typedef enum {SELECTING_ALL, REPLACING_SOME} selectionMode; /*********************************************************************/ void _fillFeaturemap( int x, int y, uchar *featuremap, int mindist, int ncols, int nrows) { int ix, iy; for (iy = y - mindist ; iy <= y + mindist ; iy++) for (ix = x - mindist ; ix <= x + mindist ; ix++) if (ix >= 0 && ix < ncols && iy >= 0 && iy < nrows) featuremap[iy*ncols+ix] = 1; } /********************************************************************* * _enforceMinimumDistance * * Removes features that are within close proximity to better features. * * INPUTS * featurelist: A list of features. The nFeatures property * is used. * * OUTPUTS * featurelist: Is overwritten. Nearby "redundant" features are removed. * Writes -1's into the remaining elements. * * RETURNS * The number of remaining features. */ void _enforceMinimumDistance( int *pointlist, /* featurepoints */ int npoints, /* number of featurepoints */ KLT_FeatureList featurelist, /* features */ int ncols, int nrows, /* size of images */ int mindist, /* min. dist b/w features */ int min_eigenvalue, /* min. eigenvalue */ KLT_BOOL overwriteAllFeatures) { int indx; /* Index into features */ int x, y, val; /* Location and trackability of pixel under consideration */ uchar *featuremap; /* Boolean array recording proximity of features */ int *ptr; /* Cannot add features with an eigenvalue less than one */ if (min_eigenvalue < 1) min_eigenvalue = 1; /* Allocate memory for feature map and clear it */ featuremap = (uchar *) malloc(ncols * nrows * sizeof(uchar)); memset(featuremap, 0, ncols*nrows); /* Necessary because code below works with (mindist-1) */ mindist--; /* If we are keeping all old good features, then add them to the featuremap */ if (!overwriteAllFeatures) for (indx = 0 ; indx < featurelist->nFeatures ; indx++) if (featurelist->feature[indx]->val >= 0) { x = (int) featurelist->feature[indx]->x; y = (int) featurelist->feature[indx]->y; _fillFeaturemap(x, y, featuremap, mindist, ncols, nrows); } /* For each feature point, in descending order of importance, do ... */ ptr = pointlist; indx = 0; while (1) { /* If we can't add all the points, then fill in the rest of the featurelist with -1's */ if (ptr >= pointlist + 3*npoints) { while (indx < featurelist->nFeatures) { if (overwriteAllFeatures || featurelist->feature[indx]->val < 0) { featurelist->feature[indx]->x = -1; featurelist->feature[indx]->y = -1; featurelist->feature[indx]->val = KLT_NOT_FOUND; } indx++; } break; } x = *ptr++; y = *ptr++; val = *ptr++; while (!overwriteAllFeatures && indx < featurelist->nFeatures && featurelist->feature[indx]->val >= 0) indx++; if (indx >= featurelist->nFeatures) break; /* If no neighbor has been selected, and if the minimum eigenvalue is large enough, then add feature to the current list */ if (!featuremap[y*ncols+x] && val >= min_eigenvalue) { featurelist->feature[indx]->x = (KLT_locType) x; featurelist->feature[indx]->y = (KLT_locType) y; featurelist->feature[indx]->val = (int) val; indx++; /* Fill in surrounding region of feature map, but make sure that pixels are in-bounds */ _fillFeaturemap(x, y, featuremap, mindist, ncols, nrows); } } /* Free feature map */ free(featuremap); } /********************************************************************* * _comparePoints * * Used by qsort (in _KLTSelectGoodFeatures) to determine * which feature is better. * By switching the '>' with the '<', qsort is fooled into sorting * in descending order. */ int _comparePoints(const void *a, const void *b) { int v1 = *(((int *) a) + 2); int v2 = *(((int *) b) + 2); if (v1 > v2) return(-1); else if (v1 < v2) return(1); else return(0); } /********************************************************************* * _sortPointList */ void _sortPointList( int *pointlist, int npoints) { qsort(pointlist, npoints, 3*sizeof(int), _comparePoints); } /********************************************************************* * _minEigenvalue * * Given the three distinct elements of the symmetric 2x2 matrix * [gxx gxy] * [gxy gyy], * Returns the minimum eigenvalue of the matrix. */ float _minEigenvalue(float gxx, float gxy, float gyy) { return (float) ((gxx + gyy - sqrt((gxx - gyy)*(gxx - gyy) + 4*gxy*gxy)) / 2.0); } /*********************************************************************/ void _KLTSelectGoodFeatures( KLT_TrackingContext tc, KLT_PixelType *img, int ncols, int nrows, KLT_FeatureList featurelist, selectionMode mode) { _KLT_FloatImage floatimg, gradx, grady; int window_hw, window_hh; int *pointlist; int npoints = 0; KLT_BOOL overwriteAllFeatures = (mode == SELECTING_ALL) ? TRUE : FALSE; KLT_BOOL floatimages_created = FALSE; /* Check window size (and correct if necessary) */ if (tc->window_width % 2 != 1) { tc->window_width = tc->window_width+1; KLTWarning("Tracking context's window width must be odd. " "Changing to %d.\n", tc->window_width); } if (tc->window_height % 2 != 1) { tc->window_height = tc->window_height+1; KLTWarning("Tracking context's window height must be odd. " "Changing to %d.\n", tc->window_height); } if (tc->window_width < 3) { tc->window_width = 3; KLTWarning("Tracking context's window width must be at least three. \n" "Changing to %d.\n", tc->window_width); } if (tc->window_height < 3) { tc->window_height = 3; KLTWarning("Tracking context's window height must be at least three. \n" "Changing to %d.\n", tc->window_height); } window_hw = tc->window_width/2; window_hh = tc->window_height/2; /* Create pointlist, which is a simplified version of a featurelist, */ /* for speed. Contains only integer locations and values. */ pointlist = (int *) malloc(ncols * nrows * 3 * sizeof(int)); /* Create temporary images, etc. */ if (mode == REPLACING_SOME && tc->sequentialMode && tc->pyramid_last != NULL) { floatimg = ((_KLT_Pyramid) tc->pyramid_last)->img[0]; gradx = ((_KLT_Pyramid) tc->pyramid_last_gradx)->img[0]; grady = ((_KLT_Pyramid) tc->pyramid_last_grady)->img[0]; } else { floatimages_created = TRUE; floatimg = _KLTCreateFloatImage(ncols, nrows); gradx = _KLTCreateFloatImage(ncols, nrows); grady = _KLTCreateFloatImage(ncols, nrows); if (tc->smoothBeforeSelecting) { _KLT_FloatImage tmpimg; tmpimg = _KLTCreateFloatImage(ncols, nrows); _KLTToFloatImage(img, ncols, nrows, tmpimg); _KLTComputeSmoothedImage(tmpimg, _KLTComputeSmoothSigma(tc), floatimg); _KLTFreeFloatImage(tmpimg); } else { _KLTToFloatImage(img, ncols, nrows, floatimg); } /* Compute gradient of image in x and y direction */ _KLTComputeGradients(floatimg, tc->grad_sigma, gradx, grady); } /* Compute trackability of each image pixel as the minimum of the two eigenvalues of the Z matrix */ { float gx, gy; float gxx, gxy, gyy; int xx, yy; int *ptr; float val; unsigned int limit = 1; int borderx = tc->borderx; /* Must not touch cols */ int bordery = tc->bordery; /* lost by convolution */ int x, y; int i; if (borderx < window_hw) borderx = window_hw; if (bordery < window_hh) bordery = window_hh; /* Find largest value of an int */ for (i = 0 ; i < sizeof(int) ; i++) limit *= 256; limit = limit/2 - 1; /* For most of the pixels in the image, do ... */ ptr = pointlist; for (y = bordery ; y < nrows - bordery ; y += tc->nSkippedPixels + 1) for (x = borderx ; x < ncols - borderx ; x += tc->nSkippedPixels + 1) { /* Sum the gradients in the surrounding window */ gxx = 0; gxy = 0; gyy = 0; for (yy = y-window_hh ; yy <= y+window_hh ; yy++) for (xx = x-window_hw ; xx <= x+window_hw ; xx++) { gx = *(gradx->data + ncols*yy+xx); gy = *(grady->data + ncols*yy+xx); gxx += gx * gx; gxy += gx * gy; gyy += gy * gy; } /* Store the trackability of the pixel as the minimum of the two eigenvalues */ *ptr++ = x; *ptr++ = y; val = _minEigenvalue(gxx, gxy, gyy); if (val > limit) { KLTWarning("(_KLTSelectGoodFeatures) minimum eigenvalue %f is " "greater than the capacity of an int; setting " "to maximum value", val); val = (float) limit; } *ptr++ = (int) val; npoints++; } } /* Sort the features */ _sortPointList(pointlist, npoints); /* Check tc->mindist */ if (tc->mindist < 0) { KLTWarning("(_KLTSelectGoodFeatures) Tracking context field tc->mindist " "is negative (%d); setting to zero", tc->mindist); tc->mindist = 0; } /* Enforce minimum distance between features */ _enforceMinimumDistance( pointlist, npoints, featurelist, ncols, nrows, tc->mindist, tc->min_eigenvalue, overwriteAllFeatures); /* Free memory */ free(pointlist); if (floatimages_created) { _KLTFreeFloatImage(floatimg); _KLTFreeFloatImage(gradx); _KLTFreeFloatImage(grady); } } /********************************************************************* * KLTSelectGoodFeatures * * Main routine, visible to the outside. Finds the good features in * an image. * * INPUTS * tc: Contains parameters used in computation (size of image, * size of window, min distance b/w features, sigma to compute * image gradients, # of features desired). * img: Pointer to the data of an image (probably unsigned chars). * * OUTPUTS * features: List of features. The member nFeatures is computed. */ void KLTSelectGoodFeatures( KLT_TrackingContext tc, KLT_PixelType *img, int ncols, int nrows, KLT_FeatureList fl) { if (tc->verbose >= 1) { fprintf(stderr, "(KLT) Selecting the %d best features " "from a %d by %d image... ", fl->nFeatures, ncols, nrows); fflush(stderr); } _KLTSelectGoodFeatures(tc, img, ncols, nrows, fl, SELECTING_ALL); if (tc->verbose >= 1) fprintf( stderr, "\n\t%d features found.\n", KLTCountRemainingFeatures(fl) ); } /********************************************************************* * KLTReplaceLostFeatures * * Main routine, visible to the outside. Replaces the lost features * in an image. * * INPUTS * tc: Contains parameters used in computation (size of image, * size of window, min distance b/w features, sigma to compute * image gradients, # of features desired). * img: Pointer to the data of an image (probably unsigned chars). * * OUTPUTS * features: List of features. The member nFeatures is computed. */ void KLTReplaceLostFeatures( KLT_TrackingContext tc, KLT_PixelType *img, int ncols, int nrows, KLT_FeatureList fl) { int nLostFeatures = fl->nFeatures - KLTCountRemainingFeatures(fl); if (tc->verbose >= 1) { fprintf(stderr, "(KLT) Attempting to replace %d features " "in a %d by %d image... ", nLostFeatures, ncols, nrows); fflush(stderr); } /* If there are any lost features, replace them */ if (nLostFeatures > 0) _KLTSelectGoodFeatures(tc, img, ncols, nrows, fl, REPLACING_SOME); if (tc->verbose >= 1) fprintf( stderr, "\n\t%d features replaced.\n", nLostFeatures - fl->nFeatures + KLTCountRemainingFeatures(fl) ); } mlt-0.9.0/src/modules/videostab/stab/klt/trackFeatures.c000066400000000000000000000377651215300731300232420ustar00rootroot00000000000000/********************************************************************* * trackFeatures.c * *********************************************************************/ /* Standard includes */ #include /* fabs() */ #include /* malloc() */ #include /* fflush() */ /* Our includes */ #include "base.h" #include "error.h" #include "convolve.h" /* for computing pyramid */ #include "klt.h" #include "klt_util.h" /* _KLT_FloatImage */ #include "pyramid.h" /* _KLT_Pyramid */ typedef float *_FloatWindow; /********************************************************************* * _interpolate * * Given a point (x,y) in an image, computes the bilinear interpolated * gray-level value of the point in the image. */ float _interpolate(float x, float y, _KLT_FloatImage img) { int xt = x; int yt = y; float ax = x - xt; float ay = y - yt; float *ptr = img->data + (img->ncols * yt) + xt; return ( (1 - ax) * (1 - ay) * (*ptr) + ax * (1 - ay) * (*(ptr + 1)) + (1 - ax) * ay * (*(ptr + img->ncols)) + ax * ay * (*(ptr + img->ncols + 1)) ); } /********************************************************************* * _computeIntensityDifference * * Given two images and the window center in both images, * aligns the images wrt the window and computes the difference * between the two overlaid images. */ void _computeIntensityDifference( _KLT_FloatImage img1, /* images */ _KLT_FloatImage img2, float x1, float y1, /* center of window in 1st img */ float x2, float y2, /* center of window in 2nd img */ int width, int height, /* size of window */ _FloatWindow imgdiff) /* output */ { int hw = width/2, hh = height/2; float g1, g2; int i, j; /* Compute values */ for (j = -hh ; j <= hh ; j++) for (i = -hw ; i <= hw ; i++) { g1 = _interpolate(x1+i, y1+j, img1); g2 = _interpolate(x2+i, y2+j, img2); *imgdiff++ = g1 - g2; } } /********************************************************************* * _computeGradientSum * * Given two gradients and the window center in both images, * aligns the gradients wrt the window and computes the sum of the two * overlaid gradients. */ void _computeGradientSum( _KLT_FloatImage gradx1, /* gradient images */ _KLT_FloatImage grady1, _KLT_FloatImage gradx2, _KLT_FloatImage grady2, float x1, float y1, /* center of window in 1st img */ float x2, float y2, /* center of window in 2nd img */ int width, int height, /* size of window */ _FloatWindow gradx, /* output */ _FloatWindow grady) /* " */ { int hw = width/2, hh = height/2; float g1, g2; int i, j; /* Compute values */ for (j = -hh ; j <= hh ; j++) for (i = -hw ; i <= hw ; i++) { g1 = _interpolate(x1+i, y1+j, gradx1); g2 = _interpolate(x2+i, y2+j, gradx2); *gradx++ = g1 + g2; g1 = _interpolate(x1+i, y1+j, grady1); g2 = _interpolate(x2+i, y2+j, grady2); *grady++ = g1 + g2; } } /********************************************************************* * _compute2by2GradientMatrix * */ void _compute2by2GradientMatrix( _FloatWindow gradx, _FloatWindow grady, int width, /* size of window */ int height, float *gxx, /* return values */ float *gxy, float *gyy) { float gx, gy; int i; /* Compute values */ *gxx = 0.0; *gxy = 0.0; *gyy = 0.0; for (i = 0 ; i < width * height ; i++) { gx = *gradx++; gy = *grady++; *gxx += gx*gx; *gxy += gx*gy; *gyy += gy*gy; } } /********************************************************************* * _compute2by1ErrorVector * */ void _compute2by1ErrorVector( _FloatWindow imgdiff, _FloatWindow gradx, _FloatWindow grady, int width, /* size of window */ int height, float step_factor, /* 2.0 comes from equations, 1.0 seems to avoid overshooting */ float *ex, /* return values */ float *ey) { float diff; int i; /* Compute values */ *ex = 0; *ey = 0; for (i = 0 ; i < width * height ; i++) { diff = *imgdiff++; *ex += diff * (*gradx++); *ey += diff * (*grady++); } *ex *= step_factor; *ey *= step_factor; } /********************************************************************* * _solveEquation * * Solves the 2x2 matrix equation * [gxx gxy] [dx] = [ex] * [gxy gyy] [dy] = [ey] * for dx and dy. * * Returns KLT_TRACKED on success and KLT_SMALL_DET on failure */ int _solveEquation( float gxx, float gxy, float gyy, float ex, float ey, float small, float *dx, float *dy) { float det = gxx*gyy - gxy*gxy; if (det < small) return KLT_SMALL_DET; *dx = (gyy*ex - gxy*ey)/det; *dy = (gxx*ey - gxy*ex)/det; return KLT_TRACKED; } /********************************************************************* * _allocateFloatWindow */ _FloatWindow _allocateFloatWindow(int width, int height) { return (_FloatWindow)malloc(width * height * sizeof(float)); } /********************************************************************* * _sumAbsFloatWindow */ float _sumAbsFloatWindow( _FloatWindow fw, int width, int height) { float sum = 0.0; int w; for ( ; height > 0 ; height--) for (w=0 ; w < width ; w++) sum += (float) fabs(*fw++); return sum; } /********************************************************************* * _trackFeature * * Tracks a feature point from one image to the next. * * RETURNS * KLT_SMALL_DET if feature is lost, * KLT_MAX_ITERATIONS if tracking stopped because iterations timed out, * KLT_TRACKED otherwise. */ int _trackFeature( float x1, /* location of window in first image */ float y1, float *x2, /* starting location of search in second image */ float *y2, _KLT_FloatImage img1, _KLT_FloatImage gradx1, _KLT_FloatImage grady1, _KLT_FloatImage img2, _KLT_FloatImage gradx2, _KLT_FloatImage grady2, int width, /* size of window */ int height, float step_factor, /* 2.0 comes from equations, 1.0 seems to avoid overshooting */ int max_iterations, float small, /* determinant threshold for declaring KLT_SMALL_DET */ float th, /* displacement threshold for stopping */ float max_residue) /* residue threshold for declaring KLT_LARGE_RESIDUE */ { _FloatWindow imgdiff, gradx, grady; float gxx, gxy, gyy, ex, ey, dx, dy; int iteration = 0; int status; int hw = width / 2; int hh = height / 2; int nc = img1->ncols; int nr = img1->nrows; float one_plus_eps = 1.001f; /* To prevent rounding errors */ /* Allocate memory for windows */ imgdiff = _allocateFloatWindow(width, height); gradx = _allocateFloatWindow(width, height); grady = _allocateFloatWindow(width, height); /* Iteratively update the window position */ do { /* If out of bounds, exit loop */ if ( x1-hw < 0.0f || nc-( x1+hw) < one_plus_eps || *x2-hw < 0.0f || nc-(*x2+hw) < one_plus_eps || y1-hh < 0.0f || nr-( y1+hh) < one_plus_eps || *y2-hh < 0.0f || nr-(*y2+hh) < one_plus_eps) { status = KLT_OOB; break; } /* Compute gradient and difference windows */ _computeIntensityDifference(img1, img2, x1, y1, *x2, *y2, width, height, imgdiff); _computeGradientSum(gradx1, grady1, gradx2, grady2, x1, y1, *x2, *y2, width, height, gradx, grady); /* Use these windows to construct matrices */ _compute2by2GradientMatrix(gradx, grady, width, height, &gxx, &gxy, &gyy); _compute2by1ErrorVector(imgdiff, gradx, grady, width, height, step_factor, &ex, &ey); /* Using matrices, solve equation for new displacement */ status = _solveEquation(gxx, gxy, gyy, ex, ey, small, &dx, &dy); if (status == KLT_SMALL_DET) break; *x2 += dx; *y2 += dy; iteration++; } while ((fabs(dx)>=th || fabs(dy)>=th) && iteration < max_iterations); /* Check whether window is out of bounds */ if (*x2-hw < 0.0f || nc-(*x2+hw) < one_plus_eps || *y2-hh < 0.0f || nr-(*y2+hh) < one_plus_eps) status = KLT_OOB; /* Check whether residue is too large */ if (status == KLT_TRACKED) { _computeIntensityDifference( img1, img2, x1, y1, *x2, *y2, width, height, imgdiff); if (_sumAbsFloatWindow(imgdiff, width, height)/(width*height) > max_residue) status = KLT_LARGE_RESIDUE; } /* Free memory */ free(imgdiff); free(gradx); free(grady); /* Return appropriate value */ if (status == KLT_SMALL_DET) return KLT_SMALL_DET; else if (status == KLT_OOB) return KLT_OOB; else if (status == KLT_LARGE_RESIDUE) return KLT_LARGE_RESIDUE; else if (iteration >= max_iterations) return KLT_MAX_ITERATIONS; else return KLT_TRACKED; } /*********************************************************************/ KLT_BOOL _outOfBounds( float x, float y, int ncols, int nrows, int borderx, int bordery) { return (x < borderx || x > ncols-1-borderx || y < bordery || y > nrows-1-bordery ); } /********************************************************************* * KLTTrackFeatures * * Tracks feature points from one image to the next. */ void KLTTrackFeatures( KLT_TrackingContext tc, KLT_PixelType *img1, KLT_PixelType *img2, int ncols, int nrows, KLT_FeatureList featurelist) { _KLT_FloatImage tmpimg = NULL; _KLT_FloatImage floatimg1 = NULL; _KLT_FloatImage floatimg2 = NULL; _KLT_Pyramid pyramid1, pyramid1_gradx, pyramid1_grady; _KLT_Pyramid pyramid2, pyramid2_gradx, pyramid2_grady; int val = 0; KLT_BOOL floatimg1_created = FALSE; float subsampling = (float)tc->subsampling; float xloc, yloc, xlocout, ylocout; int i, indx, r; if (tc->verbose >= 1) { fprintf(stderr, "(KLT) Tracking %d features in a %d by %d image... ", KLTCountRemainingFeatures(featurelist), ncols, nrows); fflush(stderr); } /* Check window size (and correct if necessary) */ if (tc->window_width % 2 != 1) { tc->window_width = tc->window_width+1; KLTWarning("Tracking context's window width must be odd. " "Changing to %d.\n", tc->window_width); } if (tc->window_height % 2 != 1) { tc->window_height = tc->window_height+1; KLTWarning("Tracking context's window height must be odd. " "Changing to %d.\n", tc->window_height); } if (tc->window_width < 3) { tc->window_width = 3; KLTWarning("Tracking context's window width must be at least three. \n" "Changing to %d.\n", tc->window_width); } if (tc->window_height < 3) { tc->window_height = 3; KLTWarning("Tracking context's window height must be at least three. \n" "Changing to %d.\n", tc->window_height); } /* Create temporary image */ tmpimg = _KLTCreateFloatImage(ncols, nrows); /* Process first image by converting to float, smoothing, computing */ /* pyramid, and computing gradient pyramids */ if (tc->sequentialMode && tc->pyramid_last != NULL) { pyramid1 = (_KLT_Pyramid) tc->pyramid_last; pyramid1_gradx = (_KLT_Pyramid) tc->pyramid_last_gradx; pyramid1_grady = (_KLT_Pyramid) tc->pyramid_last_grady; if (pyramid1->ncols[0] != ncols || pyramid1->nrows[0] != nrows) KLTError("(KLTTrackFeatures) Size of incoming image (%d by %d) " "is different from size of previous image (%d by %d)\n", ncols, nrows, pyramid1->ncols[0], pyramid1->nrows[0]); } else { floatimg1_created = TRUE; floatimg1 = _KLTCreateFloatImage(ncols, nrows); _KLTToFloatImage(img1, ncols, nrows, tmpimg); _KLTComputeSmoothedImage(tmpimg, _KLTComputeSmoothSigma(tc), floatimg1); pyramid1 = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); _KLTComputePyramid(floatimg1, pyramid1, tc->pyramid_sigma_fact); pyramid1_gradx = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); pyramid1_grady = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); for (i = 0 ; i < tc->nPyramidLevels ; i++) _KLTComputeGradients(pyramid1->img[i], tc->grad_sigma, pyramid1_gradx->img[i], pyramid1_grady->img[i]); } /* Do the same thing with second image */ floatimg2 = _KLTCreateFloatImage(ncols, nrows); _KLTToFloatImage(img2, ncols, nrows, tmpimg); _KLTComputeSmoothedImage(tmpimg, _KLTComputeSmoothSigma(tc), floatimg2); pyramid2 = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); _KLTComputePyramid(floatimg2, pyramid2, tc->pyramid_sigma_fact); pyramid2_gradx = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); pyramid2_grady = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); for (i = 0 ; i < tc->nPyramidLevels ; i++) _KLTComputeGradients(pyramid2->img[i], tc->grad_sigma, pyramid2_gradx->img[i], pyramid2_grady->img[i]); /* For each feature, do ... */ for (indx = 0 ; indx < featurelist->nFeatures ; indx++) { /* Only track features that are not lost */ if (featurelist->feature[indx]->val >= 0) { xloc = featurelist->feature[indx]->x; yloc = featurelist->feature[indx]->y; /* Transform location to coarsest resolution */ for (r = tc->nPyramidLevels - 1 ; r >= 0 ; r--) { xloc /= subsampling; yloc /= subsampling; } xlocout = xloc; ylocout = yloc; /* Beginning with coarsest resolution, do ... */ for (r = tc->nPyramidLevels - 1 ; r >= 0 ; r--) { /* Track feature at current resolution */ xloc *= subsampling; yloc *= subsampling; xlocout *= subsampling; ylocout *= subsampling; val = _trackFeature(xloc, yloc, &xlocout, &ylocout, pyramid1->img[r], pyramid1_gradx->img[r], pyramid1_grady->img[r], pyramid2->img[r], pyramid2_gradx->img[r], pyramid2_grady->img[r], tc->window_width, tc->window_height, tc->step_factor, tc->max_iterations, tc->min_determinant, tc->min_displacement, tc->max_residue); if (val==KLT_SMALL_DET || val==KLT_OOB) break; } /* Record feature */ if (val == KLT_OOB) { featurelist->feature[indx]->x = -1.0; featurelist->feature[indx]->y = -1.0; featurelist->feature[indx]->val = KLT_OOB; } else if (_outOfBounds(xlocout, ylocout, ncols, nrows, tc->borderx, tc->bordery)) { featurelist->feature[indx]->x = -1.0; featurelist->feature[indx]->y = -1.0; featurelist->feature[indx]->val = KLT_OOB; } else if (val == KLT_SMALL_DET) { featurelist->feature[indx]->x = -1.0; featurelist->feature[indx]->y = -1.0; featurelist->feature[indx]->val = KLT_SMALL_DET; } else if (val == KLT_LARGE_RESIDUE) { featurelist->feature[indx]->x = -1.0; featurelist->feature[indx]->y = -1.0; featurelist->feature[indx]->val = KLT_LARGE_RESIDUE; } else if (val == KLT_MAX_ITERATIONS) { featurelist->feature[indx]->x = -1.0; featurelist->feature[indx]->y = -1.0; featurelist->feature[indx]->val = KLT_MAX_ITERATIONS; } else { featurelist->feature[indx]->x = xlocout; featurelist->feature[indx]->y = ylocout; featurelist->feature[indx]->val = KLT_TRACKED; } } } if (tc->sequentialMode) { tc->pyramid_last = pyramid2; tc->pyramid_last_gradx = pyramid2_gradx; tc->pyramid_last_grady = pyramid2_grady; } else { _KLTFreePyramid(pyramid2); _KLTFreePyramid(pyramid2_gradx); _KLTFreePyramid(pyramid2_grady); } /* Free memory */ _KLTFreeFloatImage(tmpimg); if (floatimg1_created) _KLTFreeFloatImage(floatimg1); _KLTFreeFloatImage(floatimg2); _KLTFreePyramid(pyramid1); _KLTFreePyramid(pyramid1_gradx); _KLTFreePyramid(pyramid1_grady); if (tc->verbose >= 1) fprintf( stderr, "\n\t%d features successfully tracked.\n", KLTCountRemainingFeatures(featurelist) ); } mlt-0.9.0/src/modules/videostab/stab/main.c000066400000000000000000000115501215300731300205510ustar00rootroot00000000000000/* * Video stabilizer * * Copyright (c) 2008 Lenny * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include #include #include //#include #include "avi/avi.h" #include "vector.h" #include "utils.h" #include "estimate.h" #include "resample.h" AviMovie mv_in, mv_out; void print_help(char *argv[]) { printf( " \n" "Video stabilizer \n" " \n" "Usage: \n" " %s [options] \n" " \n" "Options: \n" " -r # | Rolling shutter angle | default: 0 | range: 0 - 180 \n" " -q # | Output MJPEG quality | default: 100 | range: 50 - 100 \n" " \n", argv[0] ); exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { int opt_shutter_angle = 0; int opt_mjpeg_quality = 100; int nf, i, nc, nr; int tfs, fps; vc *pos_i, *pos_h, *pos_y; es_ctx *es; rs_ctx *rs; opterr = 0; while ((i = getopt(argc, argv, "r:q:")) != -1) { switch (i) { case 'r': opt_shutter_angle = atoi(optarg); break; case 'q': opt_mjpeg_quality = atoi(optarg); break; default: print_help(argv); } } if (argc < optind + 2) print_help(argv); if (AVI_open_movie(argv[optind], &mv_in) != AVI_ERROR_NONE) { printf("error: can't read from %s\n", argv[optind]); return EXIT_FAILURE; } if (mv_in.header->Streams < 1 || mv_in.streams[0].sh.Type != AVIST_VIDEO) { printf("error: video stream not found on %s\n", argv[optind]); return EXIT_FAILURE; } if (AVI_open_compress(argv[optind + 1], &mv_out, 1, AVI_FORMAT_MJPEG) != AVI_ERROR_NONE) { printf("error: can't write to %s\n", argv[optind + 1]); return EXIT_FAILURE; } printf("status: setup\n"); prepare_lanc_kernels(); nc = mv_in.header->Width; nr = mv_in.header->Height; tfs = mv_in.header->TotalFrames; fps = 1000000 / mv_in.header->MicroSecPerFrame; pos_i = (vc *)malloc(tfs * sizeof(vc)); pos_h = (vc *)malloc(tfs * sizeof(vc)); pos_y = (vc *)malloc(nr * sizeof(vc)); AVI_set_compress_option(&mv_out, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_WIDTH, &nc); AVI_set_compress_option(&mv_out, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_HEIGHT, &nr); AVI_set_compress_option(&mv_out, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_FRAMERATE, &fps); AVI_set_compress_option(&mv_out, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_QUALITY, &opt_mjpeg_quality); es = es_init(nc, nr); rs = rs_init(nc, nr); printf("status: estimating\n"); for (nf = 0; nf < tfs; nf ++) { unsigned char *fr = (unsigned char *)AVI_read_frame(&mv_in, AVI_FORMAT_RGB24, nf, 0); pos_i[nf] = vc_add( nf > 0 ? pos_i[nf - 1] : vc_set(0.0, 0.0), es_estimate(es, fr) ); free(fr); if ((nf + 1) % 10 == 0) { printf("."); fflush(stdout); } } printf("\nstatus: filtering\n"); hipass(pos_i, pos_h, tfs, fps / 2); printf("status: resampling\n"); for (nf = 0; nf < tfs; nf ++) { unsigned char *fr = (unsigned char *)AVI_read_frame(&mv_in, AVI_FORMAT_RGB24, nf, 0); for (i = 0; i < nr; i ++) { pos_y[i] = interp( pos_h, tfs, nf + (i - nr / 2.0) * opt_shutter_angle / (nr * 360.0) ); } rs_resample(rs, fr, pos_y); AVI_write_frame(&mv_out, nf, AVI_FORMAT_RGB24, fr, nc * nr * 3 * sizeof(unsigned char)); if ((nf + 1) % 10 == 0) { printf("."); fflush(stdout); } } printf("\nstatus: closing\n"); es_free(es); rs_free(rs); free_lanc_kernels(); AVI_close(&mv_in); AVI_close_compress(&mv_out); return EXIT_SUCCESS; } mlt-0.9.0/src/modules/videostab/stab/resample.c000066400000000000000000000045051215300731300214370ustar00rootroot00000000000000/* * Video stabilizer * * Copyright (c) 2008 Lenny * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include "resample.h" #include "utils.h" rs_ctx *rs_init(int nc, int nr) { rs_ctx *rs = (rs_ctx *)malloc(sizeof(rs_ctx)); rs->tf = (unsigned char *)malloc(nc * nr * 3 * sizeof(unsigned char)); rs->nc = nc; rs->nr = nr; return rs; } void rs_resample(int* lanc_kernels,rs_ctx *rs, unsigned char *f, vc *p) { int i, x, y, c; for (y = 0; y < rs->nr; y ++) { int yp = y * rs->nc; int xd = floor(p[y].x); int *lk = select_lanc_kernel(lanc_kernels,p[y].x); for (x = 0; x < rs->nc; x ++) { int pd = (yp + x) * 3; int a[3]; for (c = 0; c < 3; c ++) a[c] = 0; for (i = -3; i < 5; i ++) { int ps = (yp + clamp(x + xd + i, 0, rs->nc - 1)) * 3; for (c = 0; c < 3; c ++) a[c] += f[ps + c] * lk[i + 3]; } for (c = 0; c < 3; c ++) rs->tf[pd + c] = clamp(a[c] / 1024, 0, 255); } } for (y = 0; y < rs->nr; y ++) { int yp = y * rs->nc; int yd = floor(p[y].y); int *lk = select_lanc_kernel(lanc_kernels,p[y].y); for (x = 0; x < rs->nc; x ++) { int pd = (yp + x) * 3; int a[3]; for (c = 0; c < 3; c ++) a[c] = 0; for (i = -3; i < 5; i ++) { int ps = (clamp(y + yd + i, 0, rs->nr - 1) * rs->nc + x) * 3; for (c = 0; c < 3; c ++) a[c] += rs->tf[ps + c] * lk[i + 3]; } for (c = 0; c < 3; c ++) f[pd + c] = clamp(a[c] / 1024, 0, 255); } } } void rs_free(rs_ctx *rs) { free(rs->tf); free(rs); } mlt-0.9.0/src/modules/videostab/stab/resample.h000066400000000000000000000003671215300731300214460ustar00rootroot00000000000000#ifndef RESAMPLE_H #define RESAMPLE_H #include "vector.h" typedef struct { unsigned char *tf; int nc, nr; } rs_ctx; rs_ctx *rs_init(int, int); void rs_resample(int*,rs_ctx *, unsigned char *, vc *); void rs_free(rs_ctx *); #endif mlt-0.9.0/src/modules/videostab/stab/utils.c000066400000000000000000000047701215300731300207730ustar00rootroot00000000000000/* * Video stabilizer * * Copyright (c) 2008 Lenny * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include "utils.h" float lanc(float x, float r) { float t = x * M_PI; if (x == 0.0) return 1.0; if (x <= -r || x >= r) return 0.0; return r * sin(t) * sin(t / r) / (t * t); } float hann(float x, float d) { if (x < 0.0 || x > d) return 0.0; return 0.5 * (1.0 - cos((M_PI * 2.0 * x) / (d - 1.0))); } int clamp(int a, int b, int c) { if (a < b) a = b; if (a > c) a = c; return a; } void lopass(vc *vi, vc *vo, int l, int r) { int d = r * 2 + 1; float *ck = (float *)malloc(d * sizeof(float)); float cw = 0.0; int i, j; for (i = 0; i < d; i ++) cw += ck[i] = hann(i, d - 1); for (i = 0; i < l; i ++) { vc a = vc_zero(); for (j = i - r; j <= i + r; j ++) { int jc = clamp(j, 0, l - 1); vc_mul_acc(&a, vi[jc], ck[j - i + r]); } vo[i] = vc_div(a, cw); } free(ck); } void hipass(vc *vi, vc *vo, int l, int r) { int i; lopass(vi, vo, l, r); for (i = 0; i < l; i ++) vo[i] = vc_sub(vi[i], vo[i]); } int* prepare_lanc_kernels() { int i, j; int* lanc_kernels = (int *)malloc(256 * 8 * sizeof(int)); for (i = 0; i < 256; i ++) for (j = -3; j < 5; j ++) lanc_kernels[i * 8 + j + 3] = lanc(j - i / 256.0, 4) * 1024.0; return lanc_kernels; } int *select_lanc_kernel(int* lanc_kernels,float x) { return lanc_kernels + (int)((x - floor(x)) * 256.0) * 8; } void free_lanc_kernels(int *lanc_kernels) { free(lanc_kernels); } vc interp(int* lanc_kernels, vc *vi, int l, float x) { vc a = vc_zero(); int xd = floor(x); int *lk = select_lanc_kernel(lanc_kernels,x); int i; for (i = -3; i < 5; i ++) { int ic = clamp(xd + i, 0, l - 1); vc_mul_acc(&a, vi[ic], lk[i + 3]); } return vc_div(a, 1024.0); } mlt-0.9.0/src/modules/videostab/stab/utils.h000066400000000000000000000007351215300731300207750ustar00rootroot00000000000000#ifndef UTILS_H #define UTILS_H #include "vector.h" #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif float lanc(float, float); float hann(float, float); int clamp(int, int, int); void lopass(vc *, vc *, int, int); void hipass(vc *, vc *, int, int); int* prepare_lanc_kernels(); int *select_lanc_kernel(int*,float); void free_lanc_kernels(int*); vc interp(int*,vc *, int, float); #endif mlt-0.9.0/src/modules/videostab/stab/vector.c000066400000000000000000000035521215300731300211320ustar00rootroot00000000000000/* * Video stabilizer * * Copyright (c) 2008 Lenny * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include "vector.h" vc vc_zero() { vc v3; v3.x = 0.0; v3.y = 0.0; return v3; } vc vc_one() { vc v3; v3.x = 1.0; v3.y = 1.0; return v3; } vc vc_set(float x, float y) { vc v3; v3.x = x; v3.y = y; return v3; } vc vc_add(vc v1, vc v2) { vc v3; v3.x = v1.x + v2.x; v3.y = v1.y + v2.y; return v3; } vc vc_sub(vc v1, vc v2) { vc v3; v3.x = v1.x - v2.x; v3.y = v1.y - v2.y; return v3; } vc vc_mul(vc v1, float v2) { vc v3; v3.x = v1.x * v2; v3.y = v1.y * v2; return v3; } vc vc_div(vc v1, float v2) { vc v3; v3.x = v1.x / v2; v3.y = v1.y / v2; return v3; } void vc_acc(vc *v1, vc v2) { v1->x += v2.x; v1->y += v2.y; } void vc_mul_acc(vc *v1, vc v2, float v3) { v1->x += v2.x * v3; v1->y += v2.y * v3; } float vc_len(vc v) { return sqrt(v.x * v.x + v.y * v.y); } float vc_ang(vc v1, vc v2) { float c = v1.x * v2.y - v1.y * v2.x; if (fabs(c) > 0.0) { float l = vc_len(v1) * vc_len(v2); float d = acos((v1.x * v2.x + v1.y * v2.y) / l); if (c > 0.0) return d; else return -d; } return 0.0; } mlt-0.9.0/src/modules/videostab/stab/vector.h000066400000000000000000000005011215300731300211260ustar00rootroot00000000000000#ifndef VECTOR_H #define VECTOR_H typedef struct { float x, y; } vc; vc vc_zero(); vc vc_one(); vc vc_set(float, float); vc vc_add(vc, vc); vc vc_sub(vc, vc); vc vc_mul(vc, float); vc vc_div(vc, float); void vc_acc(vc *, vc); void vc_mul_acc(vc *, vc, float); float vc_len(vc); float vc_ang(vc, vc); #endif mlt-0.9.0/src/modules/videostab/stabilize.c000066400000000000000000000747531215300731300207000ustar00rootroot00000000000000/* * filter_stabilize.c * * Copyright (C) Georg Martius - June 2007 * georg dot martius at web dot de * mlt adaption by Marco Gittler marco at gitma dot de 2011 * * This file is part of transcode, a video stream processing tool * * transcode is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * transcode is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* Typical call: * transcode -V -J stabilize=shakiness=5:show=1,preview * -i inp.mpeg -y null,null -o dummy * all parameters are optional */ #define MOD_NAME "filter_stabilize.so" #define MOD_VERSION "v0.75 (2010-04-07)" #define MOD_CAP "extracts relative transformations of \n\ subsequent frames (used for stabilization together with the\n\ transform filter in a second pass)" #define MOD_AUTHOR "Georg Martius" /* Ideas: - Try OpenCL/Cuda, this should work great - use smoothing on the frames and then use gradient decent! - stepsize could be adapted (maybe to check only one field with large stepsize and use the maximally required for the other fields */ #define MOD_FEATURES \ TC_MODULE_FEATURE_FILTER|TC_MODULE_FEATURE_VIDEO #define MOD_FLAGS \ TC_MODULE_FLAG_RECONFIGURABLE | TC_MODULE_FLAG_DELAY #define MAX(a,b) ((a < b) ? (b) : (a)) #define MIN(a,b) ((a < b) ? (a) : (b)) #include "stabilize.h" #include #include #include #include #ifdef USE_SSE2 #include #endif void addTrans(StabData* sd, Transform sl) { if (!sd->transs) { sd->transs = tlist_new(0); } tlist_append(sd->transs, &sl,sizeof(Transform) ); } /** initialise measurement fields on the frame. The size of the fields and the maxshift is used to calculate an optimal distribution in the frame. */ int initFields(StabData* sd) { int size = sd->field_size; int rows = MAX(3,(sd->height - sd->maxshift*2)/size-1); int cols = MAX(3,(sd->width - sd->maxshift*2)/size-1); // make sure that the remaining rows have the same length sd->field_num = rows*cols; sd->field_rows = rows; mlt_log_debug (NULL,"field setup: rows: %i cols: %i Total: %i fields", rows, cols, sd->field_num); if (!(sd->fields = malloc(sizeof(Field) * sd->field_num))) { mlt_log_error ( NULL, "malloc failed!\n"); return 0; } else { int i, j; // the border is the amount by which the field centers // have to be away from the image boundary // (stepsize is added in case shift is increased through stepsize) int border = size/2 + sd->maxshift + sd->stepsize; int step_x = (sd->width - 2*border)/MAX(cols-1,1); int step_y = (sd->height - 2*border) / MAX(rows-1,1); for (j = 0; j < rows; j++) { for (i = 0; i < cols; i++) { int idx = j*cols+i; sd->fields[idx].x = border + i*step_x; sd->fields[idx].y = border + j*step_y; sd->fields[idx].size = size; } } } return 1; } /** compares the two given images and returns the average absolute difference \param d_x shift in x direction \param d_y shift in y direction */ double compareImg(unsigned char* I1, unsigned char* I2, int width, int height, int bytesPerPixel, int d_x, int d_y) { int i, j; unsigned char* p1 = NULL; unsigned char* p2 = NULL; long int sum = 0; int effectWidth = width - abs(d_x); int effectHeight = height - abs(d_y); /* DEBUGGING code to export single frames */ /* char buffer[100]; */ /* sprintf(buffer, "pic_%02ix%02i_1.ppm", d_x, d_y); */ /* FILE *pic1 = fopen(buffer, "w"); */ /* sprintf(buffer, "pic_%02ix%02i_2.ppm", d_x, d_y); */ /* FILE *pic2 = fopen(buffer, "w"); */ /* fprintf(pic1, "P6\n%i %i\n255\n", effectWidth, effectHeight); */ /* fprintf(pic2, "P6\n%i %i\n255\n", effectWidth, effectHeight); */ for (i = 0; i < effectHeight; i++) { p1 = I1; p2 = I2; if (d_y > 0 ){ p1 += (i + d_y) * width * bytesPerPixel; p2 += i * width * bytesPerPixel; } else { p1 += i * width * bytesPerPixel; p2 += (i - d_y) * width * bytesPerPixel; } if (d_x > 0) { p1 += d_x * bytesPerPixel; } else { p2 -= d_x * bytesPerPixel; } #ifdef USE_SSE2 __m128i A,B,C,D,E; for (j = 0; j < effectWidth * bytesPerPixel - 16; j++) { #else for (j = 0; j < effectWidth * bytesPerPixel; j++) { #endif /* fwrite(p1,1,1,pic1);fwrite(p1,1,1,pic1);fwrite(p1,1,1,pic1); fwrite(p2,1,1,pic2);fwrite(p2,1,1,pic2);fwrite(p2,1,1,pic2); */ #ifdef USE_SSE2 A= _mm_loadu_si128((__m128i*)p1); //load unaligned data B= _mm_loadu_si128((__m128i*)p2); C= _mm_sad_epu8(A, B);//diff per 8 bit pixel stored in 2 64 byte values D = _mm_srli_si128(C, 8); // shift first 64 byte value to align at the same as C E = _mm_add_epi32(C, D); // add the 2 values (sum of all diffs) sum+= _mm_cvtsi128_si32(E); //convert _m128i to int p1+=16; p2+=16; j+=15; #else sum += abs((int)*p1 - (int)*p2); p1++; p2++; #endif } } /* fclose(pic1); fclose(pic2); */ return sum/((double) effectWidth * effectHeight * bytesPerPixel); } /** compares a small part of two given images and returns the average absolute difference. Field center, size and shift have to be choosen, so that no clipping is required \param field Field specifies position(center) and size of subimage \param d_x shift in x direction \param d_y shift in y direction */ double compareSubImg(unsigned char* const I1, unsigned char* const I2, const Field* field, int width, int height, int bytesPerPixel, int d_x, int d_y) { int k, j; unsigned char* p1 = NULL; unsigned char* p2 = NULL; int s2 = field->size / 2; double sum=0.0; p1=I1 + ((field->x - s2) + (field->y - s2)*width)*bytesPerPixel; p2=I2 + ((field->x - s2 + d_x) + (field->y - s2 + d_y)*width)*bytesPerPixel; // TODO: use some mmx or sse stuff here #ifdef USE_SSE2 __m128i A,B,C,D,E; #endif for (j = 0; j < field->size; j++){ #ifdef USE_SSE2 for (k = 0; k < (field->size * bytesPerPixel) - 16 ; k++) { A= _mm_loadu_si128((__m128i*)p1); //load unaligned data B= _mm_loadu_si128((__m128i*)p2); C= _mm_sad_epu8(A, B);//abd diff stored in 2 64 byte values D = _mm_srli_si128(C, 8); // shift value 8 byte right E = _mm_add_epi32(C, D); // add the 2 values (sum of all diffs) sum+= _mm_cvtsi128_si32(E); //convert _m128i to int p1+=16; p2+=16; k+=15; #else for (k = 0; k < (field->size * bytesPerPixel); k++) { sum += abs((int)*p1 - (int)*p2); p1++; p2++; #endif } p1 += ((width - field->size) * bytesPerPixel); p2 += ((width - field->size) * bytesPerPixel); } return sum/((double) field->size *field->size* bytesPerPixel); } /** \see contrastSubImg called with bytesPerPixel=1*/ double contrastSubImgYUV(StabData* sd, const Field* field){ return contrastSubImg(sd->curr,field,sd->width,sd->height,1); } /** \see contrastSubImg three times called with bytesPerPixel=3 for all channels */ double contrastSubImgRGB(StabData* sd, const Field* field){ unsigned char* const I = sd->curr; return ( contrastSubImg(I, field,sd->width,sd->height,3) + contrastSubImg(I+1,field,sd->width,sd->height,3) + contrastSubImg(I+2,field,sd->width,sd->height,3))/3; } /** calculates Michelson-contrast in the given small part of the given image \param I pointer to framebuffer \param field Field specifies position(center) and size of subimage \param width width of frame \param height height of frame \param bytesPerPixel calc contrast for only for first channel */ double contrastSubImg(unsigned char* const I, const Field* field, int width, int height, int bytesPerPixel) { #if USE_SSE2 int k, j; int s2 = field->size / 2; __m128i mini = _mm_set_epi64(_mm_set1_pi8(255), _mm_set1_pi8(255)); __m128i maxi = _mm_set_epi64(_mm_set1_pi8(0) , _mm_set1_pi8(0)); unsigned char* p = I + ((field->x - s2) + (field->y - s2)*width)*bytesPerPixel; __m128i A; for (j = 0; j < field->size; j++){ for (k = 0; k < (field->size * bytesPerPixel)-16 ; k++) { A= _mm_loadu_si128((__m128i*)p); //load unaligned data maxi = _mm_max_epu8(A,maxi); mini = _mm_min_epu8(A,mini); p+=16; k+=15; } p += (width - field->size) * bytesPerPixel; } int max=0; union { __m128i m; uint8_t t[16]; } m; m.m=maxi; for (j=0;j<16;j++) { if (m.t[j] >max) max=m.t[j]; } int min=255; m.m=mini; for (j=0;j<16;j++) { if (m.t[j] size / 2; unsigned char mini = 255; unsigned char maxi = 0; p = I + ((field->x - s2) + (field->y - s2)*width)*bytesPerPixel; // TODO: use some mmx or sse stuff here for (j = 0; j < field->size; j++){ for (k = 0; k < field->size * bytesPerPixel; k++) { mini = (mini < *p) ? mini : *p; maxi = (maxi > *p) ? maxi : *p; p += bytesPerPixel; } p += (width - field->size) * bytesPerPixel; } return (maxi-mini)/(maxi+mini+0.1); // +0.1 to avoid division by 0 #endif } /** tries to register current frame onto previous frame. This is the most simple algorithm: shift images to all possible positions and calc summed error Shift with minimal error is selected. */ Transform calcShiftRGBSimple(StabData* sd) { int x = 0, y = 0; int i, j; double minerror = 1e20; for (i = -sd->maxshift; i <= sd->maxshift; i++) { for (j = -sd->maxshift; j <= sd->maxshift; j++) { double error = compareImg(sd->curr, sd->prev, sd->width, sd->height, 3, i, j); if (error < minerror) { minerror = error; x = i; y = j; } } } return new_transform(x, y, 0, 0, 0); } /** tries to register current frame onto previous frame. (only the luminance is used) This is the most simple algorithm: shift images to all possible positions and calc summed error Shift with minimal error is selected. */ Transform calcShiftYUVSimple(StabData* sd) { int x = 0, y = 0; int i, j; unsigned char *Y_c, *Y_p;// , *Cb, *Cr; #ifdef STABVERBOSE FILE *f = NULL; char buffer[32]; tc_snprintf(buffer, sizeof(buffer), "f%04i.dat", sd->t); f = fopen(buffer, "w"); fprintf(f, "# splot \"%s\"\n", buffer); #endif // we only use the luminance part of the image Y_c = sd->curr; // Cb_c = sd->curr + sd->width*sd->height; //Cr_c = sd->curr + 5*sd->width*sd->height/4; Y_p = sd->prev; //Cb_p = sd->prev + sd->width*sd->height; //Cr_p = sd->prev + 5*sd->width*sd->height/4; double minerror = 1e20; for (i = -sd->maxshift; i <= sd->maxshift; i++) { for (j = -sd->maxshift; j <= sd->maxshift; j++) { double error = compareImg(Y_c, Y_p, sd->width, sd->height, 1, i, j); #ifdef STABVERBOSE fprintf(f, "%i %i %f\n", i, j, error); #endif if (error < minerror) { minerror = error; x = i; y = j; } } } #ifdef STABVERBOSE fclose(f); tc_log_msg(MOD_NAME, "Minerror: %f\n", minerror); #endif return new_transform(x, y, 0, 0, 0); } /* calculates rotation angle for the given transform and * field with respect to the given center-point */ double calcAngle(StabData* sd, Field* field, Transform* t, int center_x, int center_y) { // we better ignore fields that are to close to the rotation center if (abs(field->x - center_x) + abs(field->y - center_y) < sd->maxshift) { return 0; } else { // double r = sqrt(field->x*field->x + field->y*field->y); double a1 = atan2(field->y - center_y, field->x - center_x); double a2 = atan2(field->y - center_y + t->y, field->x - center_x + t->x); double diff = a2 - a1; return (diff>M_PI) ? diff - 2*M_PI : ( (diff<-M_PI) ? diff + 2*M_PI : diff); } } /* calculates the optimal transformation for one field in YUV frames * (only luminance) */ Transform calcFieldTransYUV(StabData* sd, const Field* field, int fieldnum) { Transform t = null_transform(); unsigned char *Y_c = sd->curr, *Y_p = sd->prev; // we only use the luminance part of the image int i, j; /* // check contrast in sub image */ /* double contr = contrastSubImg(Y_c, field, sd->width, sd->height, 1); */ /* if(contr < sd->contrast_threshold) { */ /* t.extra=-1; */ /* return t; */ /* } */ #ifdef STABVERBOSE // printf("%i %i %f\n", sd->t, fieldnum, contr); FILE *f = NULL; char buffer[32]; snprintf(buffer, sizeof(buffer), "f%04i_%02i.dat", sd->t, fieldnum); f = fopen(buffer, "w"); fprintf(f, "# splot \"%s\"\n", buffer); #endif double minerror = 1e10; double error = 1e10; for (i = -sd->maxshift; i <= sd->maxshift; i += sd->stepsize) { for (j = -sd->maxshift; j <= sd->maxshift; j += sd->stepsize) { error = compareSubImg(Y_c, Y_p, field, sd->width, sd->height, 1, i, j); #ifdef STABVERBOSE fprintf(f, "%i %i %f\n", i, j, error); #endif if (error < minerror) { minerror = error; t.x = i; t.y = j; } } } if (sd->stepsize > 1) { // make fine grain check around the best match int r = sd->stepsize - 1; for (i = t.x - r; i <= t.x + r; i += 1) { for (j = -t.y - r; j <= t.y + r; j += 1) { if (i == t.x && j == t.y) continue; //no need to check this since already done error = compareSubImg(Y_c, Y_p, field, sd->width, sd->height, 1, i, j); #ifdef STABVERBOSE fprintf(f, "%i %i %f\n", i, j, error); #endif if (error < minerror){ minerror = error; t.x = i; t.y = j; } } } } #ifdef STABVERBOSE fclose(f); mlt_log_debug ( "Minerror: %f\n", minerror); #endif if (!sd->allowmax && fabs(t.x) == sd->maxshift) { #ifdef STABVERBOSE mlt_log_debug ( "maximal x shift "); #endif t.x = 0; } if (!sd->allowmax && fabs(t.y) == sd->maxshift) { #ifdef STABVERBOSE mlt_log_debug ("maximal y shift "); #endif t.y = 0; } return t; } /* calculates the optimal transformation for one field in RGB * slower than the YUV version because it uses all three color channels */ Transform calcFieldTransRGB(StabData* sd, const Field* field, int fieldnum) { Transform t = null_transform(); unsigned char *I_c = sd->curr, *I_p = sd->prev; int i, j; double minerror = 1e20; for (i = -sd->maxshift; i <= sd->maxshift; i += 2) { for (j=-sd->maxshift; j <= sd->maxshift; j += 2) { double error = compareSubImg(I_c, I_p, field, sd->width, sd->height, 3, i, j); if (error < minerror) { minerror = error; t.x = i; t.y = j; } } } for (i = t.x - 1; i <= t.x + 1; i += 2) { for (j = -t.y - 1; j <= t.y + 1; j += 2) { double error = compareSubImg(I_c, I_p, field, sd->width, sd->height, 3, i, j); if (error < minerror) { minerror = error; t.x = i; t.y = j; } } } if (!sd->allowmax && fabs(t.x) == sd->maxshift) { t.x = 0; } if (!sd->allowmax && fabs(t.y) == sd->maxshift) { t.y = 0; } return t; } /* compares contrast_idx structures respect to the contrast (for sort function) */ int cmp_contrast_idx(const void *ci1, const void* ci2) { double a = ((contrast_idx*)ci1)->contrast; double b = ((contrast_idx*)ci2)->contrast; return a < b ? 1 : ( a > b ? -1 : 0 ); } /* select only the best 'maxfields' fields first calc contrasts then select from each part of the frame a some fields */ tlist* selectfields(StabData* sd, contrastSubImgFunc contrastfunc) { int i,j; tlist* goodflds = tlist_new(0); contrast_idx *ci = malloc(sizeof(contrast_idx) * sd->field_num); // we split all fields into row+1 segments and take from each segment // the best fields int numsegms = (sd->field_rows+1); int segmlen = sd->field_num/(sd->field_rows+1)+1; // split the frame list into rows+1 segments contrast_idx *ci_segms = malloc(sizeof(contrast_idx) * sd->field_num); int remaining = 0; // calculate contrast for each field for (i = 0; i < sd->field_num; i++) { ci[i].contrast = contrastfunc(sd, &sd->fields[i]); ci[i].index=i; if(ci[i].contrast < sd->contrast_threshold) ci[i].contrast = 0; // else printf("%i %lf\n", ci[i].index, ci[i].contrast); } memcpy(ci_segms, ci, sizeof(contrast_idx) * sd->field_num); // get best fields from each segment for(i=0; i sd->field_num ? sd->field_num : endindex; //printf("Segment: %i: %i-%i\n", i, startindex, endindex); // sort within segment qsort(ci_segms+startindex, endindex-startindex, sizeof(contrast_idx), cmp_contrast_idx); // take maxfields/numsegms for(j=0; jmaxfields/numsegms; j++){ if(startindex+j >= endindex) continue; // printf("%i %lf\n", ci_segms[startindex+j].index, // ci_segms[startindex+j].contrast); if(ci_segms[startindex+j].contrast > 0){ tlist_append(goodflds, &ci[ci_segms[startindex+j].index],sizeof(contrast_idx)); // don't consider them in the later selection process ci_segms[startindex+j].contrast=0; } } } // check whether enough fields are selected // printf("Phase2: %i\n", tc_list_size(goodflds)); remaining = sd->maxfields - tlist_size(goodflds); if(remaining > 0){ // take the remaining from the leftovers qsort(ci_segms, sd->field_num, sizeof(contrast_idx), cmp_contrast_idx); for(j=0; j < remaining; j++){ if(ci_segms[j].contrast > 0){ tlist_append(goodflds, &ci_segms[j], sizeof(contrast_idx)); } } } // printf("Ende: %i\n", tc_list_size(goodflds)); free(ci); free(ci_segms); return goodflds; } /* tries to register current frame onto previous frame. * Algorithm: * check all fields for vertical and horizontal transformation * use minimal difference of all possible positions * discards fields with low contrast * select maxfields field according to their contrast * calculate shift as cleaned mean of all remaining fields * calculate rotation angle of each field in respect to center of fields * after shift removal * calculate rotation angle as cleaned mean of all angles * compensate for possibly off-center rotation */ Transform calcTransFields(StabData* sd, calcFieldTransFunc fieldfunc, contrastSubImgFunc contrastfunc) { Transform* ts = malloc(sizeof(Transform) * sd->field_num); Field** fs = malloc(sizeof(Field*) * sd->field_num); double *angles = malloc(sizeof(double) * sd->field_num); int i, index=0, num_trans; Transform t; #ifdef STABVERBOSE FILE *f = NULL; char buffer[32]; tc_snprintf(buffer, sizeof(buffer), "k%04i.dat", sd->t); f = fopen(buffer, "w"); fprintf(f, "# plot \"%s\" w l, \"\" every 2:1:0\n", buffer); #endif tlist* goodflds = selectfields(sd, contrastfunc); // use all "good" fields and calculate optimal match to previous frame contrast_idx* f; while((f = (contrast_idx*)tlist_pop(goodflds,0) ) != 0){ int i = f->index; t = fieldfunc(sd, &sd->fields[i], i); // e.g. calcFieldTransYUV #ifdef STABVERBOSE fprintf(f, "%i %i\n%f %f %i\n \n\n", sd->fields[i].x, sd->fields[i].y, sd->fields[i].x + t.x, sd->fields[i].y + t.y, t.extra); #endif if (t.extra != -1){ // ignore if extra == -1 (unused at the moment) ts[index] = t; fs[index] = sd->fields+i; index++; } } tlist_fini(goodflds); t = null_transform(); num_trans = index; // amount of transforms we actually have if (num_trans < 1) { printf( "too low contrast! No field remains.\n" "(no translations are detected in frame %i)", sd->t); free(ts); free(fs); free(angles); return t; } int center_x = 0; int center_y = 0; // calc center point of all remaining fields for (i = 0; i < num_trans; i++) { center_x += fs[i]->x; center_y += fs[i]->y; } center_x /= num_trans; center_y /= num_trans; if (sd->show){ // draw fields and transforms into frame. // this has to be done one after another to handle possible overlap if (sd->show > 1) { for (i = 0; i < num_trans; i++) drawFieldScanArea(sd, fs[i], &ts[i]); } for (i = 0; i < num_trans; i++) drawField(sd, fs[i], &ts[i]); for (i = 0; i < num_trans; i++) drawFieldTrans(sd, fs[i], &ts[i]); } /* median over all transforms t= median_xy_transform(ts, sd->field_num);*/ // cleaned mean t = cleanmean_xy_transform(ts, num_trans); // substract avg for (i = 0; i < num_trans; i++) { ts[i] = sub_transforms(&ts[i], &t); } // figure out angle if (sd->field_num < 6) { // the angle calculation is inaccurate for 5 and less fields t.alpha = 0; } else { for (i = 0; i < num_trans; i++) { angles[i] = calcAngle(sd, fs[i], &ts[i], center_x, center_y); } double min,max; t.alpha = -cleanmean(angles, num_trans, &min, &max); if(max-min>sd->maxanglevariation){ t.alpha=0; printf( "too large variation in angle(%f)\n", max-min); } } // compensate for off-center rotation double p_x = (center_x - sd->width/2); double p_y = (center_y - sd->height/2); t.x += (cos(t.alpha)-1)*p_x - sin(t.alpha)*p_y; t.y += sin(t.alpha)*p_x + (cos(t.alpha)-1)*p_y; #ifdef STABVERBOSE fclose(f); #endif free(ts); free(fs); free(angles); return t; } /** draws the field scanning area */ void drawFieldScanArea(StabData* sd, const Field* field, const Transform* t) { if (sd->pixelformat != mlt_image_yuv420p) { mlt_log_warning (NULL, "format not usable\n"); return; } drawBox(sd->curr, sd->width, sd->height, 1, field->x, field->y, field->size+2*sd->maxshift, field->size+2*sd->maxshift, 80); } /** draws the field */ void drawField(StabData* sd, const Field* field, const Transform* t) { if (sd->pixelformat != mlt_image_yuv420p){ mlt_log_warning (NULL, "format not usable\n"); return; } drawBox(sd->curr, sd->width, sd->height, 1, field->x, field->y, field->size, field->size, t->extra == -1 ? 100 : 40); } /** draws the transform data of this field */ void drawFieldTrans(StabData* sd, const Field* field, const Transform* t) { if (sd->pixelformat != mlt_image_yuv420p){ mlt_log_warning (NULL, "format not usable\n"); return; } drawBox(sd->curr, sd->width, sd->height, 1, field->x, field->y, 5, 5, 128); // draw center drawBox(sd->curr, sd->width, sd->height, 1, field->x + t->x, field->y + t->y, 8, 8, 250); // draw translation } /** * draws a box at the given position x,y (center) in the given color (the same for all channels) */ void drawBox(unsigned char* I, int width, int height, int bytesPerPixel, int x, int y, int sizex, int sizey, unsigned char color){ unsigned char* p = NULL; int j,k; p = I + ((x - sizex/2) + (y - sizey/2)*width)*bytesPerPixel; for (j = 0; j < sizey; j++){ for (k = 0; k < sizex * bytesPerPixel; k++) { *p = color; p++; } p += (width - sizex) * bytesPerPixel; } } struct iterdata { FILE *f; int counter; }; /*************************************************************************/ /* Module interface routines and data. */ /*************************************************************************/ /* * stabilize_configure: Configure this instance of the module. See * tcmodule-data.h for function details. */ int stabilize_configure(StabData* instance /*const char *options, int pixelfmt */ /*TCModuleExtraData *xdata[]*/) { StabData *sd = instance; /* sd->framesize = sd->vob->im_v_width * MAX_PLANES * sizeof(char) * 2 * sd->vob->im_v_height * 2; */ /*TODO sd->framesize = sd->vob->im_v_size; */ sd->prev = calloc(1,sd->framesize); sd->grayimage = calloc(1,sd->width*sd->height); if (!sd->prev || !sd->grayimage) { printf( "malloc failed"); return -1; } sd->currcopy = 0; sd->hasSeenOneFrame = 0; sd->transs = 0; sd->allowmax = 0; sd->field_size = MIN(sd->width, sd->height)/12; sd->maxanglevariation = 1; sd->shakiness = MIN(10,MAX(1,sd->shakiness)); sd->accuracy = MAX(sd->shakiness,MIN(15,MAX(1,sd->accuracy))); if (1) { mlt_log_debug (NULL, "Image Stabilization Settings:\n"); mlt_log_debug (NULL, " shakiness = %d\n", sd->shakiness); mlt_log_debug (NULL, " accuracy = %d\n", sd->accuracy); mlt_log_debug (NULL, " stepsize = %d\n", sd->stepsize); mlt_log_debug (NULL, " algo = %d\n", sd->algo); mlt_log_debug (NULL, " mincontrast = %f\n", sd->contrast_threshold); mlt_log_debug (NULL, " show = %d\n", sd->show); } #ifndef USE_SSE2 mlt_log_info(NULL,"No SSE2 support enabled, this will slow down a lot\n"); #endif // shift and size: shakiness 1: height/40; 10: height/4 sd->maxshift = MIN(sd->width, sd->height)*sd->shakiness/40; sd->field_size = MIN(sd->width, sd->height)*sd->shakiness/40; mlt_log_debug ( NULL, "Fieldsize: %i, Maximal translation: %i pixel\n", sd->field_size, sd->maxshift); if (sd->algo==1) { // initialize measurement fields. field_num is set here. if (!initFields(sd)) { return -1; } sd->maxfields = (sd->accuracy) * sd->field_num / 15; mlt_log_debug ( NULL, "Number of used measurement fields: %i out of %i\n", sd->maxfields, sd->field_num); } if (sd->show){ sd->currcopy = calloc(1,sd->framesize); } /* load unsharp filter to smooth the frames. This allows larger stepsize.*/ char unsharp_param[128]; int masksize = MIN(13,sd->stepsize*1.8); // only works up to 13. sprintf(unsharp_param,"luma=-1:luma_matrix=%ix%i:pre=1", masksize, masksize); return 0; } /** * stabilize_filter_video: performs the analysis of subsequent frames * See tcmodule-data.h for function details. */ int stabilize_filter_video(StabData* instance, unsigned char *frame,mlt_image_format pixelformat) { StabData *sd = instance; sd->pixelformat=pixelformat; int l=sd->width*sd->height; unsigned char* tmpgray=sd->grayimage; if (pixelformat == mlt_image_yuv422){ while(l--){ *tmpgray++=*frame++; frame++; }; } if(sd->show) { // save the buffer to restore at the end for prev if (pixelformat == mlt_image_yuv420p){ memcpy(sd->currcopy, sd->grayimage, sd->framesize); } } if (sd->hasSeenOneFrame) { sd->curr = sd->grayimage; if (pixelformat == mlt_image_rgb24) { if (sd->algo == 0) addTrans(sd, calcShiftRGBSimple(sd)); else if (sd->algo == 1) addTrans(sd, calcTransFields(sd, calcFieldTransRGB, contrastSubImgRGB)); } else if (pixelformat == mlt_image_yuv420p ) { if (sd->algo == 0) addTrans(sd, calcShiftYUVSimple(sd)); else if (sd->algo == 1) addTrans(sd, calcTransFields(sd, calcFieldTransYUV, contrastSubImgYUV)); } else if (pixelformat == mlt_image_yuv422 ) { if (sd->algo == 0) addTrans(sd, calcShiftYUVSimple(sd)); else if (sd->algo == 1) addTrans(sd, calcTransFields(sd, calcFieldTransYUV, contrastSubImgYUV)); } else { mlt_log_warning (NULL,"unsupported Codec: %i\n", pixelformat); return 0; } } else { sd->hasSeenOneFrame = 1; addTrans(sd, null_transform()); } if(!sd->show) { // copy current frame to prev for next frame comparison memcpy(sd->prev, sd->grayimage, sd->framesize); } else { // use the copy because we changed the original frame memcpy(sd->prev, sd->currcopy, sd->framesize); } sd->t++; return 0; } /** * stabilize_stop: Reset this instance of the module. See tcmodule-data.h * for function details. */ int stabilize_stop(StabData* instance) { StabData *sd = instance; if (sd->prev) { free(sd->prev); sd->prev = NULL; } if (sd->grayimage){ free(sd->grayimage); sd->grayimage=NULL; } return 0; } mlt-0.9.0/src/modules/videostab/stabilize.h000066400000000000000000000161661215300731300206770ustar00rootroot00000000000000/* * filter_stabilize.c * * Copyright (C) Georg Martius - June 2007 * georg dot martius at web dot de * * This file is part of transcode, a video stream processing tool * * transcode is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * transcode is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* Typical call: * transcode -V -J stabilize=shakiness=5:show=1,preview * -i inp.mpeg -y null,null -o dummy * all parameters are optional */ #define MOD_NAME "filter_stabilize.so" #define MOD_VERSION "v0.75 (2010-04-07)" #define MOD_CAP "extracts relative transformations of \n\ subsequent frames (used for stabilization together with the\n\ transform filter in a second pass)" #define MOD_AUTHOR "Georg Martius" /* Ideas: - Try OpenCL/Cuda, this should work great - use smoothing on the frames and then use gradient decent! - stepsize could be adapted (maybe to check only one field with large stepsize and use the maximally required for the other fields */ #define MOD_FEATURES \ TC_MODULE_FEATURE_FILTER|TC_MODULE_FEATURE_VIDEO #define MOD_FLAGS \ TC_MODULE_FLAG_RECONFIGURABLE | TC_MODULE_FLAG_DELAY #include "transform.h" #include #include #include #include "tlist.h" #include /* if defined we are very verbose and generate files to analyse * this is really just for debugging and development */ // #define STABVERBOSE typedef struct _field { int x; // middle position x int y; // middle position y int size; // size of field } Field; // structure that contains the contrast and the index of a field typedef struct _contrast_idx { double contrast; int index; } contrast_idx; /* private date structure of this filter*/ typedef struct _stab_data { int framesize; // size of frame buffer in bytes (prev) unsigned char* curr; // current frame buffer (only pointer) unsigned char* currcopy; // copy of the current frame needed for drawing unsigned char* prev; // frame buffer for last frame (copied) unsigned char* grayimage; // frame buffer for last frame (copied) short hasSeenOneFrame; // true if we have a valid previous frame int width, height; mlt_image_format pixelformat; /* list of transforms*/ //TCList* transs; tlist* transs; Field* fields; /* Options */ /* maximum number of pixels we expect the shift of subsequent frames */ int maxshift; int stepsize; // stepsize of field transformation detection int allowmax; // 1 if maximal shift is allowed int algo; // algorithm to use int field_num; // number of measurement fields int maxfields; // maximum number of fields used (selected by contrast) int field_size; // size = min(sd->width, sd->height)/10; int field_rows; // number of rows /* if 1 and 2 then the fields and transforms are shown in the frames */ int show; /* measurement fields with lower contrast are discarded */ double contrast_threshold; /* maximal difference in angles of fields */ double maxanglevariation; /* meta parameter for maxshift and fieldsize between 1 and 10 */ int shakiness; int accuracy; // meta parameter for number of fields between 1 and 10 int t; char conf_str[1024]; } StabData; /* type for a function that calculates the transformation of a certain field */ typedef Transform (*calcFieldTransFunc)(StabData*, const Field*, int); /* type for a function that calculates the contrast of a certain field */ typedef double (*contrastSubImgFunc)(StabData* sd, const Field* field); static const char stabilize_help[] = "" "Overview:\n" " Generates a file with relative transform information\n" " (translation, rotation) about subsequent frames." " See also transform.\n" "Options\n" " 'result' path to the file used to write the transforms\n" " (def:inputfile.stab)\n" " 'shakiness' how shaky is the video and how quick is the camera?\n" " 1: little (fast) 10: very strong/quick (slow) (def: 4)\n" " 'accuracy' accuracy of detection process (>=shakiness)\n" " 1: low (fast) 15: high (slow) (def: 4)\n" " 'stepsize' stepsize of search process, region around minimum \n" " is scanned with 1 pixel resolution (def: 6)\n" " 'algo' 0: brute force (translation only);\n" " 1: small measurement fields (def)\n" " 'mincontrast' below this contrast a field is discarded (0-1) (def: 0.3)\n" " 'show' 0: draw nothing (def); 1,2: show fields and transforms\n" " in the resulting frames. Consider the 'preview' filter\n" " 'help' print this help message\n"; int initFields(StabData* sd); double compareImg(unsigned char* I1, unsigned char* I2, int width, int height, int bytesPerPixel, int d_x, int d_y); double compareSubImg(unsigned char* const I1, unsigned char* const I2, const Field* field, int width, int height, int bytesPerPixel,int d_x,int d_y); double contrastSubImgYUV(StabData* sd, const Field* field); double contrastSubImgRGB(StabData* sd, const Field* field); double contrastSubImg(unsigned char* const I, const Field* field, int width, int height, int bytesPerPixel); int cmp_contrast_idx(const void *ci1, const void* ci2); tlist* selectfields(StabData* sd, contrastSubImgFunc contrastfunc); Transform calcShiftRGBSimple(StabData* sd); Transform calcShiftYUVSimple(StabData* sd); double calcAngle(StabData* sd, Field* field, Transform* t, int center_x, int center_y); Transform calcFieldTransYUV(StabData* sd, const Field* field, int fieldnum); Transform calcFieldTransRGB(StabData* sd, const Field* field, int fieldnum); Transform calcTransFields(StabData* sd, calcFieldTransFunc fieldfunc, contrastSubImgFunc contrastfunc); void drawFieldScanArea(StabData* sd, const Field* field, const Transform* t); void drawField(StabData* sd, const Field* field, const Transform* t); void drawFieldTrans(StabData* sd, const Field* field, const Transform* t); void drawBox(unsigned char* I, int width, int height, int bytesPerPixel, int x, int y, int sizex, int sizey, unsigned char color); void addTrans(StabData* sd, Transform sl); int stabilize_configure(StabData* instance); int stabilize_stop(StabData* instance); int stabilize_filter_video(StabData* instance, unsigned char *frame,mlt_image_format imageformat); mlt-0.9.0/src/modules/videostab/tlist.c000066400000000000000000000021211215300731300200250ustar00rootroot00000000000000#include "tlist.h" #include #include tlist* tlist_new(int size){ tlist* t=malloc(sizeof(tlist)); memset(t,0,sizeof(tlist)); return t; } void tlist_append(tlist* t,void* data,int size){ tlist* next=tlist_new(0); tlist* pos=t; while (pos && pos->next) { pos=pos->next; } pos->data=malloc(size); memcpy(pos->data,data,size); pos->next=next; } int tlist_size(tlist* t){ int ret=0; tlist* pos=t; while (pos && pos->next && pos->data) { pos=pos->next ; ret++; }; return ret; } void* tlist_pop(tlist* t,int at){ int ret=0; tlist* pos=t; /*if (pos && !pos->next ){ return pos->data; }*/ while (pos && pos->next) { if (ret==at){ tlist* n=pos->next; pos->data=n->data; pos->next=n->next; return pos->data; } pos=pos->next ; ret++; }; return NULL; } void tlist_fini(tlist* list){ tlist* head=list; while (head){ if (head->data) free(head->data); tlist *del=head; head=head->next; free(del); } } mlt-0.9.0/src/modules/videostab/tlist.h000066400000000000000000000004451215300731300200410ustar00rootroot00000000000000 #ifndef __TLIST__ #define __TLIST__ typedef struct _tlist { void* data; void* next; } tlist; tlist* tlist_new(int size); void tlist_append(tlist* t,void* data,int size); int tlist_size(tlist* t); void* tlist_pop(tlist* t,int at); void tlist_fini(tlist* ); #endif mlt-0.9.0/src/modules/videostab/transform.c000066400000000000000000000206571215300731300207170ustar00rootroot00000000000000/* * transform.c * * Copyright (C) Georg Martius - June 2007 * * This file is part of transcode, a video stream processing tool * * transcode is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * transcode is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include "transform.h" /*********************************************************************** * helper functions to create and operate with transforms. * all functions are non-destructive */ /* create an initialized transform*/ Transform new_transform(double x, double y, double alpha, double zoom, int extra) { Transform t; t.x = x; t.y = y; t.alpha = alpha; t.zoom = zoom; t.extra = extra; return t; } /* create a zero initialized transform*/ Transform null_transform(void) { return new_transform(0, 0, 0, 0, 0); } /* adds two transforms */ Transform add_transforms(const Transform* t1, const Transform* t2) { Transform t; t.x = t1->x + t2->x; t.y = t1->y + t2->y; t.alpha = t1->alpha + t2->alpha; t.zoom = t1->zoom + t2->zoom; t.extra = 0; return t; } /* like add_transform but with non-pointer signature */ Transform add_transforms_(const Transform t1, const Transform t2) { return add_transforms(&t1, &t2); } /* subtracts two transforms */ Transform sub_transforms(const Transform* t1, const Transform* t2) { Transform t; t.x = t1->x - t2->x; t.y = t1->y - t2->y; t.alpha = t1->alpha - t2->alpha; t.zoom = t1->zoom - t2->zoom; t.extra = 0; return t; } /* multiplies a transforms with a scalar */ Transform mult_transform(const Transform* t1, double f) { Transform t; t.x = t1->x * f; t.y = t1->y * f; t.alpha = t1->alpha * f; t.zoom = t1->zoom * f; t.extra = 0; return t; } /* like mult_transform but with non-pointer signature */ Transform mult_transform_(const Transform t1, double f) { return mult_transform(&t1,f); } /* compares a transform with respect to x (for sort function) */ int cmp_trans_x(const void *t1, const void* t2) { double a = ((Transform*)t1)->x; double b = ((Transform*)t2)->x; return a < b ? -1 : ( a > b ? 1 : 0 ); } /* compares a transform with respect to y (for sort function) */ int cmp_trans_y(const void *t1, const void* t2) { double a = ((Transform*)t1)->y; double b = ((Transform*)t2)->y; return a < b ? -1 : ( a > b ? 1: 0 ); } /* static int cmp_trans_alpha(const void *t1, const void* t2){ */ /* double a = ((Transform*)t1)->alpha; */ /* double b = ((Transform*)t2)->alpha; */ /* return a < b ? -1 : ( a > b ? 1 : 0 ); */ /* } */ /* compares two double values (for sort function)*/ int cmp_double(const void *t1, const void* t2) { double a = *((double*)t1); double b = *((double*)t2); return a < b ? -1 : ( a > b ? 1 : 0 ); } /** * median_xy_transform: calulcates the median of an array * of transforms, considering only x and y * * Parameters: * transforms: array of transforms. * len: length of array * Return value: * A new transform with x and y beeing the median of * all transforms. alpha and other fields are 0. * Preconditions: * len>0 * Side effects: * None */ Transform median_xy_transform(const Transform* transforms, int len) { Transform* ts = malloc(sizeof(Transform) * len); Transform t; memcpy(ts,transforms, sizeof(Transform)*len ); int half = len/2; qsort(ts, len, sizeof(Transform), cmp_trans_x); t.x = len % 2 == 0 ? ts[half].x : (ts[half].x + ts[half+1].x)/2; qsort(ts, len, sizeof(Transform), cmp_trans_y); t.y = len % 2 == 0 ? ts[half].y : (ts[half].y + ts[half+1].y)/2; t.alpha = 0; t.zoom = 0; t.extra = 0; free(ts); return t; } /** * cleanmean_xy_transform: calulcates the cleaned mean of an array * of transforms, considering only x and y * * Parameters: * transforms: array of transforms. * len: length of array * Return value: * A new transform with x and y beeing the cleaned mean * (meaning upper and lower pentile are removed) of * all transforms. alpha and other fields are 0. * Preconditions: * len>0 * Side effects: * None */ Transform cleanmean_xy_transform(const Transform* transforms, int len) { Transform* ts = malloc(sizeof(Transform) * len); Transform t = null_transform(); int i, cut = len / 5; memcpy(ts, transforms, sizeof(Transform) * len); qsort(ts,len, sizeof(Transform), cmp_trans_x); for (i = cut; i < len - cut; i++){ // all but cutted t.x += ts[i].x; } qsort(ts, len, sizeof(Transform), cmp_trans_y); for (i = cut; i < len - cut; i++){ // all but cutted t.y += ts[i].y; } free(ts); return mult_transform(&t, 1.0 / (len - (2.0 * cut))); } /** * calulcates the cleaned maximum and minimum of an array of transforms, * considerung only x and y * It cuts off the upper and lower x-th percentil * * Parameters: * transforms: array of transforms. * len: length of array * percentil: the x-th percentil to cut off * min: pointer to min (return value) * max: pointer to max (return value) * Return value: * call by reference in min and max * Preconditions: * len>0, 0<=percentil<50 * Side effects: * only on min and max */ void cleanmaxmin_xy_transform(const Transform* transforms, int len, int percentil, Transform* min, Transform* max){ Transform* ts = malloc(sizeof(Transform) * len); int cut = len * percentil / 100; memcpy(ts, transforms, sizeof(Transform) * len); qsort(ts,len, sizeof(Transform), cmp_trans_x); min->x = ts[cut].x; max->x = ts[len-cut-1].x; qsort(ts, len, sizeof(Transform), cmp_trans_y); min->y = ts[cut].y; max->y = ts[len-cut-1].y; free(ts); } /** * media: median of a double array * * Parameters: * ds: array of values * len: length of array * Return value: * the median value of the array * Preconditions: len>0 * Side effects: ds will be sorted! */ double median(double* ds, int len) { int half=len/2; qsort(ds,len, sizeof(double), cmp_double); return len % 2 == 0 ? ds[half] : (ds[half] + ds[half+1])/2; } /** * mean: mean of a double array * * Parameters: * ds: array of values * len: length of array * Return value: the mean value of the array * Preconditions: len>0 * Side effects: None */ double mean(const double* ds, int len) { double sum=0; int i = 0; for (i = 0; i < len; i++) sum += ds[i]; return sum / len; } /** * cleanmean: mean with cutted upper and lower pentile * * Parameters: * ds: array of values * len: length of array * len: length of array * minimum: minimal value (after cleaning) if not NULL * maximum: maximal value (after cleaning) if not NULL * Return value: * the mean value of the array without the upper * and lower pentile (20% each) * and lower pentile (20% each) * and minimum and maximum without the pentiles * Preconditions: len>0 * Side effects: ds will be sorted! */ double cleanmean(double* ds, int len, double* minimum, double* maximum) { int cut = len / 5; double sum = 0; int i = 0; qsort(ds, len, sizeof(double), cmp_double); for (i = cut; i < len - cut; i++) { // all but first and last sum += ds[i]; } if (minimum) *minimum = ds[cut]; if (maximum) *maximum = ds[len-cut-1]; return sum / (len - (2.0 * cut)); } /* * Local variables: * c-file-style: "stroustrup" * c-file-offsets: ((case-label . *) (statement-case-intro . *)) * indent-tabs-mode: nil * End: * * vim: expandtab shiftwidth=4: */ mlt-0.9.0/src/modules/videostab/transform.h000066400000000000000000000100131215300731300207050ustar00rootroot00000000000000/* * transform.h * * Copyright (C) Georg Martius - June 2007 * * This file is part of transcode, a video stream processing tool * * transcode is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * transcode is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #ifndef __TRANSFORM_H #define __TRANSFORM_H #define DEFAULT_TRANS_FILE_NAME "transforms.dat" /* structure to hold information about frame transformations x,y are translations, alpha is a rotation around the center in RAD, zoom is a percentage to zoom in and extra is for additional information like scene cut (unused) */ typedef struct _transform { double x; double y; double alpha; double zoom; int extra; /* -1: ignore transform (only internal use); 0 for normal trans; 1 for inter scene cut (unused) */ } Transform; /* helper functions to create and operate with transforms. * all functions are non-destructive * the "_" version uses non-pointer Transforms. This is slower * but useful when cascading calculations like * add_transforms_(mult_transform(&t1, 5.0), &t2) */ Transform null_transform(void); Transform new_transform(double x, double y, double alpha, double zoom, int extra); Transform add_transforms(const Transform* t1, const Transform* t2); Transform add_transforms_(const Transform t1, const Transform t2); Transform sub_transforms(const Transform* t1, const Transform* t2); Transform mult_transform(const Transform* t1, double f); Transform mult_transform_(const Transform t1, double f); /* compares a transform with respect to x (for sort function) */ int cmp_trans_x(const void *t1, const void* t2); /* compares a transform with respect to y (for sort function) */ int cmp_trans_y(const void *t1, const void* t2); /* static int cmp_trans_alpha(const void *t1, const void* t2); */ /* compares two double values (for sort function)*/ int cmp_double(const void *t1, const void* t2); /* calculates the median of an array of transforms, * considering only x and y */ Transform median_xy_transform(const Transform* transforms, int len); /* median of a double array */ double median(double* ds, int len); /* mean of a double array */ double mean(const double* ds, int len); /* mean with cutted upper and lower pentile * (min and max are optionally returned) */ double cleanmean(double* ds, int len, double* minimum, double* maximum); /* calculates the cleaned mean of an array of transforms, * considering only x and y */ Transform cleanmean_xy_transform(const Transform* transforms, int len); /* calculates the cleaned (cutting of x-th percentil) * maximum and minimum of an array of transforms, * considerung only x and y */ void cleanmaxmin_xy_transform(const Transform* transforms, int len, int percentil, Transform* min, Transform* max); /* helper functions */ /* optimized round function */ inline static int myround(float x) { if(x>0) return x + 0.5; else return x - 0.5; } /* optimized floor function This does not give the correct value for negative integer values like -1.0. In this case it will produce -2.0. */ inline static int myfloor(float x) { if(x<0) return x - 1; else return x; } #endif /* * Local variables: * c-file-style: "stroustrup" * c-file-offsets: ((case-label . *) (statement-case-intro . *)) * indent-tabs-mode: nil * End: * * vim: expandtab shiftwidth=4: */ mlt-0.9.0/src/modules/videostab/transform_image.c000066400000000000000000000647621215300731300220660ustar00rootroot00000000000000/* * filter_transform.c * * Copyright (C) Georg Martius - June 2007 * georg dot martius at web dot de * * This file is part of transcode, a video stream processing tool * * transcode is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * transcode is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * Typical call: * transcode -J transform -i inp.mpeg -y xdiv,tcaud inp_stab.avi */ #include "transform_image.h" #include #include #include #define MAX (a,b) (((a)>(b)?(a):(b))) #define MIN (a,b) (((a)<(b)?(a):(b))) #define CLAMP(a,x,y) MIN( MAX( (a),(x) ,y)) #define TC_MAX(a, b) (((a) > (b)) ?(a) :(b)) #define TC_MIN(a, b) (((a) < (b)) ?(a) :(b)) /* clamp x between a and b */ #define TC_CLAMP(x, a, b) TC_MIN(TC_MAX((a), (x)), (b)) static const char* interpoltypes[5] = {"No (0)", "Linear (1)", "Bi-Linear (2)", "Quadratic (3)", "Bi-Cubic (4)"}; void (*interpolate)(unsigned char *rv, float x, float y, unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel) = 0; /** interpolateBiLinBorder: bi-linear interpolation function that also works at the border. This is used by many other interpolation methods at and outsize the border, see interpolate */ void interpolateBiLinBorder(unsigned char *rv, float x, float y, unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel) { int x_f = myfloor(x); int x_c = x_f+1; int y_f = myfloor(y); int y_c = y_f+1; short v1 = PIXELN(img, x_c, y_c, width, height, N, channel, def); short v2 = PIXELN(img, x_c, y_f, width, height, N, channel, def); short v3 = PIXELN(img, x_f, y_c, width, height, N, channel, def); short v4 = PIXELN(img, x_f, y_f, width, height, N, channel, def); float s = (v1*(x - x_f)+v3*(x_c - x))*(y - y_f) + (v2*(x - x_f) + v4*(x_c - x))*(y_c - y); *rv = (unsigned char)s; } /* taken from http://en.wikipedia.org/wiki/Bicubic_interpolation for alpha=-0.5 in matrix notation: a0-a3 are the neigthboring points where the target point is between a1 and a2 t is the point of interpolation (position between a1 and a2) value between 0 and 1 | 0, 2, 0, 0 | |a0| |-1, 0, 1, 0 | |a1| (1,t,t^2,t^3) | 2,-5, 4,-1 | |a2| |-1, 3,-3, 1 | |a3| */ static short bicub_kernel(float t, short a0, short a1, short a2, short a3){ return (2*a1 + t*((-a0+a2) + t*((2*a0-5*a1+4*a2-a3) + t*(-a0+3*a1-3*a2+a3) )) ) / 2; } /** interpolateBiCub: bi-cubic interpolation function using 4x4 pixel, see interpolate */ void interpolateBiCub(unsigned char *rv, float x, float y, unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel) { // do a simple linear interpolation at the border if (x < 1 || x >= width-2 || y < 1 || y >= height - 2) { interpolateBiLinBorder(rv, x,y,img,width,height,def,N,channel); } else { int x_f = myfloor(x); int y_f = myfloor(y); float tx = x-x_f; short v1 = bicub_kernel(tx, PIXN(img, x_f-1, y_f-1, width, height, N, channel), PIXN(img, x_f, y_f-1, width, height, N, channel), PIXN(img, x_f+1, y_f-1, width, height, N, channel), PIXN(img, x_f+2, y_f-1, width, height, N, channel)); short v2 = bicub_kernel(tx, PIXN(img, x_f-1, y_f, width, height, N, channel), PIXN(img, x_f, y_f, width, height, N, channel), PIXN(img, x_f+1, y_f, width, height, N, channel), PIXN(img, x_f+2, y_f, width, height, N, channel)); short v3 = bicub_kernel(tx, PIXN(img, x_f-1, y_f+1, width, height, N, channel), PIXN(img, x_f, y_f+1, width, height, N, channel), PIXN(img, x_f+1, y_f+1, width, height, N, channel), PIXN(img, x_f+2, y_f+1, width, height, N, channel)); short v4 = bicub_kernel(tx, PIXN(img, x_f-1, y_f+2, width, height, N, channel), PIXN(img, x_f, y_f+2, width, height, N, channel), PIXN(img, x_f+1, y_f+2, width, height, N, channel), PIXN(img, x_f+2, y_f+2, width, height, N, channel)); *rv = (unsigned char)bicub_kernel(y-y_f, v1, v2, v3, v4); } } /** interpolateSqr: bi-quatratic interpolation function, see interpolate */ void interpolateSqr(unsigned char *rv, float x, float y, unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel) { if (x < 0 || x >= width-1 || y < 0 || y >= height-1) { interpolateBiLinBorder(rv, x, y, img, width, height, def,N,channel); } else { int x_f = myfloor(x); int x_c = x_f+1; int y_f = myfloor(y); int y_c = y_f+1; short v1 = PIXN(img, x_c, y_c, width, height, N, channel); short v2 = PIXN(img, x_c, y_f, width, height, N, channel); short v3 = PIXN(img, x_f, y_c, width, height, N, channel); short v4 = PIXN(img, x_f, y_f, width, height, N, channel); float f1 = 1 - sqrt((x_c - x) * (y_c - y)); float f2 = 1 - sqrt((x_c - x) * (y - y_f)); float f3 = 1 - sqrt((x - x_f) * (y_c - y)); float f4 = 1 - sqrt((x - x_f) * (y - y_f)); float s = (v1*f1 + v2*f2 + v3*f3+ v4*f4)/(f1 + f2 + f3 + f4); *rv = (unsigned char)s; } } /** interpolateBiLin: bi-linear interpolation function, see interpolate */ void interpolateBiLin(unsigned char *rv, float x, float y, unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel) { if (x < 0 || x >= width-1 || y < 0 || y >= height - 1) { interpolateBiLinBorder(rv, x, y, img, width, height, def,N,channel); } else { int x_f = myfloor(x); int x_c = x_f+1; int y_f = myfloor(y); int y_c = y_f+1; short v1 = PIXN(img, x_c, y_c, width, height, N, channel); short v2 = PIXN(img, x_c, y_f, width, height, N, channel); short v3 = PIXN(img, x_f, y_c, width, height, N, channel); short v4 = PIXN(img, x_f, y_f, width, height, N, channel); float s = (v1*(x - x_f)+v3*(x_c - x))*(y - y_f) + (v2*(x - x_f) + v4*(x_c - x))*(y_c - y); *rv = (unsigned char)s; } } /** interpolateLin: linear (only x) interpolation function, see interpolate */ void interpolateLin(unsigned char *rv, float x, float y, unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel) { int x_f = myfloor(x); int x_c = x_f+1; int y_n = myround(y); float v1 = PIXELN(img, x_c, y_n, width, height, N, channel,def); float v2 = PIXELN(img, x_f, y_n, width, height, N, channel,def); float s = v1*(x - x_f) + v2*(x_c - x); *rv = (unsigned char)s; } /** interpolateZero: nearest neighbor interpolation function, see interpolate */ void interpolateZero(unsigned char *rv, float x, float y, unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel) { int x_n = myround(x); int y_n = myround(y); *rv = (unsigned char) PIXELN(img, x_n, y_n, width, height, N,channel,def); } /** * interpolateN: Bi-linear interpolation function for N channel image. * * Parameters: * rv: destination pixel (call by reference) * x,y: the source coordinates in the image img. Note this * are real-value coordinates, that's why we interpolate * img: source image * width,height: dimension of image * N: number of channels * channel: channel number (0..N-1) * def: default value if coordinates are out of range * Return value: None */ void interpolateN(unsigned char *rv, float x, float y, unsigned char* img, int width, int height, unsigned char N, unsigned char channel, unsigned char def) { if (x < - 1 || x > width || y < -1 || y > height) { *rv = def; } else { int x_f = myfloor(x); int x_c = x_f+1; int y_f = myfloor(y); int y_c = y_f+1; short v1 = PIXELN(img, x_c, y_c, width, height, N, channel, def); short v2 = PIXELN(img, x_c, y_f, width, height, N, channel, def); short v3 = PIXELN(img, x_f, y_c, width, height, N, channel, def); short v4 = PIXELN(img, x_f, y_f, width, height, N, channel, def); float s = (v1*(x - x_f)+v3*(x_c - x))*(y - y_f) + (v2*(x - x_f) + v4*(x_c - x))*(y_c - y); *rv = (unsigned char)s; } } /** * transformRGB: applies current transformation to frame * Parameters: * td: private data structure of this filter * Return value: * 0 for failture, 1 for success * Preconditions: * The frame must be in RGB format */ int transformRGB(TransformData* td) { Transform t; int x = 0, y = 0, z = 0; unsigned char *D_1, *D_2; t = td->trans[td->current_trans]; D_1 = td->src; D_2 = td->dest; float zm = 1.0-t.zoom/100; float zcos_a = zm*cos(-t.alpha); // scaled cos float zsin_a = zm*sin(-t.alpha); // scaled sin float c_s_x = td->width_src/2.0; float c_s_y = td->height_src/2.0; float c_d_x = td->width_dest/2.0; float c_d_y = td->height_dest/2.0; /* for each pixel in the destination image we calc the source * coordinate and make an interpolation: * p_d = c_d + M(p_s - c_s) + t * where p are the points, c the center coordinate, * _s source and _d destination, * t the translation, and M the rotation matrix * p_s = M^{-1}(p_d - c_d - t) + c_s */ /* All 3 channels */ if (fabs(t.alpha) > td->rotation_threshhold || t.zoom != 0) { for (x = 0; x < td->width_dest; x++) { for (y = 0; y < td->height_dest; y++) { float x_d1 = (x - c_d_x); float y_d1 = (y - c_d_y); float x_s = zcos_a * x_d1 + zsin_a * y_d1 + c_s_x -t.x; float y_s = -zsin_a * x_d1 + zcos_a * y_d1 + c_s_y -t.y; for (z = 0; z < 3; z++) { // iterate over colors unsigned char* dest = &D_2[(x + y * td->width_dest)*3+z]; interpolate(dest, myfloor(x_s), myfloor(y_s), D_1, td->width_src, td->height_src, td->crop ? 16 : *dest,3,z); } } } }else { /* no rotation, just translation *(also no interpolation, since no size change (so far) */ int round_tx = myround(t.x); int round_ty = myround(t.y); for (x = 0; x < td->width_dest; x++) { for (y = 0; y < td->height_dest; y++) { for (z = 0; z < 3; z++) { // iterate over colors short p = PIXELN(D_1, x - round_tx, y - round_ty, td->width_src, td->height_src, 3, z, -1); if (p == -1) { if (td->crop == 1) D_2[(x + y * td->width_dest)*3+z] = 16; } else { D_2[(x + y * td->width_dest)*3+z] = (unsigned char)p; } } } } } return 1; } /** * transformYUV: applies current transformation to frame * * Parameters: * td: private data structure of this filter * Return value: * 0 for failture, 1 for success * Preconditions: * The frame must be in YUV format */ int transformYUV(TransformData* td) { Transform t; int x = 0, y = 0; unsigned char *Y_1, *Y_2, *Cb_1, *Cb_2, *Cr_1, *Cr_2; t = td->trans[td->current_trans]; Y_1 = td->src; Y_2 = td->dest; Cb_1 = td->src + td->width_src * td->height_src; Cb_2 = td->dest + td->width_dest * td->height_dest; Cr_1 = td->src + 5*td->width_src * td->height_src/4; Cr_2 = td->dest + 5*td->width_dest * td->height_dest/4; float c_s_x = td->width_src/2.0; float c_s_y = td->height_src/2.0; float c_d_x = td->width_dest/2.0; float c_d_y = td->height_dest/2.0; float z = 1.0-t.zoom/100; float zcos_a = z*cos(-t.alpha); // scaled cos float zsin_a = z*sin(-t.alpha); // scaled sin /* for each pixel in the destination image we calc the source * coordinate and make an interpolation: * p_d = c_d + M(p_s - c_s) + t * where p are the points, c the center coordinate, * _s source and _d destination, * t the translation, and M the rotation and scaling matrix * p_s = M^{-1}(p_d - c_d - t) + c_s */ /* Luminance channel */ if (fabs(t.alpha) > td->rotation_threshhold || t.zoom != 0) { for (x = 0; x < td->width_dest; x++) { for (y = 0; y < td->height_dest; y++) { float x_d1 = (x - c_d_x); float y_d1 = (y - c_d_y); float x_s = zcos_a * x_d1 + zsin_a * y_d1 + c_s_x -t.x; float y_s = -zsin_a * x_d1 + zcos_a * y_d1 + c_s_y -t.y; unsigned char* dest = &Y_2[x + y * td->width_dest]; interpolate(dest, x_s, y_s, Y_1, td->width_src, td->height_src, td->crop ? 16 : *dest,1,0); } } }else { /* no rotation, no zooming, just translation *(also no interpolation, since no size change) */ int round_tx = myround(t.x); int round_ty = myround(t.y); for (x = 0; x < td->width_dest; x++) { for (y = 0; y < td->height_dest; y++) { short p = PIXEL(Y_1, x - round_tx, y - round_ty, td->width_src, td->height_src, -1); if (p == -1) { if (td->crop == 1) Y_2[x + y * td->width_dest] = 16; } else { Y_2[x + y * td->width_dest] = (unsigned char)p; } } } } /* Color channels */ int ws2 = td->width_src/2; int wd2 = td->width_dest/2; int hs2 = td->height_src/2; int hd2 = td->height_dest/2; if (fabs(t.alpha) > td->rotation_threshhold || t.zoom != 0) { for (x = 0; x < wd2; x++) { for (y = 0; y < hd2; y++) { float x_d1 = x - (c_d_x)/2; float y_d1 = y - (c_d_y)/2; float x_s = zcos_a * x_d1 + zsin_a * y_d1 + (c_s_x -t.x)/2; float y_s = -zsin_a * x_d1 + zcos_a * y_d1 + (c_s_y -t.y)/2; unsigned char* dest = &Cr_2[x + y * wd2]; interpolate(dest, x_s, y_s, Cr_1, ws2, hs2, td->crop ? 128 : *dest,1,0); dest = &Cb_2[x + y * wd2]; interpolate(dest, x_s, y_s, Cb_1, ws2, hs2, td->crop ? 128 : *dest,1,0); } } } else { // no rotation, no zoom, no interpolation, just translation int round_tx2 = myround(t.x/2.0); int round_ty2 = myround(t.y/2.0); for (x = 0; x < wd2; x++) { for (y = 0; y < hd2; y++) { short cr = PIXEL(Cr_1, x - round_tx2, y - round_ty2, wd2, hd2, -1); short cb = PIXEL(Cb_1, x - round_tx2, y - round_ty2, wd2, hd2, -1); if (cr == -1) { if (td->crop==1) { Cr_2[x + y * wd2] = 128; Cb_2[x + y * wd2] = 128; } } else { Cr_2[x + y * wd2] = (unsigned char)cr; Cb_2[x + y * wd2] = (unsigned char)cb; } } } } return 1; } /** * preprocess_transforms: does smoothing, relative to absolute conversion, * and cropping of too large transforms. * This is actually the core algorithm for canceling the jiggle in the * movie. We perform a low-pass filter in terms of transformation size. * This enables still camera movement, but in a smooth fasion. * * Parameters: * td: tranform private data structure * Return value: * 1 for success and 0 for failture * Preconditions: * None * Side effects: * td->trans will be modified */ int preprocess_transforms(TransformData* td) { Transform* ts = td->trans; int i; if (td->trans_len < 1) return 0; if (0) { mlt_log_debug(NULL,"Preprocess transforms:"); } if (td->smoothing>0) { /* smoothing */ Transform* ts2 = malloc(sizeof(Transform) * td->trans_len); memcpy(ts2, ts, sizeof(Transform) * td->trans_len); /* we will do a sliding average with minimal update * \hat x_{n/2} = x_1+x_2 + .. + x_n * \hat x_{n/2+1} = x_2+x_3 + .. + x_{n+1} = x_{n/2} - x_1 + x_{n+1} * avg = \hat x / n */ int s = td->smoothing * 2 + 1; Transform null = null_transform(); /* avg is the average over [-smoothing, smoothing] transforms around the current point */ Transform avg; /* avg2 is a sliding average over the filtered signal! (only to past) * with smoothing * 10 horizont to kill offsets */ Transform avg2 = null_transform(); double tau = 1.0/(3 * s); /* initialise sliding sum with hypothetic sum centered around * -1st element. We have two choices: * a) assume the camera is not moving at the beginning * b) assume that the camera moves and we use the first transforms */ Transform s_sum = null; for (i = 0; i < td->smoothing; i++){ s_sum = add_transforms(&s_sum, i < td->trans_len ? &ts2[i]:&null); } mult_transform(&s_sum, 2); // choice b (comment out for choice a) for (i = 0; i < td->trans_len; i++) { Transform* old = ((i - td->smoothing - 1) < 0) ? &null : &ts2[(i - td->smoothing - 1)]; Transform* new = ((i + td->smoothing) >= td->trans_len) ? &null : &ts2[(i + td->smoothing)]; s_sum = sub_transforms(&s_sum, old); s_sum = add_transforms(&s_sum, new); avg = mult_transform(&s_sum, 1.0/s); /* lowpass filter: * meaning high frequency must be transformed away */ ts[i] = sub_transforms(&ts2[i], &avg); /* kill accumulating offset in the filtered signal*/ avg2 = add_transforms_(mult_transform(&avg2, 1 - tau), mult_transform(&ts[i], tau)); ts[i] = sub_transforms(&ts[i], &avg2); if (0 /*verbose*/ ) { mlt_log_warning(NULL,"s_sum: %5lf %5lf %5lf, ts: %5lf, %5lf, %5lf\n", s_sum.x, s_sum.y, s_sum.alpha, ts[i].x, ts[i].y, ts[i].alpha); mlt_log_warning(NULL, " avg: %5lf, %5lf, %5lf avg2: %5lf, %5lf, %5lf", avg.x, avg.y, avg.alpha, avg2.x, avg2.y, avg2.alpha); } } free(ts2); } /* invert? */ if (td->invert) { for (i = 0; i < td->trans_len; i++) { ts[i] = mult_transform(&ts[i], -1); } } /* relative to absolute */ if (td->relative) { Transform t = ts[0]; for (i = 1; i < td->trans_len; i++) { if (0/*verbose*/ ) { mlt_log_warning(NULL, "shift: %5lf %5lf %lf \n", t.x, t.y, t.alpha *180/M_PI); } ts[i] = add_transforms(&ts[i], &t); t = ts[i]; } } /* crop at maximal shift */ if (td->maxshift != -1) for (i = 0; i < td->trans_len; i++) { ts[i].x = TC_CLAMP(ts[i].x, -td->maxshift, td->maxshift); ts[i].y = TC_CLAMP(ts[i].y, -td->maxshift, td->maxshift); } if (td->maxangle != - 1.0) for (i = 0; i < td->trans_len; i++) ts[i].alpha = TC_CLAMP(ts[i].alpha, -td->maxangle, td->maxangle); /* Calc optimal zoom * cheap algo is to only consider transformations * uses cleaned max and min */ if (td->optzoom != 0 && td->trans_len > 1){ Transform min_t, max_t; cleanmaxmin_xy_transform(ts, td->trans_len, 10, &min_t, &max_t); // the zoom value only for x double zx = 2*TC_MAX(max_t.x,fabs(min_t.x))/td->width_src; // the zoom value only for y double zy = 2*TC_MAX(max_t.y,fabs(min_t.y))/td->height_src; td->zoom += 100* TC_MAX(zx,zy); // use maximum mlt_log_debug(NULL,"Final zoom: %lf\n", td->zoom); } /* apply global zoom */ if (td->zoom != 0){ for (i = 0; i < td->trans_len; i++) ts[i].zoom += td->zoom; } return 1; } /** * transform_init: Initialize this instance of the module. See * tcmodule-data.h for function details. */ #if 0 static int transform_init(TCModuleInstance *self, uint32_t features) { TransformData* td = NULL; TC_MODULE_SELF_CHECK(self, "init"); TC_MODULE_INIT_CHECK(self, MOD_FEATURES, features); td = tc_zalloc(sizeof(TransformData)); if (td == NULL) { tc_log_error(MOD_NAME, "init: out of memory!"); return TC_ERROR; } self->userdata = td; if (verbose) { tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP); } return T; } #endif /** * transform_configure: Configure this instance of the module. See * tcmodule-data.h for function details. */ int transform_configure(TransformData *self,int width,int height, mlt_image_format pixelformat, unsigned char* image ,Transform* tx,int trans_len) { TransformData *td = self; /**** Initialise private data structure */ /* td->framesize = td->vob->im_v_width * * MAX_PLANES * sizeof(char) * 2 * td->vob->im_v_height * 2; */ // rgb24 = w*h*3 , yuv420p = w* h* 3/2 td->framesize_src = width*height*(pixelformat==mlt_image_rgb24 ? 3 : (3.0/2.0)); td->src = malloc(td->framesize_src); /* FIXME */ if (td->src == NULL) { mlt_log_error(NULL,"tc_malloc failed\n"); return -1; } td->width_src = width; td->height_src = height; /* Todo: in case we can scale the images, calc new size later */ td->width_dest = width; td->height_dest = height; td->framesize_dest = td->framesize_src; td->dest = 0; td->trans = tx; td->trans_len = trans_len; td->current_trans = 0; td->warned_transform_end = 0; /* Options */ // set from filter td->maxshift = -1; // set from filter td->maxangle = -1; // set from filter td->crop = 0; // set from filter td->relative = 1; // set from filter td->invert = 0; // set from filter td->smoothing = 10; td->rotation_threshhold = 0.25/(180/M_PI); // set from filter td->zoom = 0; // set from filter td->optzoom = 1; // set from filter td->interpoltype = 2; // bi-linear // set from filter td->sharpen = 0.8; td->interpoltype = TC_MIN(td->interpoltype,4); if (1) { mlt_log_debug(NULL, "Image Transformation/Stabilization Settings:\n"); mlt_log_debug(NULL, " smoothing = %d\n", td->smoothing); mlt_log_debug(NULL, " maxshift = %d\n", td->maxshift); mlt_log_debug(NULL, " maxangle = %f\n", td->maxangle); mlt_log_debug(NULL, " crop = %s\n", td->crop ? "Black" : "Keep"); mlt_log_debug(NULL, " relative = %s\n", td->relative ? "True": "False"); mlt_log_debug(NULL, " invert = %s\n", td->invert ? "True" : "False"); mlt_log_debug(NULL, " zoom = %f\n", td->zoom); mlt_log_debug(NULL, " optzoom = %s\n", td->optzoom ? "On" : "Off"); mlt_log_debug(NULL, " interpol = %s\n", interpoltypes[td->interpoltype]); mlt_log_debug(NULL, " sharpen = %f\n", td->sharpen); } if (td->maxshift > td->width_dest/2 ) td->maxshift = td->width_dest/2; if (td->maxshift > td->height_dest/2) td->maxshift = td->height_dest/2; if (!preprocess_transforms(td)) { mlt_log_error(NULL,"error while preprocessing transforms!"); return -1; } switch(td->interpoltype){ case 0: interpolate = &interpolateZero; break; case 1: interpolate = &interpolateLin; break; case 2: interpolate = &interpolateBiLin; break; case 3: interpolate = &interpolateSqr; break; case 4: interpolate = &interpolateBiCub; break; default: interpolate = &interpolateBiLin; } return 0; } /** * transform_filter_video: performs the transformation of frames * See tcmodule-data.h for function details. */ int transform_filter_video(TransformData *self, unsigned char *frame,mlt_image_format pixelformat) { TransformData *td = self; td->dest = frame; memcpy(td->src, frame, td->framesize_src); if (td->current_trans >= td->trans_len) { td->current_trans = td->trans_len-1; if(!td->warned_transform_end) mlt_log_warning(NULL,"not enough transforms found, use last transformation!\n"); td->warned_transform_end = 1; } if (pixelformat == mlt_image_rgb24 ) { transformRGB(td); } else if (pixelformat == mlt_image_yuv420p) { transformYUV(td); } else { mlt_log_error(NULL,"unsupported Codec: %i\n", pixelformat); return 1; } td->current_trans++; return 0; } mlt-0.9.0/src/modules/videostab/transform_image.h000066400000000000000000000131341215300731300220560ustar00rootroot00000000000000/* * filter_transform.c * * Copyright (C) Georg Martius - June 2007 * georg dot martius at web dot de * * This file is part of transcode, a video stream processing tool * * transcode is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * transcode is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * Typical call: * transcode -J transform -i inp.mpeg -y xdiv,tcaud inp_stab.avi */ #include "transform.h" #include #include #include "tlist.h" #include #define DEFAULT_TRANS_FILE_NAME "transforms.dat" #define PIXEL(img, x, y, w, h, def) ((x) < 0 || (y) < 0) ? def \ : (((x) >=w || (y) >= h) ? def : img[(x) + (y) * w]) #define PIX(img, x, y, w, h) (img[(x) + (y) * w]) #define PIXN(img, x, y, w, h,N,channel) (img[((x) + (y) * w)*N+channel]) // gives Pixel in N-channel image. channel in {0..N-1} #define PIXELN(img, x, y, w, h, N,channel , def) ((x) < 0 || (y) < 0) ? def \ : (((x) >=w || (y) >= h) ? def : img[((x) + (y) * w)*N + channel]) typedef struct { int framesize_src; // size of frame buffer in bytes (src) int framesize_dest; // size of frame buffer in bytes (dest) unsigned char* src; // copy of the current frame buffer unsigned char* dest; // pointer to the current frame buffer (to overwrite) int pixelformat; int width_src, height_src; int width_dest, height_dest; Transform* trans; // array of transformations int current_trans; // index to current transformation int trans_len; // length of trans array short warned_transform_end; // whether we warned that there is no transform left /* Options */ int maxshift; // maximum number of pixels we will shift double maxangle; // maximum angle in rad /* whether to consider transforms as relative (to previous frame) * or absolute transforms */ int relative; /* number of frames (forward and backward) * to use for smoothing transforms */ int smoothing; int crop; // 1: black bg, 0: keep border from last frame(s) int invert; // 1: invert transforms, 0: nothing /* constants */ /* threshhold below which no rotation is performed */ double rotation_threshhold; double zoom; // percentage to zoom: 0->no zooming 10:zoom in 10% int optzoom; // 1: determine optimal zoom, 0: nothing int interpoltype; // type of interpolation: 0->Zero,1->Lin,2->BiLin,3->Sqr double sharpen; // amount of sharpening char conf_str[1024]; } TransformData; /* forward declarations, please look below for documentation*/ void interpolateBiLinBorder(unsigned char *rv, float x, float y, unsigned char* img, int w, int h, unsigned char def,unsigned char N, unsigned char channel); void interpolateBiCub(unsigned char *rv, float x, float y, unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel); void interpolateSqr(unsigned char *rv, float x, float y, unsigned char* img, int w, int h, unsigned char def,unsigned char N, unsigned char channel); void interpolateBiLin(unsigned char *rv, float x, float y, unsigned char* img, int w, int h, unsigned char def,unsigned char N, unsigned char channel); void interpolateLin(unsigned char *rv, float x, float y, unsigned char* img, int w, int h, unsigned char def,unsigned char N, unsigned char channel); void interpolateZero(unsigned char *rv, float x, float y, unsigned char* img, int w, int h, unsigned char def,unsigned char N, unsigned char channel); void interpolateN(unsigned char *rv, float x, float y, unsigned char* img, int width, int height, unsigned char N, unsigned char channel, unsigned char def); int transformRGB(TransformData* td); int transformYUV(TransformData* td); int read_input_file(TransformData* td,tlist* list); int preprocess_transforms(TransformData* td); /** * interpolate: general interpolation function pointer for one channel image data * * Parameters: * rv: destination pixel (call by reference) * x,y: the source coordinates in the image img. Note this * are real-value coordinates, that's why we interpolate * img: source image * width,height: dimension of image * def: default value if coordinates are out of range * Return value: None */ /*void (*interpolate)(unsigned char *rv, float x, float y, unsigned char* img, int width, int height, unsigned char def) = 0; */ /** interpolateBiLinBorder: bi-linear interpolation function that also works at the border. This is used by many other interpolation methods at and outsize the border, see interpolate */ int transform_configure(TransformData *self,int width,int height, mlt_image_format pixelformat, unsigned char* image,Transform* tx,int trans_len) ; int transform_filter_video(TransformData *self, unsigned char *frame,mlt_image_format pixelformat); mlt-0.9.0/src/modules/vmfx/000077500000000000000000000000001215300731300155265ustar00rootroot00000000000000mlt-0.9.0/src/modules/vmfx/Makefile000066400000000000000000000012541215300731300171700ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt include ../../../config.mak TARGET = ../libmltvmfx$(LIBSUF) OBJS = factory.o \ filter_chroma.o \ filter_chroma_hold.o \ filter_mono.o \ filter_shape.o \ producer_pgm.o SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/vmfx" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/vmfx" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/vmfx/factory.c000066400000000000000000000046731215300731300173530ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2005 Visual Media Fx Inc. * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include extern mlt_filter filter_chroma_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_chroma_hold_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_mono_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_shape_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_pgm_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/vmfx/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( filter_type, "chroma", filter_chroma_init ); MLT_REGISTER( filter_type, "chroma_hold", filter_chroma_hold_init ); MLT_REGISTER( filter_type, "threshold", filter_mono_init ); MLT_REGISTER( filter_type, "shape", filter_shape_init ); MLT_REGISTER( producer_type, "pgm", producer_pgm_init ); MLT_REGISTER_METADATA( filter_type, "chroma", metadata, "filter_chroma.yml" ); MLT_REGISTER_METADATA( filter_type, "chroma_hold", metadata, "filter_chroma_hold.yml" ); MLT_REGISTER_METADATA( filter_type, "threshold", metadata, "filter_mono.yml" ); MLT_REGISTER_METADATA( filter_type, "shape", metadata, "filter_shape.yml" ); MLT_REGISTER_METADATA( producer_type, "pgm", metadata, "producer_pgm.yml" ); } mlt-0.9.0/src/modules/vmfx/filter_chroma.c000066400000000000000000000062421215300731300205140ustar00rootroot00000000000000/* * filter_chroma.c -- Maps a chroma key to the alpha channel * Copyright (C) 2005 Visual Media Fx Inc. * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include static inline int in_range( uint8_t v, uint8_t c, int var ) { return ( ( int )v >= c - var ) && ( ( int )v <= c + var ); } static inline uint8_t alpha_value( uint8_t a, uint8_t *p, uint8_t u, uint8_t v, int var, int odd ) { if ( odd == 0 ) return ( in_range( *( p + 1 ), u, var ) && in_range( *( p + 3 ), v, var ) ) ? 0 : a; else return ( in_range( ( *( p + 1 ) + *( p + 5 ) ) / 2, u, var ) && in_range( ( *( p + 3 ) + *( p + 7 ) ) / 2, v, var ) ) ? 0 : a; } /** Get the images and map the chroma to the alpha of the frame. */ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter this = mlt_frame_pop_service( frame ); int variance = 200 * mlt_properties_get_double( MLT_FILTER_PROPERTIES( this ), "variance" ); int32_t key_val = mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "key" ); uint8_t r = ( key_val >> 24 ) & 0xff; uint8_t g = ( key_val >> 16 ) & 0xff; uint8_t b = ( key_val >> 8 ) & 0xff; uint8_t y, u, v; RGB2YUV_601_SCALED( r, g, b, y, u, v ); *format = mlt_image_yuv422; if ( mlt_frame_get_image( frame, image, format, width, height, writable ) == 0 ) { uint8_t *alpha = mlt_frame_get_alpha_mask( frame ); uint8_t *p = *image; int size = *width * *height / 2; while ( size -- ) { *alpha = alpha_value( *alpha, p, u, v, variance, 0 ); alpha ++; *alpha = alpha_value( *alpha, p, u, v, variance, 1 ); alpha ++; p += 4; } } return 0; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { mlt_frame_push_service( frame, this ); mlt_frame_push_service( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_chroma_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "key", arg == NULL ? "0x0000ff00" : arg ); mlt_properties_set_double( MLT_FILTER_PROPERTIES( this ), "variance", 0.15 ); this->process = filter_process; } return this; } mlt-0.9.0/src/modules/vmfx/filter_chroma.yml000066400000000000000000000002641215300731300210710ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: chroma title: Chroma Key version: 1 copyright: Visual Media FX ? creator: Charles Yates license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/vmfx/filter_chroma_hold.c000066400000000000000000000062611215300731300215230ustar00rootroot00000000000000/* * filter_chroma.c -- Maps a chroma key to the alpha channel * Copyright (C) 2005 Visual Media Fx Inc. * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include static inline int in_range( uint8_t v, uint8_t c, int var ) { return ( ( int )v >= c - var ) && ( ( int )v <= c + var ); } static inline uint8_t alpha_value( uint8_t a, uint8_t *p, uint8_t u, uint8_t v, int var, int odd ) { if ( odd == 0 ) return ( in_range( *( p + 1 ), u, var ) && in_range( *( p + 3 ), v, var ) ) ? 0 : a; else return ( in_range( ( *( p + 1 ) + *( p + 5 ) ) / 2, u, var ) && in_range( ( *( p + 3 ) + *( p + 7 ) ) / 2, v, var ) ) ? 0 : a; } /** Get the images and map the chroma to the alpha of the frame. */ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter this = mlt_frame_pop_service( frame ); int variance = 200 * mlt_properties_get_double( MLT_FILTER_PROPERTIES( this ), "variance" ); int32_t key_val = mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "key" ); uint8_t r = ( key_val >> 24 ) & 0xff; uint8_t g = ( key_val >> 16 ) & 0xff; uint8_t b = ( key_val >> 8 ) & 0xff; uint8_t y, u, v; RGB2YUV_601_SCALED( r, g, b, y, u, v ); *format = mlt_image_yuv422; if ( mlt_frame_get_image( frame, image, format, width, height, writable ) == 0 ) { uint8_t alpha = 0; uint8_t *p = *image; int size = *width * *height / 2; while ( size -- ) { alpha = alpha_value( 255, p, u, v, variance, 0 ); if ( alpha ) *( p + 1 )= 128; alpha = alpha_value( 255, p, u, v, variance, 1 ); if ( alpha ) *( p + 3 ) = 128; p += 4; } } return 0; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { mlt_frame_push_service( frame, this ); mlt_frame_push_service( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_chroma_hold_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "key", arg == NULL ? "0xc0000000" : arg ); mlt_properties_set_double( MLT_FILTER_PROPERTIES( this ), "variance", 0.15 ); this->process = filter_process; } return this; } mlt-0.9.0/src/modules/vmfx/filter_chroma_hold.yml000066400000000000000000000002721215300731300220760ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: chroma_hold title: Chroma Hold version: 1 copyright: Visual Media FX ? creator: Charles Yates license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/vmfx/filter_mono.c000066400000000000000000000062411215300731300202120ustar00rootroot00000000000000/* * filter_mono.c -- Arbitrary alpha channel shaping * Copyright (C) 2005 Visual Media Fx Inc. * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include /** Get the images and apply the luminance of the mask to the alpha of the frame. */ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int use_alpha = mlt_deque_pop_back_int( MLT_FRAME_IMAGE_STACK( this ) ); int midpoint = mlt_deque_pop_back_int( MLT_FRAME_IMAGE_STACK( this ) ); int invert = mlt_deque_pop_back_int( MLT_FRAME_IMAGE_STACK( this ) ); // Render the frame *format = mlt_image_yuv422; if ( mlt_frame_get_image( this, image, format, width, height, writable ) == 0 ) { uint8_t *p = *image; uint8_t A = invert? 235 : 16; uint8_t B = invert? 16 : 235; int size = *width * *height; if ( !use_alpha ) { while( size -- ) { if ( *p < midpoint ) *p ++ = A; else *p ++ = B; *p ++ = 128; } } else { uint8_t *alpha = mlt_frame_get_alpha_mask( this ); while( size -- ) { if ( *alpha ++ < midpoint ) *p ++ = A; else *p ++ = B; *p ++ = 128; } } } return 0; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { int midpoint = mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "midpoint" ); int use_alpha = mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "use_alpha" ); int invert = mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "invert" ); mlt_deque_push_back_int( MLT_FRAME_IMAGE_STACK( frame ), invert ); mlt_deque_push_back_int( MLT_FRAME_IMAGE_STACK( frame ), midpoint ); mlt_deque_push_back_int( MLT_FRAME_IMAGE_STACK( frame ), use_alpha ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; } /** Constructor for the filter. */ mlt_filter filter_mono_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "midpoint", 128 ); mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "use_alpha", 0 ); mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "invert", 0 ); this->process = filter_process; } return this; } mlt-0.9.0/src/modules/vmfx/filter_mono.yml000066400000000000000000000002661215300731300205720ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: threshold title: Threshold version: 1 copyright: Visual Media FX ? creator: Charles Yates license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/vmfx/filter_shape.c000066400000000000000000000200551215300731300203410ustar00rootroot00000000000000/* * filter_shape.c -- Arbitrary alpha channel shaping * Copyright (C) 2005 Visual Media Fx Inc. * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include static inline double smoothstep( const double e1, const double e2, const double a ) { if ( a < e1 ) return 0.0; if ( a > e2 ) return 1.0; double v = ( a - e1 ) / ( e2 - e1 ); return ( v * v * ( 3 - 2 * v ) ); } /** Get the images and apply the luminance of the mask to the alpha of the frame. */ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Fetch the data from the stack (mix, mask, filter) double mix = mlt_deque_pop_back_double( MLT_FRAME_IMAGE_STACK( this ) ); mlt_frame mask = mlt_frame_pop_service( this ); mlt_filter filter = mlt_frame_pop_service( this ); // Obtain the constants double softness = mlt_properties_get_double( MLT_FILTER_PROPERTIES( filter ), "softness" ); int use_luminance = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "use_luminance" ); int invert = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "invert" ) * 255; // Render the frame *format = mlt_image_yuv422; if ( mlt_frame_get_image( this, image, format, width, height, writable ) == 0 && ( !use_luminance || ( int )mix != 1 ) ) { // Get the alpha mask of the source uint8_t *alpha = mlt_frame_get_alpha_mask( this ); // Obtain a scaled/distorted mask to match uint8_t *mask_img = NULL; mlt_image_format mask_fmt = mlt_image_yuv422; mlt_properties_set_int( MLT_FRAME_PROPERTIES( mask ), "distort", 1 ); mlt_properties_pass_list( MLT_FRAME_PROPERTIES( mask ), MLT_FRAME_PROPERTIES( this ), "deinterlace,deinterlace_method,rescale.interp" ); if ( mlt_frame_get_image( mask, &mask_img, &mask_fmt, width, height, 0 ) == 0 ) { int size = *width * *height; uint8_t *p = alpha; double a = 0; double b = 0; if ( !use_luminance ) { uint8_t *q = mlt_frame_get_alpha_mask( mask ); while( size -- ) { a = ( double )*q ++ / 255.0; b = 1.0 - smoothstep( a, a + softness, mix ); *p = ( uint8_t )( *p * b ) ^ invert; p ++; } } else if ( ( int )mix != 1 ) { uint8_t *q = mask_img; // Ensure softness tends to zero has mix tends to 1 softness *= ( 1.0 - mix ); while( size -- ) { a = ( ( double )*q - 16 ) / 235.0; b = smoothstep( a, a + softness, mix ); *p = ( uint8_t )( *p * b ) ^ invert; p ++; q += 2; } } } } return 0; } /** Filter processing. */ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { // Obtain the shape instance char *resource = mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "resource" ); char *last_resource = mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "_resource" ); mlt_producer producer = mlt_properties_get_data( MLT_FILTER_PROPERTIES( this ), "instance", NULL ); // Get the key framed values mlt_geometry alpha = mlt_properties_get_data( MLT_FILTER_PROPERTIES( this ), "_alpha", NULL ); char *alpha_data = mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "mix" ); double alpha_mix = 0.0; // Calculate the position and length int position = mlt_filter_get_position( this, frame ); int in = mlt_filter_get_in( this ); int out = mlt_filter_get_out( this ); int length; // Special case for attached filters - in/out come through on the frame if ( out == 0 ) { in = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "in" ); out = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "out" ); position -= in; } // Duration of the shape length = out - in + 1; // If we haven't created the instance or it's changed if ( producer == NULL || strcmp( resource, last_resource ) ) { char temp[ 512 ]; char *extension = strrchr( resource, '.' ); // Store the last resource now mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "_resource", resource ); // This is a hack - the idea is that we can indirectly reference the // luma modules pgm or png images by a short cut like %luma01.pgm - we then replace // the % with the full path to the image and use it if it exists, if not, check for // the file ending in a .png, and failing that, default to a fade in if ( strchr( resource, '%' ) ) { FILE *test; sprintf( temp, "%s/lumas/%s/%s", mlt_environment( "MLT_DATA" ), mlt_environment( "MLT_NORMALISATION" ), strchr( resource, '%' ) + 1 ); test = fopen( temp, "r" ); if ( test == NULL ) { strcat( temp, ".png" ); test = fopen( temp, "r" ); } if ( test ) fclose( test ); else strcpy( temp, "colour:0x00000080" ); resource = temp; extension = strrchr( resource, '.' ); } mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) ); producer = mlt_factory_producer( profile, NULL, resource ); if ( producer != NULL ) mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "loop" ); mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "instance", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); } // Construct the geometry item if needed, otherwise refresh it if ( alpha == NULL ) { alpha = mlt_geometry_init( ); mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "_alpha", alpha, 0, ( mlt_destructor )mlt_geometry_close, NULL ); mlt_geometry_parse( alpha, alpha_data, length, 100, 100 ); } else { mlt_geometry_refresh( alpha, alpha_data, length, 100, 100 ); } // We may still not have a producer in which case, we do nothing if ( producer != NULL ) { mlt_frame mask = NULL; struct mlt_geometry_item_s item; mlt_geometry_fetch( alpha, &item, position ); alpha_mix = item.x; mlt_properties_pass( MLT_PRODUCER_PROPERTIES( producer ), MLT_FILTER_PROPERTIES( this ), "producer." ); mlt_producer_seek( producer, position ); if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &mask, 0 ) == 0 ) { char *name = mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "_unique_id" ); mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), name, mask, 0, ( mlt_destructor )mlt_frame_close, NULL ); mlt_frame_push_service( frame, this ); mlt_frame_push_service( frame, mask ); mlt_deque_push_back_double( MLT_FRAME_IMAGE_STACK( frame ), alpha_mix / 100.0 ); mlt_frame_push_get_image( frame, filter_get_image ); if ( mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "audio_match" ) ) { mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "meta.mixdown", 1 ); mlt_properties_set_double( MLT_FRAME_PROPERTIES( frame ), "meta.volume", alpha_mix / 100.0 ); } } } return frame; } /** Constructor for the filter. */ mlt_filter filter_shape_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "resource", arg ); mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "mix", "100" ); mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "audio_match", 1 ); mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "invert", 0 ); mlt_properties_set_double( MLT_FILTER_PROPERTIES( this ), "softness", 0.1 ); this->process = filter_process; } return this; } mlt-0.9.0/src/modules/vmfx/filter_shape.yml000066400000000000000000000002641215300731300207200ustar00rootroot00000000000000schema_version: 0.1 type: filter identifier: shape title: Shape Alpha version: 1 copyright: Visual Media FX ? creator: Charles Yates license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/vmfx/producer_pgm.c000066400000000000000000000132411215300731300203610ustar00rootroot00000000000000/* * producer_pgm.c -- PGM producer * Copyright (C) 2005 Visual Media Fx Inc. * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include static int read_pgm( char *name, uint8_t **image, int *width, int *height, int *maxval ); static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ); static void producer_close( mlt_producer parent ); mlt_producer producer_pgm_init( mlt_profile profile, mlt_service_type type, const char *id, char *resource ) { mlt_producer this = NULL; uint8_t *image = NULL; int width = 0; int height = 0; int maxval = 0; if ( read_pgm( resource, &image, &width, &height, &maxval ) == 0 ) { this = calloc( 1, sizeof( struct mlt_producer_s ) ); if ( this != NULL && mlt_producer_init( this, NULL ) == 0 ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); this->get_frame = producer_get_frame; this->close = ( mlt_destructor )producer_close; mlt_properties_set( properties, "resource", resource ); mlt_properties_set_data( properties, "image", image, 0, mlt_pool_release, NULL ); mlt_properties_set_int( properties, "meta.media.width", width ); mlt_properties_set_int( properties, "meta.media.height", height ); } else { mlt_pool_release( image ); free( this ); this = NULL; } } return this; } /** Load the PGM file. */ static int read_pgm( char *name, uint8_t **image, int *width, int *height, int *maxval ) { uint8_t *input = NULL; int error = 0; FILE *f = fopen( name, "r" ); char data[ 512 ]; // Initialise *image = NULL; *width = 0; *height = 0; *maxval = 0; // Get the magic code if ( f != NULL && fgets( data, 511, f ) != NULL && data[ 0 ] == 'P' && data[ 1 ] == '5' ) { char *p = data + 2; int i = 0; int val = 0; // PGM Header parser (probably needs to be strengthened) for ( i = 0; !error && i < 3; i ++ ) { if ( *p != '\0' && *p != '\n' ) val = strtol( p, &p, 10 ); else p = NULL; while ( error == 0 && p == NULL ) { if ( fgets( data, 511, f ) == NULL ) error = 1; else if ( data[ 0 ] != '#' ) val = strtol( data, &p, 10 ); } switch( i ) { case 0: *width = val; break; case 1: *height = val; break; case 2: *maxval = val; break; } } if ( !error ) { // Determine if this is one or two bytes per pixel int bpp = *maxval > 255 ? 2 : 1; int size = *width * *height * bpp; uint8_t *p; // Allocate temporary storage for the data and the image input = mlt_pool_alloc( *width * *height * bpp ); *image = mlt_pool_alloc( *width * *height * sizeof( uint8_t ) * 2 ); p = *image; error = *image == NULL || input == NULL; if ( !error ) { // Read the raw data error = fread( input, *width * *height * bpp, 1, f ) != 1; if ( !error ) { // Convert to yuv422 (very lossy - need to extend this to allow 16 bit alpha out) for ( i = 0; i < size; i += bpp ) { *p ++ = 16 + ( input[ i ] * 219 ) / 255; *p ++ = 128; } } } } if ( error ) mlt_pool_release( *image ); mlt_pool_release( input ); } else { error = 1; } if ( f != NULL ) fclose( f ); return error; } static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { mlt_producer producer = mlt_frame_pop_service( this ); int real_width = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "meta.media.width" ); int real_height = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "meta.media.height" ); int size = real_width * real_height; uint8_t *image = mlt_pool_alloc( size * 2 ); uint8_t *source = mlt_properties_get_data( MLT_PRODUCER_PROPERTIES( producer ), "image", NULL ); mlt_frame_set_image( this, image, size * 2, mlt_pool_release ); *width = real_width; *height = real_height; *format = mlt_image_yuv422; *buffer = image; if ( image != NULL && source != NULL ) memcpy( image, source, size * 2 ); return 0; } static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Construct a test frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); // Get the frames properties mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Pass the data on the frame properties mlt_properties_set_int( properties, "has_image", 1 ); mlt_properties_set_int( properties, "progressive", 1 ); mlt_properties_set_double( properties, "aspect_ratio", 1 ); // Push the image callback mlt_frame_push_service( *frame, producer ); mlt_frame_push_get_image( *frame, producer_get_image ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); // Calculate the next timecode mlt_producer_prepare_next( producer ); return 0; } static void producer_close( mlt_producer parent ) { parent->close = NULL; mlt_producer_close( parent ); free( parent ); } mlt-0.9.0/src/modules/vmfx/producer_pgm.yml000066400000000000000000000002621215300731300207370ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: pgm title: PGM Image version: 1 copyright: Visual Media FX ? creator: Charles Yates license: LGPLv2.1 language: en tags: - Video mlt-0.9.0/src/modules/vorbis/000077500000000000000000000000001215300731300160525ustar00rootroot00000000000000mlt-0.9.0/src/modules/vorbis/Makefile000066400000000000000000000013771215300731300175220ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt include ../../../config.mak TARGET = ../libmltvorbis$(LIBSUF) OBJS = factory.o \ producer_vorbis.o CFLAGS += `pkg-config --cflags vorbis` CFLAGS += `pkg-config --cflags vorbisfile` LDFLAGS += `pkg-config --libs vorbis` LDFLAGS += `pkg-config --libs vorbisfile` SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/vorbis" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/vorbis" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/vorbis/configure000077500000000000000000000003331215300731300177600ustar00rootroot00000000000000#!/bin/sh if [ "$help" != "1" ] then pkg-config vorbisfile 2> /dev/null disable_vorbis=$? if [ "$disable_vorbis" != "0" ] then echo "- ogg vorbis not found: disabling" touch ../disable-vorbis fi exit 0 fi mlt-0.9.0/src/modules/vorbis/factory.c000066400000000000000000000027321215300731300176710ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include extern mlt_producer producer_vorbis_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/vorbis/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( producer_type, "vorbis", producer_vorbis_init ); MLT_REGISTER_METADATA( producer_type, "vorbis", metadata, "producer_vorbis.yml" ); } mlt-0.9.0/src/modules/vorbis/producer_vorbis.c000066400000000000000000000240471215300731300214340ustar00rootroot00000000000000/* * producer_vorbis.c -- vorbis producer * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // MLT Header files #include #include #include // vorbis Header files #include #include // System header files #include #include #include // Forward references. static int producer_open( mlt_producer this, mlt_profile profile, char *file ); static int producer_get_frame( mlt_producer this, mlt_frame_ptr frame, int index ); /** Structure for metadata reading */ typedef struct _sw_metadata sw_metadata; struct _sw_metadata { char * name; char * content; }; static sw_metadata *vorbis_metadata_from_str (char * str) { sw_metadata * meta = NULL; int i; for (i = 0; str[i]; i++) { str[i] = tolower(str[i]); if (str[i] == '=') { str[i] = '\0'; meta = malloc (sizeof (sw_metadata)); meta->name = malloc( strlen(str) + 18 ); sprintf(meta->name, "meta.attr.%s.markup", str); meta->content = strdup (&str[i+1]); break; } } return meta; } /** Constructor for libvorbis. */ mlt_producer producer_vorbis_init( mlt_profile profile, mlt_service_type type, const char *id, char *file ) { mlt_producer this = NULL; // Check that we have a non-NULL argument if ( file != NULL ) { // Construct the producer this = calloc( 1, sizeof( struct mlt_producer_s ) ); // Initialise it if ( mlt_producer_init( this, NULL ) == 0 ) { // Get the properties mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); // Set the resource property (required for all producers) mlt_properties_set( properties, "resource", file ); // Register our get_frame implementation this->get_frame = producer_get_frame; // Open the file if ( producer_open( this, profile, file ) != 0 ) { // Clean up mlt_producer_close( this ); this = NULL; } } } return this; } /** Destuctor for ogg files. */ static void producer_file_close( void *file ) { if ( file != NULL ) { // Close the ogg vorbis structure ov_clear( file ); // Free the memory free( file ); } } /** Open the file. */ static int producer_open( mlt_producer this, mlt_profile profile, char *file ) { // FILE pointer for file FILE *input = fopen( file, "r" ); // Error code to return int error = input == NULL; // Continue if file is open if ( error == 0 ) { // OggVorbis file structure OggVorbis_File *ov = calloc( 1, sizeof( OggVorbis_File ) ); // Attempt to open the stream error = ov == NULL || ov_open( input, ov, NULL, 0 ) != 0; // Assign to producer properties if successful if ( error == 0 ) { // Get the properties mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); // Assign the ov structure mlt_properties_set_data( properties, "ogg_vorbis_file", ov, 0, producer_file_close, NULL ); // Read metadata sw_metadata * metadata = NULL; char **ptr = ov_comment(ov, -1)->user_comments; while(*ptr) { metadata = vorbis_metadata_from_str (*ptr); if (metadata != NULL) { mlt_properties_set(properties, metadata->name, metadata->content); if (metadata->name) free(metadata->name); if (metadata->content) free(metadata->content); free(metadata); } ++ptr; } if ( ov_seekable( ov ) ) { // Get the length of the file double length = ov_time_total( ov, -1 ); // We will treat everything with the producer fps double fps = mlt_profile_fps( profile ); // Set out and length of file mlt_properties_set_position( properties, "out", ( length * fps ) - 1 ); mlt_properties_set_position( properties, "length", ( length * fps ) ); // Get the vorbis info vorbis_info *vi = ov_info( ov, -1 ); mlt_properties_set_int( properties, "audio_frequency", (int) vi->rate ); mlt_properties_set_int( properties, "audio_channels", vi->channels ); // Set some media metadata mlt_properties_set_int( properties, "meta.media.nb_streams", 1 ); mlt_properties_set_int( properties, "audio_index", 0 ); mlt_properties_set( properties, "meta.media.0.stream.type", "audio" ); mlt_properties_set( properties, "meta.media.0.codec.name", "vorbis" ); mlt_properties_set( properties, "meta.media.0.codec.long_name", "Vorbis" ); } } else { // Clean up free( ov ); // Must close input file when open fails fclose( input ); } } return error; } /** Convert a frame position to a time code. */ static double producer_time_of_frame( mlt_producer this, mlt_position position ) { return ( double )position / mlt_producer_get_fps( this ); } /** Get the audio from a frame. */ static int producer_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Obtain the frame number of this frame mlt_position position = mlt_frame_original_position( frame ); // Get the producer mlt_producer this = mlt_frame_pop_audio( frame ); // Get the producer properties mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); mlt_service_lock( MLT_PRODUCER_SERVICE( this ) ); // Get the ogg vorbis file OggVorbis_File *ov = mlt_properties_get_data( properties, "ogg_vorbis_file", NULL ); // Obtain the expected frame numer mlt_position expected = mlt_properties_get_position( properties, "audio_expected" ); // Get the fps for this producer double fps = mlt_producer_get_fps( this ); // Get the vorbis info vorbis_info *vi = ov_info( ov, -1 ); // Obtain the audio buffer int16_t *audio_buffer = mlt_properties_get_data( properties, "audio_buffer", NULL ); // Get amount of audio used int audio_used = mlt_properties_get_int( properties, "audio_used" ); // Number of frames to ignore (for ffwd) int ignore = 0; // Flag for paused (silence) int paused = 0; // Check for audio buffer and create if necessary if ( audio_buffer == NULL ) { // Allocate the audio buffer audio_buffer = mlt_pool_alloc( 131072 * sizeof( int16_t ) ); // And store it on properties for reuse mlt_properties_set_data( properties, "audio_buffer", audio_buffer, 0, mlt_pool_release, NULL ); } // Seek if necessary if ( position != expected ) { if ( position + 1 == expected ) { // We're paused - silence required paused = 1; } else if ( position > expected && ( position - expected ) < 250 ) { // Fast forward - seeking is inefficient for small distances - just ignore following frames ignore = position - expected; } else { // Seek to the required position ov_time_seek( ov, producer_time_of_frame( this, position ) ); expected = position; audio_used = 0; } } // Return info in frame *frequency = vi->rate; *channels = vi->channels; // Get the audio if required if ( !paused ) { // Bitstream section int current_section; // Get the number of samples for the current frame *samples = mlt_sample_calculator( fps, *frequency, expected ++ ); while( *samples > audio_used ) { // Read the samples int bytes = ov_read( ov, ( char * )( &audio_buffer[ audio_used * 2 ] ), 4096, 0, 2, 1, ¤t_section ); // Break if error or eof if ( bytes <= 0 ) break; // Increment number of samples used audio_used += bytes / ( sizeof( int16_t ) * *channels ); // Handle ignore while ( ignore && audio_used >= *samples ) { ignore --; audio_used -= *samples; memmove( audio_buffer, &audio_buffer[ *samples * *channels ], audio_used * sizeof( int16_t ) * *channels ); *samples = mlt_sample_calculator( fps, *frequency, expected ++ ); } } // Now handle the audio if we have enough if ( audio_used >= *samples ) { int size = *samples * *channels * sizeof( int16_t ); *format = mlt_audio_s16; *buffer = mlt_pool_alloc( size ); memcpy( *buffer, audio_buffer, size ); audio_used -= *samples; memmove( audio_buffer, &audio_buffer[ *samples * *channels ], audio_used * *channels * sizeof( int16_t ) ); mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); } else { mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); audio_used = 0; } // Store the number of audio samples still available mlt_properties_set_int( properties, "audio_used", audio_used ); } else { // Get silence and don't touch the context *samples = mlt_sample_calculator( fps, *frequency, position ); mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); } // Regardless of speed, we expect to get the next frame (cos we ain't too bright) mlt_properties_set_position( properties, "audio_expected", position + 1 ); mlt_service_unlock( MLT_PRODUCER_SERVICE( this ) ); return 0; } /** Our get frame implementation. */ static int producer_get_frame( mlt_producer this, mlt_frame_ptr frame, int index ) { // Create an empty frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( this ) ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( this ) ); // Set up the audio mlt_frame_push_audio( *frame, this ); mlt_frame_push_audio( *frame, producer_get_audio ); // Pass audio properties to the frame mlt_properties_pass_list( MLT_FRAME_PROPERTIES(*frame), MLT_PRODUCER_PROPERTIES( this ), "frequency, channels" ); // Calculate the next timecode mlt_producer_prepare_next( this ); return 0; } mlt-0.9.0/src/modules/vorbis/producer_vorbis.yml000066400000000000000000000006561215300731300220130ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: vorbis title: Ogg Vorbis version: 1 copyright: Visual Media FX ? creator: Charles Yates license: LGPLv2.1 language: en tags: - Audio description: | OGG Vorbis file reader. parameters: - identifier: argument title: File type: string description: File to use (only .ogg supported at the moment) readonly: no required: yes mutable: no widget: fileopen mlt-0.9.0/src/modules/xine/000077500000000000000000000000001215300731300155115ustar00rootroot00000000000000mlt-0.9.0/src/modules/xine/Makefile000066400000000000000000000011331215300731300171470ustar00rootroot00000000000000CFLAGS += -I../../ LDFLAGS += -L../../framework -lmlt include ../../../config.mak TARGET = ../libmltxine$(LIBSUF) OBJS = factory.o \ deinterlace.o \ yadif.o \ filter_deinterlace.o ifdef MMX_FLAGS CFLAGS += -DARCH_X86 OBJS += cpu_accel.o endif SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/xine/attributes.h000066400000000000000000000027141215300731300200540ustar00rootroot00000000000000/* * attributes.h * Copyright (C) 1999-2000 Aaron Holtzman * * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. * * mpeg2dec is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * mpeg2dec is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* use gcc attribs to align critical data structures */ #ifndef ATTRIBUTE_H_ #define ATTRIBUTE_H_ #ifdef ATTRIBUTE_ALIGNED_MAX #define ATTR_ALIGN(align) __attribute__ ((__aligned__ ((ATTRIBUTE_ALIGNED_MAX < align) ? ATTRIBUTE_ALIGNED_MAX : align))) #else #define ATTR_ALIGN(align) #endif /* disable GNU __attribute__ extension, when not compiling with GNU C */ #if defined(__GNUC__) || defined (__ICC) #ifndef ATTRIBUTE_PACKED #define ATTRIBUTE_PACKED 1 #endif #else #undef ATTRIBUTE_PACKED #ifndef __attribute__ #define __attribute__(x) /**/ #endif /* __attribute __*/ #endif #endif /* ATTRIBUTE_H_ */ mlt-0.9.0/src/modules/xine/cpu_accel.c000066400000000000000000000126431215300731300176010ustar00rootroot00000000000000/* * cpu_accel.c * Copyright (C) 1999-2001 Aaron Holtzman * * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. * * mpeg2dec is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * mpeg2dec is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ //#include "config.h" #include #include #include #include #include #include #define LOG_MODULE "cpu_accel" #define LOG_VERBOSE /* #define LOG */ #include "xineutils.h" #if defined(ARCH_X86) || defined(ARCH_X86_64) #if defined __x86_64__ static uint32_t arch_accel (void) { uint32_t caps; /* No need to test for this on AMD64, we know what the platform has. */ caps = MM_ACCEL_X86_MMX | MM_ACCEL_X86_SSE | MM_ACCEL_X86_MMXEXT | MM_ACCEL_X86_SSE2; return caps; } #else static uint32_t arch_accel (void) { #ifndef _MSC_VER uint32_t eax, ebx, ecx, edx; int AMD; uint32_t caps; #ifndef PIC #define cpuid(op,eax,ebx,ecx,edx) \ __asm__ ("cpuid" \ : "=a" (eax), \ "=b" (ebx), \ "=c" (ecx), \ "=d" (edx) \ : "a" (op) \ : "cc") #else /* PIC version : save ebx */ #define cpuid(op,eax,ebx,ecx,edx) \ __asm__ ("pushl %%ebx\n\t" \ "cpuid\n\t" \ "movl %%ebx,%1\n\t" \ "popl %%ebx" \ : "=a" (eax), \ "=r" (ebx), \ "=c" (ecx), \ "=d" (edx) \ : "a" (op) \ : "cc") #endif __asm__ ("pushfl\n\t" "pushfl\n\t" "popl %0\n\t" "movl %0,%1\n\t" "xorl $0x200000,%0\n\t" "pushl %0\n\t" "popfl\n\t" "pushfl\n\t" "popl %0\n\t" "popfl" : "=r" (eax), "=r" (ebx) : : "cc"); if (eax == ebx) /* no cpuid */ return 0; cpuid (0x00000000, eax, ebx, ecx, edx); if (!eax) /* vendor string only */ return 0; AMD = (ebx == 0x68747541) && (ecx == 0x444d4163) && (edx == 0x69746e65); cpuid (0x00000001, eax, ebx, ecx, edx); if (! (edx & 0x00800000)) /* no MMX */ return 0; caps = MM_ACCEL_X86_MMX; if (edx & 0x02000000) /* SSE - identical to AMD MMX extensions */ caps |= MM_ACCEL_X86_SSE | MM_ACCEL_X86_MMXEXT; if (edx & 0x04000000) /* SSE2 */ caps |= MM_ACCEL_X86_SSE2; cpuid (0x80000000, eax, ebx, ecx, edx); if (eax < 0x80000001) /* no extended capabilities */ return caps; cpuid (0x80000001, eax, ebx, ecx, edx); if (edx & 0x80000000) caps |= MM_ACCEL_X86_3DNOW; if (AMD && (edx & 0x00400000)) /* AMD MMX extensions */ caps |= MM_ACCEL_X86_MMXEXT; return caps; #else /* _MSC_VER */ return 0; #endif } #endif /* x86_64 */ static jmp_buf sigill_return; static void sigill_handler (int n) { longjmp(sigill_return, 1); } #endif /* ARCH_X86 */ #if defined (ARCH_PPC) && defined (ENABLE_ALTIVEC) static sigjmp_buf jmpbuf; static volatile sig_atomic_t canjump = 0; static void sigill_handler (int sig) { if (!canjump) { signal (sig, SIG_DFL); raise (sig); } canjump = 0; siglongjmp (jmpbuf, 1); } static uint32_t arch_accel (void) { signal (SIGILL, sigill_handler); if (sigsetjmp (jmpbuf, 1)) { signal (SIGILL, SIG_DFL); return 0; } canjump = 1; __asm__ volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0" : : "r" (-1)); signal (SIGILL, SIG_DFL); return MM_ACCEL_PPC_ALTIVEC; } #endif /* ARCH_PPC */ uint32_t xine_mm_accel (void) { static int initialized = 0; static uint32_t accel; if (!initialized) { #if defined (ARCH_X86) || (defined (ARCH_PPC) && defined (ENABLE_ALTIVEC)) accel = arch_accel (); #elif defined (HAVE_MLIB) #ifdef MLIB_LAZYLOAD void *hndl; if ((hndl = dlopen("libmlib.so.2", RTLD_LAZY | RTLD_GLOBAL | RTLD_NODELETE)) == NULL) { accel = 0; } else { dlclose(hndl); accel = MM_ACCEL_MLIB; } #else accel = MM_ACCEL_MLIB; #endif #else accel = 0; #endif #if defined(ARCH_X86) || defined(ARCH_X86_64) #ifndef _MSC_VER /* test OS support for SSE */ if( accel & MM_ACCEL_X86_SSE ) { void (*old_sigill_handler)(int); old_sigill_handler = signal (SIGILL, sigill_handler); if (setjmp(sigill_return)) { lprintf ("OS doesn't support SSE instructions.\n"); accel &= ~(MM_ACCEL_X86_SSE|MM_ACCEL_X86_SSE2); } else { __asm__ volatile ("xorps %xmm0, %xmm0"); } signal (SIGILL, old_sigill_handler); } #endif /* _MSC_VER */ #endif /* ARCH_X86 || ARCH_X86_64 */ if(getenv("XINE_NO_ACCEL")) { accel = 0; } initialized = 1; } return accel; } mlt-0.9.0/src/modules/xine/deinterlace.c000066400000000000000000000661371215300731300201510ustar00rootroot00000000000000 /* * Copyright (C) 2001 the xine project * * This file is part of xine, a free video player. * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * Deinterlace routines by Miguel Freitas * based of DScaler project sources (deinterlace.sourceforge.net) * * Currently only available for Xv driver and MMX extensions * * small todo list: * - implement non-MMX versions for all methods * - support MMX2 instructions * - move some generic code from xv driver to this file * - make it also work for yuy2 frames * */ #include #include #include "deinterlace.h" #include "xineutils.h" #define xine_fast_memcpy memcpy #define xine_fast_memmove memmove /* DeinterlaceFieldBob algorithm Based on Virtual Dub plugin by Gunnar Thalin MMX asm version from dscaler project (deinterlace.sourceforge.net) Linux version for Xine player by Miguel Freitas */ static void deinterlace_bob_yuv_mmx( uint8_t *pdst, uint8_t *psrc[], int width, int height ) { #ifdef USE_MMX int Line; uint64_t *YVal1; uint64_t *YVal2; uint64_t *YVal3; uint64_t *Dest; uint8_t* pEvenLines = psrc[0]; uint8_t* pOddLines = psrc[0]+width; int LineLength = width; int SourcePitch = width * 2; int IsOdd = 1; long EdgeDetect = 625; long JaggieThreshold = 73; int n; uint64_t qwEdgeDetect; uint64_t qwThreshold; static mmx_t YMask = {.ub={0xff,0,0xff,0,0xff,0,0xff,0}}; static mmx_t Mask = {.ub={0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe}}; qwEdgeDetect = EdgeDetect; qwEdgeDetect += (qwEdgeDetect << 48) + (qwEdgeDetect << 32) + (qwEdgeDetect << 16); qwThreshold = JaggieThreshold; qwThreshold += (qwThreshold << 48) + (qwThreshold << 32) + (qwThreshold << 16); // copy first even line no matter what, and the first odd line if we're // processing an odd field. xine_fast_memcpy(pdst, pEvenLines, LineLength); if (IsOdd) xine_fast_memcpy(pdst + LineLength, pOddLines, LineLength); height = height / 2; for (Line = 0; Line < height - 1; ++Line) { if (IsOdd) { YVal1 = (uint64_t *)(pOddLines + Line * SourcePitch); YVal2 = (uint64_t *)(pEvenLines + (Line + 1) * SourcePitch); YVal3 = (uint64_t *)(pOddLines + (Line + 1) * SourcePitch); Dest = (uint64_t *)(pdst + (Line * 2 + 2) * LineLength); } else { YVal1 = (uint64_t *)(pEvenLines + Line * SourcePitch); YVal2 = (uint64_t *)(pOddLines + Line * SourcePitch); YVal3 = (uint64_t *)(pEvenLines + (Line + 1) * SourcePitch); Dest = (uint64_t *)(pdst + (Line * 2 + 1) * LineLength); } // For ease of reading, the comments below assume that we're operating on an odd // field (i.e., that bIsOdd is true). The exact same processing is done when we // operate on an even field, but the roles of the odd and even fields are reversed. // It's just too cumbersome to explain the algorithm in terms of "the next odd // line if we're doing an odd field, or the next even line if we're doing an // even field" etc. So wherever you see "odd" or "even" below, keep in mind that // half the time this function is called, those words' meanings will invert. // Copy the odd line to the overlay verbatim. xine_fast_memcpy((char *)Dest + LineLength, YVal3, LineLength); n = LineLength >> 3; while( n-- ) { movq_m2r (*YVal1++, mm0); movq_m2r (*YVal2++, mm1); movq_m2r (*YVal3++, mm2); // get intensities in mm3 - 4 movq_r2r ( mm0, mm3 ); pand_m2r ( YMask, mm3 ); movq_r2r ( mm1, mm4 ); pand_m2r ( YMask, mm4 ); movq_r2r ( mm2, mm5 ); pand_m2r ( YMask, mm5 ); // get average in mm0 pand_m2r ( Mask, mm0 ); pand_m2r ( Mask, mm2 ); psrlw_i2r ( 01, mm0 ); psrlw_i2r ( 01, mm2 ); paddw_r2r ( mm2, mm0 ); // work out (O1 - E) * (O2 - E) / 2 - EdgeDetect * (O1 - O2) ^ 2 >> 12 // result will be in mm6 psrlw_i2r ( 01, mm3 ); psrlw_i2r ( 01, mm4 ); psrlw_i2r ( 01, mm5 ); movq_r2r ( mm3, mm6 ); psubw_r2r ( mm4, mm6 ); //mm6 = O1 - E movq_r2r ( mm5, mm7 ); psubw_r2r ( mm4, mm7 ); //mm7 = O2 - E pmullw_r2r ( mm7, mm6 ); // mm6 = (O1 - E) * (O2 - E) movq_r2r ( mm3, mm7 ); psubw_r2r ( mm5, mm7 ); // mm7 = (O1 - O2) pmullw_r2r ( mm7, mm7 ); // mm7 = (O1 - O2) ^ 2 psrlw_i2r ( 12, mm7 ); // mm7 = (O1 - O2) ^ 2 >> 12 pmullw_m2r ( *&qwEdgeDetect, mm7 );// mm7 = EdgeDetect * (O1 - O2) ^ 2 >> 12 psubw_r2r ( mm7, mm6 ); // mm6 is what we want pcmpgtw_m2r ( *&qwThreshold, mm6 ); movq_r2r ( mm6, mm7 ); pand_r2r ( mm6, mm0 ); pandn_r2r ( mm1, mm7 ); por_r2r ( mm0, mm7 ); movq_r2m ( mm7, *Dest++ ); } } // Copy last odd line if we're processing an even field. if (! IsOdd) { xine_fast_memcpy(pdst + (height * 2 - 1) * LineLength, pOddLines + (height - 1) * SourcePitch, LineLength); } // clear out the MMX registers ready for doing floating point // again emms(); #endif } /* Deinterlace the latest field, with a tendency to weave rather than bob. Good for high detail on low-movement scenes. Seems to produce bad output in general case, need to check if this is normal or if the code is broken. */ static int deinterlace_weave_yuv_mmx( uint8_t *pdst, uint8_t *psrc[], int width, int height ) { #ifdef USE_MMX int Line; uint64_t *YVal1; uint64_t *YVal2; uint64_t *YVal3; uint64_t *YVal4; uint64_t *Dest; uint8_t* pEvenLines = psrc[0]; uint8_t* pOddLines = psrc[0]+width; uint8_t* pPrevLines; int LineLength = width; int SourcePitch = width * 2; int IsOdd = 1; long TemporalTolerance = 300; long SpatialTolerance = 600; long SimilarityThreshold = 25; int n; uint64_t qwSpatialTolerance; uint64_t qwTemporalTolerance; uint64_t qwThreshold; static mmx_t YMask = {.ub={0xff,0,0xff,0,0xff,0,0xff,0}}; static mmx_t Mask = {.ub={0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe}}; // Make sure we have all the data we need. if ( psrc[0] == NULL || psrc[1] == NULL ) return 0; if (IsOdd) pPrevLines = psrc[1] + width; else pPrevLines = psrc[1]; // Since the code uses MMX to process 4 pixels at a time, we need our constants // to be represented 4 times per quadword. qwSpatialTolerance = SpatialTolerance; qwSpatialTolerance += (qwSpatialTolerance << 48) + (qwSpatialTolerance << 32) + (qwSpatialTolerance << 16); qwTemporalTolerance = TemporalTolerance; qwTemporalTolerance += (qwTemporalTolerance << 48) + (qwTemporalTolerance << 32) + (qwTemporalTolerance << 16); qwThreshold = SimilarityThreshold; qwThreshold += (qwThreshold << 48) + (qwThreshold << 32) + (qwThreshold << 16); // copy first even line no matter what, and the first odd line if we're // processing an even field. xine_fast_memcpy(pdst, pEvenLines, LineLength); if (!IsOdd) xine_fast_memcpy(pdst + LineLength, pOddLines, LineLength); height = height / 2; for (Line = 0; Line < height - 1; ++Line) { if (IsOdd) { YVal1 = (uint64_t *)(pEvenLines + Line * SourcePitch); YVal2 = (uint64_t *)(pOddLines + Line * SourcePitch); YVal3 = (uint64_t *)(pEvenLines + (Line + 1) * SourcePitch); YVal4 = (uint64_t *)(pPrevLines + Line * SourcePitch); Dest = (uint64_t *)(pdst + (Line * 2 + 1) * LineLength); } else { YVal1 = (uint64_t *)(pOddLines + Line * SourcePitch); YVal2 = (uint64_t *)(pEvenLines + (Line + 1) * SourcePitch); YVal3 = (uint64_t *)(pOddLines + (Line + 1) * SourcePitch); YVal4 = (uint64_t *)(pPrevLines + (Line + 1) * SourcePitch); Dest = (uint64_t *)(pdst + (Line * 2 + 2) * LineLength); } // For ease of reading, the comments below assume that we're operating on an odd // field (i.e., that bIsOdd is true). The exact same processing is done when we // operate on an even field, but the roles of the odd and even fields are reversed. // It's just too cumbersome to explain the algorithm in terms of "the next odd // line if we're doing an odd field, or the next even line if we're doing an // even field" etc. So wherever you see "odd" or "even" below, keep in mind that // half the time this function is called, those words' meanings will invert. // Copy the even scanline below this one to the overlay buffer, since we'll be // adapting the current scanline to the even lines surrounding it. The scanline // above has already been copied by the previous pass through the loop. xine_fast_memcpy((char *)Dest + LineLength, YVal3, LineLength); n = LineLength >> 3; while( n-- ) { movq_m2r ( *YVal1++, mm0 ); // mm0 = E1 movq_m2r ( *YVal2++, mm1 ); // mm1 = O movq_m2r ( *YVal3++, mm2 ); // mm2 = E2 movq_r2r ( mm0, mm3 ); // mm3 = intensity(E1) movq_r2r ( mm1, mm4 ); // mm4 = intensity(O) movq_r2r ( mm2, mm6 ); // mm6 = intensity(E2) pand_m2r ( YMask, mm3 ); pand_m2r ( YMask, mm4 ); pand_m2r ( YMask, mm6 ); // Average E1 and E2 for interpolated bobbing. // leave result in mm0 pand_m2r ( Mask, mm0 ); // mm0 = E1 with lower chroma bit stripped off pand_m2r ( Mask, mm2 ); // mm2 = E2 with lower chroma bit stripped off psrlw_i2r ( 01, mm0 ); // mm0 = E1 / 2 psrlw_i2r ( 01, mm2 ); // mm2 = E2 / 2 paddb_r2r ( mm2, mm0 ); // The meat of the work is done here. We want to see whether this pixel is // close in luminosity to ANY of: its top neighbor, its bottom neighbor, // or its predecessor. To do this without branching, we use MMX's // saturation feature, which gives us Z(x) = x if x>=0, or 0 if x<0. // // The formula we're computing here is // Z(ST - (E1 - O) ^ 2) + Z(ST - (E2 - O) ^ 2) + Z(TT - (Oold - O) ^ 2) // where ST is spatial tolerance and TT is temporal tolerance. The idea // is that if a pixel is similar to none of its neighbors, the resulting // value will be pretty low, probably zero. A high value therefore indicates // that the pixel had a similar neighbor. The pixel in the same position // in the field before last (Oold) is considered a neighbor since we want // to be able to display 1-pixel-high horizontal lines. movq_m2r ( *&qwSpatialTolerance, mm7 ); movq_r2r ( mm3, mm5 ); // mm5 = E1 psubsw_r2r ( mm4, mm5 ); // mm5 = E1 - O psraw_i2r ( 1, mm5 ); pmullw_r2r ( mm5, mm5 ); // mm5 = (E1 - O) ^ 2 psubusw_r2r ( mm5, mm7 ); // mm7 = ST - (E1 - O) ^ 2, or 0 if that's negative movq_m2r ( *&qwSpatialTolerance, mm3 ); movq_r2r ( mm6, mm5 ); // mm5 = E2 psubsw_r2r ( mm4, mm5 ); // mm5 = E2 - O psraw_i2r ( 1, mm5 ); pmullw_r2r ( mm5, mm5 ); // mm5 = (E2 - O) ^ 2 psubusw_r2r ( mm5, mm3 ); // mm0 = ST - (E2 - O) ^ 2, or 0 if that's negative paddusw_r2r ( mm3, mm7 ); // mm7 = (ST - (E1 - O) ^ 2) + (ST - (E2 - O) ^ 2) movq_m2r ( *&qwTemporalTolerance, mm3 ); movq_m2r ( *YVal4++, mm5 ); // mm5 = Oold pand_m2r ( YMask, mm5 ); psubsw_r2r ( mm4, mm5 ); // mm5 = Oold - O psraw_i2r ( 1, mm5 ); // XXX pmullw_r2r ( mm5, mm5 ); // mm5 = (Oold - O) ^ 2 psubusw_r2r ( mm5, mm3 ); /* mm0 = TT - (Oold - O) ^ 2, or 0 if that's negative */ paddusw_r2r ( mm3, mm7 ); // mm7 = our magic number /* * Now compare the similarity totals against our threshold. The pcmpgtw * instruction will populate the target register with a bunch of mask bits, * filling words where the comparison is true with 1s and ones where it's * false with 0s. A few ANDs and NOTs and an OR later, we have bobbed * values for pixels under the similarity threshold and weaved ones for * pixels over the threshold. */ pcmpgtw_m2r( *&qwThreshold, mm7 ); // mm7 = 0xffff where we're greater than the threshold, 0 elsewhere movq_r2r ( mm7, mm6 ); // mm6 = 0xffff where we're greater than the threshold, 0 elsewhere pand_r2r ( mm1, mm7 ); // mm7 = weaved data where we're greater than the threshold, 0 elsewhere pandn_r2r ( mm0, mm6 ); // mm6 = bobbed data where we're not greater than the threshold, 0 elsewhere por_r2r ( mm6, mm7 ); // mm7 = bobbed and weaved data movq_r2m ( mm7, *Dest++ ); } } // Copy last odd line if we're processing an odd field. if (IsOdd) { xine_fast_memcpy(pdst + (height * 2 - 1) * LineLength, pOddLines + (height - 1) * SourcePitch, LineLength); } // clear out the MMX registers ready for doing floating point // again emms(); #endif return 1; } // This is a simple lightweight DeInterlace method that uses little CPU time // but gives very good results for low or intermedite motion. (MORE CPU THAN BOB) // It defers frames by one field, but that does not seem to produce noticeable // lip sync problems. // // The method used is to take either the older or newer weave pixel depending // upon which give the smaller comb factor, and then clip to avoid large damage // when wrong. // // I'd intended this to be part of a larger more elaborate method added to // Blended Clip but this give too good results for the CPU to ignore here. static int deinterlace_greedy_yuv_mmx( uint8_t *pdst, uint8_t *psrc[], int width, int height ) { #ifdef USE_MMX int Line; int LoopCtr; uint64_t *L1; // ptr to Line1, of 3 uint64_t *L2; // ptr to Line2, the weave line uint64_t *L3; // ptr to Line3 uint64_t *LP2; // ptr to prev Line2 uint64_t *Dest; uint8_t* pEvenLines = psrc[0]; uint8_t* pOddLines = psrc[0]+width; uint8_t* pPrevLines; static mmx_t ShiftMask = {.ub={0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe}}; int LineLength = width; int SourcePitch = width * 2; int IsOdd = 1; long GreedyMaxComb = 15; static mmx_t MaxComb; int i; if ( psrc[0] == NULL || psrc[1] == NULL ) return 0; if (IsOdd) pPrevLines = psrc[1] + width; else pPrevLines = psrc[1]; for( i = 0; i < 8; i++ ) MaxComb.ub[i] = GreedyMaxComb; // How badly do we let it weave? 0-255 // copy first even line no matter what, and the first odd line if we're // processing an EVEN field. (note diff from other deint rtns.) xine_fast_memcpy(pdst, pEvenLines, LineLength); //DL0 if (!IsOdd) xine_fast_memcpy(pdst + LineLength, pOddLines, LineLength); //DL1 height = height / 2; for (Line = 0; Line < height - 1; ++Line) { LoopCtr = LineLength / 8; // there are LineLength / 8 qwords per line if (IsOdd) { L1 = (uint64_t *)(pEvenLines + Line * SourcePitch); L2 = (uint64_t *)(pOddLines + Line * SourcePitch); L3 = (uint64_t *)(pEvenLines + (Line + 1) * SourcePitch); LP2 = (uint64_t *)(pPrevLines + Line * SourcePitch); // prev Odd lines Dest = (uint64_t *)(pdst + (Line * 2 + 1) * LineLength); } else { L1 = (uint64_t *)(pOddLines + Line * SourcePitch); L2 = (uint64_t *)(pEvenLines + (Line + 1) * SourcePitch); L3 = (uint64_t *)(pOddLines + (Line + 1) * SourcePitch); LP2 = (uint64_t *)(pPrevLines + (Line + 1) * SourcePitch); //prev even lines Dest = (uint64_t *)(pdst + (Line * 2 + 2) * LineLength); } xine_fast_memcpy((char *)Dest + LineLength, L3, LineLength); // For ease of reading, the comments below assume that we're operating on an odd // field (i.e., that info->IsOdd is true). Assume the obvious for even lines.. while( LoopCtr-- ) { movq_m2r ( *L1++, mm1 ); movq_m2r ( *L2++, mm2 ); movq_m2r ( *L3++, mm3 ); movq_m2r ( *LP2++, mm0 ); // average L1 and L3 leave result in mm4 movq_r2r ( mm1, mm4 ); // L1 pand_m2r ( ShiftMask, mm4 ); psrlw_i2r ( 01, mm4 ); movq_r2r ( mm3, mm5 ); // L3 pand_m2r ( ShiftMask, mm5 ); psrlw_i2r ( 01, mm5 ); paddb_r2r ( mm5, mm4 ); // the average, for computing comb // get abs value of possible L2 comb movq_r2r ( mm2, mm7 ); // L2 psubusb_r2r ( mm4, mm7 ); // L2 - avg movq_r2r ( mm4, mm5 ); // avg psubusb_r2r ( mm2, mm5 ); // avg - L2 por_r2r ( mm7, mm5 ); // abs(avg-L2) movq_r2r ( mm4, mm6 ); // copy of avg for later // get abs value of possible LP2 comb movq_r2r ( mm0, mm7 ); // LP2 psubusb_r2r ( mm4, mm7 ); // LP2 - avg psubusb_r2r ( mm0, mm4 ); // avg - LP2 por_r2r ( mm7, mm4 ); // abs(avg-LP2) // use L2 or LP2 depending upon which makes smaller comb psubusb_r2r ( mm5, mm4 ); // see if it goes to zero psubusb_r2r ( mm5, mm5 ); // 0 pcmpeqb_r2r ( mm5, mm4 ); // if (mm4=0) then FF else 0 pcmpeqb_r2r ( mm4, mm5 ); // opposite of mm4 // if Comb(LP2) <= Comb(L2) then mm4=ff, mm5=0 else mm4=0, mm5 = 55 pand_r2r ( mm2, mm5 ); // use L2 if mm5 == ff, else 0 pand_r2r ( mm0, mm4 ); // use LP2 if mm4 = ff, else 0 por_r2r ( mm5, mm4 ); // may the best win // Now lets clip our chosen value to be not outside of the range // of the high/low range L1-L3 by more than abs(L1-L3) // This allows some comb but limits the damages and also allows more // detail than a boring oversmoothed clip. movq_r2r ( mm1, mm2 ); // copy L1 psubusb_r2r ( mm3, mm2 ); // - L3, with saturation paddusb_r2r ( mm3, mm2 ); // now = Max(L1,L3) pcmpeqb_r2r ( mm7, mm7 ); // all ffffffff psubusb_r2r ( mm1, mm7 ); // - L1 paddusb_r2r ( mm7, mm3 ); // add, may sat at fff.. psubusb_r2r ( mm7, mm3 ); // now = Min(L1,L3) // allow the value to be above the high or below the low by amt of MaxComb paddusb_m2r ( MaxComb, mm2 ); // increase max by diff psubusb_m2r ( MaxComb, mm3 ); // lower min by diff psubusb_r2r ( mm3, mm4 ); // best - Min paddusb_r2r ( mm3, mm4 ); // now = Max(best,Min(L1,L3) pcmpeqb_r2r ( mm7, mm7 ); // all ffffffff psubusb_r2r ( mm4, mm7 ); // - Max(best,Min(best,L3) paddusb_r2r ( mm7, mm2 ); // add may sat at FFF.. psubusb_r2r ( mm7, mm2 ); // now = Min( Max(best, Min(L1,L3), L2 )=L2 clipped movq_r2m ( mm2, *Dest++ ); // move in our clipped best } } /* Copy last odd line if we're processing an Odd field. */ if (IsOdd) { xine_fast_memcpy(pdst + (height * 2 - 1) * LineLength, pOddLines + (height - 1) * SourcePitch, LineLength); } /* clear out the MMX registers ready for doing floating point again */ emms(); #endif return 1; } /* Use one field to interpolate the other (low cpu utilization) Will lose resolution but does not produce weaving effect (good for fast moving scenes) also know as "linear interpolation" */ static void deinterlace_onefield_yuv_mmx( uint8_t *pdst, uint8_t *psrc[], int width, int height ) { #ifdef USE_MMX int Line; uint64_t *YVal1; uint64_t *YVal3; uint64_t *Dest; uint8_t* pEvenLines = psrc[0]; uint8_t* pOddLines = psrc[0]+width; int LineLength = width; int SourcePitch = width * 2; int IsOdd = 1; int n; static mmx_t Mask = {.ub={0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe}}; /* * copy first even line no matter what, and the first odd line if we're * processing an odd field. */ xine_fast_memcpy(pdst, pEvenLines, LineLength); if (IsOdd) xine_fast_memcpy(pdst + LineLength, pOddLines, LineLength); height = height / 2; for (Line = 0; Line < height - 1; ++Line) { if (IsOdd) { YVal1 = (uint64_t *)(pOddLines + Line * SourcePitch); YVal3 = (uint64_t *)(pOddLines + (Line + 1) * SourcePitch); Dest = (uint64_t *)(pdst + (Line * 2 + 2) * LineLength); } else { YVal1 = (uint64_t *)(pEvenLines + Line * SourcePitch); YVal3 = (uint64_t *)(pEvenLines + (Line + 1) * SourcePitch); Dest = (uint64_t *)(pdst + (Line * 2 + 1) * LineLength); } // Copy the odd line to the overlay verbatim. xine_fast_memcpy((char *)Dest + LineLength, YVal3, LineLength); n = LineLength >> 3; while( n-- ) { movq_m2r (*YVal1++, mm0); movq_m2r (*YVal3++, mm2); // get average in mm0 pand_m2r ( Mask, mm0 ); pand_m2r ( Mask, mm2 ); psrlw_i2r ( 01, mm0 ); psrlw_i2r ( 01, mm2 ); paddw_r2r ( mm2, mm0 ); movq_r2m ( mm0, *Dest++ ); } } /* Copy last odd line if we're processing an even field. */ if (! IsOdd) { xine_fast_memcpy(pdst + (height * 2 - 1) * LineLength, pOddLines + (height - 1) * SourcePitch, LineLength); } /* clear out the MMX registers ready for doing floating point * again */ emms(); #endif } /* Linear Blend filter - does a kind of vertical blurring on the image. (idea borrowed from mplayer's sources) */ static void deinterlace_linearblend_yuv_mmx( uint8_t *pdst, uint8_t *psrc[], int width, int height ) { #ifdef USE_MMX int Line; uint64_t *YVal1; uint64_t *YVal2; uint64_t *YVal3; uint64_t *Dest; int LineLength = width; int n; /* Copy first line */ xine_fast_memmove(pdst, psrc[0], LineLength); for (Line = 1; Line < height - 1; ++Line) { YVal1 = (uint64_t *)(psrc[0] + (Line - 1) * LineLength); YVal2 = (uint64_t *)(psrc[0] + (Line) * LineLength); YVal3 = (uint64_t *)(psrc[0] + (Line + 1) * LineLength); Dest = (uint64_t *)(pdst + Line * LineLength); n = LineLength >> 3; while( n-- ) { /* load data from 3 lines */ movq_m2r (*YVal1++, mm0); movq_m2r (*YVal2++, mm1); movq_m2r (*YVal3++, mm2); /* expand bytes to words */ punpckhbw_r2r (mm0, mm3); punpckhbw_r2r (mm1, mm4); punpckhbw_r2r (mm2, mm5); punpcklbw_r2r (mm0, mm0); punpcklbw_r2r (mm1, mm1); punpcklbw_r2r (mm2, mm2); /* * deinterlacing: * deint_line = (line0 + 2*line1 + line2) / 4 */ psrlw_i2r (07, mm0); psrlw_i2r (06, mm1); psrlw_i2r (07, mm2); psrlw_i2r (07, mm3); psrlw_i2r (06, mm4); psrlw_i2r (07, mm5); paddw_r2r (mm1, mm0); paddw_r2r (mm2, mm0); paddw_r2r (mm4, mm3); paddw_r2r (mm5, mm3); psrlw_i2r (03, mm0); psrlw_i2r (03, mm3); /* pack 8 words to 8 bytes in mm0 */ packuswb_r2r (mm3, mm0); movq_r2m ( mm0, *Dest++ ); } } /* Copy last line */ xine_fast_memmove(pdst + Line * LineLength, psrc[0] + Line * LineLength, LineLength); /* clear out the MMX registers ready for doing floating point * again */ emms(); #endif } /* Linear Blend filter - C version contributed by Rogerio Brito. This algorithm has the same interface as the other functions. The destination "screen" (pdst) is constructed from the source screen (psrc[0]) line by line. The i-th line of the destination screen is the average of 3 lines from the source screen: the (i-1)-th, i-th and (i+1)-th lines, with the i-th line having weight 2 in the computation. Remarks: * each line on pdst doesn't depend on previous lines; * due to the way the algorithm is defined, the first & last lines of the screen aren't deinterlaced. */ static void deinterlace_linearblend_yuv( uint8_t *pdst, uint8_t *psrc[], int width, int height ) { register int x, y; register uint8_t *l0, *l1, *l2, *l3; l0 = pdst; /* target line */ l1 = psrc[0]; /* 1st source line */ l2 = l1 + width; /* 2nd source line = line that follows l1 */ l3 = l2 + width; /* 3rd source line = line that follows l2 */ /* Copy the first line */ xine_fast_memcpy(l0, l1, width); l0 += width; for (y = 1; y < height-1; ++y) { /* computes avg of: l1 + 2*l2 + l3 */ for (x = 0; x < width; ++x) { l0[x] = (l1[x] + (l2[x]<<1) + l3[x]) >> 2; } /* updates the line pointers */ l1 = l2; l2 = l3; l3 += width; l0 += width; } /* Copy the last line */ xine_fast_memcpy(l0, l1, width); } static int check_for_mmx(void) { #ifdef USE_MMX static int config_flags = -1; if ( config_flags == -1 ) config_flags = xine_mm_accel(); if (config_flags & MM_ACCEL_X86_MMX) return 1; return 0; #else return 0; #endif } /* generic YUV deinterlacer pdst -> pointer to destination bitmap psrc -> array of pointers to source bitmaps ([0] = most recent) width,height -> dimension for bitmaps method -> DEINTERLACE_xxx */ void deinterlace_yuv( uint8_t *pdst, uint8_t *psrc[], int width, int height, int method ) { switch( method ) { case DEINTERLACE_NONE: xine_fast_memcpy(pdst,psrc[0],width*height); break; case DEINTERLACE_BOB: if( check_for_mmx() ) deinterlace_bob_yuv_mmx(pdst,psrc,width,height); else /* FIXME: provide an alternative? */ deinterlace_linearblend_yuv(pdst,psrc,width,height); break; case DEINTERLACE_WEAVE: if( check_for_mmx() ) { if( !deinterlace_weave_yuv_mmx(pdst,psrc,width,height) ) xine_fast_memcpy(pdst,psrc[0],width*height); } else /* FIXME: provide an alternative? */ deinterlace_linearblend_yuv(pdst,psrc,width,height); break; case DEINTERLACE_GREEDY: if( check_for_mmx() ) { if( !deinterlace_greedy_yuv_mmx(pdst,psrc,width,height) ) xine_fast_memcpy(pdst,psrc[0],width*height); } else /* FIXME: provide an alternative? */ deinterlace_linearblend_yuv(pdst,psrc,width,height); break; case DEINTERLACE_ONEFIELD: if( check_for_mmx() ) deinterlace_onefield_yuv_mmx(pdst,psrc,width,height); else /* FIXME: provide an alternative? */ deinterlace_linearblend_yuv(pdst,psrc,width,height); break; case DEINTERLACE_ONEFIELDXV: lprintf("ONEFIELDXV must be handled by the video driver.\n"); break; case DEINTERLACE_LINEARBLEND: if( check_for_mmx() ) deinterlace_linearblend_yuv_mmx(pdst,psrc,width,height); else deinterlace_linearblend_yuv(pdst,psrc,width,height); break; default: lprintf("unknown method %d.\n",method); break; } } int deinterlace_yuv_supported ( int method ) { switch( method ) { case DEINTERLACE_NONE: return 1; case DEINTERLACE_BOB: case DEINTERLACE_WEAVE: case DEINTERLACE_GREEDY: case DEINTERLACE_ONEFIELD: return check_for_mmx(); case DEINTERLACE_ONEFIELDXV: lprintf ("ONEFIELDXV must be handled by the video driver.\n"); return 0; case DEINTERLACE_LINEARBLEND: return 1; } return 0; } const char *deinterlace_methods[] = { "none", "bob", "weave", "greedy", "onefield", "onefield_xv", "linearblend", NULL }; mlt-0.9.0/src/modules/xine/deinterlace.h000066400000000000000000000030611215300731300201410ustar00rootroot00000000000000 /* * Copyright (C) 2001 the xine project * * This file is part of xine, a free video player. * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * Deinterlace routines by Miguel Freitas * based of DScaler project sources (deinterlace.sourceforge.net) * * Currently only available for Xv driver and MMX extensions * */ #ifndef __DEINTERLACE_H__ #define __DEINTERLACE_H__ //#include "video_out.h" #include int deinterlace_yuv_supported ( int method ); void deinterlace_yuv( uint8_t *pdst, uint8_t *psrc[], int width, int height, int method ); #define DEINTERLACE_NONE 0 #define DEINTERLACE_BOB 1 #define DEINTERLACE_WEAVE 2 #define DEINTERLACE_GREEDY 3 #define DEINTERLACE_ONEFIELD 4 #define DEINTERLACE_ONEFIELDXV 5 #define DEINTERLACE_LINEARBLEND 6 #define DEINTERLACE_YADIF 7 #define DEINTERLACE_YADIF_NOSPATIAL 8 extern const char *deinterlace_methods[]; #endif mlt-0.9.0/src/modules/xine/factory.c000066400000000000000000000021551215300731300173270ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include extern mlt_filter filter_deinterlace_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); MLT_REPOSITORY { MLT_REGISTER( filter_type, "deinterlace", filter_deinterlace_init ); } mlt-0.9.0/src/modules/xine/filter_deinterlace.c000066400000000000000000000316011215300731300215020ustar00rootroot00000000000000/* * filter_deinterlace.c -- deinterlace filter * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include "deinterlace.h" #include "yadif.h" #include #include #include #define YADIF_MODE_TEMPORAL_SPATIAL (0) #define YADIF_MODE_TEMPORAL (2) static yadif_filter *init_yadif( int width, int height ) { yadif_filter *yadif = mlt_pool_alloc( sizeof( *yadif ) ); yadif->cpu = 0; // Pure C #ifdef USE_SSE yadif->cpu |= AVS_CPU_INTEGER_SSE; #endif #ifdef USE_SSE2 yadif->cpu |= AVS_CPU_SSE2; #endif // Create intermediate planar planes yadif->yheight = height; yadif->ywidth = width; yadif->uvwidth = yadif->ywidth / 2; yadif->ypitch = ( yadif->ywidth + 15 ) / 16 * 16; yadif->uvpitch = ( yadif->uvwidth + 15 ) / 16 * 16; yadif->ysrc = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->ypitch ); yadif->usrc = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch); yadif->vsrc = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); yadif->yprev = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->ypitch ); yadif->uprev = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); yadif->vprev = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); yadif->ynext = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->ypitch ); yadif->unext = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); yadif->vnext = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); yadif->ydest = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->ypitch ); yadif->udest = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); yadif->vdest = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); return yadif; } static void close_yadif(yadif_filter *yadif) { mlt_pool_release( yadif->ysrc ); mlt_pool_release( yadif->usrc ); mlt_pool_release( yadif->vsrc ); mlt_pool_release( yadif->yprev ); mlt_pool_release( yadif->uprev ); mlt_pool_release( yadif->vprev ); mlt_pool_release( yadif->ynext ); mlt_pool_release( yadif->unext ); mlt_pool_release( yadif->vnext ); mlt_pool_release( yadif->ydest ); mlt_pool_release( yadif->udest ); mlt_pool_release( yadif->vdest ); mlt_pool_release( yadif ); #if defined(__GNUC__) && !defined(PIC) // Set SSSE3 bit to cpu asm (\ "mov $1, %%eax \n\t"\ "push %%ebx \n\t"\ "cpuid \n\t"\ "pop %%ebx \n\t"\ "mov %%ecx, %%edx \n\t"\ "shr $9, %%edx \n\t"\ "and $1, %%edx \n\t"\ "shl $9, %%edx \n\t"\ "and $511, %%ebx \n\t"\ "or %%edx, %%ebx \n\t"\ : "=b"(yadif->cpu) : "p"(yadif->cpu) : "%eax", "%ecx", "%edx"); #endif } static int deinterlace_yadif( mlt_frame frame, mlt_filter filter, uint8_t **image, mlt_image_format *format, int *width, int *height, int mode ) { mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_frame previous_frame = mlt_properties_get_data( properties, "previous frame", NULL ); uint8_t* previous_image = NULL; int previous_width = *width; int previous_height = *height; mlt_frame next_frame = mlt_properties_get_data( properties, "next frame", NULL ); uint8_t* next_image = NULL; int next_width = *width; int next_height = *height; mlt_log_debug( MLT_FILTER_SERVICE(filter), "previous " MLT_POSITION_FMT " current " MLT_POSITION_FMT " next " MLT_POSITION_FMT "\n", previous_frame? mlt_frame_original_position(previous_frame) : -1, mlt_frame_original_position(frame), next_frame? mlt_frame_original_position(next_frame) : -1); if ( !previous_frame || !next_frame ) return 1; // Get the preceding frame's image int error = mlt_frame_get_image( previous_frame, &previous_image, format, &previous_width, &previous_height, 0 ); int progressive = mlt_properties_get_int( MLT_FRAME_PROPERTIES( previous_frame ), "progressive" ); // Check that we aren't already progressive if ( !error && previous_image && !progressive ) { // OK, now we know we have work to do and can request the image in our format frame->convert_image( previous_frame, &previous_image, format, mlt_image_yuv422 ); // Get the current frame's image *format = mlt_image_yuv422; error = mlt_frame_get_image( frame, image, format, width, height, 0 ); if ( !error && *image && *format == mlt_image_yuv422 ) { // Get the following frame's image error = mlt_frame_get_image( next_frame, &next_image, format, &next_width, &next_height, 0 ); if ( !error && next_image && *format == mlt_image_yuv422 ) { yadif_filter *yadif = init_yadif( *width, *height ); if ( yadif ) { const int order = mlt_properties_get_int( properties, "top_field_first" ); const int pitch = *width << 1; const int parity = 0; // Convert packed to planar YUY2ToPlanes( *image, pitch, *width, *height, yadif->ysrc, yadif->ypitch, yadif->usrc, yadif->vsrc, yadif->uvpitch, yadif->cpu ); YUY2ToPlanes( previous_image, pitch, *width, *height, yadif->yprev, yadif->ypitch, yadif->uprev, yadif->vprev, yadif->uvpitch, yadif->cpu ); YUY2ToPlanes( next_image, pitch, *width, *height, yadif->ynext, yadif->ypitch, yadif->unext, yadif->vnext, yadif->uvpitch, yadif->cpu ); // Deinterlace each plane filter_plane( mode, yadif->ydest, yadif->ypitch, yadif->yprev, yadif->ysrc, yadif->ynext, yadif->ypitch, *width, *height, parity, order, yadif->cpu); filter_plane( mode, yadif->udest, yadif->uvpitch,yadif->uprev, yadif->usrc, yadif->unext, yadif->uvpitch, *width >> 1, *height, parity, order, yadif->cpu); filter_plane( mode, yadif->vdest, yadif->uvpitch, yadif->vprev, yadif->vsrc, yadif->vnext, yadif->uvpitch, *width >> 1, *height, parity, order, yadif->cpu); // Convert planar to packed YUY2FromPlanes( *image, pitch, *width, *height, yadif->ydest, yadif->ypitch, yadif->udest, yadif->vdest, yadif->uvpitch, yadif->cpu); close_yadif( yadif ); } } } } else { // Get the current frame's image error = mlt_frame_get_image( frame, image, format, width, height, 0 ); } return error; } /** Do it :-). */ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; mlt_filter filter = mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); int deinterlace = mlt_properties_get_int( properties, "consumer_deinterlace" ); // The progressive var should only represent the frame's original state and not the state // as modified by this filter! int progressive = mlt_properties_get_int( properties, "progressive" ); // At this point - before image was requested - (progressive == 0) cannot be trusted because // some producers (avformat) do not yet know. if ( deinterlace && !mlt_properties_get_int( properties, "test_image" ) ) { // Determine deinterlace method char *method_str = mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "method" ); int method = DEINTERLACE_NONE; char *frame_method_str = mlt_properties_get( properties, "deinterlace_method" ); if ( frame_method_str ) method_str = frame_method_str; if ( !method_str || strcmp( method_str, "yadif" ) == 0 ) method = DEINTERLACE_YADIF; else if ( strcmp( method_str, "yadif-nospatial" ) == 0 ) method = DEINTERLACE_YADIF_NOSPATIAL; else if ( strcmp( method_str, "onefield" ) == 0 ) method = DEINTERLACE_ONEFIELD; else if ( strcmp( method_str, "linearblend" ) == 0 ) method = DEINTERLACE_LINEARBLEND; else if ( strcmp( method_str, "bob" ) == 0 ) method = DEINTERLACE_BOB; else if ( strcmp( method_str, "weave" ) == 0 ) method = DEINTERLACE_BOB; else if ( strcmp( method_str, "greedy" ) == 0 ) method = DEINTERLACE_GREEDY; // Some producers like pixbuf want rescale_width & _height, but will not get them if you request // the previous image first. So, on the first iteration, we use linearblend. if ( ( method == DEINTERLACE_YADIF || method == DEINTERLACE_YADIF_NOSPATIAL ) && !mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "_notfirst" ) ) { mlt_properties_set_int( MLT_FILTER_PROPERTIES(filter), "_notfirst", 1 ); method = DEINTERLACE_LINEARBLEND; error = 1; } if ( method == DEINTERLACE_YADIF ) { error = deinterlace_yadif( frame, filter, image, format, width, height, YADIF_MODE_TEMPORAL_SPATIAL ); } else if ( method == DEINTERLACE_YADIF_NOSPATIAL ) { error = deinterlace_yadif( frame, filter, image, format, width, height, YADIF_MODE_TEMPORAL ); } if ( error || ( method > DEINTERLACE_NONE && method < DEINTERLACE_YADIF ) ) { mlt_service service = mlt_properties_get_data( MLT_FILTER_PROPERTIES(filter), "service", NULL ); // Get the current frame's image int error2 = mlt_frame_get_image( frame, image, format, width, height, writable ); progressive = mlt_properties_get_int( properties, "progressive" ); if ( error ) { method = DEINTERLACE_LINEARBLEND; // If YADIF requested, prev/next cancelled because some previous frames were progressive, // but new frames are interlaced, then turn prev/next frames back on. if ( !progressive ) mlt_properties_set_int( MLT_SERVICE_PROPERTIES(service), "_need_previous_next", 1 ); } else { // Signal that we no longer need previous and next frames mlt_properties_set_int( MLT_SERVICE_PROPERTIES(service), "_need_previous_next", 0 ); } error = error2; if ( !error && !progressive ) { // OK, now we know we have work to do and can request the image in our format error = frame->convert_image( frame, image, format, mlt_image_yuv422 ); // Check that we aren't already progressive if ( !error && *image && *format == mlt_image_yuv422 ) { // Deinterlace the image using one of the Xine deinterlacers int image_size = *width * *height * 2; uint8_t *new_image = mlt_pool_alloc( image_size ); deinterlace_yuv( new_image, image, *width * 2, *height, method ); mlt_frame_set_image( frame, new_image, image_size, mlt_pool_release ); *image = new_image; } } } else if ( method == DEINTERLACE_NONE ) { error = mlt_frame_get_image( frame, image, format, width, height, writable ); } // update progressive flag after having obtained image progressive = mlt_properties_get_int( properties, "progressive" ); mlt_log_debug( MLT_FILTER_SERVICE( filter ), "error %d deint %d prog %d fmt %s method %s\n", error, deinterlace, progressive, mlt_image_format_name( *format ), method_str ? method_str : "yadif" ); if ( !error ) { // Make sure that others know the frame is deinterlaced mlt_properties_set_int( properties, "progressive", 1 ); } } else { // Pass through error = mlt_frame_get_image( frame, image, format, width, height, writable ); } if ( !deinterlace || progressive ) { // Signal that we no longer need previous and next frames mlt_service service = mlt_properties_get_data( MLT_FILTER_PROPERTIES(filter), "service", NULL ); if ( service ) mlt_properties_set_int( MLT_SERVICE_PROPERTIES(service), "_need_previous_next", 0 ); } return error; } /** Deinterlace filter processing - this should be lazy evaluation here... */ static mlt_frame deinterlace_process( mlt_filter filter, mlt_frame frame ) { // Push filter on to the service stack mlt_frame_push_service( frame, filter ); // Push the get_image method on to the stack mlt_frame_push_get_image( frame, filter_get_image ); return frame; } static void on_service_changed( mlt_service owner, mlt_service filter ) { mlt_service service = mlt_properties_get_data( MLT_SERVICE_PROPERTIES(filter), "service", NULL ); mlt_properties_set_int( MLT_SERVICE_PROPERTIES(service), "_need_previous_next", 1 ); } /** Constructor for the filter. */ mlt_filter filter_deinterlace_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = mlt_filter_new( ); if ( filter != NULL ) { filter->process = deinterlace_process; mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "method", arg ); mlt_events_listen( MLT_FILTER_PROPERTIES( filter ), filter, "service-changed", (mlt_listener) on_service_changed ); } return filter; } mlt-0.9.0/src/modules/xine/gpl000066400000000000000000000000001215300731300162040ustar00rootroot00000000000000mlt-0.9.0/src/modules/xine/vf_yadif_template.h000066400000000000000000000252511215300731300213510ustar00rootroot00000000000000/* * Copyright (C) 2006 Michael Niedermayer * * SSE2/SSSE3 version (custom optimization) by h.yamagata * * Small fix by Alexander Balakhnin (fizick@avisynth.org.ru) * * MPlayer is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define LOAD8(mem,dst) \ "movq "mem", "#dst" \n\t"\ "punpcklbw %%xmm7, "#dst" \n\t" #define CHECK(pj,mj) \ "movdqu "#pj"(%[cur],%[mrefs]), %%xmm2 \n\t" /* cur[x-refs-1+j] */\ "movdqu "#mj"(%[cur],%[prefs]), %%xmm3 \n\t" /* cur[x+refs-1-j] */\ "movdqa %%xmm2, %%xmm4 \n\t"\ "movdqa %%xmm2, %%xmm5 \n\t"\ "pxor %%xmm3, %%xmm4 \n\t"\ "pavgb %%xmm3, %%xmm5 \n\t"\ "pand %[pb1], %%xmm4 \n\t"\ "psubusb %%xmm4, %%xmm5 \n\t"\ "psrldq $1, %%xmm5 \n\t"\ "punpcklbw %%xmm7, %%xmm5 \n\t" /* (cur[x-refs+j] + cur[x+refs-j])>>1 */\ "movdqa %%xmm2, %%xmm4 \n\t"\ "psubusb %%xmm3, %%xmm2 \n\t"\ "psubusb %%xmm4, %%xmm3 \n\t"\ "pmaxub %%xmm3, %%xmm2 \n\t"\ "movdqa %%xmm2, %%xmm3 \n\t"\ "movdqa %%xmm2, %%xmm4 \n\t" /* ABS(cur[x-refs-1+j] - cur[x+refs-1-j]) */\ "psrldq $1, %%xmm3 \n\t" /* ABS(cur[x-refs +j] - cur[x+refs -j]) */\ "psrldq $2, %%xmm4 \n\t" /* ABS(cur[x-refs+1+j] - cur[x+refs+1-j]) */\ "punpcklbw %%xmm7, %%xmm2 \n\t"\ "punpcklbw %%xmm7, %%xmm3 \n\t"\ "punpcklbw %%xmm7, %%xmm4 \n\t"\ "paddw %%xmm3, %%xmm2 \n\t"\ "paddw %%xmm4, %%xmm2 \n\t" /* score */ #define CHECK1 \ "movdqa %%xmm0, %%xmm3 \n\t"\ "pcmpgtw %%xmm2, %%xmm3 \n\t" /* if(score < spatial_score) */\ "pminsw %%xmm2, %%xmm0 \n\t" /* spatial_score= score; */\ "movdqa %%xmm3, %%xmm6 \n\t"\ "pand %%xmm3, %%xmm5 \n\t"\ "pandn %%xmm1, %%xmm3 \n\t"\ "por %%xmm5, %%xmm3 \n\t"\ "movdqa %%xmm3, %%xmm1 \n\t" /* spatial_pred= (cur[x-refs+j] + cur[x+refs-j])>>1; */ #define CHECK2 /* pretend not to have checked dir=2 if dir=1 was bad.\ hurts both quality and speed, but matches the C version. */\ "paddw %[pw1], %%xmm6 \n\t"\ "psllw $14, %%xmm6 \n\t"\ "paddsw %%xmm6, %%xmm2 \n\t"\ "movdqa %%xmm0, %%xmm3 \n\t"\ "pcmpgtw %%xmm2, %%xmm3 \n\t"\ "pminsw %%xmm2, %%xmm0 \n\t"\ "pand %%xmm3, %%xmm5 \n\t"\ "pandn %%xmm1, %%xmm3 \n\t"\ "por %%xmm5, %%xmm3 \n\t"\ "movdqa %%xmm3, %%xmm1 \n\t" /* mode argument mod - Fizick */ /* static attribute_align_arg void FILTER_LINE_FUNC_NAME(YadifContext *yadctx, uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int refs, int parity){ const int mode = yadctx->mode; */ static attribute_align_arg void FILTER_LINE_FUNC_NAME(int mode, uint8_t *dst, const uint8_t *prev, const uint8_t *cur, const uint8_t *next, int w, int refs, int parity){ DECLARE_ALIGNED(16, uint8_t, tmp0[16]); DECLARE_ALIGNED(16, uint8_t, tmp1[16]); DECLARE_ALIGNED(16, uint8_t, tmp2[16]); DECLARE_ALIGNED(16, uint8_t, tmp3[16]); int x; static DECLARE_ALIGNED(16, const unsigned short, pw_1[]) = { 0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001 }; static DECLARE_ALIGNED(16, const unsigned short, pb_1[]) = { 0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101 }; #define FILTER\ for(x=0; x>1 */\ "movdqa %%xmm0, %[tmp0] \n\t" /* c */\ "movdqa %%xmm3, %[tmp1] \n\t" /* d */\ "movdqa %%xmm1, %[tmp2] \n\t" /* e */\ "psubw %%xmm4, %%xmm2 \n\t"\ PABS( %%xmm4, %%xmm2) /* temporal_diff0 */\ LOAD8("(%[prev],%[mrefs])", %%xmm3) /* prev[x-refs] */\ LOAD8("(%[prev],%[prefs])", %%xmm4) /* prev[x+refs] */\ "psubw %%xmm0, %%xmm3 \n\t"\ "psubw %%xmm1, %%xmm4 \n\t"\ PABS( %%xmm5, %%xmm3)\ PABS( %%xmm5, %%xmm4)\ "paddw %%xmm4, %%xmm3 \n\t" /* temporal_diff1 */\ "psrlw $1, %%xmm2 \n\t"\ "psrlw $1, %%xmm3 \n\t"\ "pmaxsw %%xmm3, %%xmm2 \n\t"\ LOAD8("(%[next],%[mrefs])", %%xmm3) /* next[x-refs] */\ LOAD8("(%[next],%[prefs])", %%xmm4) /* next[x+refs] */\ "psubw %%xmm0, %%xmm3 \n\t"\ "psubw %%xmm1, %%xmm4 \n\t"\ PABS( %%xmm5, %%xmm3)\ PABS( %%xmm5, %%xmm4)\ "paddw %%xmm4, %%xmm3 \n\t" /* temporal_diff2 */\ "psrlw $1, %%xmm3 \n\t"\ "pmaxsw %%xmm3, %%xmm2 \n\t"\ "movdqa %%xmm2, %[tmp3] \n\t" /* diff */\ \ "paddw %%xmm0, %%xmm1 \n\t"\ "paddw %%xmm0, %%xmm0 \n\t"\ "psubw %%xmm1, %%xmm0 \n\t"\ "psrlw $1, %%xmm1 \n\t" /* spatial_pred */\ PABS( %%xmm2, %%xmm0) /* ABS(c-e) */\ \ "movdqu -1(%[cur],%[mrefs]), %%xmm2 \n\t" /* cur[x-refs-1] */\ "movdqu -1(%[cur],%[prefs]), %%xmm3 \n\t" /* cur[x+refs-1] */\ "movdqa %%xmm2, %%xmm4 \n\t"\ "psubusb %%xmm3, %%xmm2 \n\t"\ "psubusb %%xmm4, %%xmm3 \n\t"\ "pmaxub %%xmm3, %%xmm2 \n\t"\ /*"pshuflw $9,%%xmm2, %%xmm3 \n\t"*/\ /*"pshufhw $9,%%xmm2, %%xmm3 \n\t"*/\ "movdqa %%xmm2, %%xmm3 \n\t" /* correct replacement (here) */\ "psrldq $2, %%xmm3 \n\t"/* for "pshufw $9,%%mm2, %%mm3" - fix by Fizick */\ "punpcklbw %%xmm7, %%xmm2 \n\t" /* ABS(cur[x-refs-1] - cur[x+refs-1]) */\ "punpcklbw %%xmm7, %%xmm3 \n\t" /* ABS(cur[x-refs+1] - cur[x+refs+1]) */\ "paddw %%xmm2, %%xmm0 \n\t"\ "paddw %%xmm3, %%xmm0 \n\t"\ "psubw %[pw1], %%xmm0 \n\t" /* spatial_score */\ \ CHECK(-2,0)\ CHECK1\ CHECK(-3,1)\ CHECK2\ CHECK(0,-2)\ CHECK1\ CHECK(1,-3)\ CHECK2\ \ /* if(yadctx->mode<2) ... */\ "movdqa %[tmp3], %%xmm6 \n\t" /* diff */\ "cmpl $2, %[mode] \n\t"\ "jge 1f \n\t"\ LOAD8("(%["prev2"],%[mrefs],2)", %%xmm2) /* prev2[x-2*refs] */\ LOAD8("(%["next2"],%[mrefs],2)", %%xmm4) /* next2[x-2*refs] */\ LOAD8("(%["prev2"],%[prefs],2)", %%xmm3) /* prev2[x+2*refs] */\ LOAD8("(%["next2"],%[prefs],2)", %%xmm5) /* next2[x+2*refs] */\ "paddw %%xmm4, %%xmm2 \n\t"\ "paddw %%xmm5, %%xmm3 \n\t"\ "psrlw $1, %%xmm2 \n\t" /* b */\ "psrlw $1, %%xmm3 \n\t" /* f */\ "movdqa %[tmp0], %%xmm4 \n\t" /* c */\ "movdqa %[tmp1], %%xmm5 \n\t" /* d */\ "movdqa %[tmp2], %%xmm7 \n\t" /* e */\ "psubw %%xmm4, %%xmm2 \n\t" /* b-c */\ "psubw %%xmm7, %%xmm3 \n\t" /* f-e */\ "movdqa %%xmm5, %%xmm0 \n\t"\ "psubw %%xmm4, %%xmm5 \n\t" /* d-c */\ "psubw %%xmm7, %%xmm0 \n\t" /* d-e */\ "movdqa %%xmm2, %%xmm4 \n\t"\ "pminsw %%xmm3, %%xmm2 \n\t"\ "pmaxsw %%xmm4, %%xmm3 \n\t"\ "pmaxsw %%xmm5, %%xmm2 \n\t"\ "pminsw %%xmm5, %%xmm3 \n\t"\ "pmaxsw %%xmm0, %%xmm2 \n\t" /* max */\ "pminsw %%xmm0, %%xmm3 \n\t" /* min */\ "pxor %%xmm4, %%xmm4 \n\t"\ "pmaxsw %%xmm3, %%xmm6 \n\t"\ "psubw %%xmm2, %%xmm4 \n\t" /* -max */\ "pmaxsw %%xmm4, %%xmm6 \n\t" /* diff= MAX3(diff, min, -max); */\ "1: \n\t"\ \ "movdqa %[tmp1], %%xmm2 \n\t" /* d */\ "movdqa %%xmm2, %%xmm3 \n\t"\ "psubw %%xmm6, %%xmm2 \n\t" /* d-diff */\ "paddw %%xmm6, %%xmm3 \n\t" /* d+diff */\ "pmaxsw %%xmm2, %%xmm1 \n\t"\ "pminsw %%xmm3, %%xmm1 \n\t" /* d = clip(spatial_pred, d-diff, d+diff); */\ "packuswb %%xmm1, %%xmm1 \n\t"\ \ :[tmp0]"=m"(tmp0),\ [tmp1]"=m"(tmp1),\ [tmp2]"=m"(tmp2),\ [tmp3]"=m"(tmp3)\ :[prev] "r"(prev),\ [cur] "r"(cur),\ [next] "r"(next),\ [prefs]"r"((long)refs),\ [mrefs]"r"((long)-refs),\ [pw1] "m"(*pw_1),\ [pb1] "m"(*pb_1),\ [mode] "g"(mode)\ );\ __asm__ volatile("movq %%xmm1, %0" :"=m"(*dst));\ dst += 8;\ prev+= 8;\ cur += 8;\ next+= 8;\ } if(parity){ #define prev2 "prev" #define next2 "cur" FILTER #undef prev2 #undef next2 }else{ #define prev2 "cur" #define next2 "next" FILTER #undef prev2 #undef next2 } } #undef LOAD8 #undef PABS #undef CHECK #undef CHECK1 #undef CHECK2 #undef FILTER #undef FILTER_LINE_FUNC_NAME mlt-0.9.0/src/modules/xine/xineutils.h000066400000000000000000001112211215300731300177040ustar00rootroot00000000000000/* * Copyright (C) 2000-2004 the xine project * * This file is part of xine, a free video player. * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * $Id$ * */ #ifndef XINEUTILS_H #define XINEUTILS_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include #if HAVE_LIBGEN_H # include #endif //#ifdef XINE_COMPILE # include "attributes.h" //# include "compat.h" //# include "xmlparser.h" //# include "xine_buffer.h" //# include "configfile.h" //#else //# include //# include //# include //# include //# include //#endif //#ifdef HAVE_CONFIG_H //#include "config.h" //#endif #include #include /* * debugable mutexes */ typedef struct { pthread_mutex_t mutex; char id[80]; char *locked_by; } xine_mutex_t; int xine_mutex_init (xine_mutex_t *mutex, const pthread_mutexattr_t *mutexattr, char *id); int xine_mutex_lock (xine_mutex_t *mutex, char *who); int xine_mutex_unlock (xine_mutex_t *mutex, char *who); int xine_mutex_destroy (xine_mutex_t *mutex); /* CPU Acceleration */ /* * The type of an value that fits in an MMX register (note that long * long constant values MUST be suffixed by LL and unsigned long long * values by ULL, lest they be truncated by the compiler) */ /* generic accelerations */ #define MM_ACCEL_MLIB 0x00000001 /* x86 accelerations */ #define MM_ACCEL_X86_MMX 0x80000000 #define MM_ACCEL_X86_3DNOW 0x40000000 #define MM_ACCEL_X86_MMXEXT 0x20000000 #define MM_ACCEL_X86_SSE 0x10000000 #define MM_ACCEL_X86_SSE2 0x08000000 /* powerpc accelerations */ #define MM_ACCEL_PPC_ALTIVEC 0x04000000 /* x86 compat defines */ #define MM_MMX MM_ACCEL_X86_MMX #define MM_3DNOW MM_ACCEL_X86_3DNOW #define MM_MMXEXT MM_ACCEL_X86_MMXEXT #define MM_SSE MM_ACCEL_X86_SSE #define MM_SSE2 MM_ACCEL_X86_SSE2 uint32_t xine_mm_accel (void); #ifdef USE_MMX typedef union { int64_t q; /* Quadword (64-bit) value */ uint64_t uq; /* Unsigned Quadword */ int d[2]; /* 2 Doubleword (32-bit) values */ unsigned int ud[2]; /* 2 Unsigned Doubleword */ short w[4]; /* 4 Word (16-bit) values */ unsigned short uw[4]; /* 4 Unsigned Word */ char b[8]; /* 8 Byte (8-bit) values */ unsigned char ub[8]; /* 8 Unsigned Byte */ float s[2]; /* Single-precision (32-bit) value */ } ATTR_ALIGN(8) mmx_t; /* On an 8-byte (64-bit) boundary */ #define mmx_i2r(op,imm,reg) \ __asm__ __volatile__ (#op " %0, %%" #reg \ : /* nothing */ \ : "i" (imm) ) #define mmx_m2r(op,mem,reg) \ __asm__ __volatile__ (#op " %0, %%" #reg \ : /* nothing */ \ : "m" (mem)) #define mmx_r2m(op,reg,mem) \ __asm__ __volatile__ (#op " %%" #reg ", %0" \ : "=m" (mem) \ : /* nothing */ ) #define mmx_r2r(op,regs,regd) \ __asm__ __volatile__ (#op " %" #regs ", %" #regd) #define emms() __asm__ __volatile__ ("emms") #define movd_m2r(var,reg) mmx_m2r (movd, var, reg) #define movd_r2m(reg,var) mmx_r2m (movd, reg, var) #define movd_r2r(regs,regd) mmx_r2r (movd, regs, regd) #define movq_m2r(var,reg) mmx_m2r (movq, var, reg) #define movq_r2m(reg,var) mmx_r2m (movq, reg, var) #define movq_r2r(regs,regd) mmx_r2r (movq, regs, regd) #define packssdw_m2r(var,reg) mmx_m2r (packssdw, var, reg) #define packssdw_r2r(regs,regd) mmx_r2r (packssdw, regs, regd) #define packsswb_m2r(var,reg) mmx_m2r (packsswb, var, reg) #define packsswb_r2r(regs,regd) mmx_r2r (packsswb, regs, regd) #define packuswb_m2r(var,reg) mmx_m2r (packuswb, var, reg) #define packuswb_r2r(regs,regd) mmx_r2r (packuswb, regs, regd) #define paddb_m2r(var,reg) mmx_m2r (paddb, var, reg) #define paddb_r2r(regs,regd) mmx_r2r (paddb, regs, regd) #define paddd_m2r(var,reg) mmx_m2r (paddd, var, reg) #define paddd_r2r(regs,regd) mmx_r2r (paddd, regs, regd) #define paddw_m2r(var,reg) mmx_m2r (paddw, var, reg) #define paddw_r2r(regs,regd) mmx_r2r (paddw, regs, regd) #define paddsb_m2r(var,reg) mmx_m2r (paddsb, var, reg) #define paddsb_r2r(regs,regd) mmx_r2r (paddsb, regs, regd) #define paddsw_m2r(var,reg) mmx_m2r (paddsw, var, reg) #define paddsw_r2r(regs,regd) mmx_r2r (paddsw, regs, regd) #define paddusb_m2r(var,reg) mmx_m2r (paddusb, var, reg) #define paddusb_r2r(regs,regd) mmx_r2r (paddusb, regs, regd) #define paddusw_m2r(var,reg) mmx_m2r (paddusw, var, reg) #define paddusw_r2r(regs,regd) mmx_r2r (paddusw, regs, regd) #define pand_m2r(var,reg) mmx_m2r (pand, var, reg) #define pand_r2r(regs,regd) mmx_r2r (pand, regs, regd) #define pandn_m2r(var,reg) mmx_m2r (pandn, var, reg) #define pandn_r2r(regs,regd) mmx_r2r (pandn, regs, regd) #define pcmpeqb_m2r(var,reg) mmx_m2r (pcmpeqb, var, reg) #define pcmpeqb_r2r(regs,regd) mmx_r2r (pcmpeqb, regs, regd) #define pcmpeqd_m2r(var,reg) mmx_m2r (pcmpeqd, var, reg) #define pcmpeqd_r2r(regs,regd) mmx_r2r (pcmpeqd, regs, regd) #define pcmpeqw_m2r(var,reg) mmx_m2r (pcmpeqw, var, reg) #define pcmpeqw_r2r(regs,regd) mmx_r2r (pcmpeqw, regs, regd) #define pcmpgtb_m2r(var,reg) mmx_m2r (pcmpgtb, var, reg) #define pcmpgtb_r2r(regs,regd) mmx_r2r (pcmpgtb, regs, regd) #define pcmpgtd_m2r(var,reg) mmx_m2r (pcmpgtd, var, reg) #define pcmpgtd_r2r(regs,regd) mmx_r2r (pcmpgtd, regs, regd) #define pcmpgtw_m2r(var,reg) mmx_m2r (pcmpgtw, var, reg) #define pcmpgtw_r2r(regs,regd) mmx_r2r (pcmpgtw, regs, regd) #define pmaddwd_m2r(var,reg) mmx_m2r (pmaddwd, var, reg) #define pmaddwd_r2r(regs,regd) mmx_r2r (pmaddwd, regs, regd) #define pmulhw_m2r(var,reg) mmx_m2r (pmulhw, var, reg) #define pmulhw_r2r(regs,regd) mmx_r2r (pmulhw, regs, regd) #define pmullw_m2r(var,reg) mmx_m2r (pmullw, var, reg) #define pmullw_r2r(regs,regd) mmx_r2r (pmullw, regs, regd) #define por_m2r(var,reg) mmx_m2r (por, var, reg) #define por_r2r(regs,regd) mmx_r2r (por, regs, regd) #define pslld_i2r(imm,reg) mmx_i2r (pslld, imm, reg) #define pslld_m2r(var,reg) mmx_m2r (pslld, var, reg) #define pslld_r2r(regs,regd) mmx_r2r (pslld, regs, regd) #define psllq_i2r(imm,reg) mmx_i2r (psllq, imm, reg) #define psllq_m2r(var,reg) mmx_m2r (psllq, var, reg) #define psllq_r2r(regs,regd) mmx_r2r (psllq, regs, regd) #define psllw_i2r(imm,reg) mmx_i2r (psllw, imm, reg) #define psllw_m2r(var,reg) mmx_m2r (psllw, var, reg) #define psllw_r2r(regs,regd) mmx_r2r (psllw, regs, regd) #define psrad_i2r(imm,reg) mmx_i2r (psrad, imm, reg) #define psrad_m2r(var,reg) mmx_m2r (psrad, var, reg) #define psrad_r2r(regs,regd) mmx_r2r (psrad, regs, regd) #define psraw_i2r(imm,reg) mmx_i2r (psraw, imm, reg) #define psraw_m2r(var,reg) mmx_m2r (psraw, var, reg) #define psraw_r2r(regs,regd) mmx_r2r (psraw, regs, regd) #define psrld_i2r(imm,reg) mmx_i2r (psrld, imm, reg) #define psrld_m2r(var,reg) mmx_m2r (psrld, var, reg) #define psrld_r2r(regs,regd) mmx_r2r (psrld, regs, regd) #define psrlq_i2r(imm,reg) mmx_i2r (psrlq, imm, reg) #define psrlq_m2r(var,reg) mmx_m2r (psrlq, var, reg) #define psrlq_r2r(regs,regd) mmx_r2r (psrlq, regs, regd) #define psrlw_i2r(imm,reg) mmx_i2r (psrlw, imm, reg) #define psrlw_m2r(var,reg) mmx_m2r (psrlw, var, reg) #define psrlw_r2r(regs,regd) mmx_r2r (psrlw, regs, regd) #define psubb_m2r(var,reg) mmx_m2r (psubb, var, reg) #define psubb_r2r(regs,regd) mmx_r2r (psubb, regs, regd) #define psubd_m2r(var,reg) mmx_m2r (psubd, var, reg) #define psubd_r2r(regs,regd) mmx_r2r (psubd, regs, regd) #define psubw_m2r(var,reg) mmx_m2r (psubw, var, reg) #define psubw_r2r(regs,regd) mmx_r2r (psubw, regs, regd) #define psubsb_m2r(var,reg) mmx_m2r (psubsb, var, reg) #define psubsb_r2r(regs,regd) mmx_r2r (psubsb, regs, regd) #define psubsw_m2r(var,reg) mmx_m2r (psubsw, var, reg) #define psubsw_r2r(regs,regd) mmx_r2r (psubsw, regs, regd) #define psubusb_m2r(var,reg) mmx_m2r (psubusb, var, reg) #define psubusb_r2r(regs,regd) mmx_r2r (psubusb, regs, regd) #define psubusw_m2r(var,reg) mmx_m2r (psubusw, var, reg) #define psubusw_r2r(regs,regd) mmx_r2r (psubusw, regs, regd) #define punpckhbw_m2r(var,reg) mmx_m2r (punpckhbw, var, reg) #define punpckhbw_r2r(regs,regd) mmx_r2r (punpckhbw, regs, regd) #define punpckhdq_m2r(var,reg) mmx_m2r (punpckhdq, var, reg) #define punpckhdq_r2r(regs,regd) mmx_r2r (punpckhdq, regs, regd) #define punpckhwd_m2r(var,reg) mmx_m2r (punpckhwd, var, reg) #define punpckhwd_r2r(regs,regd) mmx_r2r (punpckhwd, regs, regd) #define punpcklbw_m2r(var,reg) mmx_m2r (punpcklbw, var, reg) #define punpcklbw_r2r(regs,regd) mmx_r2r (punpcklbw, regs, regd) #define punpckldq_m2r(var,reg) mmx_m2r (punpckldq, var, reg) #define punpckldq_r2r(regs,regd) mmx_r2r (punpckldq, regs, regd) #define punpcklwd_m2r(var,reg) mmx_m2r (punpcklwd, var, reg) #define punpcklwd_r2r(regs,regd) mmx_r2r (punpcklwd, regs, regd) #define pxor_m2r(var,reg) mmx_m2r (pxor, var, reg) #define pxor_r2r(regs,regd) mmx_r2r (pxor, regs, regd) /* 3DNOW extensions */ #define pavgusb_m2r(var,reg) mmx_m2r (pavgusb, var, reg) #define pavgusb_r2r(regs,regd) mmx_r2r (pavgusb, regs, regd) /* AMD MMX extensions - also available in intel SSE */ #define mmx_m2ri(op,mem,reg,imm) \ __asm__ __volatile__ (#op " %1, %0, %%" #reg \ : /* nothing */ \ : "X" (mem), "X" (imm)) #define mmx_r2ri(op,regs,regd,imm) \ __asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \ : /* nothing */ \ : "X" (imm) ) #define mmx_fetch(mem,hint) \ __asm__ __volatile__ ("prefetch" #hint " %0" \ : /* nothing */ \ : "X" (mem)) #define maskmovq(regs,maskreg) mmx_r2ri (maskmovq, regs, maskreg) #define movntq_r2m(mmreg,var) mmx_r2m (movntq, mmreg, var) #define pavgb_m2r(var,reg) mmx_m2r (pavgb, var, reg) #define pavgb_r2r(regs,regd) mmx_r2r (pavgb, regs, regd) #define pavgw_m2r(var,reg) mmx_m2r (pavgw, var, reg) #define pavgw_r2r(regs,regd) mmx_r2r (pavgw, regs, regd) #define pextrw_r2r(mmreg,reg,imm) mmx_r2ri (pextrw, mmreg, reg, imm) #define pinsrw_r2r(reg,mmreg,imm) mmx_r2ri (pinsrw, reg, mmreg, imm) #define pmaxsw_m2r(var,reg) mmx_m2r (pmaxsw, var, reg) #define pmaxsw_r2r(regs,regd) mmx_r2r (pmaxsw, regs, regd) #define pmaxub_m2r(var,reg) mmx_m2r (pmaxub, var, reg) #define pmaxub_r2r(regs,regd) mmx_r2r (pmaxub, regs, regd) #define pminsw_m2r(var,reg) mmx_m2r (pminsw, var, reg) #define pminsw_r2r(regs,regd) mmx_r2r (pminsw, regs, regd) #define pminub_m2r(var,reg) mmx_m2r (pminub, var, reg) #define pminub_r2r(regs,regd) mmx_r2r (pminub, regs, regd) #define pmovmskb(mmreg,reg) \ __asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg) #define pmulhuw_m2r(var,reg) mmx_m2r (pmulhuw, var, reg) #define pmulhuw_r2r(regs,regd) mmx_r2r (pmulhuw, regs, regd) #define prefetcht0(mem) mmx_fetch (mem, t0) #define prefetcht1(mem) mmx_fetch (mem, t1) #define prefetcht2(mem) mmx_fetch (mem, t2) #define prefetchnta(mem) mmx_fetch (mem, nta) #define psadbw_m2r(var,reg) mmx_m2r (psadbw, var, reg) #define psadbw_r2r(regs,regd) mmx_r2r (psadbw, regs, regd) #define pshufw_m2r(var,reg,imm) mmx_m2ri(pshufw, var, reg, imm) #define pshufw_r2r(regs,regd,imm) mmx_r2ri(pshufw, regs, regd, imm) #define sfence() __asm__ __volatile__ ("sfence\n\t") typedef union { float sf[4]; /* Single-precision (32-bit) value */ } ATTR_ALIGN(16) sse_t; /* On a 16 byte (128-bit) boundary */ #define sse_i2r(op, imm, reg) \ __asm__ __volatile__ (#op " %0, %%" #reg \ : /* nothing */ \ : "X" (imm) ) #define sse_m2r(op, mem, reg) \ __asm__ __volatile__ (#op " %0, %%" #reg \ : /* nothing */ \ : "X" (mem)) #define sse_r2m(op, reg, mem) \ __asm__ __volatile__ (#op " %%" #reg ", %0" \ : "=X" (mem) \ : /* nothing */ ) #define sse_r2r(op, regs, regd) \ __asm__ __volatile__ (#op " %" #regs ", %" #regd) #define sse_r2ri(op, regs, regd, imm) \ __asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \ : /* nothing */ \ : "X" (imm) ) #define sse_m2ri(op, mem, reg, subop) \ __asm__ __volatile__ (#op " %0, %%" #reg ", " #subop \ : /* nothing */ \ : "X" (mem)) #define movaps_m2r(var, reg) sse_m2r(movaps, var, reg) #define movaps_r2m(reg, var) sse_r2m(movaps, reg, var) #define movaps_r2r(regs, regd) sse_r2r(movaps, regs, regd) #define movntps_r2m(xmmreg, var) sse_r2m(movntps, xmmreg, var) #define movups_m2r(var, reg) sse_m2r(movups, var, reg) #define movups_r2m(reg, var) sse_r2m(movups, reg, var) #define movups_r2r(regs, regd) sse_r2r(movups, regs, regd) #define movhlps_r2r(regs, regd) sse_r2r(movhlps, regs, regd) #define movlhps_r2r(regs, regd) sse_r2r(movlhps, regs, regd) #define movhps_m2r(var, reg) sse_m2r(movhps, var, reg) #define movhps_r2m(reg, var) sse_r2m(movhps, reg, var) #define movlps_m2r(var, reg) sse_m2r(movlps, var, reg) #define movlps_r2m(reg, var) sse_r2m(movlps, reg, var) #define movss_m2r(var, reg) sse_m2r(movss, var, reg) #define movss_r2m(reg, var) sse_r2m(movss, reg, var) #define movss_r2r(regs, regd) sse_r2r(movss, regs, regd) #define shufps_m2r(var, reg, index) sse_m2ri(shufps, var, reg, index) #define shufps_r2r(regs, regd, index) sse_r2ri(shufps, regs, regd, index) #define cvtpi2ps_m2r(var, xmmreg) sse_m2r(cvtpi2ps, var, xmmreg) #define cvtpi2ps_r2r(mmreg, xmmreg) sse_r2r(cvtpi2ps, mmreg, xmmreg) #define cvtps2pi_m2r(var, mmreg) sse_m2r(cvtps2pi, var, mmreg) #define cvtps2pi_r2r(xmmreg, mmreg) sse_r2r(cvtps2pi, mmreg, xmmreg) #define cvttps2pi_m2r(var, mmreg) sse_m2r(cvttps2pi, var, mmreg) #define cvttps2pi_r2r(xmmreg, mmreg) sse_r2r(cvttps2pi, mmreg, xmmreg) #define cvtsi2ss_m2r(var, xmmreg) sse_m2r(cvtsi2ss, var, xmmreg) #define cvtsi2ss_r2r(reg, xmmreg) sse_r2r(cvtsi2ss, reg, xmmreg) #define cvtss2si_m2r(var, reg) sse_m2r(cvtss2si, var, reg) #define cvtss2si_r2r(xmmreg, reg) sse_r2r(cvtss2si, xmmreg, reg) #define cvttss2si_m2r(var, reg) sse_m2r(cvtss2si, var, reg) #define cvttss2si_r2r(xmmreg, reg) sse_r2r(cvtss2si, xmmreg, reg) #define movmskps(xmmreg, reg) \ __asm__ __volatile__ ("movmskps %" #xmmreg ", %" #reg) #define addps_m2r(var, reg) sse_m2r(addps, var, reg) #define addps_r2r(regs, regd) sse_r2r(addps, regs, regd) #define addss_m2r(var, reg) sse_m2r(addss, var, reg) #define addss_r2r(regs, regd) sse_r2r(addss, regs, regd) #define subps_m2r(var, reg) sse_m2r(subps, var, reg) #define subps_r2r(regs, regd) sse_r2r(subps, regs, regd) #define subss_m2r(var, reg) sse_m2r(subss, var, reg) #define subss_r2r(regs, regd) sse_r2r(subss, regs, regd) #define mulps_m2r(var, reg) sse_m2r(mulps, var, reg) #define mulps_r2r(regs, regd) sse_r2r(mulps, regs, regd) #define mulss_m2r(var, reg) sse_m2r(mulss, var, reg) #define mulss_r2r(regs, regd) sse_r2r(mulss, regs, regd) #define divps_m2r(var, reg) sse_m2r(divps, var, reg) #define divps_r2r(regs, regd) sse_r2r(divps, regs, regd) #define divss_m2r(var, reg) sse_m2r(divss, var, reg) #define divss_r2r(regs, regd) sse_r2r(divss, regs, regd) #define rcpps_m2r(var, reg) sse_m2r(rcpps, var, reg) #define rcpps_r2r(regs, regd) sse_r2r(rcpps, regs, regd) #define rcpss_m2r(var, reg) sse_m2r(rcpss, var, reg) #define rcpss_r2r(regs, regd) sse_r2r(rcpss, regs, regd) #define rsqrtps_m2r(var, reg) sse_m2r(rsqrtps, var, reg) #define rsqrtps_r2r(regs, regd) sse_r2r(rsqrtps, regs, regd) #define rsqrtss_m2r(var, reg) sse_m2r(rsqrtss, var, reg) #define rsqrtss_r2r(regs, regd) sse_r2r(rsqrtss, regs, regd) #define sqrtps_m2r(var, reg) sse_m2r(sqrtps, var, reg) #define sqrtps_r2r(regs, regd) sse_r2r(sqrtps, regs, regd) #define sqrtss_m2r(var, reg) sse_m2r(sqrtss, var, reg) #define sqrtss_r2r(regs, regd) sse_r2r(sqrtss, regs, regd) #define andps_m2r(var, reg) sse_m2r(andps, var, reg) #define andps_r2r(regs, regd) sse_r2r(andps, regs, regd) #define andnps_m2r(var, reg) sse_m2r(andnps, var, reg) #define andnps_r2r(regs, regd) sse_r2r(andnps, regs, regd) #define orps_m2r(var, reg) sse_m2r(orps, var, reg) #define orps_r2r(regs, regd) sse_r2r(orps, regs, regd) #define xorps_m2r(var, reg) sse_m2r(xorps, var, reg) #define xorps_r2r(regs, regd) sse_r2r(xorps, regs, regd) #define maxps_m2r(var, reg) sse_m2r(maxps, var, reg) #define maxps_r2r(regs, regd) sse_r2r(maxps, regs, regd) #define maxss_m2r(var, reg) sse_m2r(maxss, var, reg) #define maxss_r2r(regs, regd) sse_r2r(maxss, regs, regd) #define minps_m2r(var, reg) sse_m2r(minps, var, reg) #define minps_r2r(regs, regd) sse_r2r(minps, regs, regd) #define minss_m2r(var, reg) sse_m2r(minss, var, reg) #define minss_r2r(regs, regd) sse_r2r(minss, regs, regd) #define cmpps_m2r(var, reg, op) sse_m2ri(cmpps, var, reg, op) #define cmpps_r2r(regs, regd, op) sse_r2ri(cmpps, regs, regd, op) #define cmpeqps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 0) #define cmpeqps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 0) #define cmpltps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 1) #define cmpltps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 1) #define cmpleps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 2) #define cmpleps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 2) #define cmpunordps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 3) #define cmpunordps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 3) #define cmpneqps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 4) #define cmpneqps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 4) #define cmpnltps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 5) #define cmpnltps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 5) #define cmpnleps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 6) #define cmpnleps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 6) #define cmpordps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 7) #define cmpordps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 7) #define cmpss_m2r(var, reg, op) sse_m2ri(cmpss, var, reg, op) #define cmpss_r2r(regs, regd, op) sse_r2ri(cmpss, regs, regd, op) #define cmpeqss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 0) #define cmpeqss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 0) #define cmpltss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 1) #define cmpltss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 1) #define cmpless_m2r(var, reg) sse_m2ri(cmpss, var, reg, 2) #define cmpless_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 2) #define cmpunordss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 3) #define cmpunordss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 3) #define cmpneqss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 4) #define cmpneqss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 4) #define cmpnltss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 5) #define cmpnltss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 5) #define cmpnless_m2r(var, reg) sse_m2ri(cmpss, var, reg, 6) #define cmpnless_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 6) #define cmpordss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 7) #define cmpordss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 7) #define comiss_m2r(var, reg) sse_m2r(comiss, var, reg) #define comiss_r2r(regs, regd) sse_r2r(comiss, regs, regd) #define ucomiss_m2r(var, reg) sse_m2r(ucomiss, var, reg) #define ucomiss_r2r(regs, regd) sse_r2r(ucomiss, regs, regd) #define unpcklps_m2r(var, reg) sse_m2r(unpcklps, var, reg) #define unpcklps_r2r(regs, regd) sse_r2r(unpcklps, regs, regd) #define unpckhps_m2r(var, reg) sse_m2r(unpckhps, var, reg) #define unpckhps_r2r(regs, regd) sse_r2r(unpckhps, regs, regd) #define fxrstor(mem) \ __asm__ __volatile__ ("fxrstor %0" \ : /* nothing */ \ : "X" (mem)) #define fxsave(mem) \ __asm__ __volatile__ ("fxsave %0" \ : /* nothing */ \ : "X" (mem)) #define stmxcsr(mem) \ __asm__ __volatile__ ("stmxcsr %0" \ : /* nothing */ \ : "X" (mem)) #define ldmxcsr(mem) \ __asm__ __volatile__ ("ldmxcsr %0" \ : /* nothing */ \ : "X" (mem)) #endif /* USE_MMX */ /* Optimized/fast memcpy */ /* TODO : fix dll linkage problem for xine_fast_memcpy on win32 xine_fast_memcpy dll linkage is screwy here. declaring as dllimport seems to fix the problem but causes compiler warning with libxineutils */ #ifdef _MSC_VER __declspec( dllimport ) extern void *(* xine_fast_memcpy)(void *to, const void *from, size_t len); #else extern void *(* xine_fast_memcpy)(void *to, const void *from, size_t len); #endif #ifdef HAVE_XINE_INTERNAL_H /* Benchmark available memcpy methods */ void xine_probe_fast_memcpy(xine_t *xine); #endif /* * Debug stuff */ /* * profiling (unworkable in non DEBUG isn't defined) */ void xine_profiler_init (void); int xine_profiler_allocate_slot (char *label); void xine_profiler_start_count (int id); void xine_profiler_stop_count (int id); void xine_profiler_print_results (void); /* * Allocate and clean memory size_t 'size', then return the pointer * to the allocated memory. */ #if !defined(__GNUC__) || __GNUC__ < 3 void *xine_xmalloc(size_t size); #else void *xine_xmalloc(size_t size) __attribute__ ((__malloc__)); #endif /* * Same as above, but memory is aligned to 'alignement'. * **base is used to return pointer to un-aligned memory, use * this to free the mem chunk */ void *xine_xmalloc_aligned(size_t alignment, size_t size, void **base); /* * Get user home directory. */ const char *xine_get_homedir(void); /* * Clean a string (remove spaces and '=' at the begin, * and '\n', '\r' and spaces at the end. */ char *xine_chomp (char *str); /* * A thread-safe usecond sleep */ void xine_usec_sleep(unsigned usec); /* * Some string functions */ void xine_strdupa(char *dest, char *src); #define xine_strdupa(d, s) do { \ (d) = NULL; \ if((s) != NULL) { \ (d) = (char *) alloca(strlen((s)) + 1); \ strcpy((d), (s)); \ } \ } while(0) /* Shamefully copied from glibc 2.2.3 */ #ifdef HAVE_STRPBRK #define xine_strpbrk strpbrk #else static inline char *_private_strpbrk(char *s, const char *accept) { while(*s != '\0') { const char *a = accept; while(*a != '\0') if(*a++ == *s) return s; ++s; } return NULL; } #define xine_strpbrk _private_strpbrk #endif #if defined HAVE_STRSEP && !defined(_MSC_VER) #define xine_strsep strsep #else static inline char *_private_strsep(char **stringp, const char *delim) { char *begin, *end; begin = *stringp; if(begin == NULL) return NULL; if(delim[0] == '\0' || delim[1] == '\0') { char ch = delim[0]; if(ch == '\0') end = NULL; else { if(*begin == ch) end = begin; else if(*begin == '\0') end = NULL; else end = strchr(begin + 1, ch); } } else end = xine_strpbrk(begin, delim); if(end) { *end++ = '\0'; *stringp = end; } else *stringp = NULL; return begin; } #define xine_strsep _private_strsep #endif #ifdef HAVE_SETENV #define xine_setenv setenv #else static inline void _private_setenv(const char *name, const char *val, int _xx) { int len = strlen(name) + strlen(val) + 2; char env[len]; sprintf(env, "%s%c%s", name, '=', val); putenv(env); } #define xine_setenv _private_setenv #endif /* * Color Conversion Utility Functions * The following data structures and functions facilitate the conversion * of RGB images to packed YUV (YUY2) images. There are also functions to * convert from YUV9 -> YV12. All of the meaty details are written in * color.c. */ typedef struct yuv_planes_s { unsigned char *y; unsigned char *u; unsigned char *v; unsigned int row_width; /* frame width */ unsigned int row_count; /* frame height */ } yuv_planes_t; void init_yuv_conversion(void); void init_yuv_planes(yuv_planes_t *yuv_planes, int width, int height); void free_yuv_planes(yuv_planes_t *yuv_planes); extern void (*yuv444_to_yuy2) (yuv_planes_t *yuv_planes, unsigned char *yuy2_map, int pitch); extern void (*yuv9_to_yv12) (unsigned char *y_src, int y_src_pitch, unsigned char *y_dest, int y_dest_pitch, unsigned char *u_src, int u_src_pitch, unsigned char *u_dest, int u_dest_pitch, unsigned char *v_src, int v_src_pitch, unsigned char *v_dest, int v_dest_pitch, int width, int height); extern void (*yuv411_to_yv12) (unsigned char *y_src, int y_src_pitch, unsigned char *y_dest, int y_dest_pitch, unsigned char *u_src, int u_src_pitch, unsigned char *u_dest, int u_dest_pitch, unsigned char *v_src, int v_src_pitch, unsigned char *v_dest, int v_dest_pitch, int width, int height); extern void (*yv12_to_yuy2) (unsigned char *y_src, int y_src_pitch, unsigned char *u_src, int u_src_pitch, unsigned char *v_src, int v_src_pitch, unsigned char *yuy2_map, int yuy2_pitch, int width, int height, int progressive); extern void (*yuy2_to_yv12) (unsigned char *yuy2_map, int yuy2_pitch, unsigned char *y_dst, int y_dst_pitch, unsigned char *u_dst, int u_dst_pitch, unsigned char *v_dst, int v_dst_pitch, int width, int height); #define SCALEFACTOR 65536 #define CENTERSAMPLE 128 #define COMPUTE_Y(r, g, b) \ (unsigned char) \ ((y_r_table[r] + y_g_table[g] + y_b_table[b]) / SCALEFACTOR) #define COMPUTE_U(r, g, b) \ (unsigned char) \ ((u_r_table[r] + u_g_table[g] + u_b_table[b]) / SCALEFACTOR + CENTERSAMPLE) #define COMPUTE_V(r, g, b) \ (unsigned char) \ ((v_r_table[r] + v_g_table[g] + v_b_table[b]) / SCALEFACTOR + CENTERSAMPLE) #define UNPACK_BGR15(packed_pixel, r, g, b) \ b = (packed_pixel & 0x7C00) >> 7; \ g = (packed_pixel & 0x03E0) >> 2; \ r = (packed_pixel & 0x001F) << 3; #define UNPACK_BGR16(packed_pixel, r, g, b) \ b = (packed_pixel & 0xF800) >> 8; \ g = (packed_pixel & 0x07E0) >> 3; \ r = (packed_pixel & 0x001F) << 3; #define UNPACK_RGB15(packed_pixel, r, g, b) \ r = (packed_pixel & 0x7C00) >> 7; \ g = (packed_pixel & 0x03E0) >> 2; \ b = (packed_pixel & 0x001F) << 3; #define UNPACK_RGB16(packed_pixel, r, g, b) \ r = (packed_pixel & 0xF800) >> 8; \ g = (packed_pixel & 0x07E0) >> 3; \ b = (packed_pixel & 0x001F) << 3; extern int y_r_table[256]; extern int y_g_table[256]; extern int y_b_table[256]; extern int u_r_table[256]; extern int u_g_table[256]; extern int u_b_table[256]; extern int v_r_table[256]; extern int v_g_table[256]; extern int v_b_table[256]; /* frame copying functions */ extern void yv12_to_yv12 (unsigned char *y_src, int y_src_pitch, unsigned char *y_dst, int y_dst_pitch, unsigned char *u_src, int u_src_pitch, unsigned char *u_dst, int u_dst_pitch, unsigned char *v_src, int v_src_pitch, unsigned char *v_dst, int v_dst_pitch, int width, int height); extern void yuy2_to_yuy2 (unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch, int width, int height); /* print a hexdump of the given data */ void xine_hexdump (const char *buf, int length); /* * Optimization macros for conditions * Taken from the FIASCO L4 microkernel sources */ #if !defined(__GNUC__) || __GNUC__ < 3 # define EXPECT_TRUE(x) (x) # define EXPECT_FALSE(x) (x) #else # define EXPECT_TRUE(x) __builtin_expect((x),1) # define EXPECT_FALSE(x) __builtin_expect((x),0) #endif #ifdef NDEBUG #define _x_assert(exp) \ do { \ if (!(exp)) \ fprintf(stderr, "assert: %s:%d: %s: Assertion `%s' failed.\n", \ __FILE__, __LINE__, __XINE_FUNCTION__, #exp); \ } while(0) #else #define _x_assert(exp) \ do { \ if (!(exp)) { \ fprintf(stderr, "assert: %s:%d: %s: Assertion `%s' failed.\n", \ __FILE__, __LINE__, __XINE_FUNCTION__, #exp); \ abort(); \ } \ } while(0) #endif #define _x_abort() \ do { \ fprintf(stderr, "abort: %s:%d: %s: Aborting.\n", \ __FILE__, __LINE__, __XINE_FUNCTION__); \ abort(); \ } while(0) /****** logging with xine **********************************/ #ifndef LOG_MODULE #define LOG_MODULE __FILE__ #endif /* LOG_MODULE */ #define LOG_MODULE_STRING printf("%s: ", LOG_MODULE ); #ifdef LOG_VERBOSE #define LONG_LOG_MODULE_STRING \ printf("%s: (%s:%d) ", LOG_MODULE, __XINE_FUNCTION__, __LINE__ ); #else #define LONG_LOG_MODULE_STRING LOG_MODULE_STRING #endif /* LOG_VERBOSE */ #ifdef LOG #ifdef __GNUC__ #define lprintf(fmt, args...) \ do { \ LONG_LOG_MODULE_STRING \ printf(fmt, ##args); \ } while(0) #else /* __GNUC__ */ #ifdef _MSC_VER #define lprintf(fmtargs) \ do { \ LONG_LOG_MODULE_STRING \ printf("%s", fmtargs); \ } while(0) #else /* _MSC_VER */ #define lprintf(fmt, ...) \ do { \ LONG_LOG_MODULE_STRING \ printf(__VA_ARGS__); \ } while(0) #endif /* _MSC_VER */ #endif /* __GNUC__ */ #else /* LOG */ #ifdef __GNUC__ #define lprintf(fmt, args...) do {} while(0) #else #ifdef _MSC_VER #define lprintf #else #define lprintf(...) do {} while(0) #endif /* _MSC_VER */ #endif /* __GNUC__ */ #endif /* LOG */ #ifdef __GNUC__ #define llprintf(cat, fmt, args...) \ do{ \ if(cat){ \ LONG_LOG_MODULE_STRING \ printf( fmt, ##args ); \ } \ }while(0) #else #ifdef _MSC_VER #define llprintf(cat, fmtargs) \ do{ \ if(cat){ \ LONG_LOG_MODULE_STRING \ printf( "%s", fmtargs ); \ } \ }while(0) #else #define llprintf(cat, ...) \ do{ \ if(cat){ \ LONG_LOG_MODULE_STRING \ printf( __VA_ARGS__ ); \ } \ }while(0) #endif /* _MSC_VER */ #endif /* __GNUC__ */ #ifdef __GNUC__ #define xprintf(xine, verbose, fmt, args...) \ do { \ if((xine) && (xine)->verbosity >= verbose){ \ xine_log(xine, XINE_LOG_TRACE, fmt, ##args); \ } \ } while(0) #else #ifdef _MSC_VER #define xprintf(xine, verbose, fmtargs) \ do { \ if((xine) && (xine)->verbosity >= verbose){ \ xine_log(xine, XINE_LOG_TRACE, fmtargs); \ } \ } while(0) #else #define xprintf(xine, verbose, ...) \ do { \ if((xine) && (xine)->verbosity >= verbose){ \ xine_log(xine, XINE_LOG_TRACE, __VA_ARGS__); \ } \ } while(0) #endif /* _MSC_VER */ #endif /* __GNUC__ */ /* time measuring macros for profiling tasks */ #ifdef DEBUG # define XINE_PROFILE(function) \ do { \ struct timeval current_time; \ double dtime; \ gettimeofday(¤t_time, NULL); \ dtime = -(current_time.tv_sec + (current_time.tv_usec / 1000000.0)); \ function; \ gettimeofday(¤t_time, NULL); \ dtime += current_time.tv_sec + (current_time.tv_usec / 1000000.0); \ printf("%s: (%s:%d) took %lf seconds\n", \ LOG_MODULE, __XINE_FUNCTION__, __LINE__, dtime); \ } while(0) # define XINE_PROFILE_ACCUMULATE(function) \ do { \ struct timeval current_time; \ static double dtime = 0; \ gettimeofday(¤t_time, NULL); \ dtime -= current_time.tv_sec + (current_time.tv_usec / 1000000.0); \ function; \ gettimeofday(¤t_time, NULL); \ dtime += current_time.tv_sec + (current_time.tv_usec / 1000000.0); \ printf("%s: (%s:%d) took %lf seconds\n", \ LOG_MODULE, __XINE_FUNCTION__, __LINE__, dtime); \ } while(0) #else # define XINE_PROFILE(function) function # define XINE_PROFILE_ACCUMULATE(function) function #endif /* LOG */ /******** double chained lists with builtin iterator *******/ typedef struct xine_node_s { struct xine_node_s *next, *prev; void *content; int priority; } xine_node_t; typedef struct { xine_node_t *first, *last, *cur; } xine_list_t; xine_list_t *xine_list_new (void); /** * dispose the whole list. * note: disposes _only_ the list structure, content must be free()d elsewhere */ void xine_list_free(xine_list_t *l); /** * returns: Boolean */ int xine_list_is_empty (xine_list_t *l); /** * return content of first entry in list. */ void *xine_list_first_content (xine_list_t *l); /** * return next content in list. */ void *xine_list_next_content (xine_list_t *l); /** * Return last content of list. */ void *xine_list_last_content (xine_list_t *l); /** * Return previous content of list. */ void *xine_list_prev_content (xine_list_t *l); /** * Append content to list, sorted by decreasing priority. */ void xine_list_append_priority_content (xine_list_t *l, void *content, int priority); /** * Append content to list. */ void xine_list_append_content (xine_list_t *l, void *content); /** * Insert content in list. */ void xine_list_insert_content (xine_list_t *l, void *content); /** * Remove current content in list. * note: removes only the list entry; content must be free()d elsewhere. */ void xine_list_delete_current (xine_list_t *l); #ifndef HAVE_BASENAME /* * get base name */ char *basename (char const *name); #endif #ifdef __cplusplus } #endif #endif mlt-0.9.0/src/modules/xine/yadif.c000066400000000000000000000504301215300731300167530ustar00rootroot00000000000000/* Yadif C-plugin for Avisynth 2.5 - Yet Another DeInterlacing Filter Copyright (C)2007 Alexander G. Balakhnin aka Fizick http://avisynth.org.ru Port of YADIF filter from MPlayer Copyright (C) 2006 Michael Niedermayer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Avisynth_C plugin Assembler optimized for GNU C compiler */ #include "yadif.h" #include #include #define MIN(a,b) ((a) > (b) ? (b) : (a)) #define MAX(a,b) ((a) < (b) ? (b) : (a)) #define ABS(a) ((a) > 0 ? (a) : (-(a))) #define MIN3(a,b,c) MIN(MIN(a,b),c) #define MAX3(a,b,c) MAX(MAX(a,b),c) static void (*filter_line)(int mode, uint8_t *dst, const uint8_t *prev, const uint8_t *cur, const uint8_t *next, int w, int refs, int parity); #if defined(__GNUC__) && defined(USE_SSE) #define LOAD4(mem,dst) \ "movd "mem", "#dst" \n\t"\ "punpcklbw %%mm7, "#dst" \n\t" #define PABS(tmp,dst) \ "pxor "#tmp", "#tmp" \n\t"\ "psubw "#dst", "#tmp" \n\t"\ "pmaxsw "#tmp", "#dst" \n\t" #define CHECK(pj,mj) \ "movq "#pj"(%[cur],%[mrefs]), %%mm2 \n\t" /* cur[x-refs-1+j] */\ "movq "#mj"(%[cur],%[prefs]), %%mm3 \n\t" /* cur[x+refs-1-j] */\ "movq %%mm2, %%mm4 \n\t"\ "movq %%mm2, %%mm5 \n\t"\ "pxor %%mm3, %%mm4 \n\t"\ "pavgb %%mm3, %%mm5 \n\t"\ "pand %[pb1], %%mm4 \n\t"\ "psubusb %%mm4, %%mm5 \n\t"\ "psrlq $8, %%mm5 \n\t"\ "punpcklbw %%mm7, %%mm5 \n\t" /* (cur[x-refs+j] + cur[x+refs-j])>>1 */\ "movq %%mm2, %%mm4 \n\t"\ "psubusb %%mm3, %%mm2 \n\t"\ "psubusb %%mm4, %%mm3 \n\t"\ "pmaxub %%mm3, %%mm2 \n\t"\ "movq %%mm2, %%mm3 \n\t"\ "movq %%mm2, %%mm4 \n\t" /* ABS(cur[x-refs-1+j] - cur[x+refs-1-j]) */\ "psrlq $8, %%mm3 \n\t" /* ABS(cur[x-refs +j] - cur[x+refs -j]) */\ "psrlq $16, %%mm4 \n\t" /* ABS(cur[x-refs+1+j] - cur[x+refs+1-j]) */\ "punpcklbw %%mm7, %%mm2 \n\t"\ "punpcklbw %%mm7, %%mm3 \n\t"\ "punpcklbw %%mm7, %%mm4 \n\t"\ "paddw %%mm3, %%mm2 \n\t"\ "paddw %%mm4, %%mm2 \n\t" /* score */ #define CHECK1 \ "movq %%mm0, %%mm3 \n\t"\ "pcmpgtw %%mm2, %%mm3 \n\t" /* if(score < spatial_score) */\ "pminsw %%mm2, %%mm0 \n\t" /* spatial_score= score; */\ "movq %%mm3, %%mm6 \n\t"\ "pand %%mm3, %%mm5 \n\t"\ "pandn %%mm1, %%mm3 \n\t"\ "por %%mm5, %%mm3 \n\t"\ "movq %%mm3, %%mm1 \n\t" /* spatial_pred= (cur[x-refs+j] + cur[x+refs-j])>>1; */ #define CHECK2 /* pretend not to have checked dir=2 if dir=1 was bad.\ hurts both quality and speed, but matches the C version. */\ "paddw %[pw1], %%mm6 \n\t"\ "psllw $14, %%mm6 \n\t"\ "paddsw %%mm6, %%mm2 \n\t"\ "movq %%mm0, %%mm3 \n\t"\ "pcmpgtw %%mm2, %%mm3 \n\t"\ "pminsw %%mm2, %%mm0 \n\t"\ "pand %%mm3, %%mm5 \n\t"\ "pandn %%mm1, %%mm3 \n\t"\ "por %%mm5, %%mm3 \n\t"\ "movq %%mm3, %%mm1 \n\t" static void filter_line_mmx2(int mode, uint8_t *dst, const uint8_t *prev, const uint8_t *cur, const uint8_t *next, int w, int refs, int parity){ static const uint64_t pw_1 = 0x0001000100010001ULL; static const uint64_t pb_1 = 0x0101010101010101ULL; // const int mode = p->mode; uint64_t tmp0, tmp1, tmp2, tmp3; int x; #define FILTER\ for(x=0; x>1 */\ "movq %%mm0, %[tmp0] \n\t" /* c */\ "movq %%mm3, %[tmp1] \n\t" /* d */\ "movq %%mm1, %[tmp2] \n\t" /* e */\ "psubw %%mm4, %%mm2 \n\t"\ PABS( %%mm4, %%mm2) /* temporal_diff0 */\ LOAD4("(%[prev],%[mrefs])", %%mm3) /* prev[x-refs] */\ LOAD4("(%[prev],%[prefs])", %%mm4) /* prev[x+refs] */\ "psubw %%mm0, %%mm3 \n\t"\ "psubw %%mm1, %%mm4 \n\t"\ PABS( %%mm5, %%mm3)\ PABS( %%mm5, %%mm4)\ "paddw %%mm4, %%mm3 \n\t" /* temporal_diff1 */\ "psrlw $1, %%mm2 \n\t"\ "psrlw $1, %%mm3 \n\t"\ "pmaxsw %%mm3, %%mm2 \n\t"\ LOAD4("(%[next],%[mrefs])", %%mm3) /* next[x-refs] */\ LOAD4("(%[next],%[prefs])", %%mm4) /* next[x+refs] */\ "psubw %%mm0, %%mm3 \n\t"\ "psubw %%mm1, %%mm4 \n\t"\ PABS( %%mm5, %%mm3)\ PABS( %%mm5, %%mm4)\ "paddw %%mm4, %%mm3 \n\t" /* temporal_diff2 */\ "psrlw $1, %%mm3 \n\t"\ "pmaxsw %%mm3, %%mm2 \n\t"\ "movq %%mm2, %[tmp3] \n\t" /* diff */\ \ "paddw %%mm0, %%mm1 \n\t"\ "paddw %%mm0, %%mm0 \n\t"\ "psubw %%mm1, %%mm0 \n\t"\ "psrlw $1, %%mm1 \n\t" /* spatial_pred */\ PABS( %%mm2, %%mm0) /* ABS(c-e) */\ \ "movq -1(%[cur],%[mrefs]), %%mm2 \n\t" /* cur[x-refs-1] */\ "movq -1(%[cur],%[prefs]), %%mm3 \n\t" /* cur[x+refs-1] */\ "movq %%mm2, %%mm4 \n\t"\ "psubusb %%mm3, %%mm2 \n\t"\ "psubusb %%mm4, %%mm3 \n\t"\ "pmaxub %%mm3, %%mm2 \n\t"\ /*"pshufw $9,%%mm2, %%mm3 \n\t"*/\ "movq %%mm2, %%mm3 \n\t" /* replace for "pshufw $9,%%mm2, %%mm3" - Fizick */\ "psrlq $16, %%mm3 \n\t"/* replace for "pshufw $9,%%mm2, %%mm3" - Fizick*/\ "punpcklbw %%mm7, %%mm2 \n\t" /* ABS(cur[x-refs-1] - cur[x+refs-1]) */\ "punpcklbw %%mm7, %%mm3 \n\t" /* ABS(cur[x-refs+1] - cur[x+refs+1]) */\ "paddw %%mm2, %%mm0 \n\t"\ "paddw %%mm3, %%mm0 \n\t"\ "psubw %[pw1], %%mm0 \n\t" /* spatial_score */\ \ CHECK(-2,0)\ CHECK1\ CHECK(-3,1)\ CHECK2\ CHECK(0,-2)\ CHECK1\ CHECK(1,-3)\ CHECK2\ \ /* if(p->mode<2) ... */\ "movq %[tmp3], %%mm6 \n\t" /* diff */\ "cmpl $2, %[mode] \n\t"\ "jge 1f \n\t"\ LOAD4("(%["prev2"],%[mrefs],2)", %%mm2) /* prev2[x-2*refs] */\ LOAD4("(%["next2"],%[mrefs],2)", %%mm4) /* next2[x-2*refs] */\ LOAD4("(%["prev2"],%[prefs],2)", %%mm3) /* prev2[x+2*refs] */\ LOAD4("(%["next2"],%[prefs],2)", %%mm5) /* next2[x+2*refs] */\ "paddw %%mm4, %%mm2 \n\t"\ "paddw %%mm5, %%mm3 \n\t"\ "psrlw $1, %%mm2 \n\t" /* b */\ "psrlw $1, %%mm3 \n\t" /* f */\ "movq %[tmp0], %%mm4 \n\t" /* c */\ "movq %[tmp1], %%mm5 \n\t" /* d */\ "movq %[tmp2], %%mm7 \n\t" /* e */\ "psubw %%mm4, %%mm2 \n\t" /* b-c */\ "psubw %%mm7, %%mm3 \n\t" /* f-e */\ "movq %%mm5, %%mm0 \n\t"\ "psubw %%mm4, %%mm5 \n\t" /* d-c */\ "psubw %%mm7, %%mm0 \n\t" /* d-e */\ "movq %%mm2, %%mm4 \n\t"\ "pminsw %%mm3, %%mm2 \n\t"\ "pmaxsw %%mm4, %%mm3 \n\t"\ "pmaxsw %%mm5, %%mm2 \n\t"\ "pminsw %%mm5, %%mm3 \n\t"\ "pmaxsw %%mm0, %%mm2 \n\t" /* max */\ "pminsw %%mm0, %%mm3 \n\t" /* min */\ "pxor %%mm4, %%mm4 \n\t"\ "pmaxsw %%mm3, %%mm6 \n\t"\ "psubw %%mm2, %%mm4 \n\t" /* -max */\ "pmaxsw %%mm4, %%mm6 \n\t" /* diff= MAX3(diff, min, -max); */\ "1: \n\t"\ \ "movq %[tmp1], %%mm2 \n\t" /* d */\ "movq %%mm2, %%mm3 \n\t"\ "psubw %%mm6, %%mm2 \n\t" /* d-diff */\ "paddw %%mm6, %%mm3 \n\t" /* d+diff */\ "pmaxsw %%mm2, %%mm1 \n\t"\ "pminsw %%mm3, %%mm1 \n\t" /* d = clip(spatial_pred, d-diff, d+diff); */\ "packuswb %%mm1, %%mm1 \n\t"\ \ :[tmp0]"=m"(tmp0),\ [tmp1]"=m"(tmp1),\ [tmp2]"=m"(tmp2),\ [tmp3]"=m"(tmp3)\ :[prev] "r"(prev),\ [cur] "r"(cur),\ [next] "r"(next),\ [prefs]"r"((long)refs),\ [mrefs]"r"((long)-refs),\ [pw1] "m"(pw_1),\ [pb1] "m"(pb_1),\ [mode] "g"(mode)\ );\ asm volatile("movd %%mm1, %0" :"=m"(*dst));\ dst += 4;\ prev+= 4;\ cur += 4;\ next+= 4;\ } if(parity){ #define prev2 "prev" #define next2 "cur" FILTER #undef prev2 #undef next2 }else{ #define prev2 "cur" #define next2 "next" FILTER #undef prev2 #undef next2 } } #undef LOAD4 #undef PABS #undef CHECK #undef CHECK1 #undef CHECK2 #undef FILTER #ifndef attribute_align_arg #if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__>1) # define attribute_align_arg __attribute__((force_align_arg_pointer)) #else # define attribute_align_arg #endif #endif // for proper alignment SSE2 we need in GCC 4.2 and above #if (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__>1) #ifndef DECLARE_ALIGNED #define DECLARE_ALIGNED(n,t,v) t v __attribute__ ((aligned (n))) #endif // ================= SSE2 ================= #if defined(USE_SSE2) && defined(ARCH_X86_64) #define PABS(tmp,dst) \ "pxor "#tmp", "#tmp" \n\t"\ "psubw "#dst", "#tmp" \n\t"\ "pmaxsw "#tmp", "#dst" \n\t" #define FILTER_LINE_FUNC_NAME filter_line_sse2 #include "vf_yadif_template.h" #endif // ================ SSSE3 ================= #ifdef USE_SSE3 #define PABS(tmp,dst) \ "pabsw "#dst", "#dst" \n\t" #define FILTER_LINE_FUNC_NAME filter_line_ssse3 #include "vf_yadif_template.h" #endif #endif // GCC 4.2+ #endif // GNUC, USE_SSE static void filter_line_c(int mode, uint8_t *dst, const uint8_t *prev, const uint8_t *cur, const uint8_t *next, int w, int refs, int parity){ int x; const uint8_t *prev2= parity ? prev : cur ; const uint8_t *next2= parity ? cur : next; for(x=0; x>1; int e= cur[+refs]; int temporal_diff0= ABS(prev2[0] - next2[0]); int temporal_diff1=( ABS(prev[-refs] - c) + ABS(prev[+refs] - e) )>>1; int temporal_diff2=( ABS(next[-refs] - c) + ABS(next[+refs] - e) )>>1; int diff= MAX3(temporal_diff0>>1, temporal_diff1, temporal_diff2); int spatial_pred= (c+e)>>1; int spatial_score= ABS(cur[-refs-1] - cur[+refs-1]) + ABS(c-e) + ABS(cur[-refs+1] - cur[+refs+1]) - 1; #define CHECK(j)\ { int score= ABS(cur[-refs-1+ j] - cur[+refs-1- j])\ + ABS(cur[-refs + j] - cur[+refs - j])\ + ABS(cur[-refs+1+ j] - cur[+refs+1- j]);\ if(score < spatial_score){\ spatial_score= score;\ spatial_pred= (cur[-refs + j] + cur[+refs - j])>>1;\ CHECK(-1) CHECK(-2) }} }} CHECK( 1) CHECK( 2) }} }} if(mode<2){ int b= (prev2[-2*refs] + next2[-2*refs])>>1; int f= (prev2[+2*refs] + next2[+2*refs])>>1; #if 0 int a= cur[-3*refs]; int g= cur[+3*refs]; int max= MAX3(d-e, d-c, MIN3(MAX(b-c,f-e),MAX(b-c,b-a),MAX(f-g,f-e)) ); int min= MIN3(d-e, d-c, MAX3(MIN(b-c,f-e),MIN(b-c,b-a),MIN(f-g,f-e)) ); #else int max= MAX3(d-e, d-c, MIN(b-c, f-e)); int min= MIN3(d-e, d-c, MAX(b-c, f-e)); #endif diff= MAX3(diff, min, -max); } if(spatial_pred > d + diff) spatial_pred = d + diff; else if(spatial_pred < d - diff) spatial_pred = d - diff; dst[0] = spatial_pred; dst++; cur++; prev++; next++; prev2++; next2++; } } static void interpolate(uint8_t *dst, const uint8_t *cur0, const uint8_t *cur2, int w) { int x; for (x=0; x>1; // simple average } } void filter_plane(int mode, uint8_t *dst, int dst_stride, const uint8_t *prev0, const uint8_t *cur0, const uint8_t *next0, int refs, int w, int h, int parity, int tff, int cpu){ int y; filter_line = filter_line_c; #ifdef __GNUC__ #if (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__>1) #ifdef USE_SSE3 if (cpu & AVS_CPU_SSSE3) filter_line = filter_line_ssse3; else #endif #if defined(USE_SSE2) && defined(ARCH_X86_64) if (cpu & AVS_CPU_SSE2) filter_line = filter_line_sse2; else #endif #endif // GCC 4.2+ #ifdef USE_SSE if (cpu & AVS_CPU_INTEGER_SSE) filter_line = filter_line_mmx2; #endif #endif // GNUC y=0; if(((y ^ parity) & 1)){ memcpy(dst, cur0 + refs, w);// duplicate 1 }else{ memcpy(dst, cur0, w); } y=1; if(((y ^ parity) & 1)){ interpolate(dst + dst_stride, cur0, cur0 + refs*2, w); // interpolate 0 and 2 }else{ memcpy(dst + dst_stride, cur0 + refs, w); // copy original } for(y=2; y= AVS_CPU_INTEGER_SSE) asm volatile("emms"); #endif } #if defined(__GNUC__) && defined(USE_SSE) && !defined(PIC) static attribute_align_arg void YUY2ToPlanes_mmx(const unsigned char *srcYUY2, int pitch_yuy2, int width, int height, unsigned char *py, int pitch_y, unsigned char *pu, unsigned char *pv, int pitch_uv) { /* process by 16 bytes (8 pixels), so width is assumed mod 8 */ int widthdiv2 = width>>1; // static unsigned __int64 Ymask = 0x00FF00FF00FF00FFULL; int h; for (h=0; h> 1; int h; for (h=0; h>1)] = pSrcYUY2[w2+1]; pSrcV[(w>>1)] = pSrcYUY2[w2+3]; } pSrcY += srcPitchY; pSrcU += srcPitchUV; pSrcV += srcPitchUV; pSrcYUY2 += nSrcPitchYUY2; } } //---------------------------------------------------------------------------------------------- void YUY2FromPlanes(unsigned char *pSrcYUY2, int nSrcPitchYUY2, int nWidth, int nHeight, const unsigned char * pSrcY, int srcPitchY, const unsigned char * pSrcU, const unsigned char * pSrcV, int srcPitchUV, int cpu) { int h,w; int w0 = 0; #if defined(__GNUC__) && defined(USE_SSE) && !defined(PIC) if (cpu & AVS_CPU_INTEGER_SSE) { w0 = (nWidth/8)*8; YUY2FromPlanes_mmx(pSrcYUY2, nSrcPitchYUY2, w0, nHeight, pSrcY, srcPitchY, pSrcU, pSrcV, srcPitchUV); } #endif for (h=0; h>1)]; pSrcYUY2[w2+2] = pSrcY[w+1]; pSrcYUY2[w2+3] = pSrcV[(w>>1)]; } pSrcY += srcPitchY; pSrcU += srcPitchUV; pSrcV += srcPitchUV; pSrcYUY2 += nSrcPitchYUY2; } } mlt-0.9.0/src/modules/xine/yadif.h000066400000000000000000000041031215300731300167540ustar00rootroot00000000000000/* Yadif C-plugin for Avisynth 2.5 - Yet Another DeInterlacing Filter Copyright (C)2007 Alexander G. Balakhnin aka Fizick http://avisynth.org.ru Port of YADIF filter from MPlayer Copyright (C) 2006 Michael Niedermayer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Avisynth_C plugin Assembler optimized for GNU C compiler */ #ifndef YADIF_H_ #define YADIF_H_ #include #define AVS_CPU_INTEGER_SSE 0x1 #define AVS_CPU_SSE2 0x2 #define AVS_CPU_SSSE3 0x4 typedef struct yadif_filter { int cpu; // optimization int yheight; int ypitch; int uvpitch; int ywidth; int uvwidth; unsigned char *ysrc; unsigned char *usrc; unsigned char *vsrc; unsigned char *yprev; unsigned char *uprev; unsigned char *vprev; unsigned char *ynext; unsigned char *unext; unsigned char *vnext; unsigned char *ydest; unsigned char *udest; unsigned char *vdest; } yadif_filter; void filter_plane(int mode, uint8_t *dst, int dst_stride, const uint8_t *prev0, const uint8_t *cur0, const uint8_t *next0, int refs, int w, int h, int parity, int tff, int cpu); void YUY2ToPlanes(const unsigned char *pSrcYUY2, int nSrcPitchYUY2, int nWidth, int nHeight, unsigned char * pSrcY, int srcPitchY, unsigned char * pSrcU, unsigned char * pSrcV, int srcPitchUV, int cpu); void YUY2FromPlanes(unsigned char *pSrcYUY2, int nSrcPitchYUY2, int nWidth, int nHeight, const unsigned char * pSrcY, int srcPitchY, const unsigned char * pSrcU, const unsigned char * pSrcV, int srcPitchUV, int cpu); #endif mlt-0.9.0/src/modules/xml/000077500000000000000000000000001215300731300153465ustar00rootroot00000000000000mlt-0.9.0/src/modules/xml/Makefile000066400000000000000000000013771215300731300170160ustar00rootroot00000000000000CFLAGS += -I../.. LDFLAGS += -L../../framework -lmlt -lpthread include ../../../config.mak TARGET = ../libmltxml$(LIBSUF) OBJS = factory.o \ consumer_xml.o \ producer_xml.o CFLAGS += `pkg-config libxml-2.0 --cflags` LDFLAGS += `pkg-config libxml-2.0 --libs` SRCS := $(OBJS:.o=.c) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend distclean: clean rm -f .depend clean: rm -f $(OBJS) $(TARGET) install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/xml" install -m 644 mlt-xml.dtd "$(DESTDIR)$(mltdatadir)/xml" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/xml" ifneq ($(wildcard .depend),) include .depend endif mlt-0.9.0/src/modules/xml/configure000077500000000000000000000003341215300731300172550ustar00rootroot00000000000000#!/bin/sh if [ "$help" != "1" ] then pkg-config libxml-2.0 > /dev/null 2>&1 disable_xml2=$? if [ "$disable_xml2" != "0" ] then echo "- xml2 not found: disabling xml module" touch ../disable-xml fi exit 0 fi mlt-0.9.0/src/modules/xml/consumer_xml.c000066400000000000000000000763441215300731300202430ustar00rootroot00000000000000/* * consumer_xml.c -- a libxml2 serialiser of mlt service networks * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #define ID_SIZE 128 #define TIME_PROPERTY "_consumer_xml" #define _x (const xmlChar*) #define _s (const char*) // This maintains counters for adding ids to elements struct serialise_context_s { mlt_properties id_map; int producer_count; int multitrack_count; int playlist_count; int tractor_count; int filter_count; int transition_count; int pass; mlt_properties hide_map; char *root; char *store; int no_meta; mlt_profile profile; mlt_time_format time_format; }; typedef struct serialise_context_s* serialise_context; /** Forward references to static functions. */ static int consumer_start( mlt_consumer parent ); static int consumer_stop( mlt_consumer parent ); static int consumer_is_stopped( mlt_consumer this ); static void *consumer_thread( void *arg ); static void serialise_service( serialise_context context, mlt_service service, xmlNode *node ); static char* filter_restricted( const char *in ) { if ( !in ) return NULL; size_t n = strlen( in ); char *out = calloc( 1, n + 1 ); char *p = out; mbstate_t mbs; memset( &mbs, 0, sizeof(mbs) ); while ( *in ) { wchar_t w; size_t c = mbrtowc( &w, in, n, &mbs ); if ( c <= 0 || c > n ) break; n -= c; in += c; if ( w == 0x9 || w == 0xA || w == 0xD || ( w >= 0x20 && w <= 0xD7FF ) || ( w >= 0xE000 && w <= 0xFFFD ) || ( w >= 0x10000 && w <= 0x10FFFF ) ) { mbstate_t ps; memset( &ps, 0, sizeof(ps) ); c = wcrtomb( p, w, &ps ); if ( c > 0 ) p += c; } } return out; } typedef enum { xml_existing, xml_producer, xml_multitrack, xml_playlist, xml_tractor, xml_filter, xml_transition } xml_type; /** Create or retrieve an id associated to this service. */ static char *xml_get_id( serialise_context context, mlt_service service, xml_type type ) { char *id = NULL; int i = 0; mlt_properties map = context->id_map; // Search the map for the service for ( i = 0; i < mlt_properties_count( map ); i ++ ) if ( mlt_properties_get_data_at( map, i, NULL ) == service ) break; // If the service is not in the map, and the type indicates a new id is needed... if ( i >= mlt_properties_count( map ) && type != xml_existing ) { // Attempt to reuse existing id id = mlt_properties_get( MLT_SERVICE_PROPERTIES( service ), "id" ); // If no id, or the id is used in the map (for another service), then // create a new one. if ( id == NULL || mlt_properties_get_data( map, id, NULL ) != NULL ) { char temp[ ID_SIZE ]; do { switch( type ) { case xml_producer: sprintf( temp, "producer%d", context->producer_count ++ ); break; case xml_multitrack: sprintf( temp, "multitrack%d", context->multitrack_count ++ ); break; case xml_playlist: sprintf( temp, "playlist%d", context->playlist_count ++ ); break; case xml_tractor: sprintf( temp, "tractor%d", context->tractor_count ++ ); break; case xml_filter: sprintf( temp, "filter%d", context->filter_count ++ ); break; case xml_transition: sprintf( temp, "transition%d", context->transition_count ++ ); break; case xml_existing: // Never gets here break; } } while( mlt_properties_get_data( map, temp, NULL ) != NULL ); // Set the data at the generated name mlt_properties_set_data( map, temp, service, 0, NULL, NULL ); // Get the pointer to the name (i is the end of the list) id = mlt_properties_get_name( map, i ); } else { // Store the existing id in the map mlt_properties_set_data( map, id, service, 0, NULL, NULL ); } } else if ( type == xml_existing ) { id = mlt_properties_get_name( map, i ); } return id; } /** This is what will be called by the factory - anything can be passed in via the argument, but keep it simple. */ mlt_consumer consumer_xml_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create the consumer object mlt_consumer this = calloc( 1, sizeof( struct mlt_consumer_s ) ); // If no malloc'd and consumer init ok if ( this != NULL && mlt_consumer_init( this, NULL, profile ) == 0 ) { // Allow thread to be started/stopped this->start = consumer_start; this->stop = consumer_stop; this->is_stopped = consumer_is_stopped; mlt_properties_set( MLT_CONSUMER_PROPERTIES( this ), "resource", arg ); mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( this ), "real_time", -1 ); mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( this ), "prefill", 1 ); mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( this ), "terminate_on_pause", 1 ); // Return the consumer produced return this; } // malloc or consumer init failed free( this ); // Indicate failure return NULL; } static void serialise_properties( serialise_context context, mlt_properties properties, xmlNode *node ) { int i; xmlNode *p; // Enumerate the properties for ( i = 0; i < mlt_properties_count( properties ); i++ ) { char *name = mlt_properties_get_name( properties, i ); if ( name != NULL && name[ 0 ] != '_' && mlt_properties_get_value( properties, i ) != NULL && ( !context->no_meta || strncmp( name, "meta.", 5 ) ) && strcmp( name, "mlt" ) && strcmp( name, "in" ) && strcmp( name, "out" ) && strcmp( name, "id" ) && strcmp( name, "title" ) && strcmp( name, "root" ) && strcmp( name, "width" ) && strcmp( name, "height" ) ) { char *value = NULL; if ( !strcmp( name, "length" ) ) { char *time = mlt_properties_get_time( properties, name, context->time_format ); if ( time ) value = strdup( time ); } else value = filter_restricted( mlt_properties_get_value( properties, i ) ); if ( value ) { int rootlen = strlen( context->root ); // convert absolute path to relative if ( rootlen && !strncmp( value, context->root, rootlen ) && value[ rootlen ] == '/' ) p = xmlNewTextChild( node, NULL, _x("property"), _x(value + rootlen + 1 ) ); else p = xmlNewTextChild( node, NULL, _x("property"), _x(value) ); xmlNewProp( p, _x("name"), _x(name) ); free( value ); } } } } static void serialise_store_properties( serialise_context context, mlt_properties properties, xmlNode *node, const char *store ) { int i; xmlNode *p; // Enumerate the properties for ( i = 0; store != NULL && i < mlt_properties_count( properties ); i++ ) { char *name = mlt_properties_get_name( properties, i ); if ( !strncmp( name, store, strlen( store ) ) ) { char *value = filter_restricted( mlt_properties_get_value( properties, i ) ); if ( value ) { int rootlen = strlen( context->root ); // convert absolute path to relative if ( rootlen && !strncmp( value, context->root, rootlen ) && value[ rootlen ] == '/' ) p = xmlNewTextChild( node, NULL, _x("property"), _x(value + rootlen + 1) ); else p = xmlNewTextChild( node, NULL, _x("property"), _x(value) ); xmlNewProp( p, _x("name"), _x(name) ); free( value ); } } } } static inline void serialise_service_filters( serialise_context context, mlt_service service, xmlNode *node ) { int i; xmlNode *p; mlt_filter filter = NULL; // Enumerate the filters for ( i = 0; ( filter = mlt_producer_filter( MLT_PRODUCER( service ), i ) ) != NULL; i ++ ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); if ( mlt_properties_get_int( properties, "_loader" ) == 0 ) { // Get a new id - if already allocated, do nothing char *id = xml_get_id( context, MLT_FILTER_SERVICE( filter ), xml_filter ); if ( id != NULL ) { p = xmlNewChild( node, NULL, _x("filter"), NULL ); xmlNewProp( p, _x("id"), _x(id) ); if ( mlt_properties_get( properties, "title" ) ) xmlNewProp( p, _x("title"), _x(mlt_properties_get( properties, "title" )) ); if ( mlt_properties_get_position( properties, "in" ) ) xmlNewProp( p, _x("in"), _x( mlt_properties_get_time( properties, "in", context->time_format ) ) ); if ( mlt_properties_get_position( properties, "out" ) ) xmlNewProp( p, _x("out"), _x( mlt_properties_get_time( properties, "out", context->time_format ) ) ); serialise_properties( context, properties, p ); serialise_service_filters( context, MLT_FILTER_SERVICE( filter ), p ); } } } } static void serialise_producer( serialise_context context, mlt_service service, xmlNode *node ) { xmlNode *child = node; mlt_service parent = MLT_SERVICE( mlt_producer_cut_parent( MLT_PRODUCER( service ) ) ); if ( context->pass == 0 ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( parent ); // Get a new id - if already allocated, do nothing char *id = xml_get_id( context, parent, xml_producer ); if ( id == NULL ) return; child = xmlNewChild( node, NULL, _x("producer"), NULL ); // Set the id xmlNewProp( child, _x("id"), _x(id) ); if ( mlt_properties_get( properties, "title" ) ) xmlNewProp( child, _x("title"), _x(mlt_properties_get( properties, "title" )) ); xmlNewProp( child, _x("in"), _x(mlt_properties_get_time( properties, "in", context->time_format )) ); xmlNewProp( child, _x("out"), _x(mlt_properties_get_time( properties, "out", context->time_format )) ); serialise_properties( context, properties, child ); serialise_service_filters( context, service, child ); // Add producer to the map mlt_properties_set_int( context->hide_map, id, mlt_properties_get_int( properties, "hide" ) ); } else { char *id = xml_get_id( context, parent, xml_existing ); mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); xmlNewProp( node, _x("parent"), _x(id) ); xmlNewProp( node, _x("in"), _x(mlt_properties_get_time( properties, "in", context->time_format )) ); xmlNewProp( node, _x("out"), _x(mlt_properties_get_time( properties, "out", context->time_format )) ); } } static void serialise_tractor( serialise_context context, mlt_service service, xmlNode *node ); static void serialise_multitrack( serialise_context context, mlt_service service, xmlNode *node ) { int i; if ( context->pass == 0 ) { // Iterate over the tracks to collect the producers for ( i = 0; i < mlt_multitrack_count( MLT_MULTITRACK( service ) ); i++ ) { mlt_producer producer = mlt_producer_cut_parent( mlt_multitrack_track( MLT_MULTITRACK( service ), i ) ); serialise_service( context, MLT_SERVICE( producer ), node ); } } else { // Get a new id - if already allocated, do nothing char *id = xml_get_id( context, service, xml_multitrack ); if ( id == NULL ) return; // Serialise the tracks for ( i = 0; i < mlt_multitrack_count( MLT_MULTITRACK( service ) ); i++ ) { xmlNode *track = xmlNewChild( node, NULL, _x("track"), NULL ); int hide = 0; mlt_producer producer = mlt_multitrack_track( MLT_MULTITRACK( service ), i ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_service parent = MLT_SERVICE( mlt_producer_cut_parent( producer ) ); char *id = xml_get_id( context, MLT_SERVICE( parent ), xml_existing ); xmlNewProp( track, _x("producer"), _x(id) ); if ( mlt_producer_is_cut( producer ) ) { xmlNewProp( track, _x("in"), _x( mlt_properties_get_time( properties, "in", context->time_format ) ) ); xmlNewProp( track, _x("out"), _x( mlt_properties_get_time( properties, "out", context->time_format ) ) ); serialise_store_properties( context, MLT_PRODUCER_PROPERTIES( producer ), track, context->store ); if ( !context->no_meta ) serialise_store_properties( context, MLT_PRODUCER_PROPERTIES( producer ), track, "meta." ); serialise_service_filters( context, MLT_PRODUCER_SERVICE( producer ), track ); } hide = mlt_properties_get_int( context->hide_map, id ); if ( hide ) xmlNewProp( track, _x("hide"), _x( hide == 1 ? "video" : ( hide == 2 ? "audio" : "both" ) ) ); } serialise_service_filters( context, service, node ); } } static void serialise_playlist( serialise_context context, mlt_service service, xmlNode *node ) { int i; xmlNode *child = node; mlt_playlist_clip_info info; mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); if ( context->pass == 0 ) { // Get a new id - if already allocated, do nothing char *id = xml_get_id( context, service, xml_playlist ); if ( id == NULL ) return; // Iterate over the playlist entries to collect the producers for ( i = 0; i < mlt_playlist_count( MLT_PLAYLIST( service ) ); i++ ) { if ( ! mlt_playlist_get_clip_info( MLT_PLAYLIST( service ), &info, i ) ) { if ( info.producer != NULL ) { mlt_producer producer = mlt_producer_cut_parent( info.producer ); char *service_s = mlt_properties_get( MLT_PRODUCER_PROPERTIES( producer ), "mlt_service" ); char *resource_s = mlt_properties_get( MLT_PRODUCER_PROPERTIES( producer ), "resource" ); if ( resource_s != NULL && !strcmp( resource_s, "" ) ) serialise_playlist( context, MLT_SERVICE( producer ), node ); else if ( service_s != NULL && strcmp( service_s, "blank" ) != 0 ) serialise_service( context, MLT_SERVICE( producer ), node ); } } } child = xmlNewChild( node, NULL, _x("playlist"), NULL ); // Set the id xmlNewProp( child, _x("id"), _x(id) ); if ( mlt_properties_get( properties, "title" ) ) xmlNewProp( child, _x("title"), _x(mlt_properties_get( properties, "title" )) ); // Store application specific properties serialise_store_properties( context, properties, child, context->store ); if ( !context->no_meta ) serialise_store_properties( context, properties, child, "meta." ); // Add producer to the map mlt_properties_set_int( context->hide_map, id, mlt_properties_get_int( properties, "hide" ) ); // Iterate over the playlist entries for ( i = 0; i < mlt_playlist_count( MLT_PLAYLIST( service ) ); i++ ) { if ( ! mlt_playlist_get_clip_info( MLT_PLAYLIST( service ), &info, i ) ) { mlt_producer producer = mlt_producer_cut_parent( info.producer ); mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); char *service_s = mlt_properties_get( producer_props, "mlt_service" ); if ( service_s != NULL && strcmp( service_s, "blank" ) == 0 ) { xmlNode *entry = xmlNewChild( child, NULL, _x("blank"), NULL ); mlt_properties_set_data( producer_props, "_profile", context->profile, 0, NULL, NULL ); mlt_properties_set_position( producer_props, TIME_PROPERTY, info.frame_count ); xmlNewProp( entry, _x("length"), _x( mlt_properties_get_time( producer_props, TIME_PROPERTY, context->time_format ) ) ); } else { char temp[ 20 ]; xmlNode *entry = xmlNewChild( child, NULL, _x("entry"), NULL ); id = xml_get_id( context, MLT_SERVICE( producer ), xml_existing ); xmlNewProp( entry, _x("producer"), _x(id) ); mlt_properties_set_position( producer_props, TIME_PROPERTY, info.frame_in ); xmlNewProp( entry, _x("in"), _x( mlt_properties_get_time( producer_props, TIME_PROPERTY, context->time_format ) ) ); mlt_properties_set_position( producer_props, TIME_PROPERTY, info.frame_out ); xmlNewProp( entry, _x("out"), _x( mlt_properties_get_time( producer_props, TIME_PROPERTY, context->time_format ) ) ); if ( info.repeat > 1 ) { sprintf( temp, "%d", info.repeat ); xmlNewProp( entry, _x("repeat"), _x(temp) ); } if ( mlt_producer_is_cut( info.cut ) ) { serialise_store_properties( context, MLT_PRODUCER_PROPERTIES( info.cut ), entry, context->store ); if ( !context->no_meta ) serialise_store_properties( context, MLT_PRODUCER_PROPERTIES( info.cut ), entry, "meta." ); serialise_service_filters( context, MLT_PRODUCER_SERVICE( info.cut ), entry ); } } } } serialise_service_filters( context, service, child ); } else if ( xmlStrcmp( node->name, _x("tractor") ) != 0 ) { char *id = xml_get_id( context, service, xml_existing ); xmlNewProp( node, _x("producer"), _x(id) ); } } static void serialise_tractor( serialise_context context, mlt_service service, xmlNode *node ) { xmlNode *child = node; mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); if ( context->pass == 0 ) { // Recurse on connected producer serialise_service( context, mlt_service_producer( service ), node ); } else { // Get a new id - if already allocated, do nothing char *id = xml_get_id( context, service, xml_tractor ); if ( id == NULL ) return; child = xmlNewChild( node, NULL, _x("tractor"), NULL ); // Set the id xmlNewProp( child, _x("id"), _x(id) ); if ( mlt_properties_get( properties, "title" ) ) xmlNewProp( child, _x("title"), _x(mlt_properties_get( properties, "title" )) ); if ( mlt_properties_get( properties, "global_feed" ) ) xmlNewProp( child, _x("global_feed"), _x(mlt_properties_get( properties, "global_feed" )) ); xmlNewProp( child, _x("in"), _x(mlt_properties_get_time( properties, "in", context->time_format )) ); xmlNewProp( child, _x("out"), _x(mlt_properties_get_time( properties, "out", context->time_format )) ); // Store application specific properties serialise_store_properties( context, MLT_SERVICE_PROPERTIES( service ), child, context->store ); if ( !context->no_meta ) serialise_store_properties( context, MLT_SERVICE_PROPERTIES( service ), child, "meta." ); // Recurse on connected producer serialise_service( context, mlt_service_producer( service ), child ); serialise_service_filters( context, service, child ); } } static void serialise_filter( serialise_context context, mlt_service service, xmlNode *node ) { xmlNode *child = node; mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); // Recurse on connected producer serialise_service( context, mlt_service_producer( service ), node ); if ( context->pass == 1 ) { // Get a new id - if already allocated, do nothing char *id = xml_get_id( context, service, xml_filter ); if ( id == NULL ) return; child = xmlNewChild( node, NULL, _x("filter"), NULL ); // Set the id xmlNewProp( child, _x("id"), _x(id) ); if ( mlt_properties_get( properties, "title" ) ) xmlNewProp( child, _x("title"), _x(mlt_properties_get( properties, "title" )) ); if ( mlt_properties_get_position( properties, "in" ) ) xmlNewProp( child, _x("in"), _x( mlt_properties_get_time( properties, "in", context->time_format ) ) ); if ( mlt_properties_get_position( properties, "out" ) ) xmlNewProp( child, _x("out"), _x( mlt_properties_get_time( properties, "out", context->time_format ) ) ); serialise_properties( context, properties, child ); serialise_service_filters( context, service, child ); } } static void serialise_transition( serialise_context context, mlt_service service, xmlNode *node ) { xmlNode *child = node; mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); // Recurse on connected producer serialise_service( context, MLT_SERVICE( MLT_TRANSITION( service )->producer ), node ); if ( context->pass == 1 ) { // Get a new id - if already allocated, do nothing char *id = xml_get_id( context, service, xml_transition ); if ( id == NULL ) return; child = xmlNewChild( node, NULL, _x("transition"), NULL ); // Set the id xmlNewProp( child, _x("id"), _x(id) ); if ( mlt_properties_get( properties, "title" ) ) xmlNewProp( child, _x("title"), _x(mlt_properties_get( properties, "title" )) ); if ( mlt_properties_get_position( properties, "in" ) ) xmlNewProp( child, _x("in"), _x( mlt_properties_get_time( properties, "in", context->time_format ) ) ); if ( mlt_properties_get_position( properties, "out" ) ) xmlNewProp( child, _x("out"), _x( mlt_properties_get_time( properties, "out", context->time_format ) ) ); serialise_properties( context, properties, child ); serialise_service_filters( context, service, child ); } } static void serialise_service( serialise_context context, mlt_service service, xmlNode *node ) { // Iterate over consumer/producer connections while ( service != NULL ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); char *mlt_type = mlt_properties_get( properties, "mlt_type" ); // Tell about the producer if ( strcmp( mlt_type, "producer" ) == 0 ) { char *mlt_service = mlt_properties_get( properties, "mlt_service" ); if ( mlt_properties_get( properties, "xml" ) == NULL && ( mlt_service != NULL && !strcmp( mlt_service, "tractor" ) ) ) { context->pass = 0; serialise_tractor( context, service, node ); context->pass = 1; serialise_tractor( context, service, node ); context->pass = 0; break; } else { serialise_producer( context, service, node ); } if ( mlt_properties_get( properties, "xml" ) != NULL ) break; } // Tell about the framework container producers else if ( strcmp( mlt_type, "mlt_producer" ) == 0 ) { char *resource = mlt_properties_get( properties, "resource" ); // Recurse on multitrack's tracks if ( resource && strcmp( resource, "" ) == 0 ) { serialise_multitrack( context, service, node ); break; } // Recurse on playlist's clips else if ( resource && strcmp( resource, "" ) == 0 ) { serialise_playlist( context, service, node ); } // Recurse on tractor's producer else if ( resource && strcmp( resource, "" ) == 0 ) { context->pass = 0; serialise_tractor( context, service, node ); context->pass = 1; serialise_tractor( context, service, node ); context->pass = 0; break; } // Treat it as a normal producer else { serialise_producer( context, service, node ); } } // Tell about a filter else if ( strcmp( mlt_type, "filter" ) == 0 ) { serialise_filter( context, service, node ); break; } // Tell about a transition else if ( strcmp( mlt_type, "transition" ) == 0 ) { serialise_transition( context, service, node ); break; } // Get the next connected service service = mlt_service_producer( service ); } } xmlDocPtr xml_make_doc( mlt_consumer consumer, mlt_service service ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); xmlDocPtr doc = xmlNewDoc( _x("1.0") ); xmlNodePtr root = xmlNewNode( NULL, _x("mlt") ); struct serialise_context_s *context = calloc( 1, sizeof( struct serialise_context_s ) ); mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( consumer ) ); char tmpstr[ 32 ]; xmlDocSetRootElement( doc, root ); // Indicate the numeric locale xmlNewProp( root, _x("LC_NUMERIC"), _x( setlocale( LC_NUMERIC, NULL ) ) ); // Indicate the version xmlNewProp( root, _x("version"), _x( mlt_version_get_string() ) ); // If we have root, then deal with it now if ( mlt_properties_get( properties, "root" ) != NULL ) { xmlNewProp( root, _x("root"), _x(mlt_properties_get( properties, "root" )) ); context->root = strdup( mlt_properties_get( properties, "root" ) ); } else { context->root = strdup( "" ); } // Assign the additional 'storage' pattern for properties context->store = mlt_properties_get( MLT_CONSUMER_PROPERTIES( consumer ), "store" ); context->no_meta = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( consumer ), "no_meta" ); const char *time_format = mlt_properties_get( MLT_CONSUMER_PROPERTIES( consumer ), "time_format" ); if ( time_format && ( !strcmp( time_format, "smpte" ) || !strcmp( time_format, "SMPTE" ) || !strcmp( time_format, "timecode" ) ) ) context->time_format = mlt_time_smpte; else if ( time_format && ( !strcmp( time_format, "clock" ) || !strcmp( time_format, "CLOCK" ) ) ) context->time_format = mlt_time_clock; // Assign a title property if ( mlt_properties_get( properties, "title" ) != NULL ) xmlNewProp( root, _x("title"), _x(mlt_properties_get( properties, "title" )) ); mlt_properties_set_int( properties, "global_feed", 1 ); // Add a profile child element if ( profile ) { xmlNodePtr profile_node = xmlNewChild( root, NULL, _x("profile"), NULL ); if ( profile->description ) xmlNewProp( profile_node, _x("description"), _x(profile->description) ); sprintf( tmpstr, "%d", profile->width ); xmlNewProp( profile_node, _x("width"), _x(tmpstr) ); sprintf( tmpstr, "%d", profile->height ); xmlNewProp( profile_node, _x("height"), _x(tmpstr) ); sprintf( tmpstr, "%d", profile->progressive ); xmlNewProp( profile_node, _x("progressive"), _x(tmpstr) ); sprintf( tmpstr, "%d", profile->sample_aspect_num ); xmlNewProp( profile_node, _x("sample_aspect_num"), _x(tmpstr) ); sprintf( tmpstr, "%d", profile->sample_aspect_den ); xmlNewProp( profile_node, _x("sample_aspect_den"), _x(tmpstr) ); sprintf( tmpstr, "%d", profile->display_aspect_num ); xmlNewProp( profile_node, _x("display_aspect_num"), _x(tmpstr) ); sprintf( tmpstr, "%d", profile->display_aspect_den ); xmlNewProp( profile_node, _x("display_aspect_den"), _x(tmpstr) ); sprintf( tmpstr, "%d", profile->frame_rate_num ); xmlNewProp( profile_node, _x("frame_rate_num"), _x(tmpstr) ); sprintf( tmpstr, "%d", profile->frame_rate_den ); xmlNewProp( profile_node, _x("frame_rate_den"), _x(tmpstr) ); sprintf( tmpstr, "%d", profile->colorspace ); xmlNewProp( profile_node, _x("colorspace"), _x(tmpstr) ); context->profile = profile; } // Construct the context maps context->id_map = mlt_properties_new(); context->hide_map = mlt_properties_new(); // Ensure producer is a framework producer mlt_properties_set( MLT_SERVICE_PROPERTIES( service ), "mlt_type", "mlt_producer" ); // In pass one, we serialise the end producers and playlists, // adding them to a map keyed by address. serialise_service( context, service, root ); // In pass two, we serialise the tractor and reference the // producers and playlists context->pass++; serialise_service( context, service, root ); // Cleanup resource mlt_properties_close( context->id_map ); mlt_properties_close( context->hide_map ); free( context->root ); free( context ); return doc; } static void output_xml( mlt_consumer this ) { // Get the producer service mlt_service service = mlt_service_producer( MLT_CONSUMER_SERVICE( this ) ); mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); char *resource = mlt_properties_get( properties, "resource" ); xmlDocPtr doc = NULL; if ( !service ) return; // Set the title if provided if ( mlt_properties_get( properties, "title" ) ) mlt_properties_set( MLT_SERVICE_PROPERTIES( service ), "title", mlt_properties_get( properties, "title" ) ); else if ( mlt_properties_get( MLT_SERVICE_PROPERTIES( service ), "title" ) == NULL ) mlt_properties_set( MLT_SERVICE_PROPERTIES( service ), "title", "Anonymous Submission" ); // Check for a root on the consumer properties and pass to service if ( mlt_properties_get( properties, "root" ) ) mlt_properties_set( MLT_SERVICE_PROPERTIES( service ), "root", mlt_properties_get( properties, "root" ) ); // Specify roots in other cases... if ( resource != NULL && mlt_properties_get( properties, "root" ) == NULL ) { // Get the current working directory char *cwd = getcwd( NULL, 0 ); mlt_properties_set( MLT_SERVICE_PROPERTIES( service ), "root", cwd ); free( cwd ); } // Make the document doc = xml_make_doc( this, service ); // Handle the output if ( resource == NULL || !strcmp( resource, "" ) ) { xmlDocFormatDump( stdout, doc, 1 ); } else if ( strchr( resource, '.' ) == NULL ) { xmlChar *buffer = NULL; int length = 0; xmlDocDumpMemoryEnc( doc, &buffer, &length, "utf-8" ); mlt_properties_set( properties, resource, _s(buffer) ); #ifdef WIN32 xmlFreeFunc xmlFree = NULL; xmlMemGet( &xmlFree, NULL, NULL, NULL); #endif xmlFree( buffer ); } else { xmlSaveFormatFileEnc( resource, doc, "utf-8", 1 ); } // Close the document xmlFreeDoc( doc ); } static int consumer_start( mlt_consumer this ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); if ( mlt_properties_get_int( properties, "all" ) ) { // Check that we're not already running if ( !mlt_properties_get_int( properties, "running" ) ) { // Allocate a thread pthread_t *thread = calloc( 1, sizeof( pthread_t ) ); // Assign the thread to properties mlt_properties_set_data( properties, "thread", thread, sizeof( pthread_t ), free, NULL ); // Set the running state mlt_properties_set_int( properties, "running", 1 ); mlt_properties_set_int( properties, "joined", 0 ); // Create the thread pthread_create( thread, NULL, consumer_thread, this ); } } else { output_xml( this ); mlt_consumer_stop( this ); mlt_consumer_stopped( this ); } return 0; } static int consumer_is_stopped( mlt_consumer this ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); return !mlt_properties_get_int( properties, "running" ); } static int consumer_stop( mlt_consumer this ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); // Check that we're running if ( !mlt_properties_get_int( properties, "joined" ) ) { // Get the thread pthread_t *thread = mlt_properties_get_data( properties, "thread", NULL ); // Stop the thread mlt_properties_set_int( properties, "running", 0 ); mlt_properties_set_int( properties, "joined", 1 ); // Wait for termination if ( thread ) pthread_join( *thread, NULL ); } return 0; } static void *consumer_thread( void *arg ) { // Map the argument to the object mlt_consumer this = arg; // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); // Convenience functionality int terminate_on_pause = mlt_properties_get_int( properties, "terminate_on_pause" ); int terminated = 0; // Frame and size mlt_frame frame = NULL; // Loop while running while( !terminated && mlt_properties_get_int( properties, "running" ) ) { // Get the frame frame = mlt_consumer_rt_frame( this ); // Check for termination if ( terminate_on_pause && frame != NULL ) terminated = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0; // Check that we have a frame to work with if ( frame ) { int width = 0, height = 0; int frequency = mlt_properties_get_int( properties, "frequency" ); int channels = mlt_properties_get_int( properties, "channels" ); int samples = 0; mlt_image_format iformat = mlt_image_yuv422; mlt_audio_format aformat = mlt_audio_s16; uint8_t *buffer; mlt_frame_get_image( frame, &buffer, &iformat, &width, &height, 0 ); mlt_frame_get_audio( frame, (void**) &buffer, &aformat, &frequency, &channels, &samples ); // Close the frame mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); mlt_frame_close( frame ); } } output_xml( this ); // Indicate that the consumer is stopped mlt_properties_set_int( properties, "running", 0 ); mlt_consumer_stopped( this ); return NULL; } mlt-0.9.0/src/modules/xml/consumer_xml.yml000066400000000000000000000047071215300731300206140ustar00rootroot00000000000000schema_version: 0.1 type: consumer identifier: xml title: XML version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Audio - Video description: > Serialise the service network to XML. See docs/mlt-xml.txt for more information. bugs: - Untested arbitrary nesting of multitracks and playlists. - > Property "id" is generated as service type followed by number if no property named "id" exists, but it fails to guarantee uniqueness. parameters: - identifier: argument title: File type: string description: > The name of a file in which to store the XML. If the value does not contain a period (to start an extension), then the value is interpreted as the name of a propery in which to store the XML. This makes it easy for an application to use the consumer to serialize a service network and retrieve the XML in-memory. readonly: no required: no mutable: no default: stdout widget: fileopen - identifier: all title: Process all frames type: integer description: > Without this option, the XML consumer does not process any frames and simply serializes the service network. However, some filters (.e.g, videostab) require two passes where the first pass performs some analysis and stores the result in a property. Therefore, set this property to 1 (true) to cause the consumer to process all frames before serializing to XML. minimum: 0 maximum: 1 default: 0 - identifier: title title: Title type: string description: > You can give the composition a friendly name that some applications may use. - identifier: root title: Base path type: string description: > If a file name in the XML is relative, but not relative to the current XML file's directory, then you can set the directory to which it is relative here. - identifier: no_meta title: Exclude meta properties type: integer description: > Set this to disable the output of properties with the prefix "meta." minimum: 0 maximum: 1 default: 0 widget: checkbox - identifier: time_format title: Time format type: string description: Output time-based values as timecode or clock formats. values: - frames - smpte # or SMPTE - timecode # same as smpte - clock # or CLOCK default: frames widget: dropdown mlt-0.9.0/src/modules/xml/factory.c000066400000000000000000000035361215300731300171700ustar00rootroot00000000000000/* * factory.c -- the factory method interfaces * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include extern mlt_consumer consumer_xml_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_xml_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; snprintf( file, PATH_MAX, "%s/xml/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { MLT_REGISTER( consumer_type, "xml", consumer_xml_init ); MLT_REGISTER( producer_type, "xml", producer_xml_init ); MLT_REGISTER( producer_type, "xml-string", producer_xml_init ); MLT_REGISTER_METADATA( consumer_type, "xml", metadata, "consumer_xml.yml" ); MLT_REGISTER_METADATA( producer_type, "xml", metadata, "producer_xml.yml" ); MLT_REGISTER_METADATA( producer_type, "xml-string", metadata, "producer_xml-string.yml" ); } mlt-0.9.0/src/modules/xml/mlt-xml.dtd000066400000000000000000000050621215300731300174400ustar00rootroot00000000000000 mlt-0.9.0/src/modules/xml/producer_xml-string.yml000066400000000000000000000003151215300731300220770ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: xml-string title: XML String version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Audio - Video mlt-0.9.0/src/modules/xml/producer_xml.c000066400000000000000000001641601215300731300202250ustar00rootroot00000000000000/* * producer_xml.c -- a libxml2 parser of mlt service networks * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // TODO: destroy unreferenced producers (they are currently destroyed // when the returned producer is closed). #include #include #include #include #include #include #include #include // for xmlCreateFileParserCtxt #include #define STACK_SIZE 1000 #define BRANCH_SIG_LEN 4000 #define _x (const xmlChar*) #define _s (const char*) #undef DEBUG #ifdef DEBUG extern xmlDocPtr xml_make_doc( mlt_service service ); #endif enum service_type { mlt_invalid_type, mlt_unknown_type, mlt_producer_type, mlt_playlist_type, mlt_entry_type, mlt_tractor_type, mlt_multitrack_type, mlt_filter_type, mlt_transition_type, mlt_consumer_type, mlt_field_type, mlt_services_type, mlt_dummy_filter_type, mlt_dummy_transition_type, mlt_dummy_producer_type, mlt_dummy_consumer_type }; struct deserialise_context_s { enum service_type stack_types[ STACK_SIZE ]; mlt_service stack_service[ STACK_SIZE ]; int stack_service_size; mlt_properties producer_map; mlt_properties destructors; char *property; int is_value; xmlDocPtr value_doc; xmlNodePtr stack_node[ STACK_SIZE ]; int stack_node_size; xmlDocPtr entity_doc; int entity_is_replace; int depth; int branch[ STACK_SIZE ]; const xmlChar *publicId; const xmlChar *systemId; mlt_properties params; mlt_profile profile; int pass; char *lc_numeric; mlt_consumer consumer; int multi_consumer; int consumer_count; int seekable; mlt_consumer qglsl; }; typedef struct deserialise_context_s *deserialise_context; /** Trim the leading and trailing whitespace from a string in-place. */ static char* trim( char *s ) { int n; if ( s && ( n = strlen( s ) ) ) { int i = 0; while ( i < n && isspace( s[i] ) ) i++; while ( --n && isspace( s[n] ) ); n = n - i + 1; if ( n > 0 ) memmove( s, s + i, n ); s[ n ] = 0; } return s; } /** Convert the numerical current branch address to a dot-delimited string. */ static char *serialise_branch( deserialise_context context, char *s ) { int i; s[0] = 0; for ( i = 0; i < context->depth; i++ ) { int len = strlen( s ); snprintf( s + len, BRANCH_SIG_LEN - len, "%d.", context->branch[ i ] ); } return s; } /** Push a service. */ static int context_push_service( deserialise_context context, mlt_service that, enum service_type type ) { int ret = context->stack_service_size >= STACK_SIZE - 1; if ( ret == 0 ) { context->stack_service[ context->stack_service_size ] = that; context->stack_types[ context->stack_service_size++ ] = type; // Record the tree branch on which this service lives if ( that != NULL && mlt_properties_get( MLT_SERVICE_PROPERTIES( that ), "_xml_branch" ) == NULL ) { char s[ BRANCH_SIG_LEN ]; mlt_properties_set( MLT_SERVICE_PROPERTIES( that ), "_xml_branch", serialise_branch( context, s ) ); } } return ret; } /** Pop a service. */ static mlt_service context_pop_service( deserialise_context context, enum service_type *type ) { mlt_service result = NULL; if ( type ) *type = mlt_invalid_type; if ( context->stack_service_size > 0 ) { result = context->stack_service[ -- context->stack_service_size ]; if ( type != NULL ) *type = context->stack_types[ context->stack_service_size ]; // Set the service's profile and locale so mlt_property time-to-position conversions can get fps if ( result ) { mlt_properties_set_data( MLT_SERVICE_PROPERTIES( result ), "_profile", context->profile, 0, NULL, NULL ); mlt_properties_set_lcnumeric( MLT_SERVICE_PROPERTIES( result ), context->lc_numeric ); } } return result; } /** Push a node. */ static int context_push_node( deserialise_context context, xmlNodePtr node ) { int ret = context->stack_node_size >= STACK_SIZE - 1; if ( ret == 0 ) context->stack_node[ context->stack_node_size ++ ] = node; return ret; } /** Pop a node. */ static xmlNodePtr context_pop_node( deserialise_context context ) { xmlNodePtr result = NULL; if ( context->stack_node_size > 0 ) result = context->stack_node[ -- context->stack_node_size ]; return result; } // Set the destructor on a new service static void track_service( mlt_properties properties, void *service, mlt_destructor destructor ) { int registered = mlt_properties_get_int( properties, "registered" ); char *key = mlt_properties_get( properties, "registered" ); mlt_properties_set_data( properties, key, service, 0, destructor, NULL ); mlt_properties_set_int( properties, "registered", ++ registered ); } // Prepend the property value with the document root static inline void qualify_property( deserialise_context context, mlt_properties properties, const char *name ) { char *resource = mlt_properties_get( properties, name ); if ( resource != NULL && resource[0] ) { // Qualify file name properties char *root = mlt_properties_get( context->producer_map, "root" ); if ( root != NULL && strcmp( root, "" ) ) { char *full_resource = malloc( strlen( root ) + strlen( resource ) + 2 ); if ( resource[ 0 ] != '/' && strchr( resource, ':' ) == NULL ) { strcpy( full_resource, root ); strcat( full_resource, "/" ); strcat( full_resource, resource ); } else { strcpy( full_resource, resource ); } mlt_properties_set( properties, name, full_resource ); free( full_resource ); } } } /** This function adds a producer to a playlist or multitrack when there is no entry or track element. */ static int add_producer( deserialise_context context, mlt_service service, mlt_position in, mlt_position out ) { // Return value (0 = service remains top of stack, 1 means it can be removed) int result = 0; // Get the parent producer enum service_type type = mlt_invalid_type; mlt_service container = context_pop_service( context, &type ); int contained = 0; if ( service != NULL && container != NULL ) { char *container_branch = mlt_properties_get( MLT_SERVICE_PROPERTIES( container ), "_xml_branch" ); char *service_branch = mlt_properties_get( MLT_SERVICE_PROPERTIES( service ), "_xml_branch" ); contained = !strncmp( container_branch, service_branch, strlen( container_branch ) ); } if ( contained ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); char *hide_s = mlt_properties_get( properties, "hide" ); // Indicate that this service is no longer top of stack result = 1; switch( type ) { case mlt_tractor_type: { mlt_multitrack multitrack = mlt_tractor_multitrack( MLT_TRACTOR( container ) ); mlt_multitrack_connect( multitrack, MLT_PRODUCER( service ), mlt_multitrack_count( multitrack ) ); } break; case mlt_multitrack_type: { mlt_multitrack_connect( MLT_MULTITRACK( container ), MLT_PRODUCER( service ), mlt_multitrack_count( MLT_MULTITRACK( container ) ) ); } break; case mlt_playlist_type: { mlt_playlist_append_io( MLT_PLAYLIST( container ), MLT_PRODUCER( service ), in, out ); } break; default: result = 0; mlt_log_warning( NULL, "[producer_xml] Producer defined inside something that isn't a container\n" ); break; }; // Set the hide state of the track producer if ( hide_s != NULL ) { if ( strcmp( hide_s, "video" ) == 0 ) mlt_properties_set_int( properties, "hide", 1 ); else if ( strcmp( hide_s, "audio" ) == 0 ) mlt_properties_set_int( properties, "hide", 2 ); else if ( strcmp( hide_s, "both" ) == 0 ) mlt_properties_set_int( properties, "hide", 3 ); } } // Put the parent producer back if ( container != NULL ) context_push_service( context, container, type ); return result; } /** Attach filters defined on that to this. */ static void attach_filters( mlt_service service, mlt_service that ) { if ( that != NULL ) { int i = 0; mlt_filter filter = NULL; for ( i = 0; ( filter = mlt_service_filter( that, i ) ) != NULL; i ++ ) { mlt_service_attach( service, filter ); attach_filters( MLT_FILTER_SERVICE( filter ), MLT_FILTER_SERVICE( filter ) ); } } } static void on_start_profile( deserialise_context context, const xmlChar *name, const xmlChar **atts) { mlt_profile p = context->profile; for ( ; atts != NULL && *atts != NULL; atts += 2 ) { if ( xmlStrcmp( atts[ 0 ], _x("name") ) == 0 || xmlStrcmp( atts[ 0 ], _x("profile") ) == 0 ) { mlt_profile my_profile = mlt_profile_init( _s(atts[ 1 ]) ); if ( my_profile ) { p->description = strdup( my_profile->description ); p->display_aspect_den = my_profile->display_aspect_den; p->display_aspect_num = my_profile->display_aspect_num; p->frame_rate_den = my_profile->frame_rate_den; p->frame_rate_num = my_profile->frame_rate_num; p->width = my_profile->width; p->height = my_profile->height; p->progressive = my_profile->progressive; p->sample_aspect_den = my_profile->sample_aspect_den; p->sample_aspect_num = my_profile->sample_aspect_num; p->colorspace = my_profile->colorspace; p->is_explicit = 1; mlt_profile_close( my_profile ); } } else if ( xmlStrcmp( atts[ 0 ], _x("description") ) == 0 ) { if ( p->description ) free( p->description ); p->description = strdup( _s(atts[ 1 ]) ); p->is_explicit = 1; } else if ( xmlStrcmp( atts[ 0 ], _x("display_aspect_den") ) == 0 ) p->display_aspect_den = strtol( _s(atts[ 1 ]), NULL, 0 ); else if ( xmlStrcmp( atts[ 0 ], _x("display_aspect_num") ) == 0 ) p->display_aspect_num = strtol( _s(atts[ 1 ]), NULL, 0 ); else if ( xmlStrcmp( atts[ 0 ], _x("sample_aspect_num") ) == 0 ) p->sample_aspect_num = strtol( _s(atts[ 1 ]), NULL, 0 ); else if ( xmlStrcmp( atts[ 0 ], _x("sample_aspect_den") ) == 0 ) p->sample_aspect_den = strtol( _s(atts[ 1 ]), NULL, 0 ); else if ( xmlStrcmp( atts[ 0 ], _x("width") ) == 0 ) p->width = strtol( _s(atts[ 1 ]), NULL, 0 ); else if ( xmlStrcmp( atts[ 0 ], _x("height") ) == 0 ) p->height = strtol( _s(atts[ 1 ]), NULL, 0 ); else if ( xmlStrcmp( atts[ 0 ], _x("progressive") ) == 0 ) p->progressive = strtol( _s(atts[ 1 ]), NULL, 0 ); else if ( xmlStrcmp( atts[ 0 ], _x("frame_rate_num") ) == 0 ) p->frame_rate_num = strtol( _s(atts[ 1 ]), NULL, 0 ); else if ( xmlStrcmp( atts[ 0 ], _x("frame_rate_den") ) == 0 ) p->frame_rate_den = strtol( _s(atts[ 1 ]), NULL, 0 ); else if ( xmlStrcmp( atts[ 0 ], _x("colorspace") ) == 0 ) p->colorspace = strtol( _s(atts[ 1 ]), NULL, 0 ); } } static void on_start_tractor( deserialise_context context, const xmlChar *name, const xmlChar **atts) { mlt_tractor tractor = mlt_tractor_new( ); mlt_service service = MLT_TRACTOR_SERVICE( tractor ); mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); track_service( context->destructors, service, (mlt_destructor) mlt_tractor_close ); mlt_properties_set_lcnumeric( MLT_SERVICE_PROPERTIES( service ), context->lc_numeric ); for ( ; atts != NULL && *atts != NULL; atts += 2 ) mlt_properties_set( MLT_SERVICE_PROPERTIES( service ), (const char*) atts[0], atts[1] == NULL ? "" : (const char*) atts[1] ); mlt_properties_set_int( MLT_TRACTOR_PROPERTIES( tractor ), "global_feed", 1 ); if ( mlt_properties_get( properties, "id" ) != NULL ) mlt_properties_set_data( context->producer_map, mlt_properties_get( properties, "id" ), service, 0, NULL, NULL ); context_push_service( context, service, mlt_tractor_type ); } static void on_end_tractor( deserialise_context context, const xmlChar *name ) { // Get the tractor enum service_type type; mlt_service tractor = context_pop_service( context, &type ); if ( tractor != NULL && type == mlt_tractor_type ) { // See if the tractor should be added to a playlist or multitrack if ( add_producer( context, tractor, 0, mlt_producer_get_out( MLT_PRODUCER( tractor ) ) ) == 0 ) context_push_service( context, tractor, type ); } else { mlt_log_error( NULL, "[producer_xml] Invalid state for tractor\n" ); } } static void on_start_multitrack( deserialise_context context, const xmlChar *name, const xmlChar **atts) { enum service_type type; mlt_service parent = context_pop_service( context, &type ); // If we don't have a parent, then create one now, providing we're in a state where we can if ( parent == NULL || ( type == mlt_playlist_type || type == mlt_multitrack_type ) ) { mlt_tractor tractor = NULL; // Push the parent back if ( parent != NULL ) context_push_service( context, parent, type ); // Create a tractor to contain the multitrack tractor = mlt_tractor_new( ); parent = MLT_TRACTOR_SERVICE( tractor ); track_service( context->destructors, parent, (mlt_destructor) mlt_tractor_close ); mlt_properties_set_lcnumeric( MLT_SERVICE_PROPERTIES( parent ), context->lc_numeric ); type = mlt_tractor_type; // Flag it as a synthesised tractor for clean up later mlt_properties_set_int( MLT_SERVICE_PROPERTIES( parent ), "loader_synth", 1 ); } if ( type == mlt_tractor_type ) { mlt_service service = MLT_SERVICE( mlt_tractor_multitrack( MLT_TRACTOR( parent ) ) ); mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); for ( ; atts != NULL && *atts != NULL; atts += 2 ) mlt_properties_set( properties, (const char*) atts[0], atts[1] == NULL ? "" : (const char*) atts[1] ); if ( mlt_properties_get( properties, "id" ) != NULL ) mlt_properties_set_data( context->producer_map, mlt_properties_get( properties,"id" ), service, 0, NULL, NULL ); context_push_service( context, parent, type ); context_push_service( context, service, mlt_multitrack_type ); } else { mlt_log_error( NULL, "[producer_xml] Invalid multitrack position\n" ); } } static void on_end_multitrack( deserialise_context context, const xmlChar *name ) { // Get the multitrack from the stack enum service_type type; mlt_service service = context_pop_service( context, &type ); if ( service == NULL || type != mlt_multitrack_type ) mlt_log_error( NULL, "[producer_xml] End multitrack in the wrong state...\n" ); } static void on_start_playlist( deserialise_context context, const xmlChar *name, const xmlChar **atts) { mlt_playlist playlist = mlt_playlist_new( context->profile ); mlt_service service = MLT_PLAYLIST_SERVICE( playlist ); mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); track_service( context->destructors, service, (mlt_destructor) mlt_playlist_close ); for ( ; atts != NULL && *atts != NULL; atts += 2 ) { mlt_properties_set( properties, (const char*) atts[0], atts[1] == NULL ? "" : (const char*) atts[1] ); // Out will be overwritten later as we append, so we need to save it if ( xmlStrcmp( atts[ 0 ], _x("out") ) == 0 ) mlt_properties_set( properties, "_xml.out", ( const char* )atts[ 1 ] ); } if ( mlt_properties_get( properties, "id" ) != NULL ) mlt_properties_set_data( context->producer_map, mlt_properties_get( properties, "id" ), service, 0, NULL, NULL ); context_push_service( context, service, mlt_playlist_type ); } static void on_end_playlist( deserialise_context context, const xmlChar *name ) { // Get the playlist from the stack enum service_type type; mlt_service service = context_pop_service( context, &type ); if ( service != NULL && type == mlt_playlist_type ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); mlt_position in = -1; mlt_position out = -1; if ( mlt_properties_get( properties, "in" ) ) in = mlt_properties_get_position( properties, "in" ); if ( mlt_properties_get( properties, "out" ) ) out = mlt_properties_get_position( properties, "out" ); // See if the playlist should be added to a playlist or multitrack if ( add_producer( context, service, in, out ) == 0 ) context_push_service( context, service, type ); } else { mlt_log_error( NULL, "[producer_xml] Invalid state of playlist end %d\n", type ); } } static void on_start_producer( deserialise_context context, const xmlChar *name, const xmlChar **atts) { // use a dummy service to hold properties to allow arbitrary nesting mlt_service service = calloc( 1, sizeof( struct mlt_service_s ) ); mlt_service_init( service, NULL ); mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); context_push_service( context, service, mlt_dummy_producer_type ); for ( ; atts != NULL && *atts != NULL; atts += 2 ) mlt_properties_set( properties, (const char*) atts[0], atts[1] == NULL ? "" : (const char*) atts[1] ); } static void on_end_producer( deserialise_context context, const xmlChar *name ) { enum service_type type; mlt_service service = context_pop_service( context, &type ); mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); if ( service != NULL && type == mlt_dummy_producer_type ) { mlt_service producer = NULL; qualify_property( context, properties, "resource" ); char *resource = mlt_properties_get( properties, "resource" ); // Let Kino-SMIL src be a synonym for resource if ( resource == NULL ) { qualify_property( context, properties, "src" ); resource = mlt_properties_get( properties, "src" ); } // Instantiate the producer if ( mlt_properties_get( properties, "mlt_service" ) != NULL ) { char *service_name = trim( mlt_properties_get( properties, "mlt_service" ) ); if ( resource ) { char *temp = calloc( 1, strlen( service_name ) + strlen( resource ) + 2 ); strcat( temp, service_name ); strcat( temp, ":" ); strcat( temp, resource ); producer = MLT_SERVICE( mlt_factory_producer( context->profile, NULL, temp ) ); free( temp ); } else { producer = MLT_SERVICE( mlt_factory_producer( context->profile, NULL, service_name ) ); } } // Just in case the plugin requested doesn't exist... if ( !producer && resource ) producer = MLT_SERVICE( mlt_factory_producer( context->profile, NULL, resource ) ); if ( !producer ) mlt_log_error( NULL, "[producer_xml] failed to load producer \"%s\"\n", resource ); if ( !producer ) producer = MLT_SERVICE( mlt_factory_producer( context->profile, NULL, "+INVALID.txt" ) ); if ( !producer ) producer = MLT_SERVICE( mlt_factory_producer( context->profile, NULL, "colour:red" ) ); if ( !producer ) { mlt_service_close( service ); free( service ); return; } // Track this producer track_service( context->destructors, producer, (mlt_destructor) mlt_producer_close ); mlt_properties_set_lcnumeric( MLT_SERVICE_PROPERTIES( producer ), context->lc_numeric ); context->seekable &= mlt_properties_get_int( MLT_SERVICE_PROPERTIES( producer ), "seekable" ); // Propagate the properties qualify_property( context, properties, "resource" ); qualify_property( context, properties, "luma" ); qualify_property( context, properties, "luma.resource" ); qualify_property( context, properties, "composite.luma" ); qualify_property( context, properties, "producer.resource" ); // Handle in/out properties separately mlt_position in = -1; mlt_position out = -1; // Get in if ( mlt_properties_get( properties, "in" ) ) in = mlt_properties_get_position( properties, "in" ); // Let Kino-SMIL clipBegin be a synonym for in else if ( mlt_properties_get( properties, "clipBegin" ) ) in = mlt_properties_get_position( properties, "clipBegin" ); // Get out if ( mlt_properties_get( properties, "out" ) ) out = mlt_properties_get_position( properties, "out" ); // Let Kino-SMIL clipEnd be a synonym for out else if ( mlt_properties_get( properties, "clipEnd" ) ) out = mlt_properties_get_position( properties, "clipEnd" ); // Remove in and out mlt_properties_set( properties, "in", NULL ); mlt_properties_set( properties, "out", NULL ); // Inherit the properties mlt_properties_inherit( MLT_SERVICE_PROPERTIES( producer ), properties ); // Attach all filters from service onto producer attach_filters( producer, service ); // Add the producer to the producer map if ( mlt_properties_get( properties, "id" ) != NULL ) mlt_properties_set_data( context->producer_map, mlt_properties_get(properties, "id"), producer, 0, NULL, NULL ); // See if the producer should be added to a playlist or multitrack if ( add_producer( context, producer, in, out ) == 0 ) { // Otherwise, set in and out on... if ( in != -1 || out != -1 ) { // Get the parent service enum service_type type; mlt_service parent = context_pop_service( context, &type ); if ( parent != NULL ) { // Get the parent properties properties = MLT_SERVICE_PROPERTIES( parent ); char *resource = mlt_properties_get( properties, "resource" ); // Put the parent producer back context_push_service( context, parent, type ); // If the parent is a track or entry if ( resource && ( strcmp( resource, "" ) == 0 ) ) { if ( in > -1 ) mlt_properties_set_position( properties, "in", in ); if ( out > -1 ) mlt_properties_set_position( properties, "out", out ); } else { // Otherwise, set in and out on producer directly mlt_producer_set_in_and_out( MLT_PRODUCER( producer ), in, out ); } } else { // Otherwise, set in and out on producer directly mlt_producer_set_in_and_out( MLT_PRODUCER( producer ), in, out ); } } // Push the producer onto the stack context_push_service( context, producer, mlt_producer_type ); } } if ( service ) { mlt_service_close( service ); free( service ); } } static void on_start_blank( deserialise_context context, const xmlChar *name, const xmlChar **atts) { // Get the playlist from the stack enum service_type type; mlt_service service = context_pop_service( context, &type ); if ( type == mlt_playlist_type && service != NULL ) { // Look for the length attribute for ( ; atts != NULL && *atts != NULL; atts += 2 ) { if ( xmlStrcmp( atts[0], _x("length") ) == 0 ) { // Append a blank to the playlist mlt_playlist_blank_time( MLT_PLAYLIST( service ), _s(atts[1]) ); break; } } // Push the playlist back onto the stack context_push_service( context, service, type ); } else { mlt_log_error( NULL, "[producer_xml] blank without a playlist - a definite no no\n" ); } } static void on_start_entry( deserialise_context context, const xmlChar *name, const xmlChar **atts) { mlt_producer entry = NULL; mlt_properties temp = mlt_properties_new( ); mlt_properties_set_data( temp, "_profile", context->profile, 0, NULL, NULL ); mlt_properties_set_lcnumeric( temp, context->lc_numeric ); for ( ; atts != NULL && *atts != NULL; atts += 2 ) { mlt_properties_set( temp, (const char*) atts[0], atts[1] == NULL ? "" : (const char*) atts[1] ); // Look for the producer attribute if ( xmlStrcmp( atts[ 0 ], _x("producer") ) == 0 ) { mlt_producer producer = mlt_properties_get_data( context->producer_map, (const char*) atts[1], NULL ); if ( producer != NULL ) mlt_properties_set_data( temp, "producer", producer, 0, NULL, NULL ); } } // If we have a valid entry if ( mlt_properties_get_data( temp, "producer", NULL ) != NULL ) { mlt_playlist_clip_info info; enum service_type parent_type = mlt_invalid_type; mlt_service parent = context_pop_service( context, &parent_type ); mlt_producer producer = mlt_properties_get_data( temp, "producer", NULL ); if ( parent_type == mlt_playlist_type ) { // Append the producer to the playlist mlt_position in = -1; mlt_position out = -1; if ( mlt_properties_get( temp, "in" ) ) in = mlt_properties_get_position( temp, "in" ); if ( mlt_properties_get( temp, "out" ) ) out = mlt_properties_get_position( temp, "out" ); mlt_playlist_append_io( MLT_PLAYLIST( parent ), producer, in, out ); // Handle the repeat property if ( mlt_properties_get_int( temp, "repeat" ) > 0 ) { mlt_playlist_repeat_clip( MLT_PLAYLIST( parent ), mlt_playlist_count( MLT_PLAYLIST( parent ) ) - 1, mlt_properties_get_int( temp, "repeat" ) ); } mlt_playlist_get_clip_info( MLT_PLAYLIST( parent ), &info, mlt_playlist_count( MLT_PLAYLIST( parent ) ) - 1 ); entry = info.cut; } else { mlt_log_error( NULL, "[producer_xml] Entry not part of a playlist...\n" ); } context_push_service( context, parent, parent_type ); } // Push the cut onto the stack context_push_service( context, MLT_PRODUCER_SERVICE( entry ), mlt_entry_type ); mlt_properties_close( temp ); } static void on_end_entry( deserialise_context context, const xmlChar *name ) { // Get the entry from the stack enum service_type entry_type = mlt_invalid_type; mlt_service entry = context_pop_service( context, &entry_type ); if ( entry == NULL && entry_type != mlt_entry_type ) { mlt_log_error( NULL, "[producer_xml] Invalid state at end of entry\n" ); } } static void on_start_track( deserialise_context context, const xmlChar *name, const xmlChar **atts) { // use a dummy service to hold properties to allow arbitrary nesting mlt_service service = calloc( 1, sizeof( struct mlt_service_s ) ); mlt_service_init( service, NULL ); // Push the dummy service onto the stack context_push_service( context, service, mlt_entry_type ); mlt_properties_set( MLT_SERVICE_PROPERTIES( service ), "resource", "" ); for ( ; atts != NULL && *atts != NULL; atts += 2 ) { mlt_properties_set( MLT_SERVICE_PROPERTIES( service ), (const char*) atts[0], atts[1] == NULL ? "" : (const char*) atts[1] ); // Look for the producer attribute if ( xmlStrcmp( atts[ 0 ], _x("producer") ) == 0 ) { mlt_producer producer = mlt_properties_get_data( context->producer_map, (const char*) atts[1], NULL ); if ( producer != NULL ) mlt_properties_set_data( MLT_SERVICE_PROPERTIES( service ), "producer", producer, 0, NULL, NULL ); } } } static void on_end_track( deserialise_context context, const xmlChar *name ) { // Get the track from the stack enum service_type track_type; mlt_service track = context_pop_service( context, &track_type ); if ( track != NULL && track_type == mlt_entry_type ) { mlt_properties track_props = MLT_SERVICE_PROPERTIES( track ); enum service_type parent_type = mlt_invalid_type; mlt_service parent = context_pop_service( context, &parent_type ); mlt_multitrack multitrack = NULL; mlt_producer producer = mlt_properties_get_data( track_props, "producer", NULL ); mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); if ( parent_type == mlt_tractor_type ) multitrack = mlt_tractor_multitrack( MLT_TRACTOR( parent ) ); else if ( parent_type == mlt_multitrack_type ) multitrack = MLT_MULTITRACK( parent ); else mlt_log_error( NULL, "[producer_xml] track contained in an invalid container\n" ); if ( multitrack != NULL ) { // Set producer i/o if specified if ( mlt_properties_get( track_props, "in" ) != NULL || mlt_properties_get( track_props, "out" ) != NULL ) { mlt_position in = -1; mlt_position out = -1; if ( mlt_properties_get( track_props, "in" ) ) in = mlt_properties_get_position( track_props, "in" ); if ( mlt_properties_get( track_props, "out" ) ) out = mlt_properties_get_position( track_props, "out" ); mlt_producer cut = mlt_producer_cut( MLT_PRODUCER( producer ), in, out ); mlt_multitrack_connect( multitrack, cut, mlt_multitrack_count( multitrack ) ); mlt_properties_inherit( MLT_PRODUCER_PROPERTIES( cut ), track_props ); track_props = MLT_PRODUCER_PROPERTIES( cut ); mlt_producer_close( cut ); } else { mlt_multitrack_connect( multitrack, producer, mlt_multitrack_count( multitrack ) ); } // Set the hide state of the track producer char *hide_s = mlt_properties_get( track_props, "hide" ); if ( hide_s != NULL ) { if ( strcmp( hide_s, "video" ) == 0 ) mlt_properties_set_int( producer_props, "hide", 1 ); else if ( strcmp( hide_s, "audio" ) == 0 ) mlt_properties_set_int( producer_props, "hide", 2 ); else if ( strcmp( hide_s, "both" ) == 0 ) mlt_properties_set_int( producer_props, "hide", 3 ); } } if ( parent != NULL ) context_push_service( context, parent, parent_type ); } else { mlt_log_error( NULL, "[producer_xml] Invalid state at end of track\n" ); } if ( track ) { mlt_service_close( track ); free( track ); } } static void on_start_filter( deserialise_context context, const xmlChar *name, const xmlChar **atts) { // use a dummy service to hold properties to allow arbitrary nesting mlt_service service = calloc( 1, sizeof( struct mlt_service_s ) ); mlt_service_init( service, NULL ); mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); context_push_service( context, service, mlt_dummy_filter_type ); // Set the properties for ( ; atts != NULL && *atts != NULL; atts += 2 ) mlt_properties_set( properties, (const char*) atts[0], (const char*) atts[1] ); } static void on_end_filter( deserialise_context context, const xmlChar *name ) { enum service_type type; mlt_service service = context_pop_service( context, &type ); mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); enum service_type parent_type = mlt_invalid_type; mlt_service parent = context_pop_service( context, &parent_type ); if ( service != NULL && type == mlt_dummy_filter_type ) { char *id = trim( mlt_properties_get( properties, "mlt_service" ) ); mlt_service filter = MLT_SERVICE( mlt_factory_filter( context->profile, id, NULL ) ); mlt_properties filter_props = MLT_SERVICE_PROPERTIES( filter ); if ( !filter ) { mlt_log_error( NULL, "[producer_xml] failed to load filter \"%s\"\n", id ); if ( parent ) context_push_service( context, parent, parent_type ); mlt_service_close( service ); free( service ); return; } track_service( context->destructors, filter, (mlt_destructor) mlt_filter_close ); mlt_properties_set_lcnumeric( MLT_SERVICE_PROPERTIES( filter ), context->lc_numeric ); // Propogate the properties qualify_property( context, properties, "resource" ); qualify_property( context, properties, "luma" ); qualify_property( context, properties, "luma.resource" ); qualify_property( context, properties, "composite.luma" ); qualify_property( context, properties, "producer.resource" ); mlt_properties_inherit( filter_props, properties ); // Attach all filters from service onto filter attach_filters( filter, service ); // Associate the filter with the parent if ( parent != NULL ) { if ( parent_type == mlt_tractor_type ) { mlt_field field = mlt_tractor_field( MLT_TRACTOR( parent ) ); mlt_field_plant_filter( field, MLT_FILTER( filter ), mlt_properties_get_int( properties, "track" ) ); mlt_filter_set_in_and_out( MLT_FILTER( filter ), mlt_properties_get_int( properties, "in" ), mlt_properties_get_int( properties, "out" ) ); } else { mlt_service_attach( parent, MLT_FILTER( filter ) ); } // Put the parent back on the stack context_push_service( context, parent, parent_type ); } else { mlt_log_error( NULL, "[producer_xml] filter closed with invalid parent...\n" ); } } else { mlt_log_error( NULL, "[producer_xml] Invalid top of stack on filter close\n" ); } if ( service ) { mlt_service_close( service ); free(service); } } static void on_start_transition( deserialise_context context, const xmlChar *name, const xmlChar **atts) { // use a dummy service to hold properties to allow arbitrary nesting mlt_service service = calloc( 1, sizeof( struct mlt_service_s ) ); mlt_service_init( service, NULL ); mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); context_push_service( context, service, mlt_dummy_transition_type ); // Set the properties for ( ; atts != NULL && *atts != NULL; atts += 2 ) mlt_properties_set( properties, (const char*) atts[0], (const char*) atts[1] ); } static void on_end_transition( deserialise_context context, const xmlChar *name ) { enum service_type type; mlt_service service = context_pop_service( context, &type ); mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); enum service_type parent_type = mlt_invalid_type; mlt_service parent = context_pop_service( context, &parent_type ); if ( service != NULL && type == mlt_dummy_transition_type ) { char *id = trim( mlt_properties_get( properties, "mlt_service" ) ); mlt_service effect = MLT_SERVICE( mlt_factory_transition( context->profile, id, NULL ) ); mlt_properties effect_props = MLT_SERVICE_PROPERTIES( effect ); if ( !effect ) { mlt_log_error( NULL, "[producer_xml] failed to load transition \"%s\"\n", id ); if ( parent ) context_push_service( context, parent, parent_type ); mlt_service_close( service ); free( service ); return; } track_service( context->destructors, effect, (mlt_destructor) mlt_transition_close ); mlt_properties_set_lcnumeric( MLT_SERVICE_PROPERTIES( effect ), context->lc_numeric ); // Propogate the properties qualify_property( context, properties, "resource" ); qualify_property( context, properties, "luma" ); qualify_property( context, properties, "luma.resource" ); qualify_property( context, properties, "composite.luma" ); qualify_property( context, properties, "producer.resource" ); mlt_properties_inherit( effect_props, properties ); // Attach all filters from service onto effect attach_filters( effect, service ); // Associate the filter with the parent if ( parent != NULL ) { if ( parent_type == mlt_tractor_type ) { mlt_field field = mlt_tractor_field( MLT_TRACTOR( parent ) ); if ( mlt_properties_get_int( properties, "a_track" ) == mlt_properties_get_int( properties, "b_track" ) ) mlt_properties_set_int( properties, "b_track", mlt_properties_get_int( properties, "a_track" ) + 1 ); mlt_field_plant_transition( field, MLT_TRANSITION( effect ), mlt_properties_get_int( properties, "a_track" ), mlt_properties_get_int( properties, "b_track" ) ); mlt_transition_set_in_and_out( MLT_TRANSITION( effect ), mlt_properties_get_int( properties, "in" ), mlt_properties_get_int( properties, "out" ) ); } else { mlt_log_warning( NULL, "[producer_xml] Misplaced transition - ignoring\n" ); } // Put the parent back on the stack context_push_service( context, parent, parent_type ); } else { mlt_log_error( NULL, "[producer_xml] transition closed with invalid parent...\n" ); } } else { mlt_log_error( NULL, "[producer_xml] Invalid top of stack on transition close\n" ); } if ( service ) { mlt_service_close( service ); free( service ); } } static void on_start_consumer( deserialise_context context, const xmlChar *name, const xmlChar **atts) { if ( context->pass == 1 ) { mlt_properties properties = mlt_properties_new(); mlt_properties_set_lcnumeric( properties, context->lc_numeric ); context_push_service( context, (mlt_service) properties, mlt_dummy_consumer_type ); // Set the properties from attributes for ( ; atts != NULL && *atts != NULL; atts += 2 ) mlt_properties_set( properties, (const char*) atts[0], (const char*) atts[1] ); } } static void on_end_consumer( deserialise_context context, const xmlChar *name ) { if ( context->pass == 1 ) { // Get the consumer from the stack enum service_type type; mlt_properties properties = (mlt_properties) context_pop_service( context, &type ); if ( properties && type == mlt_dummy_consumer_type ) { qualify_property( context, properties, "resource" ); qualify_property( context, properties, "target" ); char *resource = mlt_properties_get( properties, "resource" ); if ( context->multi_consumer > 1 || context->qglsl ) { // Instantiate the multi consumer if ( !context->consumer ) { if ( context->qglsl ) context->consumer = context->qglsl; else context->consumer = mlt_factory_consumer( context->profile, "multi", NULL ); if ( context->consumer ) { // Track this consumer track_service( context->destructors, MLT_CONSUMER_SERVICE(context->consumer), (mlt_destructor) mlt_consumer_close ); mlt_properties_set_lcnumeric( MLT_CONSUMER_PROPERTIES(context->consumer), context->lc_numeric ); } } if ( context->consumer ) { // Set this properties object on multi consumer char key[20]; snprintf( key, sizeof(key), "%d", context->consumer_count++ ); mlt_properties_inc_ref( properties ); mlt_properties_set_data( MLT_CONSUMER_PROPERTIES(context->consumer), key, properties, 0, (mlt_destructor) mlt_properties_close, NULL ); } } else { // Instantiate the consumer char *id = trim( mlt_properties_get( properties, "mlt_service" ) ); context->consumer = mlt_factory_consumer( context->profile, id, resource ); if ( context->consumer ) { // Track this consumer track_service( context->destructors, MLT_CONSUMER_SERVICE(context->consumer), (mlt_destructor) mlt_consumer_close ); mlt_properties_set_lcnumeric( MLT_CONSUMER_PROPERTIES(context->consumer), context->lc_numeric ); // Inherit the properties mlt_properties_inherit( MLT_CONSUMER_PROPERTIES(context->consumer), properties ); } } } // Close the dummy if ( properties ) mlt_properties_close( properties ); } } static void on_start_property( deserialise_context context, const xmlChar *name, const xmlChar **atts) { enum service_type type; mlt_service service = context_pop_service( context, &type ); mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); const char *value = NULL; if ( service != NULL ) { // Set the properties for ( ; atts != NULL && *atts != NULL; atts += 2 ) { if ( xmlStrcmp( atts[ 0 ], _x("name") ) == 0 ) context->property = strdup( _s(atts[ 1 ]) ); else if ( xmlStrcmp( atts[ 0 ], _x("value") ) == 0 ) value = _s(atts[ 1 ]); } if ( context->property != NULL ) mlt_properties_set( properties, context->property, value == NULL ? "" : value ); // Tell parser to collect any further nodes for serialisation context->is_value = 1; context_push_service( context, service, type ); } else { mlt_log_error( NULL, "[producer_xml] Property without a service '%s'?\n", ( const char * )name ); } } static void on_end_property( deserialise_context context, const xmlChar *name ) { enum service_type type; mlt_service service = context_pop_service( context, &type ); mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); if ( service != NULL ) { // Tell parser to stop building a tree context->is_value = 0; // See if there is a xml tree for the value if ( context->property != NULL && context->value_doc != NULL ) { xmlChar *value; int size; // Serialise the tree to get value xmlDocDumpMemory( context->value_doc, &value, &size ); mlt_properties_set( properties, context->property, _s(value) ); #ifdef WIN32 xmlFreeFunc xmlFree = NULL; xmlMemGet( &xmlFree, NULL, NULL, NULL); #endif xmlFree( value ); xmlFreeDoc( context->value_doc ); context->value_doc = NULL; } // Close this property handling free( context->property ); context->property = NULL; context_push_service( context, service, type ); } else { mlt_log_error( NULL, "[producer_xml] Property without a service '%s'??\n", (const char *)name ); } } static void on_start_element( void *ctx, const xmlChar *name, const xmlChar **atts) { struct _xmlParserCtxt *xmlcontext = ( struct _xmlParserCtxt* )ctx; deserialise_context context = ( deserialise_context )( xmlcontext->_private ); if ( context->pass == 0 ) { if ( xmlStrcmp( name, _x("mlt") ) == 0 || xmlStrcmp( name, _x("profile") ) == 0 || xmlStrcmp( name, _x("profileinfo") ) == 0 ) on_start_profile( context, name, atts ); if ( xmlStrcmp( name, _x("consumer") ) == 0 ) context->multi_consumer++; // Check for a service beginning with glsl. or movit. for ( ; atts != NULL && *atts != NULL; atts += 2 ) { if ( !xmlStrncmp( atts[1], _x("glsl."), 5 ) || !xmlStrncmp( atts[1], _x("movit."), 6 ) ) { mlt_properties_set_int( context->params, "qglsl", 1 ); break; } } return; } context->branch[ context->depth ] ++; context->depth ++; // Build a tree from nodes within a property value if ( context->is_value == 1 && context->pass == 1 ) { xmlNodePtr node = xmlNewNode( NULL, name ); if ( context->value_doc == NULL ) { // Start a new tree context->value_doc = xmlNewDoc( _x("1.0") ); xmlDocSetRootElement( context->value_doc, node ); } else { // Append child to tree xmlAddChild( context->stack_node[ context->stack_node_size - 1 ], node ); } context_push_node( context, node ); // Set the attributes for ( ; atts != NULL && *atts != NULL; atts += 2 ) xmlSetProp( node, atts[ 0 ], atts[ 1 ] ); } else if ( xmlStrcmp( name, _x("tractor") ) == 0 ) on_start_tractor( context, name, atts ); else if ( xmlStrcmp( name, _x("multitrack") ) == 0 ) on_start_multitrack( context, name, atts ); else if ( xmlStrcmp( name, _x("playlist") ) == 0 || xmlStrcmp( name, _x("seq") ) == 0 || xmlStrcmp( name, _x("smil") ) == 0 ) on_start_playlist( context, name, atts ); else if ( xmlStrcmp( name, _x("producer") ) == 0 || xmlStrcmp( name, _x("video") ) == 0 ) on_start_producer( context, name, atts ); else if ( xmlStrcmp( name, _x("blank") ) == 0 ) on_start_blank( context, name, atts ); else if ( xmlStrcmp( name, _x("entry") ) == 0 ) on_start_entry( context, name, atts ); else if ( xmlStrcmp( name, _x("track") ) == 0 ) on_start_track( context, name, atts ); else if ( xmlStrcmp( name, _x("filter") ) == 0 ) on_start_filter( context, name, atts ); else if ( xmlStrcmp( name, _x("transition") ) == 0 ) on_start_transition( context, name, atts ); else if ( xmlStrcmp( name, _x("property") ) == 0 ) on_start_property( context, name, atts ); else if ( xmlStrcmp( name, _x("consumer") ) == 0 ) on_start_consumer( context, name, atts ); else if ( xmlStrcmp( name, _x("westley") ) == 0 || xmlStrcmp( name, _x("mlt") ) == 0 ) { for ( ; atts != NULL && *atts != NULL; atts += 2 ) { if ( xmlStrcmp( atts[0], _x("LC_NUMERIC") ) ) mlt_properties_set( context->producer_map, _s( atts[0] ), _s(atts[1] ) ); else if ( !context->lc_numeric ) context->lc_numeric = strdup( _s( atts[1] ) ); } } } static void on_end_element( void *ctx, const xmlChar *name ) { struct _xmlParserCtxt *xmlcontext = ( struct _xmlParserCtxt* )ctx; deserialise_context context = ( deserialise_context )( xmlcontext->_private ); if ( context->is_value == 1 && context->pass == 1 && xmlStrcmp( name, _x("property") ) != 0 ) context_pop_node( context ); else if ( xmlStrcmp( name, _x("multitrack") ) == 0 ) on_end_multitrack( context, name ); else if ( xmlStrcmp( name, _x("playlist") ) == 0 || xmlStrcmp( name, _x("seq") ) == 0 || xmlStrcmp( name, _x("smil") ) == 0 ) on_end_playlist( context, name ); else if ( xmlStrcmp( name, _x("track") ) == 0 ) on_end_track( context, name ); else if ( xmlStrcmp( name, _x("entry") ) == 0 ) on_end_entry( context, name ); else if ( xmlStrcmp( name, _x("tractor") ) == 0 ) on_end_tractor( context, name ); else if ( xmlStrcmp( name, _x("property") ) == 0 ) on_end_property( context, name ); else if ( xmlStrcmp( name, _x("producer") ) == 0 || xmlStrcmp( name, _x("video") ) == 0 ) on_end_producer( context, name ); else if ( xmlStrcmp( name, _x("filter") ) == 0 ) on_end_filter( context, name ); else if ( xmlStrcmp( name, _x("transition") ) == 0 ) on_end_transition( context, name ); else if ( xmlStrcmp( name, _x("consumer") ) == 0 ) on_end_consumer( context, name ); context->branch[ context->depth ] = 0; context->depth --; } static void on_characters( void *ctx, const xmlChar *ch, int len ) { struct _xmlParserCtxt *xmlcontext = ( struct _xmlParserCtxt* )ctx; deserialise_context context = ( deserialise_context )( xmlcontext->_private ); char *value = calloc( 1, len + 1 ); enum service_type type; mlt_service service = context_pop_service( context, &type ); mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); if ( service != NULL ) context_push_service( context, service, type ); value[ len ] = 0; strncpy( value, (const char*) ch, len ); if ( context->stack_node_size > 0 ) xmlNodeAddContent( context->stack_node[ context->stack_node_size - 1 ], ( xmlChar* )value ); // libxml2 generates an on_characters immediately after a get_entity within // an element value, and we ignore it because it is called again during // actual substitution. else if ( context->property != NULL && context->entity_is_replace == 0 ) { char *s = mlt_properties_get( properties, context->property ); if ( s != NULL ) { // Append new text to existing content char *new = calloc( 1, strlen( s ) + len + 1 ); strcat( new, s ); strcat( new, value ); mlt_properties_set( properties, context->property, new ); free( new ); } else mlt_properties_set( properties, context->property, value ); } context->entity_is_replace = 0; // Check for a service beginning with glsl. or movit. if ( !strncmp( value, "glsl.", 5 ) || !strncmp( value, "movit.", 6 ) ) mlt_properties_set_int( context->params, "qglsl", 1 ); free( value); } /** Convert parameters parsed from resource into entity declarations. */ static void params_to_entities( deserialise_context context ) { if ( context->params != NULL ) { int i; // Add our params as entitiy declarations for ( i = 0; i < mlt_properties_count( context->params ); i++ ) { xmlChar *name = ( xmlChar* )mlt_properties_get_name( context->params, i ); xmlAddDocEntity( context->entity_doc, name, XML_INTERNAL_GENERAL_ENTITY, context->publicId, context->systemId, ( xmlChar* )mlt_properties_get( context->params, _s(name) ) ); } // Flag completion mlt_properties_close( context->params ); context->params = NULL; } } // The following 3 facilitate entity substitution in the SAX parser static void on_internal_subset( void *ctx, const xmlChar* name, const xmlChar* publicId, const xmlChar* systemId ) { struct _xmlParserCtxt *xmlcontext = ( struct _xmlParserCtxt* )ctx; deserialise_context context = ( deserialise_context )( xmlcontext->_private ); context->publicId = publicId; context->systemId = systemId; xmlCreateIntSubset( context->entity_doc, name, publicId, systemId ); // Override default entities with our parameters params_to_entities( context ); } // TODO: Check this with Dan... I think this is for parameterisation // but it's breaking standard escaped entities (like < etc). static void on_entity_declaration( void *ctx, const xmlChar* name, int type, const xmlChar* publicId, const xmlChar* systemId, xmlChar* content) { struct _xmlParserCtxt *xmlcontext = ( struct _xmlParserCtxt* )ctx; deserialise_context context = ( deserialise_context )( xmlcontext->_private ); xmlAddDocEntity( context->entity_doc, name, type, publicId, systemId, content ); } // TODO: Check this functionality (see on_entity_declaration) static xmlEntityPtr on_get_entity( void *ctx, const xmlChar* name ) { struct _xmlParserCtxt *xmlcontext = ( struct _xmlParserCtxt* )ctx; deserialise_context context = ( deserialise_context )( xmlcontext->_private ); xmlEntityPtr e = NULL; // Setup for entity declarations if not ready if ( xmlGetIntSubset( context->entity_doc ) == NULL ) { xmlCreateIntSubset( context->entity_doc, _x("mlt"), _x(""), _x("") ); context->publicId = _x(""); context->systemId = _x(""); } // Add our parameters if not already params_to_entities( context ); e = xmlGetPredefinedEntity( name ); // Send signal to on_characters that an entity substitutin is pending if ( e == NULL ) { e = xmlGetDocEntity( context->entity_doc, name ); if ( e != NULL ) context->entity_is_replace = 1; } return e; } static void on_error( void * ctx, const char * msg, ... ) { struct _xmlError* err_ptr = xmlCtxtGetLastError( ctx ); switch( err_ptr->level ) { case XML_ERR_WARNING: mlt_log_warning( NULL, "[producer_xml] parse warning: %s\trow: %d\tcol: %d\n", err_ptr->message, err_ptr->line, err_ptr->int2 ); break; case XML_ERR_ERROR: mlt_log_error( NULL, "[producer_xml] parse error: %s\trow: %d\tcol: %d\n", err_ptr->message, err_ptr->line, err_ptr->int2 ); break; default: case XML_ERR_FATAL: mlt_log_fatal( NULL, "[producer_xml] parse fatal: %s\trow: %d\tcol: %d\n", err_ptr->message, err_ptr->line, err_ptr->int2 ); break; } } /** Convert a hexadecimal character to its value. */ static int tohex( char p ) { return isdigit( p ) ? p - '0' : tolower( p ) - 'a' + 10; } /** Decode a url-encoded string containing hexadecimal character sequences. */ static char *url_decode( char *dest, char *src ) { char *p = dest; while ( *src ) { if ( *src == '%' ) { *p ++ = ( tohex( *( src + 1 ) ) << 4 ) | tohex( *( src + 2 ) ); src += 3; } else { *p ++ = *src ++; } } *p = *src; return dest; } /** Extract the filename from a URL attaching parameters to a properties list. */ static void parse_url( mlt_properties properties, char *url ) { int i; int n = strlen( url ); char *name = NULL; char *value = NULL; for ( i = 0; i < n; i++ ) { switch ( url[ i ] ) { case '?': url[ i++ ] = '\0'; name = &url[ i ]; break; case ':': case '=': #ifdef WIN32 if ( url[i] == ':' && url[i + 1] != '/' ) { #endif url[ i++ ] = '\0'; value = &url[ i ]; #ifdef WIN32 } #endif break; case '&': url[ i++ ] = '\0'; if ( name != NULL && value != NULL ) mlt_properties_set( properties, name, value ); name = &url[ i ]; value = NULL; break; } } if ( name != NULL && value != NULL ) mlt_properties_set( properties, name, value ); } // Quick workaround to avoid unecessary libxml2 warnings static int file_exists( char *file ) { char *name = strdup( file ); int exists = 0; if ( name != NULL && strchr( name, '?' ) ) *( strchr( name, '?' ) ) = '\0'; if ( name != NULL ) { FILE *f = fopen( name, "r" ); exists = f != NULL; if ( exists ) fclose( f ); } free( name ); return exists; } mlt_producer producer_xml_init( mlt_profile profile, mlt_service_type servtype, const char *id, char *data ) { xmlSAXHandler *sax, *sax_orig; struct deserialise_context_s *context; mlt_properties properties = NULL; int i = 0; struct _xmlParserCtxt *xmlcontext; int well_formed = 0; char *filename = NULL; int is_filename = strcmp( id, "xml-string" ); // Strip file:// prefix if ( data && strlen( data ) >= 7 && strncmp( data, "file://", 7 ) == 0 ) data += 7; if ( data == NULL || !strcmp( data, "" ) || ( is_filename && !file_exists( data ) ) ) return NULL; context = calloc( 1, sizeof( struct deserialise_context_s ) ); if ( context == NULL ) return NULL; context->producer_map = mlt_properties_new(); context->destructors = mlt_properties_new(); context->params = mlt_properties_new(); context->profile = profile; context->seekable = 1; // Decode URL and parse parameters mlt_properties_set( context->producer_map, "root", "" ); if ( is_filename ) { filename = strdup( data ); parse_url( context->params, url_decode( filename, data ) ); // We need the directory prefix which was used for the xml if ( strchr( filename, '/' ) ) { char *root = NULL; mlt_properties_set( context->producer_map, "root", filename ); root = mlt_properties_get( context->producer_map, "root" ); *( strrchr( root, '/' ) ) = '\0'; // If we don't have an absolute path here, we're heading for disaster... if ( root[ 0 ] != '/' ) { char *cwd = getcwd( NULL, 0 ); char *real = malloc( strlen( cwd ) + strlen( root ) + 2 ); sprintf( real, "%s/%s", cwd, root ); mlt_properties_set( context->producer_map, "root", real ); free( real ); free( cwd ); } } } // We need to track the number of registered filters mlt_properties_set_int( context->destructors, "registered", 0 ); // Setup SAX callbacks for first pass sax = calloc( 1, sizeof( xmlSAXHandler ) ); sax->startElement = on_start_element; sax->characters = on_characters; sax->warning = on_error; sax->error = on_error; sax->fatalError = on_error; // Setup libxml2 SAX parsing xmlInitParser(); xmlSubstituteEntitiesDefault( 1 ); // This is used to facilitate entity substitution in the SAX parser context->entity_doc = xmlNewDoc( _x("1.0") ); if ( is_filename ) xmlcontext = xmlCreateFileParserCtxt( filename ); else xmlcontext = xmlCreateMemoryParserCtxt( data, strlen( data ) ); // Invalid context - clean up and return NULL if ( xmlcontext == NULL ) { mlt_properties_close( context->producer_map ); mlt_properties_close( context->destructors ); mlt_properties_close( context->params ); free( context ); free( sax ); free( filename ); return NULL; } // Parse sax_orig = xmlcontext->sax; xmlcontext->sax = sax; xmlcontext->_private = ( void* )context; xmlParseDocument( xmlcontext ); well_formed = xmlcontext->wellFormed; // Cleanup after parsing xmlcontext->sax = sax_orig; xmlcontext->_private = NULL; if ( xmlcontext->myDoc ) xmlFreeDoc( xmlcontext->myDoc ); xmlFreeParserCtxt( xmlcontext ); context->stack_node_size = 0; context->stack_service_size = 0; // Bad xml - clean up and return NULL if ( !well_formed ) { mlt_properties_close( context->producer_map ); mlt_properties_close( context->destructors ); mlt_properties_close( context->params ); xmlFreeDoc( context->entity_doc ); free( context ); free( sax ); free( filename ); return NULL; } // Setup the second pass context->pass ++; if ( is_filename ) xmlcontext = xmlCreateFileParserCtxt( filename ); else xmlcontext = xmlCreateMemoryParserCtxt( data, strlen( data ) ); // Invalid context - clean up and return NULL if ( xmlcontext == NULL ) { mlt_properties_close( context->producer_map ); mlt_properties_close( context->destructors ); mlt_properties_close( context->params ); xmlFreeDoc( context->entity_doc ); free( context ); free( sax ); free( filename ); return NULL; } // Create the qglsl consumer now, if requested, so that glsl.manager // may exist when trying to load glsl. or movit. services. // The "if requested" part can come from query string qglsl=1 or when // a service beginning with glsl. or movit. appears in the XML. if ( mlt_properties_get_int( context->params, "qglsl" ) ) context->qglsl = mlt_factory_consumer( profile, "qglsl", NULL ); // Setup SAX callbacks for second pass sax->endElement = on_end_element; sax->cdataBlock = on_characters; sax->internalSubset = on_internal_subset; sax->entityDecl = on_entity_declaration; sax->getEntity = on_get_entity; // Parse sax_orig = xmlcontext->sax; xmlcontext->sax = sax; xmlcontext->_private = ( void* )context; xmlParseDocument( xmlcontext ); well_formed = xmlcontext->wellFormed; // Cleanup after parsing xmlFreeDoc( context->entity_doc ); free( sax ); xmlMemoryDump( ); // for debugging xmlcontext->sax = sax_orig; xmlcontext->_private = NULL; if ( xmlcontext->myDoc ) xmlFreeDoc( xmlcontext->myDoc ); xmlFreeParserCtxt( xmlcontext ); // Get the last producer on the stack enum service_type type; mlt_service service = context_pop_service( context, &type ); if ( well_formed && service != NULL ) { // Verify it is a producer service (mlt_type="mlt_producer") // (producer, playlist, multitrack) char *type = mlt_properties_get( MLT_SERVICE_PROPERTIES( service ), "mlt_type" ); if ( type == NULL || ( strcmp( type, "mlt_producer" ) != 0 && strcmp( type, "producer" ) != 0 ) ) service = NULL; } #ifdef DEBUG xmlDocPtr doc = xml_make_doc( service ); xmlDocFormatDump( stdout, doc, 1 ); xmlFreeDoc( doc ); service = NULL; #endif if ( well_formed && service != NULL ) { char *title = mlt_properties_get( context->producer_map, "title" ); // Need the complete producer list for various reasons properties = context->destructors; // Now make sure we don't have a reference to the service in the properties for ( i = mlt_properties_count( properties ) - 1; i >= 1; i -- ) { char *name = mlt_properties_get_name( properties, i ); if ( mlt_properties_get_data_at( properties, i, NULL ) == service ) { mlt_properties_set_data( properties, name, service, 0, NULL, NULL ); break; } } // We are done referencing destructor property list // Set this var to service properties for convenience properties = MLT_SERVICE_PROPERTIES( service ); // Assign the title mlt_properties_set( properties, "title", title ); // Optimise for overlapping producers mlt_producer_optimise( MLT_PRODUCER( service ) ); // Handle deep copies if ( getenv( "MLT_XML_DEEP" ) == NULL ) { // Now assign additional properties if ( is_filename && ( mlt_service_identify( service ) == tractor_type || mlt_service_identify( service ) == playlist_type || mlt_service_identify( service ) == multitrack_type ) ) { mlt_properties_set_int( properties, "_original_type", mlt_service_identify( service ) ); mlt_properties_set( properties, "_original_resource", mlt_properties_get( properties, "resource" ) ); mlt_properties_set( properties, "resource", data ); } // This tells consumer_xml not to deep copy mlt_properties_set( properties, "xml", "was here" ); } else { // Allow the project to be edited mlt_properties_set( properties, "_xml", "was here" ); mlt_properties_set_int( properties, "_mlt_service_hidden", 1 ); } // Make consumer available mlt_properties_inc_ref( MLT_CONSUMER_PROPERTIES( context->consumer ) ); mlt_properties_set_data( properties, "consumer", context->consumer, 0, (mlt_destructor) mlt_consumer_close, NULL ); mlt_properties_set_int( properties, "seekable", context->seekable ); } else { // Return null if not well formed service = NULL; } // Clean up if ( context->qglsl && context->consumer != context->qglsl ) mlt_consumer_close( context->qglsl ); mlt_properties_close( context->producer_map ); if ( context->params != NULL ) mlt_properties_close( context->params ); mlt_properties_close( context->destructors ); if ( context->lc_numeric ) free( context->lc_numeric ); free( context ); free( filename ); return MLT_PRODUCER( service ); } mlt-0.9.0/src/modules/xml/producer_xml.yml000066400000000000000000000007441215300731300206010ustar00rootroot00000000000000schema_version: 0.1 type: producer identifier: xml title: XML File version: 1 copyright: Ushodaya Enterprises Limited creator: Dan Dennedy license: LGPLv2.1 language: en tags: - Audio - Video description: | Construct a service network from an XML description. See docs/mlt-xml.txt. parameters: - identifier: argument title: File type: string description: An XML text file containing MLT XML. readonly: no required: yes mutable: no widget: fileopen mlt-0.9.0/src/swig/000077500000000000000000000000001215300731300140475ustar00rootroot00000000000000mlt-0.9.0/src/swig/Makefile000066400000000000000000000011731215300731300155110ustar00rootroot00000000000000include ../../config.mak include config.mak all clean: list='$(SUBDIRS)'; \ for subdir in $$list; do \ if [ -x $$subdir/build -a ! -f .$$subdir -o $@ = clean ] ; \ then echo -n Building $$subdir... ; \ cd $$subdir && output=`CXXFLAGS="$(CXXFLAGS)" ./build $@ 2>&1` ; \ if [ $$? -eq 0 ] ; \ then echo OK && touch ../.$$subdir ; \ else echo $$output && exit 1 ; \ fi ; \ cd .. ; \ if [ -f $$subdir/Makefile -a -f .$$subdir ] ; \ then $(MAKE) -C $$subdir $@ || exit 1 ; \ fi ; \ if [ $@ = clean ] ; \ then rm -f .$$subdir ; \ fi ; \ fi \ done distclean: clean depend: install: uninstall: mlt-0.9.0/src/swig/configure000077500000000000000000000014001215300731300157510ustar00rootroot00000000000000#!/bin/sh if [ "$help" = "1" ] then cat << EOF SWIG options: --swig-languages=[all | [csharp | java | lua | perl | php | python | ruby | tcl]*] - High level language bindings (default: none) EOF else languages="" touch config.mak # Iterate through arguments for i in "$@" do case $i in --swig-languages=* ) languages=${i#--swig-languages=} [ "$languages" = "none" ] && languages="" if [ -z "$languages" ]; then echo SUBDIRS = $languages > config.mak continue fi which swig > /dev/null 2>&1 [ $? != 0 ] && echo "Please install swig" && exit 1 [ "$languages" = "all" ] && languages="csharp java lua perl php python ruby tcl" echo SUBDIRS = $languages > config.mak ;; esac done fi mlt-0.9.0/src/swig/csharp/000077500000000000000000000000001215300731300153275ustar00rootroot00000000000000mlt-0.9.0/src/swig/csharp/build000077500000000000000000000016361215300731300163620ustar00rootroot00000000000000#!/bin/sh if [ "$1" = "clean" ] then ( cd `dirname $0`; rm -rf *.cxx *.snk *.so *.o *.exe *.dll mlt.i ../.cs src_swig ) exit 0 fi path=`which mcs 2> /dev/null` if [ $? = 0 ] then ln -sf ../mlt.i # Invoke swig mkdir src_swig swig -c++ -I../../mlt++ -I../.. -csharp -dllimport libmltsharp -outdir src_swig -namespace Mlt mlt.i || exit $? # Compile the wrapper g++ -fPIC -D_GNU_SOURCE ${CXXFLAGS} -c -rdynamic -pthread -I../.. mlt_wrap.cxx || exit $? # Create the module g++ ${CXXFLAGS} -shared mlt_wrap.o -L../../mlt++ -lmlt++ -o libmltsharp.so || exit $? # Compile the library assembly mcs -out:mlt-sharp.dll -target:library src_swig/*.cs # uncomment the below if you want to sign the assembly # sn -k mlt-sharp.snk # mcs -out:mlt-sharp.dll -target:library -keyfile:mlt-sharp.snk src_swig/*.cs # Compile the example mcs -r:mlt-sharp.dll play.cs else echo Mono C# compiler not installed. exit 1 fi mlt-0.9.0/src/swig/csharp/play.cs000066400000000000000000000007221215300731300166240ustar00rootroot00000000000000using System; using System.Threading; using Mlt; public class Play { public static void Main(String[] args) { Console.WriteLine("Welcome to MLT."); Factory.init(); Profile profile = new Profile(""); Producer p = new Producer(profile, args[0], null); if (p.is_valid()) { Consumer c = new Consumer(profile, "sdl", null); c.set("rescale", "none"); c.connect(p); c.start(); while (!c.is_stopped()) Thread.Sleep(300); c.stop(); } } } mlt-0.9.0/src/swig/csharp/play.sh000077500000000000000000000000351215300731300166310ustar00rootroot00000000000000#!/bin/sh mono play.exe "$@" mlt-0.9.0/src/swig/java/000077500000000000000000000000001215300731300147705ustar00rootroot00000000000000mlt-0.9.0/src/swig/java/Play.java000066400000000000000000000017361215300731300165470ustar00rootroot00000000000000import org.mltframework.*; public class Play { static { System.loadLibrary("mlt_java"); } public static void main (String[] args) { // Start the mlt system Factory.init( null ); // Set the output profile Profile profile = new Profile( "" ); // Create the producer Producer p = new Producer( profile, args[0], null ); if ( p.is_valid() ) { p.set ("eof", "loop"); // Create the consumer Consumer c = new Consumer( profile, "sdl", null); // Turn off the default rescaling c.set("rescale", "none"); // Connect the producer to the consumer c.connect(p); // Start the consumer c.start(); // Wait until the user stops the consumer Object o = new Object(); while ( !c.is_stopped() ) { synchronized (o) { try { o.wait(1000); } catch (InterruptedException e) { // ignored } } } // Stop it anyway c.stop(); } else { System.out.println ("Unable to open " + args[0]); } } } mlt-0.9.0/src/swig/java/Play.sh000077500000000000000000000000761215300731300162370ustar00rootroot00000000000000#!/bin/sh java -Djava.library.path=. -cp .:src_swig Play "$@" mlt-0.9.0/src/swig/java/build000077500000000000000000000016521215300731300160210ustar00rootroot00000000000000#!/bin/sh if [ "$1" = "clean" ] then ( cd `dirname $0`; rm -rf *.cxx *.so *.o mlt.i ../.java *.class src_swig ) exit 0 fi path=`which java 2> /dev/null` if [ $? = 0 ] then # Locate the path for the include path=`dirname $path` path=`dirname $path` # Change this as needed # export JAVA_INCLUDE="-I$path/include -I$path/include/linux" ln -sf ../mlt.i # Invoke swig mkdir -p src_swig/org/mltframework swig -c++ -I../../mlt++ -I../.. -java -outdir src_swig/org/mltframework -package org.mltframework mlt.i || exit $? # Compile the wrapper g++ -fPIC -D_GNU_SOURCE ${CXXFLAGS} -c -rdynamic -pthread -I../.. mlt_wrap.cxx $JAVA_INCLUDE || exit $? # Create the module g++ ${CXXFLAGS} -shared mlt_wrap.o -L../../mlt++ -lmlt++ -o libmlt_java.so || exit $? # Compile the test javac `find src_swig -name '*.java'` || exit $? export CLASSPATH=`pwd`/src_swig javac Play.java else echo "Java command not found" exit 1 fi mlt-0.9.0/src/swig/lua/000077500000000000000000000000001215300731300146305ustar00rootroot00000000000000mlt-0.9.0/src/swig/lua/build000077500000000000000000000007741215300731300156650ustar00rootroot00000000000000#!/bin/sh if [ "$1" = "clean" ] then ( cd `dirname $0`; rm -f *.cxx *.so *.o mlt.i ../.lua ) exit 0 fi path=`which lua 2> /dev/null` if [ $? = 0 ] then ln -sf ../mlt.i # Invoke swig swig -c++ -I../../mlt++ -I../.. -lua mlt.i || exit $? # Compile the wrapper g++ -fPIC -DPIC -D_GNU_SOURCE ${CXXFLAGS} -c -rdynamic -pthread -I../.. mlt_wrap.cxx || exit $? # Create the module g++ ${CXXFLAGS} -shared mlt_wrap.o -L../../mlt++ -lmlt++ -o mlt.so || exit $? else echo Lua not installed. exit 1 fi mlt-0.9.0/src/swig/lua/play.lua000077500000000000000000000007311215300731300163040ustar00rootroot00000000000000#!/usr/bin/env lua require("mlt") mlt.Factory_init() profile = mlt.Profile() producer = mlt.Producer( profile, arg[1] ) if producer:is_valid() then consumer = mlt.Consumer( profile, "sdl" ) consumer:set( "rescale", "none" ) consumer:set( "terminate_on_pause", 1 ) consumer:connect( producer ) event = consumer:setup_wait_for( "consumer-stopped" ) consumer:start() consumer:wait_for( event ) else print( "Unable to open "..arg[1] ) end mlt.Factory_close() mlt-0.9.0/src/swig/mlt.i000066400000000000000000000135751215300731300150300ustar00rootroot00000000000000/** * mlt.i - Swig Bindings for mlt++ * Copyright (C) 2004-2005 Charles Yates * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ %module mlt %include "carrays.i" %array_class(unsigned char, unsignedCharArray); %{ #include int mlt_log_get_level( void ); void mlt_log_set_level( int ); %} /** These methods return objects which should be gc'd. */ namespace Mlt { %newobject Factory::init( const char * ); %newobject Factory::producer( Profile &, char *, char * ); %newobject Factory::filter( Profile &, char *, char * ); %newobject Factory::transition( Profile &, char *, char * ); %newobject Factory::consumer( Profile &, char *, char * ); %newobject Properties::listen( const char *, void *, mlt_listener ); %newobject Properties::setup_wait_for( const char * ); %newobject Properties::parse_yaml( const char * ); %newobject Service::producer( ); %newobject Service::consumer( ); %newobject Service::get_frame( int ); %newobject Service::filter( int ); %newobject Producer::filter( int ); %newobject Producer::cut( int, int ); %newobject Playlist::current( ); %newobject Playlist::clip_info( int ); %newobject Playlist::get_clip( int ); %newobject Multitrack::track( int ); %newobject Tractor::multitrack( ); %newobject Tractor::field( ); %newobject Tractor::track( int ); %newobject Frame::get_original_producer( ); %newobject Repository::consumers( ); %newobject Repository::filters( ); %newobject Repository::producers( ); %newobject Repository::transitions( ); %newobject Repository::metadata( mlt_service_type, const char * ); %newobject Repository::languages( ); %newobject Profile::list(); %newobject Repository::presets(); #if defined(SWIGPYTHON) %feature("shadow") Frame::get_waveform(int, int) %{ def get_waveform(*args): return _mlt.frame_get_waveform(*args) %} %feature("shadow") Frame::get_image(mlt_image_format&, int&, int&) %{ def get_image(*args): return _mlt.frame_get_image(*args) %} #endif } /** Classes to wrap. */ %include %include %include int mlt_log_get_level( void ); void mlt_log_set_level( int ); %include %include %include %include %include %include %include %include %include %include %include %include %include %include %include %include %include %include #if defined(SWIGRUBY) %{ static void ruby_listener( mlt_properties owner, void *object ); class RubyListener { protected: VALUE callback; Mlt::Event *event; public: RubyListener( VALUE callback ) : callback( callback ) {} RubyListener( Mlt::Properties &properties, char *id, VALUE callback ) : callback( callback ) { event = properties.listen( id, this, ( mlt_listener )ruby_listener ); } virtual ~RubyListener( ) { delete event; } void mark( ) { ((void (*)(VALUE))(rb_gc_mark))( callback ); } void doit( ) { ID method = rb_intern( "call" ); rb_funcall( callback, method, 0 ); } }; static void ruby_listener( mlt_properties owner, void *object ) { RubyListener *o = static_cast< RubyListener * >( object ); o->doit( ); } void markRubyListener( void* p ) { RubyListener *o = static_cast( p ); o->mark( ); } static void on_playlist_next( mlt_properties owner, void *object, int i ); class PlaylistNextListener : RubyListener { private: Mlt::Event *event; public: PlaylistNextListener( Mlt::Properties *properties, VALUE proc ) : RubyListener( proc ) { event = properties->listen( "playlist-next", this, ( mlt_listener )on_playlist_next ); } ~PlaylistNextListener() { delete event; } void yield( int i ) { ID method = rb_intern( "call" ); rb_funcall( callback, method, 1, INT2FIX( i ) ); } }; static void on_playlist_next( mlt_properties owner, void *object, int i ) { PlaylistNextListener *o = static_cast< PlaylistNextListener * >( object ); o->yield( i ); } %} // Ruby wrapper %rename( Listener ) RubyListener; %markfunc RubyListener "markRubyListener"; %markfunc PlaylistNextListener "markRubyListener"; class RubyListener { public: RubyListener( Mlt::Properties &properties, char *id, VALUE callback ); }; class PlaylistNextListener { public: PlaylistNextListener( Mlt::Properties *properties, VALUE proc ); }; #endif // SWIGGRUBY #if defined(SWIGPYTHON) %{ typedef struct { int size; char* data; } binary_data; binary_data frame_get_waveform( Mlt::Frame &frame, int w, int h ) { binary_data result = { w * h, (char*) frame.get_waveform( w, h ) }; return result; } binary_data frame_get_image( Mlt::Frame &frame, mlt_image_format format, int w, int h ) { binary_data result = { mlt_image_format_size( format, w, h, NULL ), (char*) frame.get_image( format, w, h ) }; return result; } %} %typemap(out) binary_data { $result = PyString_FromStringAndSize( $1.data, $1.size ); } binary_data frame_get_waveform(Mlt::Frame&, int, int); binary_data frame_get_image(Mlt::Frame&, mlt_image_format, int, int); #endif mlt-0.9.0/src/swig/perl/000077500000000000000000000000001215300731300150115ustar00rootroot00000000000000mlt-0.9.0/src/swig/perl/Makefile.PL000066400000000000000000000006451215300731300167700ustar00rootroot00000000000000#!/bin/env perl use ExtUtils::MakeMaker; my $CXX = $ENV{'CXX'} || 'g++'; system( "ln -sf ../mlt.i" ); system( "swig -c++ -I../../mlt++ -I../.. -perl5 mlt.i" ); WriteMakefile( 'NAME' => 'mlt', 'CC' => '${CXX} -fPIC ${CXXFLAGS} -I../..', 'OPTIMIZE' => '-O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions', 'LIBS' => ['-L../../mlt++ -lmlt++'], 'OBJECT' => 'mlt_wrap.o', 'DESTDIR' => $ENV{'DESTDIR'}, ); mlt-0.9.0/src/swig/perl/build000077500000000000000000000002501215300731300160330ustar00rootroot00000000000000#!/bin/sh if [ "$1" = "clean" ] then ( cd `dirname $0`; rm -f *.cxx *.so *.o mlt.i ../.perl mlt.pm ) exit 0 fi CXXFLAGS="$CXXFLAGS" perl Makefile.PL || exit 1 make mlt-0.9.0/src/swig/perl/play.pl000077500000000000000000000014571215300731300163250ustar00rootroot00000000000000#!/usr/bin/env perl # Import required modules use mlt; # Not sure why the mlt::Factory.init method fails... mlt::mlt_factory_init( undef ); # Establish the MLT profile $profile = new mlt::Profile( undef ); # Create the producer $p = new mlt::Producer( $profile, $ARGV[0] ); if ( $p->is_valid( ) ) { # Loop the video $p->set( "eof", "loop" ); # Create the consumer $c = new mlt::FilteredConsumer( $profile, "sdl" ); # Turn of the default rescaling $c->set( "rescale", "none" ); # Connect the producer to the consumer $c->connect( $p ); $e = $c->setup_wait_for( "consumer-stopped" ); # Start the consumer $c->start; # Wait until the user stops the consumer $c->wait_for( $e ); $e = undef; $c = undef; $p = undef; } else { print "Unable to open $ARGV[0]\n"; } mlt::mlt_factory_close( ); mlt-0.9.0/src/swig/php/000077500000000000000000000000001215300731300146365ustar00rootroot00000000000000mlt-0.9.0/src/swig/php/build000077500000000000000000000005701215300731300156650ustar00rootroot00000000000000#!/bin/sh if [ "$1" = "clean" ] then ( cd `dirname $0`; rm -f *.cpp *.so *.o mlt.i ../.php mlt.php *.h ) exit 0 fi ln -sf ../mlt.i swig -c++ -I../../mlt++ -I../.. -php5 -noproxy mlt.i g++ -fPIC -DPIC -D_GNU_SOURCE ${CXXFLAGS} -c -rdynamic -pthread -I../.. `php-config --includes` mlt_wrap.cpp g++ ${CXXFLAGS} -shared mlt_wrap.o -L../../mlt++ -lmlt++ -o mlt.so || exit $? mlt-0.9.0/src/swig/php/play.php000077500000000000000000000006661215300731300163270ustar00rootroot00000000000000 mlt-0.9.0/src/swig/python/000077500000000000000000000000001215300731300153705ustar00rootroot00000000000000mlt-0.9.0/src/swig/python/build000077500000000000000000000014471215300731300164230ustar00rootroot00000000000000#!/bin/sh if [ "$1" = "clean" ] then ( cd `dirname $0`; rm -f *.cxx *.so *.o mlt.i ../.python mlt.py* ) exit 0 fi path=`which python 2> /dev/null` if [ $? = 0 ] then # Change this as needed export PYTHON_INCLUDE=`python -c "import sys;print \"%s/include/python%d.%d\"%(sys.prefix,sys.version_info[0],sys.version_info[1])"` [ ! -d "$PYTHON_INCLUDE" ] && echo python development missing && exit 1 ln -sf ../mlt.i # Invoke swig swig -c++ -I../../mlt++ -I../.. -python mlt.i || exit $? # Compile the wrapper g++ -fPIC -D_GNU_SOURCE ${CXXFLAGS} -c -I../.. -I$PYTHON_INCLUDE mlt_wrap.cxx || exit $? # Create the module g++ ${CXXFLAGS} -shared mlt_wrap.o -L../../mlt++ -lmlt++ -L../../framework -lmlt $(python-config --ldflags) -o _mlt.so || exit $? else echo Python not installed. exit 1 fi mlt-0.9.0/src/swig/python/codecs.py000077500000000000000000000007331215300731300172100ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # Import required modules import mlt # Start the mlt system mlt.Factory().init( ) # Create the consumer c = mlt.Consumer( mlt.Profile(), "avformat" ) # Ask for video codecs supports c.set( 'vcodec', 'list' ) # Start the consumer to generate the list c.start() # Get the vcodec property codecs = mlt.Properties( c.get_data( 'vcodec' ) ) # Print the list of codecs for i in range( 0, codecs.count()): print codecs.get( i ) mlt-0.9.0/src/swig/python/getimage.py000077500000000000000000000015361215300731300175340ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import mlt import sys from PIL import Image # setup mlt.Factory.init() profile = mlt.Profile('square_pal_wide') prod = mlt.Producer(profile, sys.argv[1]) # This builds a profile from the attributes of the producer: auto-profile. profile.from_producer(prod) # Ensure the image is square pixels - optional. profile.set_width(int(profile.width() * profile.sar())) profile.set_sample_aspect(1, 0) # Seek to 10% and get a Mlt frame. prod.seek(int(prod.get_length() * 0.1)) frame = prod.get_frame() # And make sure we deinterlace if input is interlaced - optional. frame.set("consumer_deinterlace", 1) # Now we are ready to get the image and save it. size = (profile.width(), profile.height()) rgb = frame.get_image(mlt.mlt_image_rgb24, *size) img = Image.fromstring('RGB', size, rgb) img.save(sys.argv[1] + '.png') mlt-0.9.0/src/swig/python/play.py000077500000000000000000000012011215300731300167040ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # Import required modules import mlt import time import sys # Start the mlt system mlt.Factory().init( ) # Establish a profile profile = mlt.Profile( ) # Create the producer p = mlt.Producer( profile, sys.argv[1] ) if p: # Create the consumer c = mlt.Consumer( profile, "sdl" ) # Turn off the default rescaling c.set( "rescale", "none" ) # Connect the producer to the consumer c.connect( p ) # Start the consumer c.start( ) # Wait until the user stops the consumer while c.is_stopped( ) == 0: time.sleep( 1 ) else: # Diagnostics print "Unable to open ", sys.argv[ 1 ] mlt-0.9.0/src/swig/python/switcher.py000077500000000000000000000034731215300731300176040ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # Import required modules import mlt import time import sys import tornado.ioloop import tornado.web # Start the mlt system mlt.mlt_log_set_level(40) # verbose mlt.Factory.init() # Establish a pipeline profile = mlt.Profile("atsc_1080i_5994") profile.set_explicit(1) tractor = mlt.Tractor() tractor.set("eof", "loop") fg_resource = "decklink:0" bg_resource = "decklink:1" if len(sys.argv) > 2: fg_resource = sys.argv[1] bg_resource = sys.argv[2] fg = mlt.Producer(profile, fg_resource) bg = mlt.Producer(profile, bg_resource) tractor.set_track(bg, 0) tractor.set_track(fg, 1) composite = mlt.Transition(profile, "composite") composite.set("fill", 1) tractor.plant_transition(composite) # Setup the consumer consumer = "decklink:2" if len(sys.argv) > 3: consumer = sys.argv[3] consumer = mlt.Consumer(profile, consumer) consumer.connect(tractor) consumer.set("real_time", -2) consumer.start() flip_flop = False def switch(): global composite, flip_flop frame = fg.frame() + 2 if flip_flop: s = "0=20%%/0:100%%x80%%; %d=20%%/0:100%%x80%%; %d=0/0:100%%x100%%" % (frame, frame + 30) composite.set("geometry", s) else: s = "0=0/0:100%%x100%%; %d=0/0:100%%x100%%; %d=20%%/0:100%%x80%%" % (frame, frame + 30) composite.set("geometry", s) flip_flop = not flip_flop def output_form(handler): handler.write('
') class SwitchHandler(tornado.web.RequestHandler): def get(self): switch() class MainHandler(tornado.web.RequestHandler): def get(self): output_form(self) def post(self): switch() output_form(self) application = tornado.web.Application([ (r"/", MainHandler), (r"/switch", SwitchHandler) ]) application.listen(8888) tornado.ioloop.IOLoop.instance().start() mlt-0.9.0/src/swig/python/waveforms.py000077500000000000000000000005531215300731300177610ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import mlt from PIL import Image mlt.Factory.init() profile = mlt.Profile() prod = mlt.Producer(profile, 'test.wav') size = (320, 240) for i in range(0, prod.get_length()): frm = prod.get_frame() wav = frm.get_waveform(size[0], size[1]) img = Image.fromstring('L', size, wav) img.save('test-%04d.pgm' % (i)) mlt-0.9.0/src/swig/python/webvfx_generator.py000077500000000000000000000066521215300731300213250ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # webvfx_generator.py # Copyright (C) 2013 Dan Dennedy # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Import required modules import mlt import time import sys import tornado.ioloop import tornado.web import shutil import tempfile import os import os.path # Start the mlt system mlt.mlt_log_set_level(40) # verbose mlt.Factory.init() # Establish a pipeline profile = mlt.Profile("atsc_1080i_5994") #profile = mlt.Profile('square_ntsc_wide') profile.set_explicit(1) tractor = mlt.Tractor() tractor.set('eof', 'loop') playlist = mlt.Playlist() playlist.append(mlt.Producer(profile, 'color:')) # Setup the consumer consumer = 'decklink:0' if len(sys.argv) > 1: consumer = sys.argv[1] consumer = mlt.Consumer(profile, consumer) consumer.connect(playlist) #consumer.set("real_time", -2) consumer.start() def switch(resource): global playlist resource = resource playlist.lock() playlist.append(mlt.Producer(profile, str(resource))) playlist.remove(0) playlist.unlock() state = {} state['tempdir'] = None class MainHandler(tornado.web.RequestHandler): def get(self): resource = self.get_argument('url', None) if resource: global state self.write('Playing %s\n' % (resource)) switch(resource) olddir = state['tempdir'] if olddir: shutil.rmtree(olddir, True) state['tempdir'] = None else: self.write('''

POST a bunch of files to / to change the output.

Or GET / with query string parameter "url" to display something from the network.

''') def post(self): if len(self.request.files) == 0: self.write('POST a bunch of files to / to change the output') else: global state olddir = state['tempdir'] resource = None state['tempdir'] = tempfile.mkdtemp() for key, items in self.request.files.iteritems(): for item in items: path = os.path.dirname(key) fn = item.filename if path: if not os.path.exists(os.path.join(state['tempdir'], path)): os.makedirs(os.path.join(state['tempdir'], path)) fn = os.path.join(path, fn) fn = os.path.join(state['tempdir'], fn) if not path and fn.endswith('.html') or fn.endswith('.qml'): resource = fn with open(fn, 'w') as fo: fo.write(item.body) self.write("Uploaded %s\n" % (fn)) if resource: self.write('Playing %s\n' % (resource)) switch(resource) if olddir: shutil.rmtree(olddir, True) application = tornado.web.Application([ (r"/", MainHandler), ]) application.listen(8888) try: tornado.ioloop.IOLoop.instance().start() except: pass consumer.stop() if state['tempdir']: shutil.rmtree(state['tempdir'], True) mlt-0.9.0/src/swig/ruby/000077500000000000000000000000001215300731300150305ustar00rootroot00000000000000mlt-0.9.0/src/swig/ruby/build000077500000000000000000000005161215300731300160570ustar00rootroot00000000000000#!/usr/bin/env ruby require 'mkmf' if ARGV.shift == 'clean' system( "rm -f *.cxx *.so *.o mlt.i ../.ruby Makefile" ) exit 0 end system( "ln -sf ../mlt.i" ) system( "swig -c++ -ruby -I../../mlt++ -I../.. mlt.i" ) $CFLAGS += " -I../.. " + ENV['CXXFLAGS'] $LDFLAGS += " -L../../mlt++ -lmlt++" create_makefile('mlt') system( "make" ) mlt-0.9.0/src/swig/ruby/metadata.rb000077500000000000000000000053031215300731300171410ustar00rootroot00000000000000#!/usr/bin/env ruby require 'erb' require 'yaml' require 'mlt' $repo = Mlt::Factory::init $optional_params = [ 'minimum', 'maximum', 'default', 'unit', 'scale', 'format', 'widget' ] template = %q{%%META:TOPICPARENT{name="Plugins<%= type_title %>s"}% ---+ <%= type_title %>: <%= yml['identifier'] %> %%TOC% ---++ Plugin Information title: <%= yml['title'] %> %BR% % if yml['tags'] media types: % yml['tags'].each do |x| <%= x %> % end %%BR% % end description: <%= yml['description'] %> %BR% version: <%= yml['version'] %> %BR% creator: <%= yml['creator'] %> %BR% % yml['contributor'] and yml['contributor'].each do |x| contributor: <%= x %> %BR% % end <%= "license: #{yml['license']} %BR%\n" if yml['license'] %> <%= "URL: [[#{yml['url']}]] %BR%\n" if yml['url'] %> % if yml['notes'] ---++ Notes % yml['notes'].each do |x| <%= x %> % end % end % if yml['bugs'] ---++ Bugs % yml['bugs'].each do |x| * <%= x %> % end % end % if yml['parameters'] ---++ Parameters % yml['parameters'].each do |param| ---+++ <%= param['identifier'] %> <%= "title: #{param['title']} %BR%\n" if param['title'] %> <%= "description: #{param['description']} %BR%\n" if param['description'] %> type: <%= param['type'] %> %BR% readonly: <%= param['readonly'] or 'no' %> %BR% required: <%= param['required'] or 'no' %> %BR% % $optional_params.each do |key| <%= "#{key}: #{param[key]} %BR%\n" if param[key] %> % end % if param['values'] values: % param['values'].each do |value| * <%= value %> % end % end % end % end } $processor = ERB.new(template, 0, "%<>") def output(mlt_type, services, type_title) index = File.open("Plugins#{type_title}s.txt", 'w') index.puts '%META:TOPICPARENT{name="Documentation"}%' index.puts '' index.puts "---+ #{type_title} Plugins" unsorted = [] (0..(services.count - 1)).each do |i| unsorted << services.get_name(i) end unsorted.sort().each do |name| meta = $repo.metadata(mlt_type, name) if meta.is_valid filename = type_title + name.capitalize.gsub('.', '-') puts "Processing #{filename}" yml = YAML.load(meta.serialise_yaml) if yml File.open(filename + '.txt', 'w') do |f| f.puts $processor.result(binding) end else puts "Failed to write file for #{filename}" end index.puts " * [[#{filename}][#{name}]]: #{meta.get('title')}\n" end end index.puts '' index.close end [ [Mlt::Consumer_type, $repo.consumers, 'Consumer'], [Mlt::Filter_type, $repo.filters, 'Filter'], [Mlt::Producer_type, $repo.producers, 'Producer'], [Mlt::Transition_type, $repo.transitions, 'Transition'] ].each {|x| output *x} mlt-0.9.0/src/swig/ruby/play.rb000077500000000000000000000015431215300731300163300ustar00rootroot00000000000000#!/usr/bin/env ruby # Import required modules require 'mlt' # Create the mlt system Mlt::Factory::init # Establish the mlt profile profile = Mlt::Profile.new # Get and check the argument file = ARGV.shift raise "Usage: test.rb file" if file.nil? # Create the producer producer = Mlt::Factory::producer( profile, file ) raise "Unable to load #{file}" if !producer.is_valid # Create the consumer consumer = Mlt::Consumer.new( profile, "sdl" ) raise "Unable to open sdl consumer" if !consumer.is_valid # Turn off the default rescaling consumer.set( "rescale", "none" ) # Set up a 'wait for' event event = consumer.setup_wait_for( "consumer-stopped" ) # Start the consumer consumer.start # Connect the producer to the consumer consumer.connect( producer ) # Wait until the user stops the consumer consumer.wait_for( event ) # Clean up consumer consumer.stop mlt-0.9.0/src/swig/ruby/playlist.rb000077500000000000000000000024721215300731300172260ustar00rootroot00000000000000#!/usr/bin/env ruby # Import required modules require 'mlt' # Create the mlt system Mlt::Factory::init # Establish the mlt profile profile = Mlt::Profile.new # Get and check the argument file = ARGV.shift raise "Usage: test.rb file1 file2" if file.nil? file2 = ARGV.shift raise "Usage: test.rb file1 file2" if file2.nil? pls = Mlt::Playlist.new(profile) # Create the producer producer = Mlt::Factory::producer( profile, file ) raise "Unable to load #{file}" if !producer.is_valid producer2 = Mlt::Factory::producer( profile, file2 ) raise "Unable to load #{file2}" if !producer2.is_valid pls.append(producer) #pls.repeat(0, 2) pls.append(producer2) # Create the consumer consumer = Mlt::Consumer.new( profile, "sdl" ) raise "Unable to open sdl consumer" if !consumer.is_valid # Turn off the default rescaling consumer.set( "rescale", "none" ) consumer.set("volume", 0.1) consumer.set("terminate_on_pause", 1) Mlt::PlaylistNextListener.new(pls, Proc.new { |i| info = pls.clip_info(i) puts "finished playing #{info.resource}\n" }) # Set up a 'wait for' event event = consumer.setup_wait_for( "consumer-stopped" ) # Start the consumer consumer.start # Connect the producer to the consumer consumer.connect( pls ) # Wait until the user stops the consumer consumer.wait_for( event ) # Clean up consumer consumer.stop mlt-0.9.0/src/swig/ruby/thumbs.rb000077500000000000000000000017371215300731300166720ustar00rootroot00000000000000#!/usr/bin/env ruby # Required modules require 'mlt' # Create the mlt system Mlt::Factory::init # Establish the mlt profile profile = Mlt::Profile.new( "quarter_pal" ) # Get and check the argument file = ARGV.shift name = ARGV.shift size = ARGV.shift size = "176x144" if size.nil? raise "Usage: thumbs.rb file name [ size ]" if file.nil? || name.nil? # Create the producer producer = Mlt::Producer.new( profile, file ) raise "Unable to load #{file}" if !producer.is_valid # Construct the playlist playlist = Mlt::Playlist.new( ) # Get the out point out = producer.get_int( "out" ); # Calculate position of frames [ 0, 0.25, 0.5, 0.75, 1 ].each { |x| playlist.append( producer, Integer(x*out), Integer(x*out) ) } # Create the thumb nail generator generator = Mlt::Consumer.new( profile, "avformat", "#{name}%d.jpg" ) generator.set( "real_time", "0" ) generator.set( "progressive", "1" ) generator.set( "s", size ) # Connect the consumer generator.connect( playlist ); generator.run mlt-0.9.0/src/swig/tcl/000077500000000000000000000000001215300731300146315ustar00rootroot00000000000000mlt-0.9.0/src/swig/tcl/build000077500000000000000000000010021215300731300156470ustar00rootroot00000000000000#!/bin/sh if [ "$1" = "clean" ] then ( cd `dirname $0`; rm -f *.cxx *.so *.o mlt.i ../.tcl ) exit 0 fi path=`which tclsh 2>/dev/null` if [ "$path" != "" ] then ln -sf ../mlt.i # Invoke swig swig -c++ -I../../mlt++ -I../.. -tcl mlt.i || exit 1 # Compile the wrapper g++ -fPIC -D_GNU_SOURCE ${CXXFLAGS} -c -rdynamic -pthread -I../.. mlt_wrap.cxx || exit 1 # Create the module g++ ${CXXFLAGS} -shared mlt_wrap.o -L../../mlt++ -lmlt++ -o mlt.so || exit 1 else echo "Unable to locate tclsh." exit 1 fi mlt-0.9.0/src/swig/tcl/play.tcl000077500000000000000000000005531215300731300163100ustar00rootroot00000000000000#!/usr/bin/env tclsh load mlt.so Factory_init set profile [Profile] set arg1 [lindex $argv 0] set p [Factory_producer $profile loader $arg1] set c [Factory_consumer $profile sdl ""] Properties_set $c "rescale" "none" Consumer_connect $c $p Consumer_start $c while { ![Consumer_is_stopped $c] } { after 1000 } delete_Consumer $c delete_Producer $p Factory_close mlt-0.9.0/src/tests/000077500000000000000000000000001215300731300142405ustar00rootroot00000000000000mlt-0.9.0/src/tests/clock16ntsc.pgm000066400000000000000000025060211215300731300171050ustar00rootroot00000000000000P5 720 480 65535 ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááááââââââââââââââââââââããããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææææççççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððððññññññññññññòòòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""############################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''''''((((××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááááââââââââââââââââââââããããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêêêëëëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððððññññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""############################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''''((((((((××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââââããããããããããããããããããääääääääääääääääääääååååååååååååååååååææææææææææææææææççççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""############################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''''((((((((((××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââããããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææææççççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððððññññññññññññòòòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""""############################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''''((((((((((((((××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââããããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððððññññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""############################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''''((((((((((((((((ÖÖ××××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââããããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""############################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''''((((((((((((((((((((ÖÖÖÖ××××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááááááââââââââââââââââââââããããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææççççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììììííííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððððññññññññññññòòòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""############################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''''((((((((((((((((((((((ÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááááááââââââââââââââââââââããããããããããããããããããääääääääääääääääääääååååååååååååååååææææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""############################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''((((((((((((((((((((((((((ÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááááââââââââââââââââââââããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""############################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''''((((((((((((((((((((((((((((ÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááááââââââââââââââââââããããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððððññññññññññññòòòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''((((((((((((((((((((((((((((((((ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââããããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''''((((((((((((((((((((((((((((((((((ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââããããããããããããããããããääääääääääääääääääääååååååååååååååååææææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""############################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''((((((((((((((((((((((((((((((((((((((ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""############################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((((())ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""############################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((((())))))ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââããããããããããããããããããääääääääääääääääääååååååååååååååååææææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((((())))))))ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââããããããããããããããããããããääääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((((())))))))))))ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((())))))))))))))))ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((((())))))))))))))))))ÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááââââââââââââââââââââããããããããããããããããããääääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((())))))))))))))))))))))ÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââããããããããããããããããããääääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((())))))))))))))))))))))))ÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââããããããããããããããããããääääääääääääääääååååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììííííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììííííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääååååååååååååååååååææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììííííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))**ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))******ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááââââââââââââââââââââããããããããããããããããääääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììííííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))********ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))************ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììííííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))****************ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))******************ÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))**********************ÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááââââââââââââââââââããããããããããããããããääääääääääääääääääååååååååååååååååææææææææææææææççççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))**************************ÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááááââââââââââââââââââããããããããããããããããääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))****************************ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááááââââââââââââââââããããããããããããããããããääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))********************************ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááááââââââââââââââââããããããããããããããããããääääääääääääääääååååååååååååååååææææææææææææææççççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))************************************ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääååååååååååååååææææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))**************************************ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââââããããããããããããããããääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))****************************************++ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââââããããããããããããããããääääääääääääääääååååååååååååååååææææææææææææææççççççççççççççççèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííííîîîîîîîîîîîîïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))****************************************++++++ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââââããããããããããããããããääääääääääääääääååååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))**************************************++++++++++ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââââããããããããããããããããääääääääääääääääååååååååååååååææææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))****************************************++++++++++++ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââããããããããããããããããããääääääääääääääååååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññññòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))****************************************++++++++++++++++ÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááââââââââââââââââããããããããããããããããääääääääääääääääååååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))**************************************++++++++++++++++++++ÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááââââââââââââââââããããããããããããããããääääääääääääääääååååååååååååååææææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))**************************************++++++++++++++++++++++++ÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááââââââââââââââââââããããããããããããããããääääääääääääääääååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))**************************************++++++++++++++++++++++++++ÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááââââââââââââââââââããããããããããããããããääääääääääääääååååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))**************************************++++++++++++++++++++++++++++++ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââââããããããããããããããããääääääääääääääååååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))**************************************++++++++++++++++++++++++++++++++++ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââããããããããããããããããääääääääääääääääååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))************************************++++++++++++++++++++++++++++++++++++++ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââããããããããããããããããääääääääääääääääååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))************************************++++++++++++++++++++++++++++++++++++++++++ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââããããããããããããããããääääääääääääääååååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))**************************************++++++++++++++++++++++++++++++++++++++++,,,,ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââããããããããããããããããääääääääääääääååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))************************************++++++++++++++++++++++++++++++++++++++++,,,,,,,,ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââããããããããããããããääääääääääääääääååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))************************************++++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááââââââââââââââââââããããããããããããããääääääääääääääääååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))************************************++++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááââââââââââââââââããããããããããããããããääääääääääääääååååååååååååååååææææææææææææææççççççççççççèèèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííîîîîîîîîîîîîïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))************************************++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,ÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááââââââââââââââââããããããããããããããããääääääääääääääååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))************************************++++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,ÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááââââââââââââââââããããããããããããããããääääääääääääääååååååååååååååææææææææææææææççççççççççççèèèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííîîîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))************************************++++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,ÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááââââââââââââââââããããããããããããããääääääääääääääääååååååååååååååææææææææææææææççççççççççççèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááââââââââââââââââããããããããããããããääääääääääääääääååååååååååååååææææææææææææççççççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííîîîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))************************************++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááââââââââââââââââããããããããããããããääääääääääääääååååååååååååååææææææææææææææççççççççççççèèèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììííííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))************************************++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááááââââââââââââââããããããããããããããããääääääääääääääååååååååååååååææææææææææææææççççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââââããããããããããããããããääääääääääääääååååååååååååååææææææææææææççççççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììííííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââââããããããããããããããääääääääääääääääååååååååååååææææææææææææææççççççççççççèèèèèèèèèèèèèèééééééééééééêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððððññññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))************************************++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââââããããããããããããããääääääääääääääååååååååååååååææææææææææææææççççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââââããããããããããããããääääääääääääääååååååååååååååææææææææææææççççççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââââããããããããããããããääääääääääääääååååååååååååååææææææææææææççççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((((())))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------ÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââããããããããããããããããääääääääääääääååååååååååååææææææææææææææççççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëììììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((())))))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------ÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââããããããããããããããääääääääääääääååååååååååååååææææææææææææççççççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((((())))))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------ÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââããããããããããããããääääääääääääääååååååååååååååææææææææææææççççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((())))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââããããããããããããããääääääääääääääååååååååååååææææææææææææææççççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêëëëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((((())))))))))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááââââââââââââââââããããããããããããããääääääääääääääååååååååååååææææææææææææççççççççççççççèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííííîîîîîîîîîîïïïïïïïïïïððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((())))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------------ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááââââââââââââââââããããããããããããããääääääääääääååååååååååååååææææææææææææççççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêëëëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((((())))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------------ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááââââââââââââââããããããããããããããääääääääääääääååååååååååååååææææææææææææççççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííííîîîîîîîîîîïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((((())))))))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------------....ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààááááááááááááááááââââââââââââââããããããããããããããääääääääääääääååååååååååååææææææææææææççççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêëëëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññòòòòòòòòòòóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((((())))))))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------------........ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààááááááááááááááááââââââââââââââããããããããããããããääääääääääääääååååååååååååææææææææææææççççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------------............ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààááááááááááááááááââââââââââââââããããããããããããããääääääääääääååååååååååååååææææææææææææççççççççççççèèèèèèèèèèééééééééééééêêêêêêêêêêëëëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððññññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((((())))))))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------------................ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââããããããããããããããääääääääääääååååååååååååææææææææææææææççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññòòòòòòòòòòóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------------....................ÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââããããããããããããääääääääääääääååååååååååååææææææææææææççççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïððððððððððññññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""""""##################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''(((((((((((((((((((((((((((())))))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------------........................ÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááââââââââââââââããããããããããããããääääääääääääääååååååååååååææææææææææææççççççççççççèèèèèèèèèèééééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððññññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""""""##################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------------............................ÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááââââââââââââââããããããããããããããääääääääääääååååååååååååååææææææææææææççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîïïïïïïïïïïððððððððððññññññññòòòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''(((((((((((((((((((((((((((())))))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------------..................................ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááââââââââââââââããããããããããããããääääääääääääååååååååååååææææææææææææççççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððññññññññññòòòòòòòòóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------------......................................ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááââââââââââââââããããããããããããããääääääääääääååååååååååååææææææææææææççççççççççççèèèèèèèèèèééééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîïïïïïïïïïïððððððððððññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))))))******************************++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------------..........................................ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááââââââââââââââããããããããããããääääääääääääääååååååååååååææææææææææææççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïððððððððððññññññññòòòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""""##################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------------..............................................ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááââââââââââââââããããããããããããääääääääääääååååååååååååææææææææææææççççççççççççèèèèèèèèèèééééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîïïïïïïïïïïððððððððññññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""##################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------------..............................................////ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààààááááááááááááááââââââââââââããããããããããããããääääääääääääååååååååååååææææææææææææççççççççççççèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïððððððððððññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""##################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))))******************************++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------------............................................//////////ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààààááááááááááááááââââââââââââããããããããããããããääääääääääääååååååååååååææææææææææææççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííîîîîîîîîîîïïïïïïïïïïððððððððññññññññòòòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))))******************************++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------------............................................//////////////ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááááââââââââââââââããããããããããããããääääääääääääååååååååååååææææææææææççççççççççççèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîïïïïïïïïïïððððððððññññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""##################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------------............................................//////////////////ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááááââââââââââââââããããããããããããääääääääääääååååååååååååææææææææææææççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííîîîîîîîîîîïïïïïïïïððððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""""##################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))))******************************++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------------............................................//////////////////////ÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááááââââââââââââââããããããããããããääääääääääääååååååååååååææææææææææææççççççççççèèèèèèèèèèééééééééééééêêêêêêêêêêëëëëëëëëììììììììììííííííííííîîîîîîîîïïïïïïïïïïððððððððññññññññòòòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""""##################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))))))******************************++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------------..........................................////////////////////////////ÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááááââââââââââââââããããããããããããääääääääääääååååååååååååææææææææææççççççççççççèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííîîîîîîîîîîïïïïïïïïððððððððññññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""""##################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))******************************++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------------............................................////////////////////////////////ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááááââââââââââââããããããããããããããääääääääääääååååååååååææææææææææææççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëììììììììììííííííííííîîîîîîîîïïïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""""##################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))))))****************************++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------------............................................////////////////////////////////////ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááááââââââââââââããããããããããããääääääääääääååååååååååååææææææææææææççççççççççèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííîîîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""""################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))******************************++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------------............................................////////////////////////////////////////ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááááââââââââââââããããããããããããääääääääääääååååååååååååææææææææææççççççççççççèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëììììììììììííííííííííîîîîîîîîïïïïïïïïððððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""##################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))))******************************++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------------..........................................//////////////////////////////////////////////ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááááââââââââââââããããããããããããääääääääääääååååååååååååææææææææææççççççççççèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííîîîîîîîîïïïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""##################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))****************************++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------------..........................................////////////////////////////////////////////////00ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááââââââââââââââããããããããããããääääääääääääååååååååååææææææææææææççççççççççèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëììììììììììííííííííîîîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúúúûûûûûûûûüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""##################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))))****************************++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------------..........................................//////////////////////////////////////////////00000000ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááââââââââââââââããããããããããããääääääääääååååååååååååææææææææææççççççççççççèèèèèèèèèèééééééééééêêêêêêêêëëëëëëëëëëììììììììììííííííííîîîîîîîîïïïïïïïïððððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúúúûûûûûûûûüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""##################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))))))****************************++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------------..........................................//////////////////////////////////////////////000000000000ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááââââââââââââããããããããããããääääääääääääååååååååååååææææææææææççççççççççèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëëëììììììììííííííííîîîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúúúûûûûûûûûüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))))****************************++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------------........................................//////////////////////////////////////////////000000000000000000ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááââââââââââââããããããããããããääääääääääääååååååååååææææææææææææççççççççççèèèèèèèèèèééééééééééêêêêêêêêëëëëëëëëëëììììììììííííííííííîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúûûûûûûûûüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))))****************************++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------------........................................//////////////////////////////////////////////0000000000000000000000ÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááââââââââââââããããããããããããääääääääääääååååååååååææææææææææççççççççççççèèèèèèèèèèééééééééêêêêêêêêêêëëëëëëëëëëììììììììííííííííîîîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúûûûûûûûûüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""""##################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))))**************************++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------------........................................//////////////////////////////////////////////00000000000000000000000000ÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààááááááááááááááââââââââââââããããããããããããääääääääääååååååååååååææææææææææççççççççççèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëììììììììííííííííííîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøùùùùùùùùúúúúúúûûûûûûûûüüüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""""##################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))))****************************++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------..........................................////////////////////////////////////////////00000000000000000000000000000000ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààááááááááááááááââââââââââââããããããããããããääääääääääååååååååååååææææææææææççççççççççèèèèèèèèèèééééééééêêêêêêêêêêëëëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷÷÷øøøøøøùùùùùùùùúúúúúúúúûûûûûûüüüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""""##################$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))****************************++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------........................................//////////////////////////////////////////////000000000000000000000000000000000000ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààááááááááááááááââââââââââââããããããããããääääääääääääååååååååååææææææææææææççççççççççèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëììììììììííííííííííîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóôôôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúúúûûûûûûüüüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""""################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))))**************************++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------........................................////////////////////////////////////////////000000000000000000000000000000000000000000ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààááááááááááááááââââââââââããããããããããããääääääääääääååååååååååææææææææææççççççççççèèèèèèèèèèééééééééééêêêêêêêêëëëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúúúûûûûûûüüüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""""################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((((())))))))))))))))))))))))))**************************++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------........................................////////////////////////////////////////////0000000000000000000000000000000000000000000000ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààááááááááááááââââââââââââããããããããããããääääääääääääååååååååååææææææææææççççççççççèèèèèèèèèèééééééééêêêêêêêêêêëëëëëëëëììììììììííííííííííîîîîîîîîïïïïïïïïððððððððññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõöööööööö÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúúúûûûûûûüüüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""""################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))****************************++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------........................................////////////////////////////////////////////00000000000000000000000000000000000000000000000011ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààááááááááááááââââââââââââããããããããããããääääääääääååååååååååååææææææææææççççççççèèèèèèèèèèééééééééééêêêêêêêêëëëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóôôôôôôôôõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøùùùùùùùùúúúúúúûûûûûûüüüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""""################$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((((())))))))))))))))))))))))))**************************++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------......................................////////////////////////////////////////////00000000000000000000000000000000000000000000000000111111ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààááááááááááááââââââââââââããããããããããããääääääääääååååååååååææææææææææççççççççççèèèèèèèèèèééééééééêêêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷÷÷øøøøøøùùùùùùùùúúúúúúûûûûûûüüüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))**************************++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------......................................////////////////////////////////////////////000000000000000000000000000000000000000000000000111111111111ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààááááááááááááââââââââââââããããããããããääääääääääääååååååååååææææææææææççççççççççèèèèèèèèééééééééééêêêêêêêêëëëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïïïððððððððññññññòòòòòòòòóóóóóóóóôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷÷÷øøøøøøùùùùùùùùúúúúúúûûûûûûûûüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((((())))))))))))))))))))))))**************************++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------......................................//////////////////////////////////////////000000000000000000000000000000000000000000000000111111111111111111ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààááááááááááááââââââââââââããããããããããääääääääääääååååååååååææææææææææççççççççèèèèèèèèèèééééééééééêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòóóóóóóóóôôôôôôôôõõõõõõöööööööö÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúûûûûûûûûüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))**************************++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------......................................//////////////////////////////////////////0000000000000000000000000000000000000000000000001111111111111111111111ÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààááááááááááááââââââââââââããããããããããääääääääääååååååååååææææææææææççççççççççèèèèèèèèèèééééééééêêêêêêêêëëëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïïïððððððññññññññòòòòòòòòóóóóóóôôôôôôôôõõõõõõöööööööö÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúûûûûûûûûüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""""################$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((((())))))))))))))))))))))))**************************++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------......................................//////////////////////////////////////////0000000000000000000000000000000000000000000000001111111111111111111111111111ÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààááááááááááááââââââââââããããããããããããääääääääääååååååååååææææææææææççççççççççèèèèèèèèééééééééééêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïïïððððððððññññññòòòòòòòòóóóóóóóóôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""""################$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((())))))))))))))))))))))))**************************++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------......................................//////////////////////////////////////////00000000000000000000000000000000000000000000000011111111111111111111111111111111ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààààááááááááááááââââââââââããããããããããããääääääääääååååååååååææææææææææççççççççèèèèèèèèèèééééééééêêêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïððððððððññññññññòòòòòòóóóóóóóóôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""""##############$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((((())))))))))))))))))))))))************************++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------......................................//////////////////////////////////////////000000000000000000000000000000000000000000000011111111111111111111111111111111111111ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààààááááááááááââââââââââââããããããããããääääääääääääååååååååååææææææææççççççççççèèèèèèèèééééééééééêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïïïððððððññññññññòòòòòòòòóóóóóóôôôôôôôôõõõõõõöööööö÷÷÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""################$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((())))))))))))))))))))))))**************************++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------......................................////////////////////////////////////////000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááááââââââââââââããããããããããääääääääääååååååååååææææææææææççççççççççèèèèèèèèééééééééêêêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîïïïïïïïïððððððððññññññòòòòòòòòóóóóóóôôôôôôôôõõõõõõöööööööö÷÷÷÷÷÷øøøøøøùùùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""################$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((((())))))))))))))))))))))**************************++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------....................................//////////////////////////////////////////0000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááááââââââââââââããããããããããääääääääääååååååååååææææææææææççççççççèèèèèèèèèèééééééééêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïïïððððððññññññññòòòòòòóóóóóóóóôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""################$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((())))))))))))))))))))))))************************++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------....................................////////////////////////////////////////0000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111122ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááááââââââââââââããããããããããääääääääääååååååååååææææææææççççççççççèèèèèèèèééééééééééêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîïïïïïïïïððððððððññññññòòòòòòòòóóóóóóôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""################$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((((())))))))))))))))))))))************************++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------....................................////////////////////////////////////////00000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111222222ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááááââââââââââããããããããããããääääääääääååååååååææææææææææççççççççççèèèèèèèèééééééééêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïððððððððññññññòòòòòòòòóóóóóóôôôôôôôôõõõõõõöööööö÷÷÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""##############$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((())))))))))))))))))))))**************************++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------....................................////////////////////////////////////////000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111222222222222ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááááââââââââââããããããããããääääääääääååååååååååææææææææææççççççççèèèèèèèèèèééééééééêêêêêêêêëëëëëëëëììììììììííííííîîîîîîîîïïïïïïïïððððððññññññññòòòòòòóóóóóóóóôôôôôôõõõõõõöööööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""##############$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((())))))))))))))))))))))))************************++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------..................................////////////////////////////////////////000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111222222222222222222ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááááââââââââââããããããããããääääääääääååååååååååææææææææççççççççççèèèèèèèèééééééééêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïððððððððññññññòòòòòòòòóóóóóóôôôôôôõõõõõõöööööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""##############$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((())))))))))))))))))))))************************++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------..................................////////////////////////////////////////0000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111222222222222222222222222ÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááááââââââââââããããããããããääääääääääååååååååååææææææææççççççççèèèèèèèèèèééééééééêêêêêêêêëëëëëëëëììììììììííííííîîîîîîîîïïïïïïïïððððððññññññòòòòòòòòóóóóóóôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""""################$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''(((((((((((((((((((())))))))))))))))))))))************************++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------....................................//////////////////////////////////////0000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111222222222222222222222222222222ÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááââââââââââââããããããããããääääääääääååååååååææææææææææççççççççèèèèèèèèééééééééêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîïïïïïïïïððððððññññññññòòòòòòóóóóóóôôôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""""################$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((())))))))))))))))))))))************************++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------....................................//////////////////////////////////////00000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111112222222222222222222222222222222222ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááââââââââââââããããããããããääääääääååååååååååææææææææççççççççççèèèèèèèèééééééééêêêêêêêêëëëëëëëëììììììììííííííîîîîîîîîïïïïïïððððððððññññññòòòòòòóóóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""""##############$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''(((((((((((((((((((())))))))))))))))))))))************************++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------..................................////////////////////////////////////////000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááââââââââââããããããããããääääääääääååååååååååææææææææççççççççèèèèèèèèèèééééééééêêêêêêêêëëëëëëììììììììííííííííîîîîîîïïïïïïïïððððððññññññññòòòòòòóóóóóóôôôôôôõõõõõõöööööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""""##############$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((())))))))))))))))))))************************++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------..................................//////////////////////////////////////000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááââââââââââããããããããããääääääääääååååååååææææææææææççççççççèèèèèèèèééééééééêêêêêêêêëëëëëëëëììììììììííííííîîîîîîîîïïïïïïððððððððññññññòòòòòòóóóóóóôôôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""""##############$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''(((((((((((((((((((())))))))))))))))))))))**********************++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------..................................//////////////////////////////////////0000000000000000000000000000000000000000001111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááââââââââââããããããããããääääääääääååååååååææææææææççççççççççèèèèèèèèééééééééêêêêêêêêëëëëëëììììììììííííííííîîîîîîïïïïïïïïððððððññññññòòòòòòóóóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""""##############$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''(((((((((((((((((())))))))))))))))))))))************************++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------..................................////////////////////////////////////0000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222233ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááââââââââââããããããããããääääääääååååååååååææææææææççççççççèèèèèèèèééééééééêêêêêêêêëëëëëëëëììììììììííííííîîîîîîîîïïïïïïððððððññññññññòòòòòòóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""##############$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''''(((((((((((((((((((())))))))))))))))))))************************++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------................................//////////////////////////////////////00000000000000000000000000000000000000000011111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222233333333ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááááááââââââââââããããããããããääääääääååååååååååææææææææççççççççèèèèèèèèééééééééêêêêêêêêëëëëëëììììììììííííííííîîîîîîïïïïïïððððððððññññññòòòòòòóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""##############$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''(((((((((((((((((())))))))))))))))))))))**********************++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------................................//////////////////////////////////////000000000000000000000000000000000000000011111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222233333333333333ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááááááââââââââââããããããããääääääääääååååååååææææææææææççççççççèèèèèèèèééééééééêêêêêêëëëëëëëëììììììííííííííîîîîîîïïïïïïïïððððððññññññòòòòòòóóóóóóôôôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""##############$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''''(((((((((((((((((((())))))))))))))))))))**********************++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------................................////////////////////////////////////000000000000000000000000000000000000000000111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222233333333333333333333ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááááââââââââââããããããããããääääääääääååååååååææææææææççççççççèèèèèèèèééééééééêêêêêêêêëëëëëëììììììììííííííîîîîîîîîïïïïïïððððððññññññññòòòòòòóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""##############$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''''(((((((((((((((((())))))))))))))))))))**********************++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------..................................////////////////////////////////////0000000000000000000000000000000000000000111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222233333333333333333333333333ËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááááââââââââââããããããããããääääääääååååååååååææææææææççççççççèèèèèèèèééééééééêêêêêêëëëëëëëëììììììííííííííîîîîîîïïïïïïïïððððððññññññòòòòòòóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""##############$$$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''(((((((((((((((((((())))))))))))))))))))**********************++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------................................////////////////////////////////////0000000000000000000000000000000000000000001111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222233333333333333333333333333333333ËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááááââââââââââããããããããããääääääääååååååååææææææææææççççççççèèèèèèééééééééêêêêêêêêëëëëëëììììììììííííííîîîîîîîîïïïïïïððððððññññññòòòòòòóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""""############$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''''(((((((((((((((((())))))))))))))))))))**********************++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------................................////////////////////////////////////00000000000000000000000000000000000000001111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333ËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááááââââââââââããããããããääääääääääååååååååææææææææççççççççèèèèèèèèééééééééêêêêêêëëëëëëëëììììììííííííííîîîîîîïïïïïïððððððññññññññòòòòòòóóóóóóôôôôôôõõõõõõöööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""""############$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''(((((((((((((((((())))))))))))))))))))**********************++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------................................////////////////////////////////////000000000000000000000000000000000000001111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333ËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááááââââââââââããããããããääääääääääååååååååææææææææççççççççèèèèèèèèééééééêêêêêêêêëëëëëëììììììììííííííîîîîîîîîïïïïïïððððððññññññòòòòòòóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""##############$$$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''''(((((((((((((((((())))))))))))))))))))********************++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------................................//////////////////////////////////000000000000000000000000000000000000000011111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááááââââââââââããããããããääääääääååååååååååææææææææççççççççèèèèèèééééééééêêêêêêêêëëëëëëììììììííííííííîîîîîîïïïïïïððððððññññññòòòòòòóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøùùùùùùúúúúúúûûûûûûüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""##############$$$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''(((((((((((((((((())))))))))))))))))))**********************++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------..............................////////////////////////////////////0000000000000000000000000000000000000011111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááááââââââââããããããããããääääääääååååååååææææææææççççççççèèèèèèèèééééééééêêêêêêëëëëëëëëììììììííííííîîîîîîïïïïïïððððððððññññññòòòòòòóóóóôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùúúúúúúûûûûûûüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""##############$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''''''''(((((((((((((((((())))))))))))))))))**********************++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------..............................//////////////////////////////////0000000000000000000000000000000000000000111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333334444ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááááââââââââããããããããããääääääääååååååååææææææææççççççççèèèèèèèèééééééêêêêêêêêëëëëëëììììììííííííííîîîîîîïïïïïïððððððññññññòòòòòòóóóóóóôôôôôôõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùúúúúúúûûûûûûüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""############$$$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''(((((((((((((((((())))))))))))))))))))********************++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,----------------------------..............................//////////////////////////////////00000000000000000000000000000000000000111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333334444444444ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááââââââââââããããããããääääääääääååååååååææææææææççççççèèèèèèèèééééééééêêêêêêëëëëëëëëììììììííííííîîîîîîïïïïïïððððððññññññòòòòòòóóóóóóôôôôôôõõõõõõöööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúûûûûûûüüüüüüýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""############$$$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''(((((((((((((((((())))))))))))))))))********************++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,----------------------------..............................//////////////////////////////////000000000000000000000000000000000000001111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333334444444444444444ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááââââââââââããããããããääääääääååååååååææææææææççççççççèèèèèèèèééééééêêêêêêêêëëëëëëììììììííííííííîîîîîîïïïïïïððððððññññññòòòòóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷øøøøøøùùùùùùúúúúûûûûûûüüüüüüýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""############$$$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''''''(((((((((((((((((())))))))))))))))))**********************++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,----------------------------..............................////////////////////////////////000000000000000000000000000000000000001111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333444444444444444444444444ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßààààààààààááááááááââââââââââããããããããääääääääååååååååææææææææççççççççèèèèèèééééééééêêêêêêëëëëëëëëììììììííííííîîîîîîïïïïïïððððððññññññòòòòòòóóóóóóôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøùùùùùùúúúúûûûûûûüüüüüüýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""############$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''(((((((((((((((())))))))))))))))))))********************++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,--------------------------..............................//////////////////////////////////0000000000000000000000000000000000001111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333444444444444444444444444444444ÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßààààààààááááááááááââââââââââããããããããääääääääååååååååææææææææççççççèèèèèèèèééééééêêêêêêêêëëëëëëììììììííííííîîîîîîïïïïïïððððððññññññòòòòòòóóóóóóôôôôôôõõõõöööööö÷÷÷÷÷÷øøøøùùùùùùúúúúúúûûûûüüüüüüýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""############$$$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''''''(((((((((((((((((())))))))))))))))))********************++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,--------------------------..............................////////////////////////////////0000000000000000000000000000000000000011111111111111111111111111111111111111111122222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333444444444444444444444444444444444444ÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßààààààààááááááááááââââââââããããããããããääääääääååååååååææææææççççççççèèèèèèèèééééééêêêêêêëëëëëëëëììììììííííííîîîîîîïïïïïïððððððññññññòòòòóóóóóóôôôôôôõõõõõõöööö÷÷÷÷÷÷øøøøùùùùùùúúúúúúûûûûüüüüüüýýýýþþþþþþÿÿ  !!!!!!!!!!""""""""""""############$$$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''''''(((((((((((((((())))))))))))))))))********************++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,--------------------------..............................////////////////////////////////00000000000000000000000000000000000011111111111111111111111111111111111111111122222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßààààààààááááááááááââââââââããããããããääääääääååååååååææææææææççççççççèèèèèèééééééééêêêêêêëëëëëëììììììííííííîîîîîîïïïïïïððððððññññññòòòòòòóóóóôôôôôôõõõõõõöööö÷÷÷÷÷÷øøøøøøùùùùúúúúúúûûûûüüüüüüýýýýþþþþþþÿÿ  !!!!!!!!!!""""""""""""############$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''(((((((((((((((((())))))))))))))))))********************++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,--------------------------..............................////////////////////////////////000000000000000000000000000000000000111111111111111111111111111111111111111122222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßààààààààááááááááááââââââââããããããããääääääääååååååååææææææææççççççèèèèèèèèééééééêêêêêêëëëëëëëëììììììííííííîîîîîîïïïïïïððððññññññòòòòòòóóóóóóôôôôõõõõõõöööööö÷÷÷÷øøøøøøùùùùúúúúúúûûûûüüüüüüýýýýþþþþþþÿÿ  !!!!!!!!!!""""""""""""############$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''''''(((((((((((((((())))))))))))))))))********************++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,--------------------------............................////////////////////////////////000000000000000000000000000000000000111111111111111111111111111111111111111122222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßààààààààááááááááááââââââââããããããããääääääääååååååååææææææççççççççèèèèèèééééééééêêêêêêëëëëëëììììììííííííîîîîîîïïïïïïððððððññññññòòòòóóóóóóôôôôôôõõõõöööööö÷÷÷÷øøøøøøùùùùúúúúúúûûûûüüüüüüýýýýþþþþþþÿÿ  !!!!!!!!!!""""""""""""############$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''''(((((((((((((((((())))))))))))))))********************++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,--------------------------............................////////////////////////////////0000000000000000000000000000000000001111111111111111111111111111111111111111222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444444444ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààààááááááááááââââââââããããããããääääääääååååååææææææææççççççççèèèèèèééééééêêêêêêêêëëëëëëììììììííííííîîîîîîïïïïððððððññññññòòòòòòóóóóôôôôôôõõõõõõöööö÷÷÷÷÷÷øøøøùùùùùùúúúúûûûûûûüüüüýýýýþþþþþþÿÿ  !!!!!!!!!!""""""""""""##########$$$$$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''''''(((((((((((((((())))))))))))))))))******************++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,--------------------------............................//////////////////////////////0000000000000000000000000000000000001111111111111111111111111111111111111111222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444444444555555ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààààááááááááââââââââââããããããããääääääååååååååææææææææççççççèèèèèèèèééééééêêêêêêëëëëëëììììììííííííîîîîîîïïïïïïððððððññññòòòòòòóóóóóóôôôôõõõõõõöööö÷÷÷÷÷÷øøøøùùùùùùúúúúûûûûûûüüüüýýýýþþþþþþÿÿ  !!!!!!!!!!""""""""""############$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''''(((((((((((((((())))))))))))))))))********************++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,--------------------------............................//////////////////////////////00000000000000000000000000000000001111111111111111111111111111111111111111222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444444455555555555555ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààààááááááááââââââââããããããããääääääääååååååååææææææççççççççèèèèèèééééééêêêêêêêêëëëëëëììììììííííííîîîîïïïïïïððððððññññññòòòòóóóóóóôôôôõõõõõõöööö÷÷÷÷÷÷øøøøùùùùùùúúúúûûûûûûüüüüýýýýþþþþþþÿÿ  !!!!!!!!!!""""""""""############$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&''''''''''''''''(((((((((((((((())))))))))))))))))******************++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,--------------------------..........................////////////////////////////////000000000000000000000000000000000011111111111111111111111111111111111111222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444445555555555555555555555ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààààááááááááââââââââããããããããääääääääååååååååææææææççççççççèèèèèèééééééêêêêêêëëëëëëììììììííííííîîîîîîïïïïïïððððññññññòòòòòòóóóóôôôôôôõõõõöööööö÷÷÷÷øøøøøøùùùùúúúúûûûûûûüüüüýýýýýýþþþþÿÿ  !!!!!!!!!!""""""""""############$$$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''''(((((((((((((((())))))))))))))))))******************++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,--------------------------..........................//////////////////////////////000000000000000000000000000000000011111111111111111111111111111111111111112222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444445555555555555555555555555555ÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààààááááááááââââââââããããããããääääääääååååååææææææææççççççèèèèèèééééééééêêêêêêëëëëëëììììììííííîîîîîîïïïïïïððððððññññòòòòòòóóóóôôôôôôõõõõöööööö÷÷÷÷øøøøøøùùùùúúúúúúûûûûüüüüýýýýýýþþþþÿÿ  !!!!!!!!!!""""""""""############$$$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''''(((((((((((((((())))))))))))))))******************++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,------------------------............................//////////////////////////////0000000000000000000000000000000000111111111111111111111111111111111111112222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555ÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààààááááááááââââââââããããããããääääääååååååååææææææææççççççèèèèèèééééééêêêêêêëëëëëëììììììííííííîîîîîîïïïïððððððññññññòòòòóóóóóóôôôôõõõõõõöööö÷÷÷÷÷÷øøøøùùùùúúúúúúûûûûüüüüýýýýýýþþþþÿÿ  !!!!!!!!!!""""""""""##########$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&''''''''''''''(((((((((((((((())))))))))))))))))******************++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,------------------------............................////////////////////////////0000000000000000000000000000000000111111111111111111111111111111111111112222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààààááááááááââââââââããããããããääääääååååååååææææææççççççèèèèèèèèééééééêêêêêêëëëëëëììììììííííîîîîîîïïïïïïððððññññññòòòòòòóóóóôôôôõõõõõõöööö÷÷÷÷÷÷øøøøùùùùúúúúúúûûûûüüüüýýýýýýþþþþÿÿ  !!!!!!!!""""""""""""##########$$$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''''(((((((((((((((())))))))))))))))******************++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,------------------------..........................//////////////////////////////00000000000000000000000000000000111111111111111111111111111111111111112222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444455555555555555555555555555555555555555555555555555ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààààááááááááââââââââããããããääääääääååååååååææææææççççççèèèèèèééééééêêêêêêëëëëëëììììììííííííîîîîîîïïïïððððððññññòòòòòòóóóóôôôôôôõõõõöööööö÷÷÷÷øøøøùùùùùùúúúúûûûûüüüüýýýýýýþþþþÿÿ  !!!!!!!!""""""""""""##########$$$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&&&''''''''''''''(((((((((((((((())))))))))))))))******************++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,------------------------..........................//////////////////////////////000000000000000000000000000000001111111111111111111111111111111111112222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááááááââââââããããããããääääääääååååååææææææææççççççèèèèèèééééééêêêêêêëëëëëëììììììííííîîîîîîïïïïïïððððññññññòòòòóóóóóóôôôôõõõõöööööö÷÷÷÷øøøøùùùùùùúúúúûûûûüüüüýýýýýýþþþþÿÿ  !!!!!!!!!!""""""""""############$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&''''''''''''''(((((((((((((())))))))))))))))))****************++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,------------------------..........................////////////////////////////000000000000000000000000000000001111111111111111111111111111111111111122222222222222222222222222222222222222222233333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááááââââââââããããããããääääääääååååååææææææççççççèèèèèèèèééééééêêêêëëëëëëììììììííííííîîîîïïïïïïððððððññññòòòòóóóóóóôôôôõõõõõõöööö÷÷÷÷øøøøøøùùùùúúúúûûûûüüüüýýýýýýþþþþÿÿ  !!!!!!!!!!""""""""""############$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''(((((((((((((((())))))))))))))))******************++++++++++++++++++,,,,,,,,,,,,,,,,,,,,------------------------..........................////////////////////////////0000000000000000000000000000000011111111111111111111111111111111111122222222222222222222222222222222222222222233333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555556666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááááââââââââããããããããääääääååååååååææææææççççççèèèèèèééééééêêêêêêëëëëëëììììììííííîîîîîîïïïïððððððññññòòòòòòóóóóôôôôôôõõõõöööö÷÷÷÷øøøøøøùùùùúúúúûûûûüüüüüüýýýýþþþþÿÿ  !!!!!!!!!!""""""""""##########$$$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&&&''''''''''''''(((((((((((((())))))))))))))))******************++++++++++++++++++,,,,,,,,,,,,,,,,,,,,------------------------........................////////////////////////////0000000000000000000000000000000011111111111111111111111111111111111122222222222222222222222222222222222222222233333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555666666666666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááááââââââââããããããããääääääååååååææææææææççççççèèèèèèééééééêêêêêêëëëëììììììííííííîîîîïïïïïïððððññññññòòòòóóóóôôôôôôõõõõöööö÷÷÷÷÷÷øøøøùùùùúúúúûûûûüüüüüüýýýýþþþþÿÿ  !!!!!!!!!!""""""""""##########$$$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&&&''''''''''''''(((((((((((((())))))))))))))))****************++++++++++++++++++,,,,,,,,,,,,,,,,,,,,------------------------........................////////////////////////////00000000000000000000000000000000111111111111111111111111111111111122222222222222222222222222222222222222222233333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444455555555555555555555555555555555555555555555555555555555555555555566666666666666666666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááááââââââââããããããääääääääååååååææææææççççççèèèèèèééééééêêêêêêëëëëëëììììííííííîîîîîîïïïïððððððññññòòòòóóóóóóôôôôõõõõöööööö÷÷÷÷øøøøùùùùúúúúûûûûûûüüüüýýýýþþþþÿÿ  !!!!!!!!!!""""""""""##########$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&&&''''''''''''''(((((((((((((())))))))))))))))****************++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,----------------------........................////////////////////////////000000000000000000000000000000111111111111111111111111111111111111222222222222222222222222222222222222222233333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555556666666666666666666666666666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááááââââââââããããããääääääääååååååææææææççççççèèèèèèééééééêêêêêêëëëëììììììííííííîîîîïïïïïïððððññññòòòòòòóóóóôôôôõõõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûûûüüüüýýýýþþþþÿÿ  !!!!!!!!!!""""""""""##########$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&&&''''''''''''''(((((((((((((())))))))))))))******************++++++++++++++++++,,,,,,,,,,,,,,,,,,,,--------------------..........................//////////////////////////000000000000000000000000000000111111111111111111111111111111111111222222222222222222222222222222222222222233333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666ÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááááââââââããããããããääääääååååååååææææææççççççèèèèèèééééêêêêêêëëëëëëììììííííííîîîîîîïïïïððððññññññòòòòóóóóôôôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúúúûûûûüüüüýýýýþþþþÿÿ  !!!!!!!!!!""""""""##########$$$$$$$$$$$$%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''(((((((((((((())))))))))))))))****************++++++++++++++++++,,,,,,,,,,,,,,,,,,,,--------------------........................////////////////////////////0000000000000000000000000000001111111111111111111111111111111111222222222222222222222222222222222222222233333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááááââââââããããããããääääääååååååææææææççççççèèèèèèééééééêêêêêêëëëëììììììííííîîîîîîïïïïððððððññññòòòòóóóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùùùúúúúûûûûüüüüýýýýþþþþÿÿ  !!!!!!!!!!""""""""##########$$$$$$$$$$$$%%%%%%%%%%&&&&&&&&&&&&''''''''''''''(((((((((((())))))))))))))))****************++++++++++++++++++,,,,,,,,,,,,,,,,,,,,--------------------........................//////////////////////////0000000000000000000000000000001111111111111111111111111111111111222222222222222222222222222222222222222233333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááááââââââããããããããääääääååååååææææææççççççèèèèèèééééééêêêêëëëëëëììììííííííîîîîïïïïïïððððññññòòòòòòóóóóôôôôõõõõöööö÷÷÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿ  !!!!!!!!!!""""""""##########$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&&&''''''''''''(((((((((((((())))))))))))))****************++++++++++++++++++,,,,,,,,,,,,,,,,,,,,--------------------........................//////////////////////////00000000000000000000000000000011111111111111111111111111111111222222222222222222222222222222222222222233333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444455555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááââââââââããããããääääääääååååååææææææççççççèèèèééééééêêêêêêëëëëììììììííííîîîîîîïïïïððððññññññòòòòóóóóôôôôõõõõöööööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿ  !!!!!!!!""""""""""##########$$$$$$$$$$%%%%%%%%%%&&&&&&&&&&&&''''''''''''''(((((((((((())))))))))))))))****************++++++++++++++++,,,,,,,,,,,,,,,,,,,,--------------------........................//////////////////////////000000000000000000000000000011111111111111111111111111111111112222222222222222222222222222222222222233333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááââââââââããããããääääääååååååææææææççççççèèèèèèééééééêêêêëëëëëëììììííííííîîîîïïïïïïððððññññòòòòóóóóôôôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿ  !!!!!!!!""""""""""##########$$$$$$$$$$%%%%%%%%%%&&&&&&&&&&&&''''''''''''(((((((((((((())))))))))))))****************++++++++++++++++,,,,,,,,,,,,,,,,,,,,--------------------......................//////////////////////////000000000000000000000000000000111111111111111111111111111111112222222222222222222222222222222222222233333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666666666666666666666666666ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááââââââââããããããääääääååååååææææææççççççèèèèèèééééêêêêêêëëëëììììììííííîîîîîîïïïïððððññññòòòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿ  !!!!!!!!""""""""""########$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&''''''''''''''(((((((((((())))))))))))))****************++++++++++++++++,,,,,,,,,,,,,,,,,,,,--------------------......................//////////////////////////0000000000000000000000000000111111111111111111111111111111112222222222222222222222222222222222222233333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666666667777777777ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááââââââããããããããääääääååååååææææææççççççèèèèééééééêêêêëëëëëëììììííííííîîîîïïïïððððððññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿ  !!!!!!!!""""""""""########$$$$$$$$$$%%%%%%%%%%&&&&&&&&&&&&''''''''''''(((((((((((((())))))))))))))**************++++++++++++++++++,,,,,,,,,,,,,,,,,,--------------------......................////////////////////////0000000000000000000000000000111111111111111111111111111111112222222222222222222222222222222222222233333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààááááááááââââââããããããããääääääååååååææææççççççèèèèèèééééêêêêêêëëëëììììììííííîîîîïïïïïïððððññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿ  !!!!!!!!""""""""##########$$$$$$$$$$%%%%%%%%%%&&&&&&&&&&&&''''''''''''(((((((((((())))))))))))))****************++++++++++++++++,,,,,,,,,,,,,,,,,,--------------------......................////////////////////////00000000000000000000000000001111111111111111111111111111112222222222222222222222222222222222222233333333333333333333333333333333333333334444444444444444444444444444444444444444444444444455555555555555555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààááááááááââââââããããããääääääååååååææææææççççççèèèèééééééêêêêêêëëëëììììííííííîîîîïïïïððððññññòòòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùúúúúûûûûüüüüýýýýþþþþÿÿ  !!!!!!!!""""""""##########$$$$$$$$$$%%%%%%%%%%&&&&&&&&&&''''''''''''(((((((((((())))))))))))))****************++++++++++++++++,,,,,,,,,,,,,,,,,,--------------------....................//////////////////////////000000000000000000000000001111111111111111111111111111111122222222222222222222222222222222222233333333333333333333333333333333333333334444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777ÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààááááááááââââââããããããääääääååååååææææææççççèèèèèèééééééêêêêëëëëììììììííííîîîîïïïïïïððððññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûüüüüýýýýþþþþÿÿ  !!!!!!!!""""""""##########$$$$$$$$%%%%%%%%%%&&&&&&&&&&&&''''''''''''(((((((((((())))))))))))))**************++++++++++++++++,,,,,,,,,,,,,,,,,,------------------......................////////////////////////000000000000000000000000000011111111111111111111111111111122222222222222222222222222222222223333333333333333333333333333333333333333334444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààááááááááââââââããããããääääääååååååææææççççççèèèèèèééééêêêêêêëëëëììììííííííîîîîïïïïððððññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûüüüüýýýýþþþþÿÿ  !!!!!!!!""""""""########$$$$$$$$$$%%%%%%%%%%&&&&&&&&&&''''''''''''(((((((((((())))))))))))))**************++++++++++++++++,,,,,,,,,,,,,,,,,,------------------......................////////////////////////0000000000000000000000000011111111111111111111111111111122222222222222222222222222222222223333333333333333333333333333333333333333334444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààááááááââââââââããããããääääääååååææææææççççççèèèèééééééêêêêëëëëììììììííííîîîîïïïïððððññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüýýýýþþþþÿÿ  !!!!!!!!""""""""########$$$$$$$$$$%%%%%%%%%%&&&&&&&&&&''''''''''''(((((((((((())))))))))))**************++++++++++++++++,,,,,,,,,,,,,,,,,,------------------......................//////////////////////0000000000000000000000000011111111111111111111111111111122222222222222222222222222222222223333333333333333333333333333333333333333444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààááááááââââââããããããääääääååååååææææææççççèèèèèèééééêêêêêêëëëëììììííííîîîîîîïïïïððððññññòòòòóóóóôôôôõõõõöö÷÷÷÷øøøøùùùùúúúúûûûûüüýýýýþþþþÿÿ  !!!!!!!!""""""""########$$$$$$$$$$%%%%%%%%&&&&&&&&&&&&''''''''''(((((((((((())))))))))))))**************++++++++++++++,,,,,,,,,,,,,,,,,,------------------....................////////////////////////00000000000000000000000000111111111111111111111111111111222222222222222222222222222222223333333333333333333333333333333333333333444444444444444444444444444444444444444444444455555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààááááááââââââããããããääääääååååååææææççççççèèèèèèééééêêêêëëëëëëììììííííîîîîïïïïððððññññòòòòóóóóôôôôõõõõöööö÷÷øøøøùùùùúúúúûûûûüüýýýýþþþþÿÿ  !!!!!!""""""""##########$$$$$$$$%%%%%%%%%%&&&&&&&&&&''''''''''''(((((((((((())))))))))))**************++++++++++++++++,,,,,,,,,,,,,,,,------------------....................////////////////////////000000000000000000000000111111111111111111111111111111222222222222222222222222222222223333333333333333333333333333333333333333444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777777777777777777777ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààááááááââââââããããããääääääååååååææææççççççèèèèééééêêêêêêëëëëììììííííîîîîïïïïððððññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøùùùùúúúúûûûûüüüüýýþþþþÿÿ  !!!!!!""""""""##########$$$$$$$$%%%%%%%%%%&&&&&&&&&&''''''''''(((((((((((())))))))))))**************++++++++++++++++,,,,,,,,,,,,,,,,------------------....................//////////////////////000000000000000000000000001111111111111111111111111111222222222222222222222222222222223333333333333333333333333333333333333344444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777777788888888ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßßßààààààááááááââââââããããããääääääååååææææææççççèèèèèèééééêêêêëëëëëëììììííííîîîîïïïïððððññññòòòòóóóóôôõõõõöööö÷÷÷÷øøøøùùúúúúûûûûüüüüýýþþþþÿÿ  !!!!!!""""""""########$$$$$$$$$$%%%%%%%%&&&&&&&&&&''''''''''''(((((((((())))))))))))))************++++++++++++++++,,,,,,,,,,,,,,,,------------------....................//////////////////////0000000000000000000000001111111111111111111111111111222222222222222222222222222222223333333333333333333333333333333333333344444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777777777777777777777888888888888888888ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßßßààààààááááááââââââããããããääääååååååææææææççççèèèèééééééêêêêëëëëììììííííîîîîïïïïððððññññòòòòóóóóôôôôõõöööö÷÷÷÷øøøøùùùùúúûûûûüüüüýýþþþþÿÿ  !!!!!!""""""""########$$$$$$$$%%%%%%%%%%&&&&&&&&&&''''''''''(((((((((((())))))))))))**************++++++++++++++,,,,,,,,,,,,,,,,------------------..................//////////////////////0000000000000000000000000011111111111111111111111111222222222222222222222222222222223333333333333333333333333333333333333344444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßßßààààààááááááââââââããããääääääååååååææææççççççèèèèééééêêêêëëëëëëììììííííîîîîïïïïððððññòòòòóóóóôôôôõõõõöö÷÷÷÷øøøøùùùùúúûûûûüüüüýýþþþþÿÿ  !!!!!!!!""""""""########$$$$$$$$%%%%%%%%%%&&&&&&&&&&''''''''''(((((((((())))))))))))**************++++++++++++++,,,,,,,,,,,,,,,,------------------..................//////////////////////00000000000000000000000011111111111111111111111111112222222222222222222222222222223333333333333333333333333333333333333344444444444444444444444444444444444444444455555555555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888ÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßßßààààààááááááââââââããããääääääååååææææææççççèèèèèèééééêêêêëëëëììììííííîîîîïïïïððððññññòòòòóóôôôôõõõõöööö÷÷øøøøùùùùúúûûûûüüüüýýþþþþÿÿ  !!!!!!!!""""""""########$$$$$$$$%%%%%%%%&&&&&&&&&&''''''''''(((((((((((())))))))))))************++++++++++++++,,,,,,,,,,,,,,,,----------------....................////////////////////00000000000000000000000011111111111111111111111111112222222222222222222222222222223333333333333333333333333333333333334444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààààááááááââââããããããääääääååååææææææççççèèèèééééêêêêêêëëëëììììííííîîîîïïððððññññòòòòóóóóôôõõõõöööö÷÷÷÷øøùùùùúúúúûûüüüüýýþþþþÿÿ  !!!!!!!!""""""""######$$$$$$$$$$%%%%%%%%&&&&&&&&&&''''''''''(((((((((())))))))))))************++++++++++++++,,,,,,,,,,,,,,,,----------------....................////////////////////000000000000000000000000111111111111111111111111112222222222222222222222222222223333333333333333333333333333333333334444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââââããããããääääååååååææææççççççèèèèééééêêêêëëëëììììííííîîîîïïïïððððññòòòòóóóóôôôôõõöööö÷÷÷÷øøùùùùúúúúûûüüüüýýþþþþÿÿ  !!!!!!!!""""""########$$$$$$$$%%%%%%%%%%&&&&&&&&''''''''''(((((((((((())))))))))**************++++++++++++++,,,,,,,,,,,,,,----------------..................//////////////////////0000000000000000000000111111111111111111111111112222222222222222222222222222223333333333333333333333333333333333334444444444444444444444444444444444444444555555555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888888888ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââââããããããääääååååååææææççççèèèèééééééêêêêëëëëììììííííîîïïïïððððññññòòòòóóôôôôõõõõöö÷÷÷÷øøøøùùúúúúûûüüüüýýýýþþÿÿ  !!!!!!!!""""""########$$$$$$$$%%%%%%%%&&&&&&&&&&''''''''''(((((((((())))))))))))************++++++++++++++,,,,,,,,,,,,,,----------------..................////////////////////0000000000000000000000001111111111111111111111111122222222222222222222222222223333333333333333333333333333333333334444444444444444444444444444444444444444555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888888888888888ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââââããããääääääååååææææææççççèèèèééééêêêêëëëëììììííííîîîîïïïïððññññòòòòóóóóôôõõõõöööö÷÷øøøøùùúúúúûûüüüüýýýýþþÿÿ  !!!!!!!!""""""########$$$$$$$$%%%%%%%%&&&&&&&&''''''''''(((((((((())))))))))))************++++++++++++++,,,,,,,,,,,,,,----------------..................////////////////////00000000000000000000001111111111111111111111111122222222222222222222222222223333333333333333333333333333333333444444444444444444444444444444444444444455555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888888888888ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââââããããääääääååååææææççççèèèèèèééééêêêêëëëëììììííîîîîïïïïððððññòòòòóóóóôôõõõõöööö÷÷øøøøùùúúúúûûûûüüýýýýþþÿÿ  !!!!!!""""""""########$$$$$$$$%%%%%%%%&&&&&&&&''''''''''(((((((((())))))))))************++++++++++++++,,,,,,,,,,,,,,----------------..................//////////////////00000000000000000000001111111111111111111111111122222222222222222222222222223333333333333333333333333333333333444444444444444444444444444444444444444455555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888888888888888888888888888888899999999ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââââããããääääååååååææææççççèèèèééééêêêêëëëëììììííííîîîîïïððððññññòòóóóóôôôôõõöööö÷÷øøøøùùùùúúûûûûüüýýýýþþÿÿ  !!!!!!""""""""######$$$$$$$$%%%%%%%%&&&&&&&&&&''''''''(((((((((())))))))))))************++++++++++++,,,,,,,,,,,,,,----------------................////////////////////000000000000000000000011111111111111111111111122222222222222222222222222223333333333333333333333333333333333444444444444444444444444444444444444445555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââããããããääääååååææææææççççèèèèééééêêêêëëëëììììííîîîîïïïïððððññòòòòóóôôôôõõõõöö÷÷÷÷øøùùùùúúûûûûüüýýýýþþÿÿ  !!!!!!""""""""######$$$$$$$$%%%%%%%%&&&&&&&&''''''''''(((((((((())))))))))************++++++++++++,,,,,,,,,,,,,,----------------................////////////////////0000000000000000000011111111111111111111111122222222222222222222222222223333333333333333333333333333333344444444444444444444444444444444444444555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888888888888999999999999999999999999999999ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââããããããääääååååææææççççèèèèééééêêêêëëëëììììííííîîîîïïððððññññòòóóóóôôõõõõöö÷÷÷÷øøùùùùúúûûûûüüýýýýþþÿÿ  !!!!!!""""""########$$$$$$$$%%%%%%%%&&&&&&&&''''''''(((((((((())))))))))************++++++++++++,,,,,,,,,,,,,,----------------................//////////////////0000000000000000000000111111111111111111111111222222222222222222222222223333333333333333333333333333333344444444444444444444444444444444444444555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888888888888888888888888888999999999999999999999999999999999999999999ÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââããããääääääååååææææççççèèèèééééêêêêëëëëììííííîîîîïïïïððññññòòóóóóôôôôõõöööö÷÷øøùùùùúúûûûûüüýýýýþþÿÿ  !!!!!!""""""########$$$$$$%%%%%%%%&&&&&&&&''''''''''(((((((((())))))))))**********++++++++++++,,,,,,,,,,,,,,----------------................//////////////////00000000000000000000111111111111111111111111222222222222222222222222223333333333333333333333333333333344444444444444444444444444444444444455555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááââââââããããääääååååååææææççççèèèèééééêêëëëëììììííííîîïïïïððððññòòòòóóôôôôõõöööö÷÷øøøøùùúúúúûûüüýýýýþþÿÿ  !!!!!!""""""########$$$$$$%%%%%%%%&&&&&&&&''''''''(((((((((())))))))))************++++++++++++,,,,,,,,,,,,--------------................//////////////////00000000000000000000001111111111111111111111222222222222222222222222223333333333333333333333333333333344444444444444444444444444444444444455555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999999999999999ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞßßßßßßààààààááááââââââããããääääååååææææççççèèèèééééêêêêëëëëììííííîîîîïïððððññññòòóóóóôôõõõõöö÷÷øøøøùùúúúúûûüüýýýýþþÿÿ  !!!!!!""""""######$$$$$$$$%%%%%%%%&&&&&&&&''''''''(((((((())))))))))************++++++++++++,,,,,,,,,,,,--------------................//////////////////000000000000000000001111111111111111111111222222222222222222222222223333333333333333333333333333334444444444444444444444444444444444445555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞßßßßßßààààààááááââââââããããääääååååææææççççèèèèééééêêêêëëììììííííîîïïïïððññññòòóóóóôôõõõõöö÷÷÷÷øøùùúúúúûûüüýýýýþþÿÿ  !!!!!!""""""######$$$$$$$$%%%%%%&&&&&&&&''''''''(((((((((())))))))))**********++++++++++++,,,,,,,,,,,,--------------................//////////////////0000000000000000001111111111111111111111112222222222222222222222223333333333333333333333333333334444444444444444444444444444444444555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999999999999999ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞßßßßßßààààààááááââââããããããääääååååææææççççèèèèééêêêêëëëëììííííîîîîïïððððññòòòòóóôôôôõõöö÷÷÷÷øøùùúúúúûûüüýýýýþþÿÿ  !!!!!!""""""######$$$$$$%%%%%%%%&&&&&&&&''''''''(((((((())))))))))**********++++++++++++,,,,,,,,,,,,--------------................////////////////0000000000000000000011111111111111111111112222222222222222222222223333333333333333333333333333334444444444444444444444444444444444555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞßßßßßßààààààááááââââããããääääååååææææççççèèèèééééêêêêëëììììííííîîïïïïððññññòòóóôôôôõõöööö÷÷øøùùùùúúûûüüüüýýþþÿÿ  !!!!!!""""""######$$$$$$%%%%%%%%&&&&&&''''''''(((((((((())))))))************++++++++++,,,,,,,,,,,,--------------................////////////////000000000000000000111111111111111111111122222222222222222222222233333333333333333333333333334444444444444444444444444444444444555555555555555555555555555555555555555566666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßààààááááááââââããããääääååååææææççççèèèèééêêêêëëëëììííííîîïïïïððññññòòóóóóôôõõöööö÷÷øøùùùùúúûûüüüüýýþþÿÿ  !!!!!!""""######$$$$$$$$%%%%%%&&&&&&&&''''''''(((((((())))))))))**********++++++++++,,,,,,,,,,,,--------------..............////////////////0000000000000000000011111111111111111111222222222222222222222222333333333333333333333333333344444444444444444444444444444444445555555555555555555555555555555555555566666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××××ØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßààààááááááââââããããääääååååææææççççèèééééêêêêëëììììííîîîîïïððððññòòòòóóôôõõõõöö÷÷øøøøùùúúûûüüüüýýþþÿÿ  !!!!""""""######$$$$$$%%%%%%%%&&&&&&&&''''''(((((((((())))))))**********++++++++++,,,,,,,,,,,,--------------..............////////////////00000000000000000011111111111111111111222222222222222222222222333333333333333333333333333344444444444444444444444444444444555555555555555555555555555555555555556666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßààààááááááââââããããääääååååææççççèèèèééééêêëëëëììííííîîïïïïððññññòòóóôôôôõõöö÷÷øøøøùùúúûûüüüüýýþþÿÿ  !!!!""""""######$$$$$$%%%%%%%%&&&&&&''''''''(((((((())))))))**********++++++++++++,,,,,,,,,,--------------..............////////////////0000000000000000001111111111111111111122222222222222222222223333333333333333333333333333444444444444444444444444444444555555555555555555555555555555555555556666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::ÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××ØØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßààààááááââââââããããääååååææææççççèèèèééêêêêëëììììííîîîîïïððððññòòóóóóôôõõöö÷÷÷÷øøùùúúûûûûüüýýþþÿÿ  !!!!""""""######$$$$$$%%%%%%&&&&&&&&''''''(((((((())))))))))**********++++++++++,,,,,,,,,,--------------..............//////////////00000000000000000011111111111111111111222222222222222222222233333333333333333333333333444444444444444444444444444444445555555555555555555555555555555555556666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××ØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÞÞÞÞÞÞßßßßààààááááââââããããääääååååææææççççèèééééêêëëëëììííííîîïïïïððññòòòòóóôôõõöööö÷÷øøùùúúûûûûüüýýþþÿÿ  !!!!""""""######$$$$$$%%%%%%&&&&&&''''''''(((((((())))))))**********++++++++++,,,,,,,,,,--------------............////////////////000000000000000011111111111111111111222222222222222222222233333333333333333333333333444444444444444444444444444444555555555555555555555555555555555555666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××ØØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÞÞÞÞÞÞßßßßààààááááââââããããääääååååææææççèèèèééêêêêëëììììííîîîîïïððññññòòóóôôõõõõöö÷÷øøùùúúúúûûüüýýþþÿÿ  !!!!""""""####$$$$$$%%%%%%%%&&&&&&''''''(((((((())))))))))********++++++++++,,,,,,,,,,------------..............//////////////0000000000000000001111111111111111112222222222222222222222333333333333333333333333334444444444444444444444444444445555555555555555555555555555555555666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÞÞÞÞÞÞßßßßààààááááââââããããääääååååææççççèèééééêêëëëëììííííîîïïððððññòòóóôôôôõõöö÷÷øøùùùùúúûûüüýýþþÿÿ  !!!!""""""####$$$$$$%%%%%%&&&&&&''''''''(((((((())))))))********++++++++++,,,,,,,,,,------------..............//////////////000000000000000011111111111111111122222222222222222222223333333333333333333333334444444444444444444444444444445555555555555555555555555555555555666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××ØØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÜÜÜÜÜÜÝÝÝÝÞÞÞÞÞÞßßßßààààááááââââããããääääååææææççèèèèééééêêëëììììííîîïïïïððññòòóóóóôôõõöö÷÷øøøøùùúúûûüüýýþþÿÿ  !!!!!!""""######$$$$$$%%%%%%&&&&&&''''''(((((((())))))))**********++++++++,,,,,,,,,,------------..............//////////////00000000000000001111111111111111112222222222222222222233333333333333333333333344444444444444444444444444445555555555555555555555555555555555666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÜÜÜÜÜÜÝÝÝÝÞÞÞÞÞÞßßßßààààááááââââããããääååååææææççèèèèééêêêêëëììííííîîïïððññññòòóóôôõõöö÷÷÷÷øøùùúúûûüüýýþþÿÿ  !!!!!!""""######$$$$$$%%%%%%&&&&&&''''''(((((((())))))))********++++++++,,,,,,,,,,------------............//////////////00000000000000001111111111111111112222222222222222222233333333333333333333333344444444444444444444444444445555555555555555555555555555555566666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞÞÞßßßßààààááááââââããääääååååææççççèèééééêêëëììììííîîïïïïððññòòóóôôõõõõöö÷÷øøùùúúûûüüýýþþÿÿ  !!!!!!""""######$$$$%%%%%%&&&&&&''''''''(((((())))))))********++++++++++,,,,,,,,,,----------............//////////////0000000000000011111111111111111122222222222222222222333333333333333333333333444444444444444444444444445555555555555555555555555555555566666666666666666666666666666666666666667777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖ××××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÛÛÛÛÛÛÜÜÜÜÝÝÝÝÝÝÞÞÞÞßßßßààààááááââããããääääååææææççèèèèééêêêêëëììííîîîîïïððññòòóóóóôôõõöö÷÷øøùùúúûûüüýýþþÿÿ  !!!!!!""""####$$$$$$%%%%%%&&&&&&''''''(((((())))))))********++++++++++,,,,,,,,,,----------............////////////00000000000000001111111111111111222222222222222222223333333333333333333333444444444444444444444444444455555555555555555555555555555566666666666666666666666666666666666666667777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÝÝÞÞÞÞßßßßààààááââââããããääääååææææççèèééééêêëëììììííîîïïððññññòòóóôôõõöö÷÷øøùùúúûûüüýýþþÿÿ  !!!!""""""####$$$$$$%%%%&&&&&&''''''''(((((())))))))********++++++++,,,,,,,,,,----------............////////////000000000000001111111111111111112222222222222222223333333333333333333333444444444444444444444444445555555555555555555555555555556666666666666666666666666666666666666677777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÜÜÜÜÜÜÝÝÝÝÞÞÞÞßßßßààààááââââããããääååååææççççèèééêêêêëëììííîîîîïïððññòòóóôôõõöö÷÷øøùùúúûûüüýýþþÿÿ  !!!!""""""####$$$$%%%%%%&&&&&&''''''(((((())))))))********++++++++,,,,,,,,,,----------..........//////////////00000000000000111111111111111122222222222222222233333333333333333333334444444444444444444444445555555555555555555555555555556666666666666666666666666666666666666677777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÚÚÚÚÚÚÛÛÛÛÜÜÜÜÜÜÝÝÝÝÞÞÞÞßßßßààááááââââããããääååååææççèèèèééêêëëììììííîîïïððññòòóóôôõõöö÷÷øøùùúúûûüüýýþþÿÿ  !!!!""""######$$$$%%%%%%&&&&&&''''''(((((())))))********++++++++,,,,,,,,,,----------..........////////////000000000000001111111111111111222222222222222222333333333333333333334444444444444444444444444455555555555555555555555555556666666666666666666666666666666666667777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÛÛÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞßßßßààááááââââããääääååææææççèèééééêêëëììííîîïïïïððññòòóóôôõõöö÷÷øøùùúúüüýýþþÿÿ  !!!!""""######$$$$%%%%&&&&&&''''''(((((())))))))******++++++++,,,,,,,,,,--------............////////////00000000000000111111111111112222222222222222223333333333333333333344444444444444444444444455555555555555555555555555555566666666666666666666666666666666667777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÚÚÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞßßßßààááááââââããääääååææççççèèééêêëëììììííîîïïððññòòóóôôõõöö÷÷øøùùúúûûýýþþÿÿ  !!!!""""####$$$$$$%%%%&&&&&&''''''(((((())))))******++++++++,,,,,,,,,,--------............//////////00000000000000111111111111112222222222222222223333333333333333333344444444444444444444444455555555555555555555555555556666666666666666666666666666666666777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÚÚÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞßßßßààááááââããããääååååææççèèèèééêêëëììííîîïïððññòòóóôôõõöö÷÷øøùùúúûûýýþþÿÿ  !!!!""""####$$$$%%%%%%&&&&''''''(((((())))))********++++++++,,,,,,,,--------..........////////////0000000000001111111111111111222222222222222233333333333333333333444444444444444444444455555555555555555555555555556666666666666666666666666666666677777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØÙÙÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞßßßßààááááââããããääååææææççèèééêêëëëëììííîîïïððññòòóóõõöö÷÷øøùùúúûûüüþþÿÿ  !!!!""""####$$$$%%%%&&&&&&''''''(((())))))))******++++++++,,,,,,,,--------..........////////////000000000000111111111111112222222222222222333333333333333333444444444444444444444455555555555555555555555555556666666666666666666666666666666677777777777777777777777777777777777777778888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖ××××××ØØØØØØÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞßßßßààááááââããääääååææççççèèééêêëëììííîîïïððññòòóóôôõõ÷÷øøùùúúûûüüþþÿÿ  !!!!""""####$$$$%%%%&&&&&&''''(((((())))))******++++++++,,,,,,,,--------..........//////////000000000000111111111111112222222222222222333333333333333333444444444444444444444455555555555555555555555555666666666666666666666666666666777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞßßààààááááââããääääååææççèèééêêêêëëììííîîððññòòóóôôõõöö÷÷ùùúúûûüüþþÿÿ  !!!!""""##$$$$$$%%%%&&&&''''''(((())))))******++++++++,,,,,,,,--------..........//////////00000000000011111111111122222222222222223333333333333333334444444444444444444455555555555555555555555555666666666666666666666666666666777777777777777777777777777777777777778888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××ØØØØÙÙÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÜÝÝÞÞÞÞßßààààááââââããääååååææççèèééêêëëììííîîïïððññòòôôõõöö÷÷øøúúûûüüýýÿÿ  !!!!""####$$$$%%%%&&&&&&''''(((((())))))******++++++,,,,,,,,--------........//////////000000000000111111111111112222222222222233333333333333333344444444444444444444555555555555555555555555666666666666666666666666666677777777777777777777777777777777777777888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÖÖÖÖÖÖ××××××ØØØØÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÜÝÝÞÞÞÞßßààààááââââããääååææççèèèèééêêëëììîîïïððññòòóóõõöö÷÷øøúúûûüüýýÿÿ  !!""""####$$$$%%%%&&&&''''''(((())))))******++++++,,,,,,,,--------........//////////00000000001111111111111122222222222222333333333333333344444444444444444444555555555555555555555555666666666666666666666666666677777777777777777777777777777777777788888888888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××ØØØØÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÜÝÝÞÞÞÞßßààààááââããããääååææççèèééêêëëììííîîïïððòòóóôôõõ÷÷øøùùûûüüýýÿÿ  !!""""####$$$$%%%%&&&&''''(((((())))******++++++,,,,,,,,--------........//////////000000000011111111111122222222222222333333333333333344444444444444444455555555555555555555555566666666666666666666666666777777777777777777777777777777777777888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖ××××ØØØØØØÙÙÙÙÚÚÛÛÛÛÜÜÜÜÝÝÞÞÞÞßßààààááââããääääååææççèèééêêëëííîîïïððññóóôôõõööøøùùûûüüýýÿÿ  !!""""####$$%%%%&&&&''''''(((())))))****++++++,,,,,,,,--------........////////0000000000111111111111222222222222223333333333333333444444444444444444555555555555555555555566666666666666666666666666777777777777777777777777777777777788888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÖÖÖÖÖÖ××××ØØØØÙÙÙÙÚÚÚÚÛÛÜÜÜÜÝÝÝÝÞÞßßààààááââããääååææççèèééêêëëììííîîððññòòóóõõööøøùùúúüüýýÿÿ  !!""""##$$$$%%%%&&&&''''(((())))))******++++++,,,,,,------........//////////000000000011111111112222222222222233333333333333444444444444444444555555555555555555555566666666666666666666666666777777777777777777777777777777778888888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÕÕÕÕÕÕÖÖÖÖ××××ØØØØÙÙÙÙÚÚÚÚÛÛÛÛÜÜÝÝÝÝÞÞßßààààááââããääååææççèèééêêëëííîîïïððòòóóôôöö÷÷ùùúúüüýýÿÿ  !!""""##$$$$%%%%&&&&''''(((())))******++++++,,,,,,------........////////000000000011111111111122222222222233333333333333444444444444444444555555555555555555556666666666666666666666667777777777777777777777777777777788888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÔÔÔÔÔÔÕÕÕÕÖÖÖÖÖÖ××××ØØØØÙÙÚÚÚÚÛÛÛÛÜÜÝÝÝÝÞÞßßààááááââããääååææççèèêêëëììííïïððññóóôôöö÷÷ùùúúüüýýÿÿ  !!""####$$$$%%&&&&''''(((())))))****++++++,,,,,,------........////////00000000001111111111222222222222333333333333334444444444444444555555555555555555556666666666666666666666667777777777777777777777777777778888888888888888888888888888888888888899999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÔÔÔÔÔÔÕÕÕÕÖÖÖÖ××××ØØØØÙÙÙÙÚÚÛÛÛÛÜÜÝÝÝÝÞÞßßààááááââããääååççèèééêêëëííîîïïññòòôôõõ÷÷øøúúüüýýÿÿ  !!""####$$%%%%&&&&''''(((())))****++++++,,,,,,------........////////0000000011111111112222222222223333333333333344444444444444555555555555555555556666666666666666666666777777777777777777777777777777888888888888888888888888888888888888999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<============================================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÖÖÖÖ×××רØÙÙÙÙÚÚÚÚÛÛÜÜÜÜÝÝÞÞßßààááââããääååææççèèééëëììííïïððòòóóõõööøøúúûûýýÿÿ  !!""####$$%%%%&&''''(((())))******++++,,,,,,------......////////0000000011111111112222222222223333333333334444444444444444555555555555555555666666666666666666666677777777777777777777777777778888888888888888888888888888888888999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<========================================================================ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÓÓÓÓÓÓÔÔÔÔÕÕÕÕÖÖÖÖ××××ØØØØÙÙÚÚÚÚÛÛÜÜÜÜÝÝÞÞßßààááââããääååææççééêêëëííîîððññóóôôööøøùùûûýýÿÿ  !!""##$$$$%%&&&&''''(((())))****++++,,,,,,------......////////000000001111111122222222222233333333333344444444444444555555555555555555666666666666666666667777777777777777777777777777888888888888888888888888888888889999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==================================================================================================ÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÓÓÓÓÓÓÔÔÔÔÕÕÕÕÖÖÖÖ×××רØÙÙÙÙÚÚÛÛÜÜÜÜÝÝÞÞßßààááââããääååææèèééêêììííïïññòòôôöö÷÷ùùûûýýÿÿ  !!!!""##$$$$%%&&&&''(((())))****++++,,,,,,------......//////0000000011111111112222222222333333333333444444444444445555555555555555666666666666666666667777777777777777777777777788888888888888888888888888888888999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==============================================================================================================================ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÓÓÓÓÓÓÔÔÔÔÕÕÕÕÖÖ××××ØØØØÙÙÚÚÛÛÛÛÜÜÝÝÞÞßßààááââããääææççèèêêëëííîîððòòóóõõ÷÷ùùûûýýÿÿ  !!!!""##$$%%%%&&''''(())))****++++++,,,,------......//////000000001111111122222222223333333333444444444444445555555555555555666666666666666666667777777777777777777777778888888888888888888888888888889999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<========================================================================================================================================================ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÓÓÓÓÔÔÔÔÕÕÕÕÖÖÖÖ××ØØØØÙÙÚÚÚÚÛÛÜÜÝÝÞÞßßààááââããååææççééêêììîîïïññóóõõ÷÷ùùûûýýÿÿ  !!""""##$$%%&&&&''(((())))****++++,,,,------....////////0000001111111122222222223333333333444444444444555555555555555566666666666666666677777777777777777777777788888888888888888888888888889999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<====================================================================================================================================================================================ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÓÓÓÓÔÔÔÔÕÕÕÕÖÖ×××רØÙÙÙÙÚÚÛÛÜÜÝÝÞÞßßààááââääååææèèééëëííïïððòòôôööøøúúýýÿÿ  !!""####$$%%&&''''(())))****++++,,,,----......//////00000000111111222222222233333333334444444444445555555555555566666666666666666677777777777777777777778888888888888888888888888899999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==============================================================================================================================================================================================================ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÑÑÑÑÑÑÒÒÒÒÓÓÓÓÔÔÔÔÕÕÖÖÖÖ××ØØØØÙÙÚÚÛÛÜÜÝÝÞÞßßààááããääååççèèêêììîîððòòôôööøøúúýýÿÿ  !!""##$$%%%%&&''(((())****++++,,,,----......//////0000001111111122222222333333333344444444445555555555555566666666666666667777777777777777777777888888888888888888888888889999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==========================================================================================================================================================================================================================================ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÒÒÒÒÓÓÓÓÔÔÕÕÕÕÖÖ×××רØÙÙÚÚÛÛÜÜÝÝÞÞßßààááããääææççééëëííïïññóóõõøøúúüüÿÿ  !!""##$$%%&&&&''(())))**++++,,,,----......////0000001111111122222222333333334444444444445555555555556666666666666666777777777777777777778888888888888888888888889999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<====================================================================================================================================================================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÐÐÐÐÐÐÑÑÑÑÒÒÒÒÓÓÓÓÔÔÕÕÕÕÖÖ×רØÙÙÙÙÚÚÛÛÜÜÞÞßßààââããååææèèêêììîîððòòõõ÷÷úúüüÿÿ  !!""##$$%%&&''(((())****++,,,,----....//////000000111111222222223333333344444444445555555555556666666666666677777777777777777777888888888888888888888899999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<========================================================================================================================================================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÌÌÌÍÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÑÑÑÑÒÒÒÒÓÓÔÔÔÔÕÕÖÖÖÖ×רØÙÙÚÚÛÛÜÜÞÞßßààââããååççééëëííïïòòôô÷÷ùùüüÿÿ  !!""##$$%%&&''(())****++,,,,----....//////00001111112222222233333333444444445555555555556666666666666677777777777777777788888888888888888888889999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==========================================================================================================================================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÌÌÌÍÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÐÐÐÐÑÑÑÑÒÒÒÒÓÓÔÔÔÔÕÕÖÖ×רØÙÙÚÚÛÛÜÜÝÝßßààââääææèèêêììîîññóóööùùüüÿÿ  !!""$$%%&&''(())))**++++,,----....////000000111122222222333333444444444455555555556666666666666677777777777777778888888888888888888899999999999999999999999999::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==============================================================================================================================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÌÍÍÍÍÍÍÎÎÎÎÏÏÏÏÐÐÐÐÑÑÑÑÒÒÒÒÓÓÔÔÕÕÖÖÖÖ×רØÚÚÛÛÜÜÝÝßßááââääææèèëëííððóóööùùüüÿÿ  !!##$$%%&&''(())**++++,,----....////0000111111222222333333444444445555555555666666666666777777777777777788888888888888888899999999999999999999999999::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==============================================================================================================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÌÍÍÍÍÎÎÎÎÎÎÏÏÏÏÐÐÑÑÑÑÒÒÓÓÓÓÔÔÕÕÖÖ×רØÙÙÚÚÜÜÝÝßßááããååççééììïïòòõõøøûûÿÿ  !!##$$%%''(())****++,,----..////00001111112222223333334444444455555555666666666666777777777777778888888888888888999999999999999999999999::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==================================================================================================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊËËËËËËÌÌÌÌÌÌÍÍÍÍÎÎÎÎÏÏÏÏÐÐÐÐÑÑÒÒÓÓÓÓÔÔÕÕÖÖ××ÙÙÚÚÜÜÝÝßßááããååèèêêííññôô÷÷ûûÿÿ  !!##$$&&''(())**++,,----..////0000111122222233333344444455555555666666666677777777777777888888888888888899999999999999999999::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<====================================================================================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÊÊÊÊÊÊËËËËËËÌÌÌÌÌÌÍÍÍÍÎÎÎÎÏÏÐÐÐÐÑÑÒÒÓÓÔÔÕÕÖÖ×רØÚÚÛÛÝÝßßááããææééììïïóó÷÷ûûÿÿ  ""##%%&&(())**++,,----..////00111122222233334444445555555566666666667777777777778888888888888899999999999999999999::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<========================================================================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÊÊÊÊÊÊÊÊËËËËÌÌÌÌÍÍÍÍÎÎÎÎÏÏÏÏÐÐÑÑÒÒÓÓÔÔÕÕÖÖØØÙÙÛÛÝÝßßááääççêêîîòòööúúÿÿ  ""$$%%''((**++,,--....//000011112222333344444455555566666666777777777777888888888888999999999999999999::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==========================================================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÉÉÉÉÉÉÊÊÊÊÊÊËËËËÌÌÌÌÍÍÍÍÎÎÎÎÏÏÐÐÑÑÒÒÓÓÔÔÕÕ××ÙÙÚÚÜÜßßââååèèììððõõúúÿÿ  ""$$&&(())**,,--..////00111122223333444455555566666666777777777788888888889999999999999999::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<============================================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÉÉÉÉÉÉÊÊÊÊËËËËÌÌÌÌÍÍÍÍÎÎÏÏÐÐÑÑÒÒÓÓÔÔÖÖØØÚÚÜÜßßââææêêîîóóùùÿÿ  ""%%''))**++--..//000011222233444444555566666666777777778888888888999999999999::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==============================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÈÈÈÈÈÈÉÉÉÉÉÉÊÊÊÊËËËËÌÌÍÍÎÎÎÎÏÏÑÑÒÒÓÓÕÕ××ÙÙÜÜßßããççììòòøøÿÿ  ##%%((**++--..//0011222233444455556666667777777788888888999999999999::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÇÇÇÇÇÇÈÈÈÈÈÈÉÉÉÉÊÊËËËËÌÌÍÍÎÎÏÏÐÐÒÒÔÔÖÖØØÛÛßßããééïï÷÷ÿÿ ##&&))++--..//112222334455556666667777778888889999999999::::::::::::::;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<====================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÇÇÇÇÇÇÈÈÈÈÉÉÊÊÊÊËËÌÌÍÍÎÎÐÐÒÒÔÔ××ÚÚßßååììõõÿÿ  $$((**--//0011223344556666777777888899999999::::::::::::;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<======================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÆÆÆÆÇÇÇÇÈÈÈÈÉÉÊÊËËÌÌÎÎÏÏÒÒÕÕÙÙßßççòòÿÿ  %%**--//11224455666677778888999999::::::::;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<========================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÅÅÅÅÆÆÆÆÇÇÈÈÉÉÊÊÌÌÎÎÒÒ××ßßììÿÿ ((--002244667777889999::::::;;;;;;;;<<<<<<<<<<<<============================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÄÄÅÅÆÆÇÇÉÉÌÌÒÒßßÿÿ --22667799::::;;;;<<<<<<==============>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼»»»»»»ºº¹¹¸¸··µµ²²¬¬ŸŸ__RRMMIIHHFFEEEEDDDDCCCCCCBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»ºººººº¹¹¹¹¸¸¸¸··¶¶µµ´´²²°°¬¬§§ŸŸ’’ll__WWRROOMMKKIIHHHHGGFFFFEEEEEEDDDDDDDDCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»ºººººººººº¹¹¹¹¹¹¸¸¸¸····¶¶¶¶µµ´´³³²²°°¯¯¬¬©©¥¥ŸŸ——ŒŒrrgg__ZZUURRPPNNMMKKJJIIIIHHHHGGGGFFFFFFEEEEEEEEDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»ºººººººººººº¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸······¶¶¶¶µµ´´´´³³²²±±°°®®¬¬ªª§§¤¤ŸŸ™™’’‰‰uullee__[[WWUURRPPOONNMMLLKKJJIIIIHHHHHHGGGGFFFFFFFFEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸······¶¶¶¶¶¶µµµµ´´³³³³²²±±°°¯¯®®¬¬ªª¨¨¦¦££ŸŸ››••‡‡wwppiidd__\\YYVVTTRRQQPPNNMMMMLLKKKKJJIIIIIIHHHHHHGGGGGGFFFFFFFFFFEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸········¶¶¶¶¶¶µµµµµµ´´´´³³³³²²±±°°°°¯¯­­¬¬««©©§§¥¥¢¢ŸŸ››——’’ŒŒ††yyrrllggcc__\\ZZWWUUTTRRQQPPOONNMMMMLLKKKKJJJJIIIIIIHHHHHHHHGGGGGGGGFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸··········¶¶¶¶¶¶µµµµµµ´´´´³³³³³³²²±±±±°°¯¯®®­­¬¬««ªª¨¨¦¦¤¤¢¢ŸŸœœ˜˜””‹‹……yyttoojjffbb__]]ZZXXWWUUTTRRQQPPOOOONNMMMMLLKKKKKKJJJJIIIIIIIIHHHHHHHHGGGGGGGGGGFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸··········¶¶¶¶¶¶¶¶µµµµµµ´´´´´´³³³³²²²²±±±±°°°°¯¯®®­­¬¬««ªª©©§§¥¥¤¤¢¢ŸŸœœ™™––’’ŽŽ‰‰„„zzuuqqlliieebb__]][[YYWWVVUUSSRRQQPPPPOONNNNMMMMLLLLKKKKJJJJJJIIIIIIIIHHHHHHHHHHGGGGGGGGGGFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸············¶¶¶¶¶¶¶¶¶¶µµµµµµµµ´´´´´´³³³³²²²²±±±±°°°°¯¯¯¯®®­­¬¬««ªª©©¨¨¦¦¥¥££¡¡ŸŸšš——””ŒŒˆˆ„„{{vvrrnnkkggddbb__]][[ZZXXWWUUTTSSRRQQQQPPOOOONNNNMMMMLLLLKKKKKKJJJJJJIIIIIIIIHHHHHHHHHHHHGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸············¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµ´´´´´´³³³³³³²²²²²²±±±±°°°°¯¯®®®®­­¬¬««ªª©©¨¨§§¦¦¤¤££¡¡ŸŸ››˜˜••’’‹‹‡‡ƒƒ{{wwsspplliiffddbb__]]\\ZZYYWWVVUUTTSSRRRRQQPPPPOONNNNMMMMMMLLLLKKKKKKKKJJJJJJIIIIIIIIIIHHHHHHHHHHHHGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··············¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµ´´´´´´´´³³³³³³²²²²²²±±±±°°°°¯¯¯¯®®®®­­¬¬««««ªª©©¨¨§§¥¥¤¤££¡¡ŸŸ››™™––””‘‘ŠŠ‡‡ƒƒ||xxttqqnnkkhhffccaa__^^\\[[YYXXWWVVUUTTSSRRRRQQPPPPOOOONNNNMMMMMMLLLLLLKKKKKKJJJJJJJJIIIIIIIIIIHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸················¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµ´´´´´´´´³³³³³³³³²²²²²²±±±±°°°°°°¯¯¯¯®®­­­­¬¬««««ªª©©¨¨§§¦¦¥¥¤¤¢¢¡¡ŸŸ››™™——••’’ŒŒ‰‰††ƒƒ||yyuurroolljjggeeccaa__^^\\[[ZZXXWWVVUUUUTTSSRRRRQQPPPPOOOONNNNNNMMMMMMLLLLLLKKKKKKKKJJJJJJJJIIIIIIIIIIIIHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸················¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµ´´´´´´´´´´³³³³³³³³²²²²²²±±±±±±°°°°¯¯¯¯®®®®­­­­¬¬¬¬««ªª©©©©¨¨§§¦¦¥¥££¢¢¡¡ŸŸžžœœšš˜˜––““‘‘ŽŽ‹‹ˆˆ……‚‚||yyvvssppnnkkiiggeeccaa__^^\\[[ZZYYXXWWVVUUTTTTSSRRRRQQQQPPPPOOOONNNNNNMMMMMMLLLLLLKKKKKKKKJJJJJJJJJJIIIIIIIIIIIIHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··················¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´³³³³³³³³³³²²²²²²±±±±±±°°°°°°¯¯¯¯®®®®­­­­¬¬¬¬««ªªªª©©¨¨§§¦¦¥¥¤¤££¢¢¡¡ŸŸžžœœšš˜˜––””’’‹‹ˆˆ……‚‚||yywwttqqoolljjhhffddbbaa__^^]][[ZZYYXXWWWWVVUUTTTTSSRRRRQQQQPPPPOOOOOONNNNMMMMMMMMLLLLLLKKKKKKKKKKJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´´´³³³³³³³³²²²²²²²²±±±±±±°°°°°°¯¯¯¯¯¯®®®®­­­­¬¬¬¬««ªªªª©©¨¨¨¨§§¦¦¥¥¤¤££¢¢  ŸŸžžœœ››™™——••““‘‘ŒŒŠŠ‡‡……‚‚}}zzwwuurrppnnkkiiggffddbbaa__^^]]\\[[ZZYYXXWWVVUUUUTTSSSSRRRRQQQQPPPPPPOOOONNNNNNMMMMMMMMLLLLLLLLKKKKKKKKKKJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµ´´´´´´´´´´´´³³³³³³³³²²²²²²²²±±±±±±±±°°°°°°¯¯¯¯®®®®®®­­­­¬¬¬¬««««ªª©©©©¨¨§§¦¦¥¥¥¥¤¤££¢¢  ŸŸžžœœ››™™˜˜––””’’ŽŽŒŒ‰‰‡‡„„‚‚}}zzxxuussqqoolljjiiggeeddbbaa__^^]]\\[[ZZYYXXWWWWVVUUUUTTSSSSRRRRQQQQPPPPPPOOOOOONNNNNNMMMMMMMMLLLLLLLLKKKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµ´´´´´´´´´´´´³³³³³³³³³³²²²²²²²²±±±±±±±±°°°°°°¯¯¯¯¯¯®®®®®®­­­­¬¬¬¬««««ªª©©©©¨¨¨¨§§¦¦¥¥¤¤££¢¢¡¡  ŸŸžž››šš˜˜——••““‘‘‹‹‰‰††„„‚‚}}{{xxvvttqqoommkkjjhhffeeccbbaa__^^]]\\[[ZZYYYYXXWWVVVVUUTTTTSSSSRRRRQQQQQQPPPPOOOOOONNNNNNNNMMMMMMMMLLLLLLLLKKKKKKKKKKKKJJJJJJJJJJJJIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAA½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµ´´´´´´´´´´´´³³³³³³³³³³²²²²²²²²±±±±±±±±°°°°°°°°¯¯¯¯¯¯®®®®­­­­­­¬¬¬¬««««ªªªª©©¨¨¨¨§§¦¦¦¦¥¥¤¤££¢¢¡¡  ŸŸžž››šš™™——––””’’ŽŽŒŒŠŠˆˆ††„„‚‚}}{{yyvvttrrppnnllkkiiggffddccbbaa__^^]]\\[[ZZZZYYXXWWWWVVUUUUTTTTSSSSRRRRQQQQQQPPPPPPOOOOOONNNNNNNNMMMMMMMMLLLLLLLLLLKKKKKKKKKKJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµ´´´´´´´´´´´´³³³³³³³³³³³³²²²²²²²²²²±±±±±±±±°°°°°°¯¯¯¯¯¯®®®®®®­­­­­­¬¬¬¬««««ªªªª©©©©¨¨§§§§¦¦¥¥¥¥¤¤££¢¢¡¡  ŸŸžžœœšš™™˜˜––••““‘‘ŽŽŒŒŠŠˆˆ††„„}}{{yywwuussqqoommlljjhhggeeddccbb``__^^]]\\\\[[ZZYYXXXXWWVVVVUUUUTTTTSSSSRRRRRRQQQQPPPPPPOOOOOOOONNNNNNMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKKJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´³³³³³³³³³³³³²²²²²²²²²²±±±±±±±±°°°°°°°°¯¯¯¯¯¯®®®®®®­­­­­­¬¬¬¬««««ªªªª©©©©¨¨¨¨§§§§¦¦¥¥¤¤¤¤££¢¢¡¡  ŸŸžžœœ››™™˜˜——••””’’‹‹‰‰‡‡……ƒƒ}}{{yywwuussrrppnnllkkiihhffeeddccbb``__^^]]]]\\[[ZZYYYYXXWWWWVVVVUUUUTTTTSSSSRRRRRRQQQQPPPPPPPPOOOOOONNNNNNNNMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKKKKJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®­­­­­­¬¬¬¬««««««ªªªª©©©©¨¨§§§§¦¦¦¦¥¥¤¤££££¢¢¡¡  ŸŸžžœœ››šš˜˜——––””““‘‘ŽŽŒŒ‹‹‰‰‡‡……ƒƒ}}{{yyxxvvttrrppoommlljjiiggffeeddbbaa``__^^^^]]\\[[ZZZZYYXXXXWWWWVVUUUUTTTTTTSSSSRRRRRRQQQQQQPPPPPPOOOOOOOONNNNNNNNMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±°°°°°°°°¯¯¯¯¯¯®®®®®®®®­­­­­­¬¬¬¬««««««ªªªª©©©©¨¨¨¨§§§§¦¦¥¥¥¥¤¤££££¢¢¡¡  ŸŸžžœœ››šš™™˜˜––••””’’‘‘ŒŒŠŠˆˆ‡‡……ƒƒ}}||zzxxvvttssqqoonnllkkjjhhggffeeccbbaa``__^^^^]]\\[[[[ZZYYYYXXWWWWVVVVUUUUTTTTSSSSSSRRRRRRQQQQQQPPPPPPOOOOOOOONNNNNNNNNNMMMMMMMMMMLLLLLLLLLLLLKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­¬¬¬¬««««««ªªªª©©©©¨¨¨¨§§§§¦¦¦¦¥¥¤¤¤¤££¢¢¢¢¡¡  ŸŸžžœœ››šš™™˜˜——••””““‘‘ŽŽ‹‹ŠŠˆˆ††……ƒƒ}}||zzxxwwuussrrppoommlljjiihhggeeddccbbaa``____^^]]\\[[[[ZZYYYYXXXXWWWWVVVVUUUUTTTTSSSSSSRRRRRRQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNNMMMMMMMMMMLLLLLLLLLLLLKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®­­­­­­­­¬¬¬¬««««««ªªªªªª©©©©¨¨¨¨§§§§¦¦¥¥¥¥¤¤¤¤££¢¢¢¢¡¡  ŸŸžžœœ››šš™™˜˜——––••““’’‘‘ŽŽŒŒ‹‹‰‰ˆˆ††„„ƒƒ~~||zzyywwuuttrrqqoonnllkkjjiiggffeeddccbbaa``____^^]]\\\\[[ZZZZYYXXXXWWWWVVVVUUUUUUTTTTSSSSSSRRRRRRQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLLLKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­­¬¬¬¬¬¬««««ªªªªªª©©©©¨¨¨¨§§§§¦¦¦¦¥¥¥¥¤¤££££¢¢¡¡¡¡  ŸŸžžœœ››šš™™——––••””““‘‘ŒŒŠŠ‰‰‡‡††„„‚‚~~||zzyywwvvttssqqppnnmmllkkiihhggffeeddccbbaa``____^^]]\\\\[[ZZZZYYYYXXXXWWWWVVVVUUUUTTTTTTSSSSSSRRRRRRQQQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­¬¬¬¬¬¬¬¬««««ªªªªªª©©©©©©¨¨¨¨§§§§¦¦¦¦¥¥¥¥¤¤££££¢¢¡¡¡¡  ŸŸžžžžœœ››šš™™˜˜——––””““’’‘‘ŽŽ‹‹ŠŠˆˆ‡‡……„„‚‚~~||{{yyxxvvuussrrppoonnllkkjjiihhggffeeddccbbaa``____^^]]\\\\[[[[ZZYYYYXXXXWWWWVVVVVVUUUUTTTTTTSSSSSSRRRRRRQQQQQQQQPPPPPPPPOOOOOOOOOONNNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBB¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­¬¬¬¬¬¬¬¬««««««ªªªª©©©©©©¨¨¨¨§§§§¦¦¦¦¥¥¥¥¤¤¤¤££££¢¢¡¡¡¡  ŸŸžžžžœœ››šš™™˜˜——––••””““‘‘ŽŽŒŒ‹‹ŠŠˆˆ‡‡……„„‚‚~~||{{yyxxvvuuttrrqqppnnmmllkkjjhhggffeeddddccbbaa``____^^]]]]\\[[[[ZZZZYYYYXXXXWWWWVVVVUUUUUUTTTTTTSSSSSSRRRRRRQQQQQQQQPPPPPPPPOOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­¬¬¬¬¬¬¬¬««««««ªªªªªª©©©©¨¨¨¨¨¨§§§§¦¦¦¦¥¥¥¥¤¤¤¤££¢¢¢¢¡¡¡¡  ŸŸžžžžœœ››šš™™˜˜——––••””““’’‘‘ŽŽŒŒ‹‹‰‰ˆˆ††……„„‚‚~~||{{yyxxwwuuttssqqppoonnllkkjjiihhggffeeddccbbbbaa``____^^]]]]\\[[[[ZZZZYYYYXXXXWWWWWWVVVVUUUUUUTTTTTTSSSSSSRRRRRRQQQQQQQQPPPPPPPPPPOOOOOOOOOONNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬««««««ªªªªªª©©©©©©¨¨¨¨§§§§¦¦¦¦¦¦¥¥¥¥¤¤££££¢¢¢¢¡¡    ŸŸžžžžœœ››šššš™™˜˜——––••””““’’ŽŽ‹‹ŠŠ‰‰ˆˆ††……ƒƒ‚‚~~||{{zzxxwwvvttssrrqqoonnmmllkkjjiihhggffeeddccbbbbaa``____^^]]]]\\\\[[ZZZZYYYYXXXXXXWWWWVVVVVVUUUUTTTTTTTTSSSSSSRRRRRRRRQQQQQQQQPPPPPPPPOOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬««««««ªªªªªª©©©©©©¨¨¨¨¨¨§§§§¦¦¦¦¥¥¥¥¤¤¤¤££££¢¢¢¢¡¡    ŸŸžžžžœœ››››šš™™˜˜——––••””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰‡‡††……ƒƒ‚‚~~}}{{zzyywwvvuussrrqqppoonnllkkjjiihhggffffeeddccbbbbaa``____^^]]]]\\\\[[[[ZZZZYYYYXXXXWWWWWWVVVVUUUUUUTTTTTTSSSSSSSSRRRRRRRRQQQQQQQQPPPPPPPPPPOOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸········································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬««««««ªªªªªªªª©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¥¥¥¥¤¤¤¤££££¢¢¢¢¡¡    ŸŸžžžžœœœœ››šš™™˜˜————––••””““’’ŽŽŒŒ‹‹ŠŠˆˆ‡‡††„„ƒƒ‚‚~~}}{{zzyywwvvuuttssqqppoonnmmllkkjjiihhggffeeeeddccbbaaaa``____^^^^]]\\\\[[[[ZZZZYYYYXXXXXXWWWWVVVVVVUUUUUUTTTTTTSSSSSSSSRRRRRRRRQQQQQQQQPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··········································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªª©©©©©©¨¨¨¨¨¨§§§§¦¦¦¦¥¥¥¥¥¥¤¤¤¤££££¢¢¢¢¡¡    ŸŸžžžžœœœœ››šš™™™™˜˜——––••””““’’‘‘ŽŽŒŒŠŠ‰‰ˆˆ‡‡††„„ƒƒ‚‚~~}}{{zzyyxxwwuuttssrrqqppoommllkkjjjjiihhggffeeddddccbbaaaa``____^^^^]]\\\\[[[[ZZZZYYYYYYXXXXWWWWWWVVVVVVUUUUUUTTTTTTSSSSSSSSRRRRRRRRQQQQQQQQPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··········································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªª©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¥¥¥¥¤¤¤¤¤¤££££¢¢¡¡¡¡    ŸŸŸŸžžœœ››šššš™™˜˜——––••””””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡……„„ƒƒ‚‚€€~~}}||zzyyxxwwvvttssrrqqppoonnmmllkkjjiihhggggffeeddccccbbaaaa``____^^^^]]]]\\\\[[[[ZZZZYYYYXXXXXXWWWWVVVVVVUUUUUUTTTTTTTTSSSSSSSSRRRRRRRRQQQQQQQQQQPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸············································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªª©©©©©©©©¨¨¨¨¨¨§§§§¦¦¦¦¦¦¥¥¥¥¤¤¤¤££££¢¢¢¢¡¡¡¡    ŸŸŸŸžžœœ››šššš™™˜˜————––••””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰‡‡††……„„ƒƒ‚‚€€~~}}||{{yyxxwwvvuuttssqqppoonnmmllkkkkjjiihhggffffeeddccccbbaaaa``____^^^^]]]]\\\\[[[[ZZZZYYYYYYXXXXWWWWWWVVVVVVUUUUUUTTTTTTTTSSSSSSSSRRRRRRRRQQQQQQQQQQPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··············································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªªªª©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¥¥¥¥¥¥¤¤¤¤££££¢¢¢¢¡¡¡¡    ŸŸŸŸžžœœ››››šš™™˜˜˜˜——––••””““““’’‘‘ŽŽŒŒ‹‹‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{yyxxwwvvuuttssrrqqppoonnmmllkkjjiihhhhggffeeeeddccbbbbaaaa``____^^^^]]]]\\\\[[[[ZZZZYYYYYYXXXXXXWWWWWWVVVVVVUUUUUUTTTTTTTTSSSSSSSSRRRRRRRRQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCC»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··············································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªªªª©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¤¤¤¤¤¤££££¢¢¢¢¡¡¡¡    ŸŸŸŸžžœœ››››šš™™™™˜˜——––––••””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyywwvvuuttssrrqqppoonnmmllllkkjjiihhggggffeeddddccbbbbaaaa``____^^^^]]]]\\\\[[[[ZZZZZZYYYYXXXXXXWWWWWWVVVVVVUUUUUUUUTTTTTTTTSSSSSSSSRRRRRRRRQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸················································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««ªªªªªª©©©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¤¤¤¤¤¤££££¢¢¢¢¡¡¡¡    ŸŸŸŸžžœœœœ››šššš™™˜˜————––••””““““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ€€~~}}||{{zzyyxxwwvvuuttssrrqqppoonnmmllkkjjiiiihhggffffeeddddccbbbbaaaa``____^^^^]]]]\\\\[[[[[[ZZZZYYYYYYXXXXXXWWWWWWVVVVVVUUUUUUUUTTTTTTSSSSSSSSSSRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··················································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««ªªªªªªªª©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤££££££¢¢¢¢¡¡¡¡    ŸŸŸŸžžœœœœ››šššš™™˜˜˜˜——––••••””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„‚‚€€~~}}||{{zzyyxxwwvvuuttssrrqqppoonnmmllllkkjjiihhhhggffeeeeddccccbbbbaa````____^^^^]]]]\\\\\\[[[[ZZZZYYYYYYXXXXXXWWWWWWVVVVVVVVUUUUUUTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··················································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««ªªªªªªªª©©©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤££££¢¢¢¢¢¢¡¡¡¡    ŸŸŸŸžžžžœœœœ››››šš™™™™˜˜——––––••””““’’’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyxxwwvvuuttssrrqqppoooonnmmllkkjjjjiihhggggffeeeeddccccbbbbaa````____^^^^]]]]\\\\\\[[[[ZZZZZZYYYYYYXXXXXXWWWWWWVVVVVVUUUUUUUUTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··················································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««ªªªªªªªª©©©©©©©©¨¨¨¨¨¨§§§§§§§§¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££¢¢¢¢¢¢¡¡¡¡    ŸŸŸŸžžžžœœœœ››››šš™™™™˜˜————––••””””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyxxwwvvuuttssssrrqqppoonnmmllllkkjjiiiihhggffffeeddddccccbbbbaa````____^^^^]]]]]]\\\\[[[[ZZZZZZYYYYYYXXXXXXWWWWWWVVVVVVVVUUUUUUUUTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······················································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««ªªªªªªªªªª©©©©©©¨¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££¢¢¢¢¡¡¡¡¡¡    ŸŸŸŸžžžžœœœœ››››šššš™™˜˜˜˜——––••••””““’’’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyxxwwvvvvuuttssrrqqppoonnnnmmllkkkkjjiihhhhggffffeeddddccccbbaaaa````____^^^^]]]]]]\\\\[[[[[[ZZZZZZYYYYXXXXXXXXWWWWWWVVVVVVVVUUUUUUUUTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······················································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªª©©©©©©©©¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤££££££¢¢¢¢¡¡¡¡¡¡    ŸŸŸŸžžžžœœ››››šššš™™˜˜˜˜——––––••””””““’’‘‘ŽŽŒŒ‹‹‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyyyxxwwvvuuttssrrqqppppoonnmmllllkkjjiiiihhggggffeeeeddddccbbbbaaaa````____^^^^^^]]]]\\\\[[[[[[ZZZZZZYYYYYYXXXXXXWWWWWWWWVVVVVVUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······················································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¡¡¡¡      ŸŸŸŸžžžžœœœœ››šššš™™™™˜˜————––••••””““’’’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{{{zzyyxxwwvvuuttssrrrrqqppoonnnnmmllkkkkjjiihhhhggggffeeeeddddccbbbbaaaa````____^^^^^^]]]]\\\\\\[[[[ZZZZZZYYYYYYXXXXXXXXWWWWWWVVVVVVVVUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··························································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¡¡¡¡      ŸŸŸŸžžžžœœœœ››››šš™™™™˜˜˜˜——––––••””””““’’‘‘‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡‡‡††……„„ƒƒ‚‚€€~~}}||||{{zzyyxxwwvvuuttttssrrqqppoooonnmmllllkkjjjjiihhhhggffffeeeeddccccbbbbaaaa````____^^^^^^]]]]\\\\\\[[[[[[ZZZZZZYYYYYYXXXXXXWWWWWWWWVVVVVVVVUUUUUUUUTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··························································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££¢¢¢¢¢¢¡¡¡¡      ŸŸŸŸžžžžœœœœ››››šššš™™˜˜˜˜——––––••••””““’’’’‘‘ŽŽŒŒ‹‹‹‹ŠŠ‰‰ˆˆ‡‡††††……„„ƒƒ‚‚€€~~}}}}||{{zzyyxxwwvvvvuuttssrrqqqqppoonnnnmmllkkkkjjiiiihhggggffffeeddddccccbbbbaaaa````____^^^^^^]]]]\\\\\\[[[[[[ZZZZZZYYYYYYXXXXXXXXWWWWWWVVVVVVVVUUUUUUUUUUTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEºººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··························································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡      ŸŸŸŸžžžžœœœœ››››šššš™™™™˜˜————––••••””““““’’‘‘‘‘ŽŽŽŽŒŒ‹‹ŠŠŠŠ‰‰ˆˆ‡‡††…………„„ƒƒ‚‚€€~~}}}}||{{zzyyxxwwwwvvuuttssrrrrqqppoooonnmmllllkkjjjjiihhhhggggffeeeeddddccccbbbbaaaa````______^^^^]]]]]]\\\\[[[[[[ZZZZZZYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEºººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······························································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡      ŸŸŸŸžžžžœœœœ››››šššš™™™™˜˜˜˜——––––••””””““’’’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰‰‰ˆˆ‡‡††……„„„„ƒƒ‚‚€€~~~~}}||{{zzyyxxxxwwvvuuttttssrrqqppppoonnmmmmllkkkkjjiiiihhhhggffffeeeeddddccccbbbbaaaa````______^^^^]]]]]]\\\\[[[[[[ZZZZZZZZYYYYYYXXXXXXXXWWWWWWVVVVVVVVVVUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEºººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······························································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡      ŸŸŸŸžžžžœœœœ››››šššš™™™™˜˜˜˜————––••••””““““’’‘‘‘‘ŽŽŒŒŒŒ‹‹ŠŠ‰‰ˆˆˆˆ‡‡††……„„ƒƒƒƒ‚‚€€~~~~}}||{{zzyyyyxxwwvvuuuuttssrrqqqqppoooonnmmllllkkjjjjiiiihhggggffffeeeeddddccccbbbbaaaa````______^^^^]]]]]]\\\\\\[[[[[[ZZZZZZYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEºº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······························································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸžžžžœœœœœœ››››šššš™™˜˜˜˜————––––••””””““’’’’‘‘ŽŽŽŽŒŒ‹‹‹‹ŠŠ‰‰ˆˆ‡‡‡‡††……„„ƒƒƒƒ‚‚€€~~~~}}||{{zzyyyyxxwwvvvvuuttssrrrrqqppppoonnmmmmllkkkkjjjjiihhhhggggffffeeddddccccbbbbbbaaaa````______^^^^]]]]]]\\\\\\[[[[[[ZZZZZZYYYYYYYYXXXXXXWWWWWWWWWWVVVVVVVVUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸžžžžœœœœ››››šššš™™™™˜˜————––––••••””““““’’‘‘‘‘ŽŽŒŒ‹‹ŠŠŠŠ‰‰ˆˆ‡‡††††……„„ƒƒ‚‚‚‚€€~~~~}}||{{zzzzyyxxwwvvvvuuttssssrrqqqqppoonnnnmmllllkkkkjjiiiihhhhggffffeeeeddddccccbbbbbbaaaa````______^^^^]]]]]]\\\\\\[[[[[[ZZZZZZZZYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVVVUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸžžžžœœœœ››››šššš™™™™˜˜˜˜————––••••””””““’’’’‘‘ŽŽŽŽŒŒŒŒ‹‹ŠŠ‰‰‰‰ˆˆ‡‡††††……„„ƒƒ‚‚‚‚€€~~~~}}||{{{{zzyyxxwwwwvvuuttttssrrqqqqppoooonnmmmmllkkkkjjjjiiiihhggggffffeeeeddddccccbbbbaaaaaa````______^^^^]]]]]]\\\\\\[[[[[[[[ZZZZZZYYYYYYYYXXXXXXWWWWWWWWWWVVVVVVVVUUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸžžžžžžœœœœ››››šššš™™™™˜˜˜˜————––––••””””““““’’‘‘‘‘ŽŽŒŒ‹‹‹‹ŠŠ‰‰ˆˆˆˆ‡‡††…………„„ƒƒ‚‚‚‚€€~~~~}}||{{{{zzyyxxxxwwvvuuuuttssrrrrqqppppoonnnnmmllllkkkkjjiiiihhhhggggffffeeeeddddccccbbbbaaaaaa````______^^^^^^]]]]\\\\\\\\[[[[[[ZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEE¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸžžžžžžœœœœ››››šššš™™™™˜˜˜˜————––––••••””””““’’’’‘‘‘‘ŽŽŒŒ‹‹ŠŠŠŠ‰‰ˆˆˆˆ‡‡††…………„„ƒƒ‚‚‚‚€€~~~~}}||{{{{zzyyxxxxwwvvuuuuttssssrrqqqqppoooonnmmmmllllkkjjjjiiiihhhhggggffffeeeeddddccccbbbbaaaaaa````______^^^^^^]]]]]]\\\\\\[[[[[[ZZZZZZZZYYYYYYXXXXXXXXWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEE¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤££££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸžžžžžžœœœœ››››››šššš™™™™˜˜˜˜————––––••””””““““’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹ŠŠŠŠ‰‰ˆˆ‡‡‡‡††……„„„„ƒƒ‚‚‚‚€€~~}}||||{{zzyyyyxxwwvvvvuuttttssrrrrqqppppoonnnnmmllllkkkkjjjjiihhhhggggffffeeeeddddddccccbbbbaaaaaa````______^^^^^^]]]]]]\\\\\\[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸········································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤££££££££¢¢¢¢¢¢¡¡¡¡¡¡    ŸŸŸŸŸŸžžžžžžœœœœœœ››››šššš™™™™˜˜˜˜————––––••••””””““’’’’‘‘‘‘ŽŽŒŒ‹‹‹‹ŠŠ‰‰‰‰ˆˆ‡‡‡‡††……„„„„ƒƒ‚‚€€~~}}||||{{zzyyyyxxwwwwvvuuttttssrrrrqqppppoooonnmmmmllllkkjjjjiiiihhhhggggffffeeeeddddccccccbbbbaaaaaa````______^^^^^^]]]]]]\\\\\\[[[[[[[[ZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸········································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡    ŸŸŸŸŸŸžžžžžžœœœœœœ››››šššš™™™™˜˜˜˜————––––••••””””““““’’‘‘‘‘ŽŽŽŽŒŒ‹‹‹‹ŠŠ‰‰‰‰ˆˆ‡‡††††……„„„„ƒƒ‚‚€€~~}}||||{{zzyyyyxxwwwwvvuuuuttssssrrqqqqppoooonnnnmmllllkkkkjjjjiiiihhhhggggffffeeeeddddccccbbbbbbaaaa``````______^^^^^^]]]]]]\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸········································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡¡¡¡    ŸŸŸŸŸŸžžžžžžœœœœœœ››››šššš™™™™™™˜˜˜˜————––––••••””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹ŠŠŠŠ‰‰ˆˆˆˆ‡‡††††……„„„„ƒƒ‚‚€€~~}}||||{{zzzzyyxxxxwwvvuuuuttssssrrrrqqppppoonnnnmmmmllllkkjjjjiiiihhhhggggffffeeeeeeddddccccbbbbbbaaaa``````______^^^^^^]]]]]]\\\\\\\\[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸············································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««ªªªªªªªªªª©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤££££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœ››››šššššš™™™™˜˜˜˜————––––••••””””““““’’’’‘‘ŽŽŒŒ‹‹‹‹ŠŠŠŠ‰‰ˆˆˆˆ‡‡††††……„„ƒƒƒƒ‚‚€€~~}}||||{{zzzzyyxxxxwwvvvvuuttttssrrrrqqqqppoooonnnnmmllllkkkkjjjjiiiihhhhggggffffeeeeddddddccccbbbbbbaaaa``````______^^^^^^]]]]]]\\\\\\\\[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXXXWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸············································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««ªªªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœ››››››šššš™™™™˜˜˜˜————––––••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒ‹‹‹‹ŠŠ‰‰‰‰ˆˆ‡‡‡‡††…………„„ƒƒƒƒ‚‚€€~~}}}}||{{zzzzyyxxxxwwvvvvuuuuttssssrrqqqqppppoonnnnmmmmllllkkkkjjjjiiiihhhhggggffffeeeeddddddccccbbbbbbaaaa``````______^^^^^^]]]]]]]]\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸············································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««ªªªªªªªªªªªª©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœ››››››šššš™™™™˜˜˜˜˜˜————––––••••””””““““’’’’‘‘ŽŽŽŽŒŒŒŒ‹‹ŠŠŠŠ‰‰‰‰ˆˆ‡‡‡‡††…………„„ƒƒƒƒ‚‚€€~~}}}}||{{{{zzyyyyxxwwwwvvuuuuttssssrrrrqqppppoooonnnnmmllllkkkkjjjjiiiihhhhggggffffffeeeeddddccccccbbbbbbaaaa``````______^^^^^^]]]]]]]]\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXXXWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸················································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªªªªª©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœœ››››šššš™™™™™™˜˜˜˜————––––••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹ŠŠŠŠ‰‰ˆˆˆˆ‡‡††††…………„„ƒƒƒƒ‚‚€€~~}}}}||{{{{zzyyyyxxwwwwvvuuuuttttssrrrrqqqqppoooonnnnmmmmllllkkkkjjjjiiiihhhhggggffffeeeeeeddddccccccbbbbaaaaaa``````______^^^^^^]]]]]]]]\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYYYXXXXXXXXWWWWWWWWWWVVVVVVVVVVVVUUUUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFF¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸················································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœœ››››šššššš™™™™˜˜˜˜——————––––••••””””““““’’’’‘‘ŽŽŽŽŒŒ‹‹‹‹ŠŠŠŠ‰‰ˆˆˆˆ‡‡††††……„„„„ƒƒƒƒ‚‚€€~~}}}}||{{{{zzyyyyxxwwwwvvvvuuttttssssrrqqqqppppoooonnmmmmllllkkkkjjjjiiiihhhhhhggggffffeeeeeeddddccccccbbbbaaaaaa``````______^^^^^^^^]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXXXWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFF¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸················································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««ªªªªªªªªªªªª©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœœ››››šššššš™™™™˜˜˜˜˜˜————––––••••””””““““’’’’‘‘‘‘ŽŽŒŒŒŒ‹‹‹‹ŠŠ‰‰‰‰ˆˆˆˆ‡‡††††……„„„„ƒƒ‚‚‚‚€€~~}}}}||{{{{zzyyyyxxxxwwvvvvuuuuttssssrrrrqqppppoooonnnnmmmmllllkkkkjjjjiiiihhhhggggggffffeeeeddddddccccbbbbbbaaaaaa``````______^^^^^^^^]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYYYXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····················································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««ªªªªªªªªªªªª©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššš™™™™™™˜˜˜˜————––––••••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹ŠŠŠŠ‰‰‰‰ˆˆ‡‡‡‡††††……„„„„ƒƒ‚‚‚‚€€~~}}}}||{{{{zzzzyyxxxxwwwwvvuuuuttttssrrrrqqqqppppoooonnmmmmllllkkkkjjjjjjiiiihhhhggggffffffeeeeddddddccccbbbbbbaaaaaa``````______^^^^^^^^]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYYYXXXXXXXXXXWWWWWWWWWWVVVVVVVVVVVVUUUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····················································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««ªªªªªªªªªªªªªª©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¡¡¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžžžœœœœœœ››››››šššš™™™™™™˜˜˜˜——————––––••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒ‹‹‹‹ŠŠŠŠ‰‰ˆˆˆˆ‡‡‡‡††…………„„„„ƒƒ‚‚‚‚€€~~}}}}||||{{zzzzyyxxxxwwwwvvuuuuttttssssrrqqqqppppoooonnnnmmmmllllkkkkjjjjiiiihhhhhhggggffffeeeeeeddddccccccbbbbbbaaaaaa``````______^^^^^^^^]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZZZYYYYYYYYXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····················································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««ªªªªªªªªªªªªªª©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¡¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸŸžžžžžžœœœœ››››››šššššš™™™™˜˜˜˜˜˜————––––••••””””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††…………„„„„ƒƒ‚‚‚‚€€€€~~}}}}||||{{zzzzyyyyxxwwwwvvvvuuttttssssrrrrqqqqppoooonnnnmmmmllllkkkkkkjjjjiiiihhhhggggggffffeeeeeeddddccccccbbbbbbaaaaaa``````______^^^^^^^^]]]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYYYXXXXXXXXXXWWWWWWWWWWVVVVVVVVVVVVUUUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG¸¸¸¸······················································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««ªªªªªªªªªªªªªª©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸŸžžžžžžœœœœœœ››››šššššš™™™™˜˜˜˜˜˜————––––––••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡††††…………„„ƒƒƒƒ‚‚‚‚€€€€~~}}}}||||{{zzzzyyyyxxwwwwvvvvuuuuttssssrrrrqqqqppppoooonnnnmmmmllllkkkkjjjjiiiiiihhhhggggffffffeeeeddddddccccccbbbbbbaaaaaa``````______^^^^^^^^]]]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYYYXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVUUUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG··················································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««ªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸŸžžžžžžœœœœœœ››››šššššš™™™™™™˜˜˜˜——————––––••••””””““““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆ‡‡‡‡††††…………„„ƒƒƒƒ‚‚‚‚€€€€~~}}}}||||{{{{zzyyyyxxxxwwvvvvuuuuttttssssrrqqqqppppoooonnnnmmmmllllkkkkkkjjjjiiiihhhhhhggggffffffeeeeddddddccccccbbbbbbaaaaaa``````________^^^^^^]]]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZZZYYYYYYYYYYXXXXXXXXXXWWWWWWWWWWVVVVVVVVVVVVUUUUUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG········································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««ªªªªªªªªªªªªªª©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššš™™™™™™˜˜˜˜˜˜————––––••••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆ‡‡‡‡††††…………„„ƒƒƒƒ‚‚‚‚€€€€~~}}}}||||{{{{zzyyyyxxxxwwwwvvuuuuttttssssrrrrqqqqppppoooonnnnmmmmllllkkkkjjjjiiiiiihhhhggggggffffeeeeeeddddddccccccbbbbbbaaaaaa``````________^^^^^^]]]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZZZYYYYYYYYYYXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVUUUUUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGG······························································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««ªªªªªªªªªªªªªª©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššššš™™™™˜˜˜˜˜˜————––––––••••””””““““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††……„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}||||{{{{zzyyyyxxxxwwwwvvvvuuttttssssrrrrqqqqppppoooonnnnmmmmllllllkkkkjjjjiiiihhhhhhggggffffffeeeeeeddddddccccbbbbbbbbaaaaaa``````________^^^^^^]]]]]]]]\\\\\\\\[[[[[[[[[[ZZZZZZZZYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVUUUUUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGG······················································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««ªªªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššššš™™™™™™˜˜˜˜——————––––••••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}||||{{{{zzzzyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqppppoooonnnnmmmmllllkkkkjjjjjjiiiihhhhhhggggffffffeeeeeeddddccccccbbbbbbaaaaaaaa``````________^^^^^^]]]]]]]]\\\\\\\\\\[[[[[[[[ZZZZZZZZZZYYYYYYYYYYXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGG············································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««ªªªªªªªªªªªªªªªª©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššššš™™™™™™˜˜˜˜˜˜————––––––••••””””““““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}||||{{{{zzzzyyyyxxwwwwvvvvuuuuttttssssrrrrqqqqppppoooonnnnmmmmllllllkkkkjjjjiiiiiihhhhggggggffffffeeeeddddddccccccbbbbbbaaaaaaaa``````________^^^^^^]]]]]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZZZYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH··································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««ªªªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžœœœœœœœœ››››››šššš™™™™™™˜˜˜˜˜˜————––––––••••””””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚€€€€~~~~}}||||{{{{zzzzyyyyxxxxwwvvvvuuuuttttssssrrrrqqqqppppoooonnnnnnmmmmllllkkkkjjjjjjiiiihhhhhhggggggffffeeeeeeddddddccccccbbbbbbaaaaaaaa``````________^^^^^^^^]]]]]]]]\\\\\\\\[[[[[[[[[[ZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVVVUUUUUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH··························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««ªªªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššššš™™™™˜˜˜˜˜˜——————––––••••••””””““““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚€€€€~~~~}}}}||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqppppoooonnnnmmmmllllllkkkkjjjjiiiiiihhhhhhggggffffffeeeeeeddddddccccccbbbbbbaaaaaaaa``````________^^^^^^^^]]]]]]]]\\\\\\\\[[[[[[[[[[ZZZZZZZZZZYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««ªªªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššššš™™™™™™˜˜˜˜——————––––––••••””””””““““’’’’‘‘‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒ‚‚‚‚€€€€~~~~}}}}||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqppppoooonnnnnnmmmmllllkkkkkkjjjjiiiiiihhhhggggggffffffeeeeeeddddddccccccbbbbbbaaaaaa````````________^^^^^^^^]]]]]]]]\\\\\\\\[[[[[[[[[[ZZZZZZZZZZYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVVVUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH······¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««ªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššššš™™™™™™˜˜˜˜˜˜————––––––••••••””””““““’’’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒ‚‚‚‚€€€€~~~~}}}}||||{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqppppppoooonnnnmmmmllllllkkkkjjjjjjiiiihhhhhhggggggffffeeeeeeddddddccccccccbbbbbbaaaaaa````````________^^^^^^^^]]]]]]]]\\\\\\\\\\[[[[[[[[ZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVVVUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««ªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššššš™™™™™™˜˜˜˜˜˜——————––––••••••””””””““““’’’’‘‘‘‘‘‘ŽŽŽŽŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††……„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzyyyyxxxxwwwwvvvvuuuuttttssssssrrrrqqqqppppoooonnnnnnmmmmllllkkkkkkjjjjiiiiiihhhhhhggggffffffeeeeeeddddddccccccbbbbbbbbaaaaaa````````________^^^^^^^^]]]]]]]]\\\\\\\\\\[[[[[[[[[[ZZZZZZZZZZYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««ªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœ››››››››šššššš™™™™™™˜˜˜˜——————––––––••••””””””““““’’’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqppppoooooonnnnmmmmllllllkkkkjjjjjjiiiihhhhhhggggggffffffeeeeeeddddddccccccbbbbbbbbaaaaaa````````________^^^^^^^^]]]]]]]]\\\\\\\\\\[[[[[[[[[[ZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHH¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««ªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››šššššš™™™™™™˜˜˜˜˜˜——————––––••••••””””““““““’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqqqppppoooonnnnmmmmmmllllkkkkkkjjjjiiiiiihhhhhhggggggffffffeeeeeeddddddccccccbbbbbbbbaaaaaa````````________^^^^^^^^]]]]]]]]]]\\\\\\\\[[[[[[[[[[ZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHH¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««ªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››šššššš™™™™™™˜˜˜˜˜˜——————––––––••••””””””““““’’’’’’‘‘‘‘ŽŽŽŽŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssssrrrrqqqqppppoooooonnnnmmmmllllllkkkkjjjjjjiiiiiihhhhhhggggffffffeeeeeeddddddddccccccbbbbbbbbaaaaaa````````________^^^^^^^^]]]]]]]]]]\\\\\\\\[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHH¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««ªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››šššššš™™™™™™˜˜˜˜˜˜——————––––––••••••””””““““““’’’’‘‘‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttttssssrrrrqqqqppppppoooonnnnmmmmmmllllkkkkkkjjjjjjiiiihhhhhhggggggffffffeeeeeeddddddddccccccbbbbbbaaaaaaaa````````________^^^^^^^^]]]]]]]]]]\\\\\\\\\\[[[[[[[[[[ZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››šššššššš™™™™™™˜˜˜˜˜˜——————––––••••••””””””““““’’’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvvvuuuuttttssssrrrrqqqqqqppppoooonnnnnnmmmmllllllkkkkkkjjjjiiiiiihhhhhhggggggffffffeeeeeeddddddccccccccbbbbbbaaaaaaaa````````________^^^^^^^^]]]]]]]]]]\\\\\\\\\\[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœ››››››››šššššš™™™™™™˜˜˜˜˜˜——————––––––••••••””””““““““’’’’‘‘‘‘‘‘ŽŽŽŽŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxxxwwwwvvvvuuuuttttssssrrrrrrqqqqppppoooooonnnnmmmmmmllllkkkkkkjjjjjjiiiiiihhhhhhggggggffffffeeeeeeddddddccccccccbbbbbbaaaaaaaa````````________^^^^^^^^^^]]]]]]]]\\\\\\\\\\[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««ªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœ››››››››šššššš™™™™™™˜˜˜˜˜˜——————––––––••••••””””””““““’’’’’’‘‘‘‘ŽŽŽŽŽŽŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††………………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyyyxxxxwwwwvvvvuuuuttttttssssrrrrqqqqppppppoooonnnnnnmmmmllllllkkkkkkjjjjiiiiiihhhhhhggggggffffffeeeeeeeeddddddccccccbbbbbbbbaaaaaaaa````````________^^^^^^^^^^]]]]]]]]\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««ªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœ››››››››šššššš™™™™™™™™˜˜˜˜˜˜——————––––––••••””””””““““““’’’’‘‘‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{{{zzzzyyyyxxxxwwwwvvvvuuuuuuttttssssrrrrqqqqqqppppoooooonnnnmmmmmmllllkkkkkkjjjjjjiiiiiihhhhhhggggggffffffeeeeeeddddddddccccccbbbbbbbbaaaaaaaa````````________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››šššššššš™™™™™™˜˜˜˜˜˜——————––––––••••••””””””““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{{{zzzzyyyyxxxxwwwwvvvvvvuuuuttttssssrrrrrrqqqqppppppoooonnnnnnmmmmllllllkkkkkkjjjjjjiiiihhhhhhhhggggggffffffeeeeeeddddddddccccccbbbbbbbbaaaaaaaa````````________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››šššššššš™™™™™™˜˜˜˜˜˜——————––––––••••••””””””““““““’’’’’’‘‘‘‘ŽŽŽŽŽŽŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||||{{{{zzzzyyyyxxxxwwwwwwvvvvuuuuttttssssssrrrrqqqqqqppppoooooonnnnmmmmmmllllllkkkkjjjjjjiiiiiihhhhhhggggggffffffffeeeeeeddddddccccccccbbbbbbbbaaaaaaaa````````________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››››šššššš™™™™™™˜˜˜˜˜˜˜˜——————––––––••••••””””””““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€~~~~}}}}||||||{{{{zzzzyyyyxxxxxxwwwwvvvvuuuuttttttssssrrrrrrqqqqppppoooooonnnnnnmmmmllllllkkkkkkjjjjjjiiiiiihhhhhhggggggffffffeeeeeeeeddddddccccccccbbbbbbbbaaaaaaaa````````________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››››šššššš™™™™™™™™˜˜˜˜˜˜——————––––––••••••””””””““““““’’’’’’‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††††…………„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€~~~~}}}}}}||||{{{{zzzzyyyyxxxxxxwwwwvvvvuuuuuuttttssssrrrrrrqqqqppppppoooonnnnnnmmmmmmllllllkkkkjjjjjjiiiiiihhhhhhggggggggffffffeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa````````________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››››šššššššš™™™™™™˜˜˜˜˜˜——————––––––––••••••””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆ‡‡‡‡††††††…………„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€~~~~}}}}}}||||{{{{zzzzyyyyyyxxxxwwwwvvvvvvuuuuttttssssssrrrrqqqqqqppppoooooonnnnnnmmmmllllllkkkkkkjjjjjjiiiiiihhhhhhggggggffffffffeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa````````________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœ››››››››šššššššš™™™™™™˜˜˜˜˜˜˜˜——————––––––••••••””””””““““““’’’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡††††………………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}}}||||{{{{zzzzyyyyyyxxxxwwwwvvvvvvuuuuttttttssssrrrrrrqqqqppppppoooonnnnnnmmmmmmllllllkkkkkkjjjjjjiiiiiihhhhhhggggggffffffeeeeeeeeddddddddccccccbbbbbbbbaaaaaaaaaa````````__________^^^^^^^^]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœ››››››šššššššš™™™™™™™™˜˜˜˜˜˜——————––––––••••••””””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡††††………………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}}}||||{{{{zzzzzzyyyyxxxxwwwwwwvvvvuuuuttttttssssrrrrrrqqqqqqppppoooooonnnnnnmmmmllllllkkkkkkjjjjjjiiiiiihhhhhhggggggggffffffeeeeeeeeddddddccccccccbbbbbbbbaaaaaaaaaa````````__________^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœ››››››››šššššš™™™™™™™™˜˜˜˜˜˜————————––––––••••••””””””““““““’’’’’’‘‘‘‘ŽŽŽŽŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡‡‡††††…………„„„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~~~}}}}||||{{{{zzzzzzyyyyxxxxwwwwwwvvvvuuuuuuttttssssssrrrrqqqqqqppppppoooonnnnnnmmmmmmllllllkkkkkkjjjjjjiiiiiihhhhhhggggggffffffffeeeeeeeeddddddccccccccbbbbbbbbaaaaaaaaaa````````__________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœ››››››››šššššššš™™™™™™˜˜˜˜˜˜˜˜——————––––––••••••””””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡‡††††…………„„„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~~~}}}}||||{{{{{{zzzzyyyyxxxxxxwwwwvvvvvvuuuuttttttssssrrrrrrqqqqppppppoooooonnnnmmmmmmllllllkkkkkkjjjjjjiiiiiiiihhhhhhggggggffffffffeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa``````````__________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœ››››››››šššššššš™™™™™™˜˜˜˜˜˜˜˜——————––––––––••••••””””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡††††††…………„„„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~~~}}}}||||{{{{{{zzzzyyyyxxxxxxwwwwvvvvvvuuuuttttttssssrrrrrrqqqqqqppppoooooonnnnnnmmmmmmllllllkkkkkkjjjjjjiiiiiihhhhhhggggggggffffffeeeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa``````````__________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœ››››››››šššššššš™™™™™™™™˜˜˜˜˜˜————————––––––••••••””””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡††††††…………„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€~~~~~~}}}}||||{{{{{{zzzzyyyyyyxxxxwwwwwwvvvvuuuuuuttttssssssrrrrqqqqqqppppppoooooonnnnmmmmmmllllllkkkkkkjjjjjjjjiiiiiihhhhhhggggggggffffffeeeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa``````````__________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœ››››››››šššššššš™™™™™™™™˜˜˜˜˜˜˜˜——————––––––••••••••””””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡††††………………„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€~~~~~~}}}}||||||{{{{zzzzyyyyyyxxxxwwwwwwvvvvuuuuuuttttssssssrrrrrrqqqqppppppoooooonnnnnnmmmmmmllllllkkkkkkjjjjjjiiiiiihhhhhhhhggggggffffffffeeeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa``````````__________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœœœ››››››››šššššššš™™™™™™˜˜˜˜˜˜˜˜——————––––––––••••••””””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡‡††††………………„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€€€~~~~~~}}}}||||||{{{{zzzzyyyyyyxxxxwwwwwwvvvvvvuuuuttttttssssrrrrrrqqqqqqppppppoooonnnnnnmmmmmmllllllkkkkkkjjjjjjjjiiiiiihhhhhhggggggggffffffffeeeeeeddddddddccccccccbbbbbbbbbbaaaaaaaa``````````__________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››››šššššššš™™™™™™™™˜˜˜˜˜˜————————––––––••••••””””””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡‡††††………………„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€€€~~~~~~}}}}||||||{{{{zzzzzzyyyyxxxxxxwwwwvvvvvvuuuuttttttssssssrrrrqqqqqqppppppoooooonnnnnnmmmmmmllllllkkkkkkjjjjjjiiiiiiiihhhhhhggggggggffffffeeeeeeeeddddddddccccccccbbbbbbbbbbaaaaaaaa``````````__________^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››››šššššššš™™™™™™™™˜˜˜˜˜˜————————––––––••••••••””””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡††††††………………„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}||||||{{{{zzzzzzyyyyxxxxxxwwwwvvvvvvuuuuuuttttssssssrrrrrrqqqqqqppppoooooonnnnnnmmmmmmllllllkkkkkkkkjjjjjjiiiiiihhhhhhhhggggggffffffffeeeeeeeeddddddddccccccccbbbbbbbbbbaaaaaaaa``````````__________^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››››šššššššš™™™™™™™™˜˜˜˜˜˜˜˜——————––––––––••••••””””””““““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡††††††…………„„„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}||||||{{{{zzzzzzyyyyxxxxxxwwwwwwvvvvuuuuuuttttttssssrrrrrrqqqqqqppppppoooooonnnnnnmmmmmmllllllkkkkkkjjjjjjjjiiiiiihhhhhhggggggggffffffffeeeeeeeeddddddddccccccccbbbbbbbbaaaaaaaaaa``````````__________^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››››šššššššš™™™™™™™™˜˜˜˜˜˜˜˜————————––––––••••••••””””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡‡††††††…………„„„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}||||||{{{{{{zzzzyyyyyyxxxxwwwwwwvvvvvvuuuuttttttssssssrrrrqqqqqqppppppoooooonnnnnnmmmmmmllllllkkkkkkkkjjjjjjiiiiiiiihhhhhhggggggggffffffffeeeeeeeeddddddddccccccccbbbbbbbbaaaaaaaaaa``````````__________^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››››››šššššššš™™™™™™™™˜˜˜˜˜˜————————––––––––••••••””””””““““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡‡††††††…………„„„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||{{{{{{zzzzyyyyyyxxxxwwwwwwvvvvvvuuuuttttttssssssrrrrrrqqqqqqppppppoooooonnnnnnmmmmmmllllllkkkkkkjjjjjjjjiiiiiihhhhhhhhggggggffffffffeeeeeeeeddddddddccccccccccbbbbbbbbaaaaaaaaaa``````````__________^^^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœœœ››››››››šššššššš™™™™™™™™˜˜˜˜˜˜˜˜——————––––––––••••••””””””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††………………„„„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||{{{{{{zzzzyyyyyyxxxxxxwwwwvvvvvvuuuuuuttttssssssrrrrrrqqqqqqppppppoooooonnnnnnmmmmmmllllllllkkkkkkjjjjjjiiiiiiiihhhhhhggggggggffffffffeeeeeeeeddddddddccccccccccbbbbbbbbaaaaaaaaaa``````````__________^^^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœœœ››››››››šššššššš™™™™™™™™˜˜˜˜˜˜˜˜————————––––––••••••••””””””““““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††………………„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||{{{{{{zzzzyyyyyyxxxxxxwwwwwwvvvvuuuuuuttttttssssssrrrrrrqqqqppppppoooooonnnnnnnnmmmmmmllllllkkkkkkjjjjjjjjiiiiiihhhhhhhhggggggggffffffffeeeeeeeeddddddddccccccccbbbbbbbbbbaaaaaaaaaa``````````__________^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœœœ››››››››šššššššš™™™™™™™™˜˜˜˜˜˜˜˜————————––––––––••••••””””””””““““““’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡††††††………………„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||{{{{{{zzzzzzyyyyxxxxxxwwwwwwvvvvuuuuuuttttttssssssrrrrrrqqqqqqppppppoooooonnnnnnmmmmmmllllllllkkkkkkjjjjjjiiiiiiiihhhhhhhhggggggggffffffffeeeeeeeeddddddddccccccccbbbbbbbbbbaaaaaaaaaa``````````__________^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKK³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœ››››››››šššššššššš™™™™™™™™˜˜˜˜˜˜˜˜——————––––––––••••••••””””””““““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||{{{{{{zzzzzzyyyyxxxxxxwwwwwwvvvvvvuuuuuuttttssssssrrrrrrqqqqqqppppppoooooonnnnnnnnmmmmmmllllllkkkkkkkkjjjjjjiiiiiiiihhhhhhggggggggffffffffeeeeeeeeddddddddddccccccccbbbbbbbbbbaaaaaaaaaa``````````__________^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKK³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœ››››››››››šššššššš™™™™™™™™˜˜˜˜˜˜˜˜————————––––––––••••••””””””””““““““’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††…………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~}}}}}}||||||{{{{zzzzzzyyyyyyxxxxwwwwwwvvvvvvuuuuuuttttttssssssrrrrrrqqqqqqppppppoooooonnnnnnmmmmmmllllllllkkkkkkjjjjjjjjiiiiiihhhhhhhhggggggggffffffffeeeeeeeeddddddddddccccccccbbbbbbbbbbaaaaaaaaaa``````````__________^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKK³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœ››››››››››šššššššš™™™™™™™™˜˜˜˜˜˜˜˜————————––––––––••••••••””””””““““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††…………„„„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€€€~~~~}}}}}}||||||{{{{zzzzzzyyyyyyxxxxxxwwwwvvvvvvuuuuuuttttttssssssrrrrrrqqqqqqppppppoooooonnnnnnmmmmmmmmllllllkkkkkkkkjjjjjjiiiiiiiihhhhhhhhggggggggffffffffeeeeeeeeddddddddccccccccccbbbbbbbbbbaaaaaaaaaa``````````__________^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKK³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœœœ››››››››šššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜————————––––––••••••••””””””””““““““’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€€€~~~~}}}}}}||||||{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvuuuuuuttttttssssssrrrrrrqqqqqqppppppoooooooonnnnnnmmmmmmllllllllkkkkkkjjjjjjjjiiiiiiiihhhhhhggggggggffffffffeeeeeeeeeeddddddddccccccccccbbbbbbbbbbaaaaaaaaaa``````````__________^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœœœ››››››››šššššššššš™™™™™™™™˜˜˜˜˜˜˜˜————————––––––––••••••””””””””““““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€€€~~~~}}}}}}||||||{{{{{{zzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuuttttttssssssrrrrrrqqqqqqppppppoooooonnnnnnmmmmmmmmllllllkkkkkkkkjjjjjjiiiiiiiihhhhhhhhggggggggffffffffeeeeeeeeeeddddddddccccccccccbbbbbbbbaaaaaaaaaaaa``````````__________^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœœœ››››››››››šššššššš™™™™™™™™˜˜˜˜˜˜˜˜————————––––––––••••••••””””””““““““““’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€€€~~~~}}}}}}||||||{{{{{{zzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuuttttttssssssrrrrrrqqqqqqppppppoooooooonnnnnnmmmmmmllllllllkkkkkkjjjjjjjjiiiiiiiihhhhhhhhggggggggffffffffeeeeeeeeddddddddddccccccccbbbbbbbbbbaaaaaaaaaa````````````__________^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœœœ››››››››››šššššššš™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————––––––––••••••””””””””““““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~}}}}}}||||||{{{{{{zzzzzzyyyyxxxxxxwwwwwwvvvvvvuuuuuuttttttssssssrrrrrrqqqqqqppppppppoooooonnnnnnmmmmmmmmllllllkkkkkkkkjjjjjjjjiiiiiihhhhhhhhggggggggffffffffffeeeeeeeeddddddddddccccccccbbbbbbbbbbaaaaaaaaaa````````````____________^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœœœ››››››››››šššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜————————––––––––••••••••””””””““““““““’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwvvvvvvuuuuuuttttttssssssssrrrrrrqqqqqqppppppoooooonnnnnnnnmmmmmmllllllllkkkkkkjjjjjjjjiiiiiiiihhhhhhhhggggggggffffffffeeeeeeeeeeddddddddccccccccccbbbbbbbbbbaaaaaaaaaa````````````____________^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœ››››››››››šššššššššš™™™™™™™™˜˜˜˜˜˜˜˜————————––––––––••••••••””””””””““““““’’’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuuttttttssssssrrrrrrqqqqqqppppppppoooooonnnnnnmmmmmmmmllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhggggggggffffffffeeeeeeeeeeddddddddccccccccccbbbbbbbbbbaaaaaaaaaa````````````____________^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLL²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœœœ››››››››šššššššššš™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————––––––––••••••••””””””““““““““’’’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††…………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuuttttttssssssrrrrrrqqqqqqqqppppppoooooonnnnnnnnmmmmmmllllllllkkkkkkkkjjjjjjiiiiiiiihhhhhhhhggggggggggffffffffeeeeeeeeddddddddddccccccccccbbbbbbbbbbaaaaaaaaaa````````````____________^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLL²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœ››››››››››šššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜————————––––––––••••••••””””””””““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuuttttttssssssssrrrrrrqqqqqqppppppoooooooonnnnnnmmmmmmmmllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhggggggggffffffffffeeeeeeeeddddddddddccccccccccbbbbbbbbbbaaaaaaaaaa````````````____________^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLL²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœ››››››››››šššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜————————––––––––••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuuuuttttttssssssrrrrrrqqqqqqppppppppoooooonnnnnnnnmmmmmmllllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhggggggggffffffffeeeeeeeeeeddddddddddccccccccccbbbbbbbbbbaaaaaaaaaa````````````____________^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLL²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————––––––––••••••••””””””””““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzyyyyyyxxxxxxxxwwwwwwvvvvvvuuuuuuttttttssssssrrrrrrqqqqqqqqppppppoooooooonnnnnnmmmmmmmmllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhggggggggggffffffffeeeeeeeeeeddddddddccccccccccbbbbbbbbbbbbaaaaaaaaaa````````````____________^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————––––––––••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuuttttttssssssssrrrrrrqqqqqqppppppppoooooonnnnnnnnmmmmmmllllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhggggggggffffffffffeeeeeeeeddddddddddccccccccccbbbbbbbbbbbbaaaaaaaaaa````````````____________^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜————————––––––––––••••••••””””””””““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuuttttttttssssssrrrrrrqqqqqqqqppppppoooooonnnnnnnnmmmmmmmmllllllllkkkkkkjjjjjjjjiiiiiiiihhhhhhhhhhggggggggffffffffffeeeeeeeeddddddddddccccccccccbbbbbbbbbbaaaaaaaaaaaa````````````____________^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››šššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————––––––––••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuuuuttttttssssssrrrrrrrrqqqqqqppppppoooooooonnnnnnnnmmmmmmllllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhggggggggggffffffffeeeeeeeeeeddddddddddccccccccccbbbbbbbbbbaaaaaaaaaaaa````````````____________^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————––––––––••••••••••””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††……………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvvvvvuuuuuuttttttssssssrrrrrrrrqqqqqqppppppppoooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhggggggggffffffffffeeeeeeeeeeddddddddddccccccccccbbbbbbbbbbaaaaaaaaaaaa````````````____________^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜——————————––––––––••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwwwvvvvvvuuuuuuttttttssssssssrrrrrrqqqqqqqqppppppoooooooonnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhhhggggggggffffffffffeeeeeeeeeeddddddddddccccccccccbbbbbbbbbbaaaaaaaaaaaa````````````____________^^^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMM±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜——————————––––––––••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxxxwwwwwwvvvvvvuuuuuuttttttttssssssrrrrrrrrqqqqqqppppppppoooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhggggggggggffffffffffeeeeeeeeddddddddddccccccccccccbbbbbbbbbbaaaaaaaaaaaa````````````____________^^^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMM±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————––––––––––••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyyyxxxxxxwwwwwwvvvvvvuuuuuuuuttttttssssssrrrrrrrrqqqqqqppppppppoooooooonnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjiiiiiiiiiihhhhhhhhggggggggggffffffffeeeeeeeeeeddddddddddccccccccccbbbbbbbbbbbbaaaaaaaaaaaa````````````____________^^^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMM±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœ››››››››››››šššššššššš™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzzzzzyyyyyyxxxxxxwwwwwwvvvvvvvvuuuuuuttttttssssssssrrrrrrqqqqqqqqppppppoooooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhhhggggggggffffffffffeeeeeeeeeeddddddddddccccccccccbbbbbbbbbbbbaaaaaaaaaaaa````````````____________^^^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMM±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜——————————––––––––••••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwwwvvvvvvuuuuuuttttttttssssssrrrrrrrrqqqqqqppppppppoooooooonnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjjjiiiiiiiihhhhhhhhggggggggggffffffffffeeeeeeeeeeddddddddddccccccccccbbbbbbbbbbbbaaaaaaaaaaaa````````````____________^^^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMM±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————––––––––––••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††……………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwwwvvvvvvuuuuuuuuttttttssssssrrrrrrrrqqqqqqqqppppppoooooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhhhggggggggggffffffffeeeeeeeeeeddddddddddddccccccccccbbbbbbbbbbbbaaaaaaaaaaaa````````````____________^^^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––••••••••””””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††……………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||||{{{{{{zzzzzzyyyyyyxxxxxxxxwwwwwwvvvvvvuuuuuuuuttttttssssssssrrrrrrqqqqqqqqppppppppoooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjjjiiiiiiiihhhhhhhhhhggggggggffffffffffeeeeeeeeeeddddddddddccccccccccccbbbbbbbbbbbbaaaaaaaaaaaa````````````____________^^^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››šššššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜——————————––––––––––••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~}}}}}}||||||||{{{{{{zzzzzzyyyyyyyyxxxxxxwwwwwwvvvvvvvvuuuuuuttttttttssssssrrrrrrrrqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjiiiiiiiiiihhhhhhhhggggggggggffffffffffeeeeeeeeeeddddddddddccccccccccccbbbbbbbbbbaaaaaaaaaaaa``````````````____________^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœ››››››››››››šššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————––––––––––••••••••””””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~}}}}}}||||||||{{{{{{zzzzzzyyyyyyyyxxxxxxwwwwwwvvvvvvvvuuuuuuttttttttssssssrrrrrrrrqqqqqqqqppppppoooooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhhhggggggggggffffffffffeeeeeeeeeeddddddddddccccccccccccbbbbbbbbbbaaaaaaaaaaaa``````````````____________^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœ››››››››››››šššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––••••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~}}}}}}}}||||||{{{{{{zzzzzzyyyyyyyyxxxxxxwwwwwwwwvvvvvvuuuuuuuuttttttssssssssrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjjjiiiiiiiihhhhhhhhhhggggggggffffffffffeeeeeeeeeeeeddddddddddccccccccccbbbbbbbbbbbbaaaaaaaaaaaa``````````````____________^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••””””””””““““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††††………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~}}}}}}}}||||||{{{{{{zzzzzzzzyyyyyyxxxxxxwwwwwwwwvvvvvvuuuuuuuuttttttssssssssrrrrrrrrqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkkkjjjjjjjjiiiiiiiiiihhhhhhhhggggggggggffffffffffeeeeeeeeeeddddddddddddccccccccccbbbbbbbbbbbbaaaaaaaaaaaa``````````````____________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNN°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››šššššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————––––––––––••••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††††………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~}}}}}}}}||||||{{{{{{zzzzzzzzyyyyyyxxxxxxxxwwwwwwvvvvvvvvuuuuuuttttttttssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjjjiiiiiiiihhhhhhhhhhggggggggggffffffffffeeeeeeeeeeddddddddddddccccccccccbbbbbbbbbbbbaaaaaaaaaaaa``````````````____________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNN°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››šššššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––••••••••••””””””””““““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††……………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~}}}}}}}}||||||{{{{{{{{zzzzzzyyyyyyxxxxxxxxwwwwwwvvvvvvvvuuuuuuttttttttssssssssrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkkkjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggffffffffffeeeeeeeeeeddddddddddccccccccccccbbbbbbbbbbbbaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNN°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››šššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••””””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††……………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~}}}}}}}}||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxwwwwwwwwvvvvvvuuuuuuuuttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhggggggggggffffffffffeeeeeeeeeeeeddddddddddccccccccccccbbbbbbbbbbbbaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNN°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››šššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––••••••••••””””””””““““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††……………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~}}}}}}}}||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxwwwwwwwwvvvvvvuuuuuuuuttttttttssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmllllllllllkkkkkkkkjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggffffffffffeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNN°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••””””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††††………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxwwwwwwwwvvvvvvvvuuuuuuttttttttssssssssrrrrrrrrqqqqqqppppppppoooooooonnnnnnnnnnmmmmmmmmllllllllkkkkkkkkkkjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggffffffffffeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONN°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››šššššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••••””””””””““““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††††………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxxxwwwwwwvvvvvvvvuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmllllllllllkkkkkkkkjjjjjjjjjjiiiiiiiihhhhhhhhhhggggggggggffffffffffffeeeeeeeeeeddddddddddddccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››šššššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————––––––––••••••••••””””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||||{{{{{{zzzzzzzzyyyyyyxxxxxxxxwwwwwwvvvvvvvvuuuuuuuuttttttttssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmmmllllllllkkkkkkkkkkjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggffffffffffeeeeeeeeeeeeddddddddddccccccccccccbbbbbbbbbbbbaaaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››šššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••••””””””””““““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††……………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||||{{{{{{zzzzzzzzyyyyyyxxxxxxxxwwwwwwwwvvvvvvuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmllllllllllkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggffffffffffeeeeeeeeeeeeddddddddddccccccccccccbbbbbbbbbbbbaaaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••••””””””””””““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††……………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||||{{{{{{zzzzzzzzyyyyyyyyxxxxxxwwwwwwwwvvvvvvvvuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmmmllllllllkkkkkkkkkkjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggffffffffffffeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbaaaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••””””””””””““““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††……………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||||{{{{{{zzzzzzzzyyyyyyyyxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooooonnnnnnnnmmmmmmmmllllllllllkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggffffffffffffeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbaaaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOO¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••••””””””””””““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††††……………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxxxwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmmmllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggffffffffffeeeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbaaaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOO¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››šššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••••””””””””””““““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxxxwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnnnmmmmmmmmllllllllllkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggggffffffffffeeeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbaaaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOO¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————————––––––––––••••••••••””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppppoooooooonnnnnnnnmmmmmmmmmmllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggffffffffffffeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOO¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••••””””””””””““““““““““’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||{{{{{{{{zzzzzzzzyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnnnmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggffffffffffeeeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOO¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––––––••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooooonnnnnnnnmmmmmmmmmmllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggggffffffffffeeeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaa````````````````______________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————————––––––––––••••••••••””””””””””““““““““““’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqqqppppppppoooooooonnnnnnnnnnmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggffffffffffffeeeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaa````````````````______________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››››šššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuttttttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooooonnnnnnnnmmmmmmmmmmllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggffffffffffffeeeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````______________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––––––••••••••••””””””””””““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppppoooooooonnnnnnnnnnmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggggffffffffffeeeeeeeeeeeeddddddddddddccccccccccccccbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````______________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————————––––––––––••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqqqppppppppoooooooooonnnnnnnnmmmmmmmmmmllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhggggggggggffffffffffffeeeeeeeeeeeeddddddddddddccccccccccccccbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````______________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••••••””””””””””““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssssrrrrrrrrqqqqqqqqppppppppoooooooooonnnnnnnnnnmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggffffffffffffeeeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````______________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPP¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppppoooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkjjjjjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````______________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPP®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————————––––––––––••••••••••””””””””””””““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqqqppppppppoooooooooonnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffeeeeeeeeeeeeddddddddddddddccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````______________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPP®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————––––––––––––••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssssrrrrrrrrqqqqqqqqppppppppppoooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggffffffffffffeeeeeeeeeeeeddddddddddddccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````______________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPP®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttttssssssssrrrrrrrrqqqqqqqqqqppppppppoooooooooonnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeddddddddddddccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````________________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPP®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––••••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttssssssssrrrrrrrrrrqqqqqqqqppppppppppoooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeddddddddddddccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````________________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPP®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››šššššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————––––––––––––••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssssrrrrrrrrqqqqqqqqppppppppppoooooooooonnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggffffffffffffeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````________________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––••••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssssrrrrrrrrqqqqqqqqqqppppppppoooooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeddddddddddddddccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````________________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttttssssssssrrrrrrrrrrqqqqqqqqppppppppppoooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeddddddddddddddccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````________________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————––––––––––––••••••••••””””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttssssssssrrrrrrrrrrqqqqqqqqqqppppppppoooooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggffffffffffffeeeeeeeeeeeeeeddddddddddddccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````________________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––••••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvvvuuuuuuuuttttttttssssssssssrrrrrrrrqqqqqqqqqqppppppppppoooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeeeddddddddddddccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````________________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQ®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››šššššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––••••••••••””””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuttttttttttssssssssrrrrrrrrrrqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————––––––––––––••••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttssssssssrrrrrrrrrrqqqqqqqqqqppppppppoooooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––••••••••••””””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttssssssssssrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––••••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvvvuuuuuuuuttttttttttssssssssrrrrrrrrrrqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeeeddddddddddddccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaa``````````````````________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––••••••••••••””””””””””““““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuttttttttttssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaa``````````````````________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQ­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––••••••••••””””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttssssssssssrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffffeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````__________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQ­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››šššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––••••••••••••””””””””””““““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppoooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````__________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––••••••••••••””””””””””””““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxxxwwwwwwwwvvvvvvvvvvuuuuuuuuttttttttttssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmllllllllllllkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````__________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––••••••••••••””””””””””““““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||||{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvvvuuuuuuuuttttttttttssssssssssrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````__________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––••••••••••••””””””””””””““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||||{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmllllllllllllkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffffeeeeeeeeeeeeddddddddddddddccccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````__________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––••••••••••””””””””””””““““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||||{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttttssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````__________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRR­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––••••••••••••””””””””””””““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||||{{{{{{{{zzzzzzzzzzyyyyyyyyxxxxxxxxxxwwwwwwwwvvvvvvvvvvuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqppppppppppoooooooooooonnnnnnnnnnmmmmmmmmmmllllllllllllkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````__________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRR¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}}}||||||||{{{{{{{{zzzzzzzzzzyyyyyyyyxxxxxxxxxxwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````__________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRR¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––••••••••••••””””””””””””““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}}}||||||||{{{{{{{{zzzzzzzzzzyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttttssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnnnmmmmmmmmmmllllllllllllkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeddddddddddddddddccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````__________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRR¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````__________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRR¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––––••••••••••••””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnnnmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````__________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRR¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````____________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRR¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnnnmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffeeeeeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````____________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggffffffffffffffeeeeeeeeeeeeeeddddddddddddddddccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````____________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{zzzzzzzzzzyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnnnmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````____________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}||||||||||{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````____________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}||||||||||{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````____________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSS¬¬¬¬««««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––••••••••••••••””””””””””””““““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSS««««««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSS««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––••••••••••••””””””””””””””““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppppoooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeddddddddddddddddccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSS««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqqqppppppppppoooooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSS««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppppoooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSS««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––••••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqqqppppppppppoooooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSS««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffffffeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––––••••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppppoooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––••••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqqqppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••””””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrrrqqqqqqqqqqppppppppppppoooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffffffeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffffeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTT««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••””””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqqqppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTT««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrrrqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––••••••••••••••””””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrqqqqqqqqqqqqppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffffeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••””””””””””””””““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••••””””””””””””““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttttssssssssssrrrrrrrrrrrrqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––••••••••••••””””””””””””””““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••••””””””””””””““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa``````````````````______________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••••””””””””””””””““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuttttttttttttssssssssssrrrrrrrrrrrrqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––••••••••••••••””””””””””””““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttttssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••••””””””””””””””““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––––••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––••••••••••••••””””””””””””””““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuttttttttttttssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUU©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––––••••••••••••••””””””””””””””““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUU©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUU©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••••••””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUU©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––––••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUU©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUU©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––––••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggffffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUU©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––••••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––––••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––••••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVV©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVV©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••””””””””””””””””““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVV¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––••••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggggffffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVV¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••””””””””””””””““““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqqqppppppppppppoooooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa``````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVV¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa``````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVV¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••””””””””””””””““““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVV¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••””””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVV¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVV¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••””””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqqqppppppppppppoooooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————————––––––––––––––••••••••••••••••””””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppppoooooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqqqppppppppppppoooooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWW¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••••””””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppppoooooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWW¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————————––––––––––––––––••••••••••••••””””””””””””””””““““““““““““““’’’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqqqppppppppppppoooooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWW¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••••””””””””””””””““““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqqqppppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggggffffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWW§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••••””””””””””””””””““““““““““““““’’’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppppoooooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWW§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————————––––––––––––––––••••••••••••••••””””””””””””””““““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqqqppppppppppppoooooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWW§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••••””””””””””””””””““““““““““““““’’’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}}}||||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqqqppppppppppppppoooooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggggffffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWW§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––––••••••••••••••••””””””””””””””““““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}}}||||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttttssssssssssssrrrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppppoooooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWmlt-0.9.0/src/tests/clock16pal.pgm000066400000000000000000031240211215300731300167070ustar00rootroot00000000000000P5 720 576 65535 ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááááââââââââââââââââââââããããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææææççççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððððññññññññññññòòòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""############################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''''''((((×××××××××××××××××××××××ר Ø ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßßàààààààààààààààààààààáááááááááááááááááááááâââââââââââââââââââãããããããããããããããããããäääääääääääääääääåååååååååååååååååæææææææææææææææææçççççççççççççççççèèèèèèèèèèèèèèèèéééééééééééééééêêêêêêêêêêêêêêêêëëëëëëëëëëëëëëìììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððððññññññññññññò$òòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ Ø ÜÝÞßàãäæçéêëí î!!!!!!!!!!!!!!!!!!!!!!!!!ï"""""""""""""""""""""""""ð###########################ñ$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%ó&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ô'''''''''''''''''''''''''''''''''''õ'õ((((×××××××××××××××××××××××××××ר>ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ?Ù?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßßßßßßßßßßßàFààààààààààààààààààààáGááááááááááááááááááááââââââââââââââââââââãIããããããããããããããããããääääääääääääääääääåKååååååååååååååååæLææææææææææææææææççççççççççççççççèNèèèèèèèèèèèèèèèèééééééééééééééêPêêêêêêêêêêêêêêëQëëëëëëëëëëëëëëììììììììììììììíSííííííííííííîTîîîîîîîîîîîîïUïïïïïïïïïïïïðVððððððððððððññññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôZôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøù_ùùùùùùùùùùú`úúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿžŸ ¡ ¥ §­®±´µ¶·¸¹ º!!!!!!!!!!!!!!!!!!!!!!!!!»"""""""""""""""""""""""""¼###########################½$$$$$$$$$$$$$$$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&À'''''''''''''''''''''''''''''''''''Á((((((((×××××××××××××××××××××××××××××רqØqØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßßßßßßßßßßßàyààààààààààààààààààààázááááááááááááááááááâ{ââââââââââââââââââââããããããããããããããããããä}ääääääääääääääääääååååååååååååååååååææææææææææææææææç€ççççççççççççççççèèèèèèèèèèèèèèèé‚ééééééééééééééêƒêêêêêêêêêêêêêêëëëëëëëëëëëëëëì…ììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððñŠññññññññññññòòòòòòòòòòòòóŒóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷ø‘øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúû”ûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿjo s vwxy{|}~€ƒ„…† ‡!!!!!!!!!!!!!!!!!!!!!!!ˆ!ˆ"""""""""""""""""""""""""‰###########################Š$$$$$$$$$$$$$$$$$$$$$$$$$$$‹$‹%%%%%%%%%%%%%%%%%%%%%%%%%%%%%Œ%Œ&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''''''''''''Ž'Ž((((((((((×××××××××××××××××××××××××××××××××ר¥ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ¦Ù¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛܩܩÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßßßßßßßßßßßà­ààààààààààààààààààààá®ááááááááááááááááááâ¯ââââââââââââââââââã°ããããããããããããããããããä±ääääääääääääääääå²ååååååååååååååååæ³ææææææææææææææææç´ççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêë¸ëëëëëëëëëëëëëëììììììììììììììíºííííííííííííî»îîîîîîîîîîîîï¼ïïïïïïïïïïïïððððððððððððððññññññññññññò¿òòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõÂõõõõõõõõõõöÃöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüÉüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ5 < = AFKLMNPQR S!!!!!!!!!!!!!!!!!!!!!!!T"""""""""""""""""""""""""U"U#########################V#V$$$$$$$$$$$$$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%X&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Y'''''''''''''''''''''''''''''''''''Z((((((((((((((××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââããããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððððññññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""############################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''''((((((((((((((((ÖÖ××××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââããããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""############################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''''((((((((((((((((((((ÖÖ× ×××××××××××××××××××××××××××××××××××ר ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ Û ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßßàààààààààààààààààààààááááááááááááááááááááâââââââââââââââââââãããããããããããããããããããäääääääääääääääääåååååååååååååååååæææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèéééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëëììììììììììììììíííííííííííííî îîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððñ#ññññññññññññòòòòòòòòòòòòó%óóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ Ú ÜÝáãäæèéêëìí î!!!!!!!!!!!!!!!!!!!!!!!ï"""""""""""""""""""""""""ð###########################ñ$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%%%%%%%%%%%%%%%ó%ó&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ô'''''''''''''''''''''''''''''''''''õ((((((((((((((((((((ÖÖÖÖ×=×=×××××××××××××××××××××××××××××××××ר>Ø>ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ?Ù?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@Ú@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßßßßßßßßßßßàFààààààààààààààààààáGááááááááááááááááááááâHââââââââââââââââââãIããããããããããããããããããääääääääääääääääääåKååååååååååååååååææææææææææææææææçMççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééêPêêêêêêêêêêêêêêëëëëëëëëëëëëëëìRììììììììììììììííííííííííííííîîîîîîîîîîîîïUïïïïïïïïïïïïðVððððððððððððññññññññññññòXòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýcýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ¢ ª«¬®±²³´µ¶·¸¹ º!!!!!!!!!!!!!!!!!!!!!!!»"""""""""""""""""""""""""¼###########################½$$$$$$$$$$$$$$$$$$$$$$$$$$$¾$¾%%%%%%%%%%%%%%%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&À'''''''''''''''''''''''''''''''''Á'Á((((((((((((((((((((((ÖÖÖÖÖÖÖÖ×p×p×××××××××××××××××××××××××××××××××רqØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààázááááááááááááááááááááâ{ââââââââââââââââââã|ããããããããããããããããä}ääääääääääääääääääååååååååååååååååæææææææææææææææææç€ççççççççççççççèèèèèèèèèèèèèèèé‚ééééééééééééééêƒêêêêêêêêêêêêë„ëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõŽõõõõõõõõõõööööööööööö÷÷÷÷÷÷÷÷÷÷÷ø‘øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿhmn p q tvz|}~€ƒ„…† ‡!!!!!!!!!!!!!!!!!!!!!!!ˆ"""""""""""""""""""""""""‰###########################Š$$$$$$$$$$$$$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''''''''''''Ž((((((((((((((((((((((((((ÖÖÖÖÖÖÖÖÖÖÖÖפ×××××××××××××××××××××××××××××××××ר¥ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßßßßßßßßßà­ààààààààààààààààààààá®ááááááááááááááááááááâ¯ââââââââââââââââââããããããããããããããããããä±ääääääääääääääääå²ååååååååååååååååæ³ææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêë¸ëëëëëëëëëëëëì¹ììììììììììììíºííííííííííííî»îîîîîîîîîîîîï¼ïïïïïïïïïïïïððððððððððððñ¾ññññññññññññòòòòòòòòòòòòóÀóóóóóóóóóóôÁôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùÆùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ8 > ADEGIKLMNOPQR S!!!!!!!!!!!!!!!!!!!!!!!T"""""""""""""""""""""""""U#########################V#V$$$$$$$$$$$$$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%%%%%%%%%%%%%%%X%X&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Y'''''''''''''''''''''''''''''''''Z'Z((((((((((((((((((((((((((((ÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááááââââââââââââââââââããããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððððññññññññññññòòòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''((((((((((((((((((((((((((((((((ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââããããããããããããããããããããääääääääääääääääääååååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''''((((((((((((((((((((((((((((((((((ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××××××××××××××××××××××××××ר ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßàààààààààààààààààààààáááááááááááááááááááâââââââââââââââââââãããããããããããããããããããääääääääääääääääääåååååååååååååååååææææææææææææææææçççççççççççççççèèèèèèèèèèèèèèèéééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëìììììììììììììíííííííííííííî îîîîîîîîîîîîï!ïïïïïïïïïïïïððððððððððððñ#ññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿÒ Ûàâãäåæçèéêëìí î!!!!!!!!!!!!!!!!!!!!!!!ï"""""""""""""""""""""""ð"ð#########################ñ$$$$$$$$$$$$$$$$$$$$$$$$$$$ò$ò%%%%%%%%%%%%%%%%%%%%%%%%%%%%%ó&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ô'''''''''''''''''''''''''''''''''õ'õ((((((((((((((((((((((((((((((((((ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××××××××××××××××××××××××ר>Ø>ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ?Ù?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßßßßßßßßßàFààààààààààààààààààààáGááááááááááááááááááâHââââââââââââââââââãIããããããããããããããããäJääääääääääääääääääååååååååååååååååæLææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééêPêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïðVððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôZôôôôôôôôôôõ[õõõõõõõõõõö\öööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûaûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿ¢ £ ¤ ¥ ¨ª«­®³´µ¶·¸¹ º º!!!!!!!!!!!!!!!!!!!!!!!»"""""""""""""""""""""""¼###########################½$$$$$$$$$$$$$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%%%%%%%%%%%%%%%¿%¿&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&À'''''''''''''''''''''''''''''''''Á(((((((((((((((((((((((((((((((((((((ÂÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×××××××××××××××××××××××××××××××××רqØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßßßßßßßßßàyààààààààààààààààààààázááááááááááááááááááâ{ââââââââââââââââââã|ããããããããããããããããä}ääääääääääääääääå~ååååååååååååååååæææææææææææææææç€ççççççççççççççèèèèèèèèèèèèèèèé‚ééééééééééééééêêêêêêêêêêêêêêë„ëëëëëëëëëëëëì…ììììììììììììí†ííííííííííííî‡îîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññò‹òòòòòòòòòòóŒóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþþþÿÿÿÿn s tvy|}~‚ƒ„…† ‡!!!!!!!!!!!!!!!!!!!!!!!ˆ!ˆ"""""""""""""""""""""""‰###########################Š$$$$$$$$$$$$$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''''''''''Ž'Ž(((((((((((((((((((((((((((((((((((())ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפפ×××××××××××××××××××××××××××××××ר¥Ø¥ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨Û¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßßßßßßßßßà­ààààààààààààààààààààá®ááááááááááááááááááâ¯ââââââââââââââââââã°ããããããããããããããããä±ääääääääääääääääå²ååååååååååååååååææææææææææææææææç´ççççççççççççççèµèèèèèèèèèèèèèèééééééééééééééê·êêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîï¼ïïïïïïïïïïïïððððððððððððñ¾ññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øÅøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþËþþþþþþþþþþÿÿÿÿ69 ACDFGIJKLOPQR S!!!!!!!!!!!!!!!!!!!!!!!T"""""""""""""""""""""""""U#########################V#V$$$$$$$$$$$$$$$$$$$$$$$$$W$W%%%%%%%%%%%%%%%%%%%%%%%%%%%%%X&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Y'''''''''''''''''''''''''''''''''Z((((((((((((((((((((((((((((((((((((([))))))ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââããããããããããããããããããääääääääääääääääääååååååååååååååååææææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((((())))))))ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààààááááááááááááááááááááââââââââââââââââââããããããããããããããããããããääääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((((())))))))))))ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× × ×××××××××××××××××××××××××××××××ר Ø ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ Ú ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßàààààààààààààààààààààáááááááááááááááááááâââââââââââââââââãããããããããããããããããããääääääääääääääääääååååååååååååååååæææææææææææææææçççççççççççççççèèèèèèèèèèèèèèèéééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîï!ïïïïïïïïïïïïððððððððððððññññññññññññò$òòòòòòòòòòó%óóóóóóóóóóô&ôôôôôôôôôôõ'õõõõõõõõõõö(öööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿÓ × Ø Ú Ûßàáâãäåæçèéêëìí î!!!!!!!!!!!!!!!!!!!!!!!ï"""""""""""""""""""""""""ð#########################ñ$$$$$$$$$$$$$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%%%%%%%%%%%%%%%ó&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ô'''''''''''''''''''''''''''''''''õ(((((((((((((((((((((((((((((((((((ö(ö))))))))))))ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×××××××××××××××××××××××××××××××××ר>ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßßßßßßßßßàFààààààààààààààààààààáGááááááááááááááááááâHââââââââââââââââãIããããããããããããããããäJääääääääääääääääåKååååååååååååååååæLææææææææææææææçMççççççççççççççèNèèèèèèèèèèèèèèééééééééééééééêPêêêêêêêêêêêêëQëëëëëëëëëëëëìRììììììììììììíSííííííííííííîTîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððñWññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷]÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûübüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ¢ ¨ª­°±²´µ·¸¹ º!!!!!!!!!!!!!!!!!!!!!!!»"""""""""""""""""""""""""¼#########################½$$$$$$$$$$$$$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&&&&&&&&&&&&&&&À&À'''''''''''''''''''''''''''''''Á'Á(((((((((((((((((((((((((((((((((((Â))))))))))))))))ÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×p×××××××××××××××××××××××××××××××רqØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙrÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßßßßßßßßßàyààààààààààààààààààààázááááááááááááááááááââââââââââââââââââã|ããããããããããããããããä}ääääääääääääääääå~ååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèé‚ééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííííîîîîîîîîîîîîïˆïïïïïïïïïïð‰ððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùú“úúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿn vxy{|€‚ƒ„…† ‡!!!!!!!!!!!!!!!!!!!!!!!ˆ"""""""""""""""""""""""‰"‰#######################Š#Š$$$$$$$$$$$$$$$$$$$$$$$$$‹$‹%%%%%%%%%%%%%%%%%%%%%%%%%%%Œ%Œ&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''''''''''''Ž(((((((((((((((((((((((((((((((((((())))))))))))))))))ÕÕÕÕÖ£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפ×××××××××××××××××××××××××××××××ר¥Ø¥ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßßßßßßßßßà­ààààààààààààààààààààááááááááááááááááááâ¯ââââââââââââââââââã°ããããããããããããããããä±ääääääääääääääääå²ååååååååååååååæ³ææææææææææææææç´ççççççççççççççèµèèèèèèèèèèèèèèé¶ééééééééééééê·êêêêêêêêêêêêë¸ëëëëëëëëëëëëì¹ììììììììììììíºííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððñ¾ññññññññññò¿òòòòòòòòòòóÀóóóóóóóóóóôÁôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øÅøøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ57 = > ? @CFGIJKLOPR S!!!!!!!!!!!!!!!!!!!!!!!T"""""""""""""""""""""""U#########################V$$$$$$$$$$$$$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%%%%%%%%%%%%%%%X&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Y'''''''''''''''''''''''''''''''''Z((((((((((((((((((((((((((((((((((([))))))))))))))))))))))ÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââããããããããããããããããããääääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((())))))))))))))))))))))))ÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááááââââââââââââââââââââããããããããããããããããããääääääääääääääääååååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììííííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))ÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××××××××××××××××××××××××ר Ø ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßàààààààààààààààààààáááááááááááááááááááâââââââââââââââââââããããããããããããããããããääääääääääääääääåååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèéééééééééééééêêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììíííííííííííííîîîîîîîîîîîîï!ïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõö(öööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿÖ Þáâäæèéêëìí î!!!!!!!!!!!!!!!!!!!!!!!ï"""""""""""""""""""""""ð#########################ñ$$$$$$$$$$$$$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%%%%%%%%%%%%%ó%ó&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ô'''''''''''''''''''''''''''''''''õ(((((((((((((((((((((((((((((((((((ö))))))))))))))))))))))))))))ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××××××××××××××××××××××××ר>ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßßßßßßßßßàFààààààààààààààààààáGááááááááááááááááááâHââââââââââââââââãIããããããããããããããããäJääääääääääääääääåKååååååååååååååæLææææææææææææææçMççççççççççççççèNèèèèèèèèèèèèèèééééééééééééééêPêêêêêêêêêêêêëQëëëëëëëëëëëëìRììììììììììììííííííííííííîTîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððñWññññññññññòXòòòòòòòòòòóYóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷]÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøù_ùùùùùùùùùùúúúúúúúúúúûaûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ ¥ ¦ §¨«¬¯°±³´µ¶·¸¹ º!!!!!!!!!!!!!!!!!!!!!!!»"""""""""""""""""""""""¼#########################½$$$$$$$$$$$$$$$$$$$$$$$$$¾$¾%%%%%%%%%%%%%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&&&&&&&&&&&&&&&À&À'''''''''''''''''''''''''''''''Á'Á(((((((((((((((((((((((((((((((((Â(Â))))))))))))))))))))))))))))))ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×p×××××××××××××××××××××××××××××רqØqØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙrÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßßßßßßßßßàyààààààààààààààààààázááááááááááááááááááâ{ââââââââââââââââã|ããããããããããããããããä}ääääääääääääääääå~ååååååååååååååæææææææææææææææç€ççççççççççççççèèèèèèèèèèèèèèé‚ééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììí†ííííííííííííîîîîîîîîîîîîïˆïïïïïïïïïïð‰ððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôôõõõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿgln q vwz{|~€‚ƒ„…† ‡!!!!!!!!!!!!!!!!!!!!!ˆ!ˆ"""""""""""""""""""""""‰#######################Š#Š$$$$$$$$$$$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%%%%%%%%%%%%%Œ%Œ&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''''''''''''Ž(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפ×××××××××××××××××××××××××××××××ר¥ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßßßßßßßßßà­ààààààààààààààààààá®ááááááááááááááááááâ¯ââââââââââââââââã°ããããããããããããããããä±ääääääääääääääääååååååååååååååååæ³ææææææææææææææççççççççççççççèµèèèèèèèèèèèèèèé¶ééééééééééééê·êêêêêêêêêêêêë¸ëëëëëëëëëëëëì¹ììììììììììììííííííííííííî»îîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõÂõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ6 < DEIKLMNPQR S!!!!!!!!!!!!!!!!!!!!!T"""""""""""""""""""""""U"U#######################V$$$$$$$$$$$$$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%%%%%%%%%%%%%X&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Y'''''''''''''''''''''''''''''''Z'Z((((((((((((((((((((((((((((((((([)))))))))))))))))))))))))))))))))))))\ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääååååååååååååååååååææææææææææææææççççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììííííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))**ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""##########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))******ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××××××××××××××××××××××××ר ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ Ú ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßßàààààààààààààààààààáááááááááááááááááááââââââââââââââââââãããããããããããããããããääääääääääääääääåååååååååååååååæææææææææææææææçççççççççççççççèèèèèèèèèèèèèèéééééééééééééêêêêêêêêêêêêêëëëëëëëëëëëëëìììììììììììììííííííííííííî îîîîîîîîîîï!ïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóô&ôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿÔÖ Ù Þàåæçèéêëìí î!!!!!!!!!!!!!!!!!!!!!ï"""""""""""""""""""""""ð#########################ñ$$$$$$$$$$$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%%%%%%%%%%%%%ó%ó&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ô'''''''''''''''''''''''''''''''õ'õ(((((((((((((((((((((((((((((((((ö)))))))))))))))))))))))))))))))))))))÷******ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××××××××××××××××××××××ר>Ø>ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßßßßßßßßßàFààààààààààààààààààáGááááááááááááááááâHââââââââââââââââââããããããããããããããããäJääääääääääääääääåKååååååååååååååæLææææææææææææææçMççççççççççççèNèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììíSííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõ[õõõõõõõõõõöööööööööö÷]÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ ¤ ¨«­®¯°²³´µ¶·¸¹ º!!!!!!!!!!!!!!!!!!!!!»"""""""""""""""""""""""¼#########################½$$$$$$$$$$$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&&&&&&&&&&&&&&&À&À'''''''''''''''''''''''''''''''Á(((((((((((((((((((((((((((((((((Â(Â)))))))))))))))))))))))))))))))))))Ã)Ã********ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×××××××××××××××××××××××××××××××רqØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙrÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßßßßßßßßßàyààààààààààààààààààázááááááááááááááááâ{ââââââââââââââââã|ããããããããããããããããä}ääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççèèèèèèèèèèèèèé‚ééééééééééééêƒêêêêêêêêêêêêë„ëëëëëëëëëëëëì…ììììììììììììííííííííííííî‡îîîîîîîîîîïˆïïïïïïïïïïð‰ððððððððððñŠññññññññññò‹òòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøù’ùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿkn p s tvwy{|~€‚ƒ„…† ‡!!!!!!!!!!!!!!!!!!!!!ˆ"""""""""""""""""""""""‰#######################Š#Š$$$$$$$$$$$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''''''''''Ž'Ž((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))************ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפפ×××××××××××××××××××××××××××××ר¥ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§Ú§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬߬ßßßßßßßßßßßßßßßßßßà­ààààààààààààààààààá®ááááááááááááááááâ¯ââââââââââââââââã°ããããããããããããããããä±ääääääääääääääå²ååååååååååååååæ³ææææææææææææææç´ççççççççççççççèèèèèèèèèèèèèèé¶ééééééééééééê·êêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììíºííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòóÀóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöÃöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüÉüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ > DFIJKMNOPQR S!!!!!!!!!!!!!!!!!!!!!T"""""""""""""""""""""""U#######################V$$$$$$$$$$$$$$$$$$$$$$$$$W$W%%%%%%%%%%%%%%%%%%%%%%%%%X%X&&&&&&&&&&&&&&&&&&&&&&&&&&&Y&Y'''''''''''''''''''''''''''''''Z((((((((((((((((((((((((((((((((([([)))))))))))))))))))))))))))))))))))\****************ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççèèèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))******************ÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääååååååååååååååååææææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))**********************ÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× × ×××××××××××××××××××××××××××××ר ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ Ù ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ Û ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßàààààààààààààààààààáááááááááááááááááâââââââââââââââââãããããããããããããããããääääääääääääääääåååååååååååååååæææææææææææææææççççççççççççççèèèèèèèèèèèèèéééééééééééééêêêêêêêêêêêêêëëëëëëëëëëëëëììììììììììììíííííííííííî îîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññò$òòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõ'õõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúû-ûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿÏ Ú ßáåæçèéëìí î!!!!!!!!!!!!!!!!!!!!!ï"""""""""""""""""""""ð"ð#######################ñ$$$$$$$$$$$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%%%%%%%%%%%%%ó&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ô'''''''''''''''''''''''''''''''õ(((((((((((((((((((((((((((((((((ö)))))))))))))))))))))))))))))))))))÷)÷**********************ÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×××××××××××××××××××××××××××××ר>Ø>ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßßßßßßßàFààààààààààààààààààááááááááááááááááááâHââââââââââââââââãIããããããããããããããäJääääääääääääääääååååååååååååååååææææææææææææææçMççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëìRììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòóYóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööö÷]÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  £ ¥ ¬®¯°±µ¶·¸¹ º!!!!!!!!!!!!!!!!!!!!!»"""""""""""""""""""""¼#######################½#½$$$$$$$$$$$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%%%%%%%%%%%¿%¿&&&&&&&&&&&&&&&&&&&&&&&&&&&À&À'''''''''''''''''''''''''''''Á'Á(((((((((((((((((((((((((((((((Â(Â)))))))))))))))))))))))))))))))))))Ã**************************ÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×p×××××××××××××××××××××××××××××רqØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙrÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßßßßßßßàyààààààààààààààààázááááááááááááááááááâ{ââââââââââââââââããããããããããããããããä}ääääääääääääääå~ååååååååååååååæææææææææææææææç€ççççççççççççèèèèèèèèèèèèèé‚ééééééééééééêƒêêêêêêêêêêêêë„ëëëëëëëëëëëëììììììììììììí†ííííííííííî‡îîîîîîîîîîïˆïïïïïïïïïïð‰ððððððððððñŠññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôôõõõõõõõõõõöööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùú“úúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿn tuvwxz|}€‚ƒ„…† ‡!!!!!!!!!!!!!!!!!!!!!ˆ"""""""""""""""""""""‰#######################Š$$$$$$$$$$$$$$$$$$$$$$$$$‹$‹%%%%%%%%%%%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''''''''''Ž((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))****************************ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפ×××××××××××××××××××××××××××××ר¥Ø¥ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßßßßßßßà­ààààààààààààààààá®ááááááááááááááááááâ¯ââââââââââââââã°ããããããããããããããããä±ääääääääääääääå²ååååååååååååååæ³ææææææææææææææççççççççççççççèµèèèèèèèèèèèèé¶ééééééééééééê·êêêêêêêêêêêêëëëëëëëëëëëëì¹ììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññò¿òòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöÃöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ5 = ? EFGJKLMNOPQR S!!!!!!!!!!!!!!!!!!!T!T"""""""""""""""""""""U#######################V$$$$$$$$$$$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%%%%%%%%%%%%%X&&&&&&&&&&&&&&&&&&&&&&&&&&&Y&Y'''''''''''''''''''''''''''''Z'Z((((((((((((((((((((((((((((((([([)))))))))))))))))))))))))))))))))\)\********************************ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááááââââââââââââââââããããããããããããããããããääääääääääääääääååååååååååååååååææææææææææææææççççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññññòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))************************************ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââââããããããããããããããããããääääääääääääääääååååååååååååååææææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))**************************************ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××××××××××××××××××××××ר Ø ØØØØØØØØØØØØØØØØØØØØØØØØØØÙ Ù ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ Ú ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßàààààààààààààààààáááááááááááááááááâââââââââââââââââãããããããããããããããããääääääääääääääääååååååååååååååæææææææææææææææçççççççççççççèèèèèèèèèèèèèéééééééééééééêêêêêêêêêêêêêëëëëëëëëëëëëìììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððñ#ññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷ø*øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿÒ × Ù Ûàáæèéêëìí î!!!!!!!!!!!!!!!!!!!!!ï"""""""""""""""""""""""ð#######################ñ$$$$$$$$$$$$$$$$$$$$$$$ò$ò%%%%%%%%%%%%%%%%%%%%%%%%%ó&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ô'''''''''''''''''''''''''''''õ'õ(((((((((((((((((((((((((((((((ö(ö)))))))))))))))))))))))))))))))))÷)÷*************************************øÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××××××××××××××××××××××ר>ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßßßßßßßàFààààààààààààààààáGááááááááááááááááâHââââââââââââââââãIããããããããããããããäJääääääääääääääåKååååååååååååååæLææææææææææææææççççççççççççççèNèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëQëëëëëëëëëëëëììììììììììììííííííííííííîTîîîîîîîîîîïUïïïïïïïïïïððððððððððððññññññññññòXòòòòòòòòòòóóóóóóóóóóôZôôôôôôôôôôõõõõõõõõõõöööööööööö÷]÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿŸ ¦ ©ª«®¯°±²³µ¶·¸¹ º!!!!!!!!!!!!!!!!!!!!!»"""""""""""""""""""""¼"¼#####################½#½$$$$$$$$$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&&&&&&&&&&&&&À&À'''''''''''''''''''''''''''''Á(((((((((((((((((((((((((((((((Â(Â)))))))))))))))))))))))))))))))))Ã)Ã*************************************Ä*Ä++ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×××××××××××××××××××××××××××××רqØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßßßßßßßàyààààààààààààààààázááááááááááááááááâ{ââââââââââââââââã|ããããããããããããããä}ääääääääääääääå~ååååååååååååååæææææææææææææç€ççççççççççççççèèèèèèèèèèèèé‚ééééééééééééêƒêêêêêêêêêêêêëëëëëëëëëëëëì…ììììììììììí†ííííííííííííîîîîîîîîîîîîïïïïïïïïïïð‰ððððððððððññññññññññññòòòòòòòòòòóŒóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõööööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿm q uyz|}~€‚„† ‡!!!!!!!!!!!!!!!!!!!!!ˆ"""""""""""""""""""""‰#######################Š$$$$$$$$$$$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%%%%%%%%%%%Œ%Œ&&&&&&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''''''''Ž'Ž((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))))*************************************‘*‘++++++ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפפ×××××××××××××××××××××××××××ר¥Ø¥ØØØØØØØØØØØØØØØØØØØØØØØØØØÙ¦Ù¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§Ú§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨Û¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßßßßßßßà­ààààààààààààààààá®ááááááááááááááááâ¯ââââââââââââââââã°ããããããããããããããä±ääääääääääääääå²ååååååååååååååææææææææææææææç´ççççççççççççèµèèèèèèèèèèèèé¶ééééééééééééêêêêêêêêêêêêë¸ëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððñ¾ññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõÂõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ:; > @CDGKLMNOPQR S!!!!!!!!!!!!!!!!!!!!!T"""""""""""""""""""""U#######################V$$$$$$$$$$$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%%%%%%%%%%%X&&&&&&&&&&&&&&&&&&&&&&&&&&&Y&Y'''''''''''''''''''''''''''''Z((((((((((((((((((((((((((((((([([)))))))))))))))))))))))))))))))))\)\*************************************]++++++++++ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââââããããããããããããããããääääääääääääääääååååååååååååååææææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))****************************************++++++++++++ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââããããããããããããããããããääääääääääääääååååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññññòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))****************************************++++++++++++++++ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××××××××××××××××××××ר Ø ØØØØØØØØØØØØØØØØØØØØØØØØØØÙ Ù ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßßààààààààààààààààààáááááááááááááááááâââââââââââââââãããããããããããããããããääääääääääääääåååååååååååååååæææææææææææææçççççççççççççèèèèèèèèèèèèèéééééééééééééêêêêêêêêêêêëëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððñ#ññññññññññòòòòòòòòòòó%óóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷ø*øøøøøøøøù+ùùùùùùùùú,úúúúúúúúû-ûûûûûûûûü.üüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ Ø Üâäåçêëìí î!!!!!!!!!!!!!!!!!!!!!ï"""""""""""""""""""""ð#######################ñ$$$$$$$$$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%%%%%%%%%%%ó%ó&&&&&&&&&&&&&&&&&&&&&&&&&&&ô'''''''''''''''''''''''''''''õ(((((((((((((((((((((((((((((((ö(ö)))))))))))))))))))))))))))))))))÷*************************************ø*ø++++++++++++++++ÓÓÔ:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××××××××××××××××××××ר>ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@Ú@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßßßßßàFààààààààààààààààààáGááááááááááááááááâHââââââââââââââãIããããããããããããããäJääääääääääääääåKååååååååååååååææææææææææææææçMççççççççççççèNèèèèèèèèèèèèéOééééééééééééêêêêêêêêêêêêëQëëëëëëëëëëìRììììììììììíSííííííííííîTîîîîîîîîîîïUïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõö\öööööööö÷]÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþþþÿÿÿÿ ¥ §©ª«¬­¯²³´µ¶·¸¹ º!!!!!!!!!!!!!!!!!!!!!»"""""""""""""""""""""¼#####################½#½$$$$$$$$$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&&&&&&&&&&&&&À&À'''''''''''''''''''''''''''Á'Á(((((((((((((((((((((((((((((((Â)))))))))))))))))))))))))))))))))Ã)Ã***********************************Ä*Ä++++++++++++++++++++ÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×××××××××××××××××××××××××××רqØqØØØØØØØØØØØØØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßßßßßàyààààààààààààààààààázááááááááááááááááââââââââââââââââã|ããããããããããããããä}ääääääääääääääå~ååååååååååååæææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééêƒêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïð‰ððððððððððññññññññññò‹òòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõŽõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüý–ýýýýýýýýþþþþþþþþþþÿÿÿÿ s u{|}~€‚ƒ„…† ‡!!!!!!!!!!!!!!!!!!!!!ˆ"""""""""""""""""""""‰#####################Š$$$$$$$$$$$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''''''''Ž(((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))*************************************‘++++++++++++++++++++++++ÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפפ×××××××××××××××××××××××××××ר¥ØØØØØØØØØØØØØØØØØØØØØØØØØØÙ¦Ù¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßßßßßà­ààààààààààààààààààá®ááááááááááááááâ¯ââââââââââââââââã°ããããããããããããããä±ääääääääääääääååååååååååååååæ³ææææææææææææç´ççççççççççççèµèèèèèèèèèèèèé¶ééééééééééééêêêêêêêêêêêêë¸ëëëëëëëëëëì¹ììììììììììíºííííííííííî»îîîîîîîîîîï¼ïïïïïïïïïïððððððððððñ¾ññññññññññòòòòòòòòòòóóóóóóóóóóôÁôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþþþÿÿÿÿ89:; < CDEFGJKMNOPQR S!!!!!!!!!!!!!!!!!!!T!T"""""""""""""""""""U"U#####################V$$$$$$$$$$$$$$$$$$$$$$$W$W%%%%%%%%%%%%%%%%%%%%%%%X%X&&&&&&&&&&&&&&&&&&&&&&&&&Y&Y'''''''''''''''''''''''''''Z'Z((((((((((((((((((((((((((((([([)))))))))))))))))))))))))))))))))\)\***********************************]*]++++++++++++++++++++++++++ÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààààááááááááááááááááââââââââââââââââââããããããããããããããããääääääääääääääååååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))**************************************++++++++++++++++++++++++++++++ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââââããããããããããããããããääääääääääääääååååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))**************************************++++++++++++++++++++++++++++++++++ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× × ×××××××××××××××××××××××××××ר ØØØØØØØØØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ Ú ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßàààààààààààààààààáááááááááááááááááâââââââââââââââââããããããããããããããããääääääääääääääåååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèéééééééééééééêêêêêêêêêêêêëëëëëëëëëëëìììììììììììíííííííííííî îîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññò$òòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþþþÿÿÿÿÑ Ù ÜÞßàáâäåæçèêëìí î!!!!!!!!!!!!!!!!!!!ï"""""""""""""""""""""ð#######################ñ$$$$$$$$$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%%%%%%%%%%%ó&&&&&&&&&&&&&&&&&&&&&&&&&ô&ô'''''''''''''''''''''''''''õ'õ(((((((((((((((((((((((((((((ö(ö)))))))))))))))))))))))))))))))))÷***********************************ø*ø++++++++++++++++++++++++++++++++++ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×××××××××××××××××××××××××××ר>Ø>ØØØØØØØØØØØØØØØØØØØØØØØØÙ?Ù?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßßßßßàFààààààààààààààààáGááááááááááááááááâHââââââââââââââãIããããããããããããããäJääääääääääääääåKååååååååååååæLææææææææææææçMççççççççççççèNèèèèèèèèèèèèéOééééééééééêPêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîïUïïïïïïïïïïððððððððððñWññññññññññòòòòòòòòòòóóóóóóóóóóôZôôôôôôôôõ[õõõõõõõõö\öööööööö÷]÷÷÷÷÷÷÷÷ø^øøøøøøøøù_ùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýþdþþþþþþþþÿÿÿÿ ¦ §©¯±²´µ¶·¸¹ º!!!!!!!!!!!!!!!!!!!»"""""""""""""""""""""¼#####################½#½$$$$$$$$$$$$$$$$$$$$$¾$¾%%%%%%%%%%%%%%%%%%%%%%%¿%¿&&&&&&&&&&&&&&&&&&&&&&&&&À'''''''''''''''''''''''''''''Á(((((((((((((((((((((((((((((((Â)))))))))))))))))))))))))))))))))Ã)Ã*********************************Ä*Ä++++++++++++++++++++++++++++++++++++++ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×p×××××××××××××××××××××××××××רqØØØØØØØØØØØØØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßßßßßàyààààààààààààààààázááááááááááááááááâ{ââââââââââââââã|ããããããããããããããä}ääääääääääääääååååååååååååååæææææææææææææç€ççççççççççççèèèèèèèèèèèèèééééééééééééêƒêêêêêêêêêêë„ëëëëëëëëëëì…ììììììììììí†ííííííííííî‡îîîîîîîîîîïïïïïïïïïïð‰ððððððððððññññññññññòòòòòòòòòòóŒóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ uxyz{|}€‚ƒ„…† ‡!!!!!!!!!!!!!!!!!!!ˆ"""""""""""""""""""""‰#####################Š$$$$$$$$$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''''''Ž'Ž(((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))***********************************‘+++++++++++++++++++++++++++++++++++++++’+’ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפ×××××××××××××××××××××××××××ר¥ØØØØØØØØØØØØØØØØØØØØØØØØØØÙ¦Ù¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§Ú§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßßßßßà­ààààààààààààààààá®ááááááááááááááááâ¯ââââââââââââââã°ããããããããããããããä±ääääääääääääå²ååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèé¶ééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîï¼ïïïïïïïïïïððððððððððñ¾ññññññññò¿òòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúÇúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ5:; < = > CIJKLMNOPQR S!!!!!!!!!!!!!!!!!!!T"""""""""""""""""""""U#####################V$$$$$$$$$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%%%%%%%%%%%X&&&&&&&&&&&&&&&&&&&&&&&&&Y&Y'''''''''''''''''''''''''''Z((((((((((((((((((((((((((((((([)))))))))))))))))))))))))))))))))\***********************************]*]+++++++++++++++++++++++++++++++++++++^+^,,,,ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââããããããããããããããããääääääääääääääååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîîîïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))************************************++++++++++++++++++++++++++++++++++++++++,,,,,,,,ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááááââââââââââââââââããããããããããããããääääääääääääääääååååååååååååååææææææææææææææççççççççççççççèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííîîîîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""########################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))************************************++++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××××××××××××××××××××ר ØØØØØØØØØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ Û ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßàààààààààààààààààáááááááááááááááááââââââââââââââââãããããããããããããäääääääääääääääåååååååååååååæææææææææææææçççççççççççççèèèèèèèèèèèéééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííî îîîîîîîîîîïïïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòó%óóóóóóóóô&ôôôôôôôôõ'õõõõõõõõö(öööööööö÷)÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿÓ ÜÞáäèéêëìí î!!!!!!!!!!!!!!!!!!!ï"""""""""""""""""""ð#####################ñ#ñ$$$$$$$$$$$$$$$$$$$$$ò$ò%%%%%%%%%%%%%%%%%%%%%%%ó&&&&&&&&&&&&&&&&&&&&&&&&&ô&ô'''''''''''''''''''''''''''õ(((((((((((((((((((((((((((((ö(ö)))))))))))))))))))))))))))))))÷)÷*********************************ø*ø+++++++++++++++++++++++++++++++++++++ù+ù,,,,,,,,,,,,ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××××××××××××××××××ר>Ø>ØØØØØØØØØØØØØØØØØØØØØØØØÙ?Ù?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@Ú@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßßßßßàFààààààààààààààààáGááááááááááááááâHââââââââââââââââããããããããããããããäJääääääääääääääååååååååååååååæLææææææææææææçMççççççççççççèèèèèèèèèèèèéOééééééééééêPêêêêêêêêêêëQëëëëëëëëëëìRììììììììììíSííííííííííîîîîîîîîîîïUïïïïïïïïïïððððððððððñWññññññññòXòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷ø^øøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ ¤ ¥ ©«¬®¯°±²³´·¸¹ º!!!!!!!!!!!!!!!!!!!»"""""""""""""""""""¼#####################½$$$$$$$$$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&&&&&&&&&&&À'''''''''''''''''''''''''''Á'Á(((((((((((((((((((((((((((((Â)))))))))))))))))))))))))))))))))Ã***********************************Ä+++++++++++++++++++++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,ÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×××××××××××××××××××××××××××רqØØØØØØØØØØØØØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßßßßßàyààààààààààààààààázááááááááááááááâ{ââââââââââââââã|ããããããããããããããä}ääääääääääääå~ååååååååååååååææææææææææææææççççççççççççèèèèèèèèèèèèèééééééééééééêƒêêêêêêêêêêë„ëëëëëëëëëëììììììììììììííííííííííî‡îîîîîîîîîîïïïïïïïïïïð‰ððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿko p s twz{~€‚ƒ„…† ‡!!!!!!!!!!!!!!!!!!!ˆ"""""""""""""""""""‰#####################Š$$$$$$$$$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%%%%%%%%%Œ%Œ&&&&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''''''Ž(((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))*********************************‘*‘+++++++++++++++++++++++++++++++++++++’,,,,,,,,,,,,,,,,,,,,ÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפפ×××××××××××××××××××××××××ר¥Ø¥ØØØØØØØØØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛܩܩÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßßßßßà­ààààààààààààààààá®ááááááááááááááâ¯ââââââââââââââã°ããããããããããããããä±ääääääääääääå²ååååååååååååæ³ææææææææææææç´ççççççççççççèèèèèèèèèèèèé¶ééééééééééééêêêêêêêêêêêêëëëëëëëëëëì¹ììììììììììíºííííííííííîîîîîîîîîîï¼ïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóÀóóóóóóóóôÁôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùÆùùùùùùùùúúúúúúúúúúûûûûûûûûüÉüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ: ADEHIKLNOPQR S!!!!!!!!!!!!!!!!!T!T"""""""""""""""""""U#####################V$$$$$$$$$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%%%%%%%%%X&&&&&&&&&&&&&&&&&&&&&&&&&Y&Y'''''''''''''''''''''''''Z'Z((((((((((((((((((((((((((((([)))))))))))))))))))))))))))))))\)\*********************************]*]+++++++++++++++++++++++++++++++++++++^+^,,,,,,,,,,,,,,,,,,,,,,ÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááââââââââââââââââããããããããããããããããääääääääääääääååååååååååååååææææææææææææææççççççççççççèèèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííîîîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))************************************++++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,ÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààààááááááááááááááááââââââââââââââââããããããããããããããääääääääääääääääååååååååååååååææææææææææææææççççççççççççèèèèèèèèèèèèééééééééééééééêêêêêêêêêêêêëëëëëëëëëëììììììììììììííííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× × ×××××××××××××××××××××××××ר Ø ØØØØØØØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßàààààààààààààààààáááááááááááááááâââââââââââââââãããããããããããããäääääääääääääääåååååååååååååæææææææææææææççççççççççççèèèèèèèèèèèéééééééééééééêêêêêêêêêêêêëëëëëëëëëëìììììììììììíííííííííííîîîîîîîîîîï!ïïïïïïïïð"ððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööö÷)÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùú,úúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿÔ Ø Ù Ú ÛÜàäåæçèéêëí î!!!!!!!!!!!!!!!!!ï"""""""""""""""""""""ð###################ñ#ñ$$$$$$$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%%%%%%%%%ó%ó&&&&&&&&&&&&&&&&&&&&&&&ô&ô'''''''''''''''''''''''''õ'õ(((((((((((((((((((((((((((((ö)))))))))))))))))))))))))))))))÷)÷*********************************ø+++++++++++++++++++++++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××××××××××××××××××ר>ØØØØØØØØØØØØØØØØØØØØØØØØÙ?Ù?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßßßßßàFààààààààààààààààáGááááááááááááááâHââââââââââââââãIããããããããããããäJääääääääääääääååååååååååååååææææææææææææçMççççççççççççèèèèèèèèèèèèéOééééééééééêPêêêêêêêêêêëQëëëëëëëëëëìRììììììììììííííííííííîTîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòXòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ £ ©«­®¯°²³´¶·¸¹ º!!!!!!!!!!!!!!!!!»"""""""""""""""""""¼"¼###################½$$$$$$$$$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&&&&&&&&&&&À'''''''''''''''''''''''''''Á(((((((((((((((((((((((((((((Â(Â)))))))))))))))))))))))))))))Ã)Ã*********************************Ä*Ä+++++++++++++++++++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×××××××××××××××××××××××××רqØØØØØØØØØØØØØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßßßßßàyààààààààààààààààááááááááááááááááâ{ââââââââââââââããããããããããããããä}ääääääääääääå~ååååååååååååæææææææææææææç€ççççççççççèèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììí†ííííííííííîîîîîîîîîîïïïïïïïïïïð‰ððððððððñŠññññññññññòòòòòòòòóŒóóóóóóóóôôôôôôôôôõŽõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷ø‘øøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿlo wy~€‚ƒ„…† ‡ ‡!!!!!!!!!!!!!!!!!ˆ"""""""""""""""""""‰#####################Š$$$$$$$$$$$$$$$$$$$$$‹$‹%%%%%%%%%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''''Ž'Ž(((((((((((((((((((((((((((()))))))))))))))))))))))))))))))*********************************‘*‘+++++++++++++++++++++++++++++++++++’+’,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפפ×××××××××××××××××××××××ר¥Ø¥ØØØØØØØØØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§Ú§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨Û¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛܩܩÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßßßßßà­ààààààààààààààá®ááááááááááááááááââââââââââââââã°ããããããããããããããä±ääääääääääääå²ååååååååååååæ³ææææææææææææççççççççççççèµèèèèèèèèèèé¶ééééééééééê·êêêêêêêêêêë¸ëëëëëëëëëëì¹ììììììììììííííííííííî»îîîîîîîîï¼ïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ: > ? @ABDFGHIJKNPQR S!!!!!!!!!!!!!!!!!!!T"""""""""""""""""""U#####################V$$$$$$$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%%%%%%%%%X%X&&&&&&&&&&&&&&&&&&&&&&&Y&Y'''''''''''''''''''''''''Z((((((((((((((((((((((((((((([)))))))))))))))))))))))))))))))\)\*******************************]*]+++++++++++++++++++++++++++++++++++^+^,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,_,_ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââââããããããããããããããããääääääääääääääååååååååååååååææææææææææææççççççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììííííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââââããããããããããããããääääääääääääääääååååååååååååææææææææææææææççççççççççççèèèèèèèèèèèèèèééééééééééééêêêêêêêêêêëëëëëëëëëëëëììììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððððññññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))************************************++++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× × ×××××××××××××××××××××××ר Ø ØØØØØØØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßàààààààààààààààáááááááááááááááâââââââââââââââãããããããããããããäääääääääääääääååååååååååååæææææææææææææçççççççççççèèèèèèèèèèèèèééééééééééééêêêêêêêêêêëëëëëëëëëëëìììììììììììííííííííííîîîîîîîîîîï!ïïïïïïïïð"ððððððððððññññññññññòòòòòòòòó%óóóóóóóóô&ôôôôôôôôõõõõõõõõõõöööööööö÷)÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüý/ýýýýýýýýþþþþþþþþÿÿÿÿ × ßáåçèéêëìí î!!!!!!!!!!!!!!!!!!!ï"""""""""""""""""""ð###################ñ#ñ$$$$$$$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%%%%%%%%%ó&&&&&&&&&&&&&&&&&&&&&&&ô&ô'''''''''''''''''''''''''õ(((((((((((((((((((((((((((((ö)))))))))))))))))))))))))))))))÷*********************************ø*ø+++++++++++++++++++++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ú,ú--------ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×××××××××××××××××××××××××ר>ØØØØØØØØØØØØØØØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@Ú@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßßßßßàFààààààààààààààáGááááááááááááááâHââââââââââââââãIããããããããããããäJääääääääääääåKååååååååååååæLææææææææææææççççççççççççèNèèèèèèèèèèéOééééééééééêPêêêêêêêêêêëëëëëëëëëëëëììììììììììíSííííííííîTîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôõ[õõõõõõõõöööööööööö÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿž ¢ ¦ §¨©ª¬®¯°±²³´¶·¸¹ º!!!!!!!!!!!!!!!!!!!»"""""""""""""""""""¼###################½$$$$$$$$$$$$$$$$$$$$$¾$¾%%%%%%%%%%%%%%%%%%%%%¿%¿&&&&&&&&&&&&&&&&&&&&&&&À'''''''''''''''''''''''''Á'Á(((((((((((((((((((((((((((Â(Â)))))))))))))))))))))))))))))Ã)Ã*******************************Ä*Ä+++++++++++++++++++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Æ,Æ------------ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×p×××××××××××××××××××××××רqØqØØØØØØØØØØØØØØØØØØØØØØÙrÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßßßßßàyààààààààààààààázááááááááááááááâ{ââââââââââââââã|ããããããããããããä}ääääääääääääå~ååååååååååååæææææææææææç€ççççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêë„ëëëëëëëëëëì…ììììììììììííííííííííîîîîîîîîîîïˆïïïïïïïïð‰ððððððððñŠññññññññò‹òòòòòòòòóóóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷ø‘øøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿi q r xz‚ƒ„…† ‡!!!!!!!!!!!!!!!!!!!ˆ"""""""""""""""""‰"‰###################Š$$$$$$$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''''Ž((((((((((((((((((((((((((((())))))))))))))))))))))))))))))*******************************‘*‘+++++++++++++++++++++++++++++++++++’+’,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,“,“----------------ÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפ×××××××××××××××××××××××××ר¥ØØØØØØØØØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨Û¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßßßßßà­ààààààààààààààá®ááááááááááááááâ¯ââââââââââââââããããããããããããããä±ääääääääääääå²ååååååååååååææææææææææææç´ççççççççççèµèèèèèèèèèèé¶ééééééééééê·êêêêêêêêêêë¸ëëëëëëëëëëììììììììììíºííííííííî»îîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòóÀóóóóóóóóôôôôôôôôôôõõõõõõõõöÃöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúÇúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ @ABEGHIJKLMNOPQR S!!!!!!!!!!!!!!!!!!!T"""""""""""""""""U#####################V$$$$$$$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%%%%%%%%%X&&&&&&&&&&&&&&&&&&&&&&&Y'''''''''''''''''''''''''''Z((((((((((((((((((((((((((([([)))))))))))))))))))))))))))))\*********************************]+++++++++++++++++++++++++++++++++++^+^,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,_,_--------------------ÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââããããããããããããããããääääääääääääääååååååååååååææææææææææææææççççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêêêëëëëëëëëëëììììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóôôôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!!!""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''''(((((((((((((((((((((((((((())))))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------ÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââããããããããããããããääääääääääääääååååååååååååååææææææææææææççççççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêêêëëëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""""######################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((((())))))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------ÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××××××××××××××××××ר ØØØØØØØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßàààààààààààààààáááááááááááááááâââââââââââââãããããããããããããäääääääääääääåååååååååååååæææææææææææçççççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêêëëëëëëëëëëëììììììììììííííííííííî îîîîîîîîï!ïïïïïïïïð"ððððððððñ#ññññññññò$òòòòòòòòóóóóóóóóóóôôôôôôôôõ'õõõõõõõõöööööööö÷)÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûü.üüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ Ù àâæèéëìí î!!!!!!!!!!!!!!!!!ï"""""""""""""""""""ð###################ñ#ñ$$$$$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%%%%%%%%%ó&&&&&&&&&&&&&&&&&&&&&&&ô&ô'''''''''''''''''''''''''õ(((((((((((((((((((((((((((ö)))))))))))))))))))))))))))))÷)÷*******************************ø*ø+++++++++++++++++++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ú----------------------------ÑÑÑÑÑÑÑÑÑÑÒ8Ò8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××××××××××××××××ר>Ø>ØØØØØØØØØØØØØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßßßßßàFààààààààààààààáGááááááááááááááâHââââââââââââãIããããããããããããäJääääääääääääåKååååååååååååææææææææææææçMççççççççççèNèèèèèèèèèèéOééééééééééêPêêêêêêêêêêëëëëëëëëëëìRììììììììíSííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòóYóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööööö÷÷÷÷÷÷÷÷øøøøøøøøù_ùùùùùùùùúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ¢ ¤ §¨©ª«­¯°±²³´µ¶·¸¹ º!!!!!!!!!!!!!!!!!»"""""""""""""""""""¼###################½$$$$$$$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%%%%%%%¿%¿&&&&&&&&&&&&&&&&&&&&&&&À'''''''''''''''''''''''''Á'Á(((((((((((((((((((((((((Â(Â)))))))))))))))))))))))))))))Ã*******************************Ä*Ä+++++++++++++++++++++++++++++++++++Å,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Æ,Æ------------------------------ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×××××××××××××××××××××××××רqØØØØØØØØØØØØØØØØØØØØØØÙrÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßßßßßàyààààààààààààààázááááááááááááááââââââââââââââã|ããããããããããããä}ääääääääääääå~ååååååååååæææææææææææææççççççççççççèèèèèèèèèèèééééééééééééêêêêêêêêêêë„ëëëëëëëëëëììììììììììííííííííííî‡îîîîîîîîïˆïïïïïïïïð‰ððððððððññññññññññòòòòòòòòòòóóóóóóóóôôôôôôôôôõõõõõõõõööööööööö÷÷÷÷÷÷÷÷øøøøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿjm s yz{}~€ƒ„…† ‡!!!!!!!!!!!!!!!!!ˆ"""""""""""""""""""‰###################Š$$$$$$$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''''Ž((((((((((((((((((((((((((())))))))))))))))))))))))))))))*******************************‘+++++++++++++++++++++++++++++++++++’+’,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,“,“----------------------------------ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפפ×××××××××××××××××××××××ר¥ØØØØØØØØØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßßßßßà­ààààààààààààààá®ááááááááááááâ¯ââââââââââââââã°ããããããããããããä±ääääääääääääååååååååååååæ³ææææææææææç´ççççççççççççèèèèèèèèèèé¶ééééééééééê·êêêêêêêêêêëëëëëëëëëëì¹ììììììììíºííííííííííîîîîîîîîîîïïïïïïïïïïððððððððñ¾ññññññññò¿òòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øÅøøøøøøøøùùùùùùùùúúúúúúúúûÈûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ < > BCDGHKLMNOPQR S!!!!!!!!!!!!!!!!!T"""""""""""""""""""U###################V$$$$$$$$$$$$$$$$$$$W$W%%%%%%%%%%%%%%%%%%%%%X&&&&&&&&&&&&&&&&&&&&&&&Y'''''''''''''''''''''''''Z'Z((((((((((((((((((((((((([([)))))))))))))))))))))))))))\)\*******************************]*]+++++++++++++++++++++++++++++++++^+^,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,_,_--------------------------------------ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááââââââââââââââââããããããããããããããääääääääääääååååååååååååååææææææææææææççççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêëëëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((((())))))))))))))))))))))))))))))**********************************++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------------ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááââââââââââââââããããããããããããããääääääääääääääååååååååååååååææææææææææææççççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííííîîîîîîîîîîïïïïïïïïððððððððððññññññññññòòòòòòòòòòóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((((())))))))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------------....ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× × ×××××××××××××××××××××××ר ØØØØØØØØØØØØØØØØØØØØØØÙ Ù ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßßàààààààààààààààááááááááááááááâââââââââââââãããããããããããããäääääääääääääåååååååååååååææææææææææææççççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêêëëëëëëëëëëìììììììììíííííííííííîîîîîîîîîîïïïïïïïïð"ððððððððñ#ññññññññòòòòòòòòòòóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööö÷)÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿÖ Ø Ú Þßâåçèéêëìí î!!!!!!!!!!!!!!!!!ï"""""""""""""""""ð###################ñ$$$$$$$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%%%%%%%ó&&&&&&&&&&&&&&&&&&&&&&&ô&ô'''''''''''''''''''''''õ'õ(((((((((((((((((((((((((ö(ö)))))))))))))))))))))))))))÷)÷*****************************ø*ø+++++++++++++++++++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ú,ú---------------------------------------û-û....ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×××××××××××××××××××××××ר>Ø>ØØØØØØØØØØØØØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@Ú@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßßßßßàFààààààààààààáGááááááááááááááâHââââââââââââãIããããããããããããäJääääääääääääåKååååååååååæLææææææææææçMççççççççççèNèèèèèèèèèèéOééééééééééêêêêêêêêêêëQëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññòXòòòòòòòòóóóóóóóóôZôôôôôôôôõõõõõõõõö\öööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùú`úúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿŸ ¨©¬­¯°²³µ¶·¸¹ º!!!!!!!!!!!!!!!!!»"""""""""""""""""¼###################½$$$$$$$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&&&&&&&&&À'''''''''''''''''''''''''Á(((((((((((((((((((((((((Â(Â)))))))))))))))))))))))))))Ã)Ã*******************************Ä+++++++++++++++++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Æ,Æ---------------------------------------Ç-Ç........ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×p×××××××××××××××××××××××רqØØØØØØØØØØØØØØØØØØØØØØÙrÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßßßßßàyààààààààààààázááááááááááááááâ{ââââââââââââã|ããããããããããããä}ääääääääääääååååååååååååæææææææææææç€ççççççççççèèèèèèèèèèèééééééééééêƒêêêêêêêêêêëëëëëëëëëëì…ììììììììí†ííííííííî‡îîîîîîîîïˆïïïïïïïïð‰ððððððððññññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøù’ùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ p r t{}~€„…† ‡!!!!!!!!!!!!!!!!!ˆ"""""""""""""""""‰###################Š$$$$$$$$$$$$$$$$$$$‹$‹%%%%%%%%%%%%%%%%%%%Œ%Œ&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''Ž'Ž((((((((((((((((((((((((()))))))))))))))))))))))))))))*******************************‘*‘+++++++++++++++++++++++++++++++’+’,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,“,“---------------------------------------”-”............ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפפ×××××××××××××××××××××ר¥Ø¥ØØØØØØØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßßßßßààààààààààààààá®ááááááááááááááâ¯ââââââââââââã°ããããããããããããä±ääääääääääå²ååååååååååååææææææææææææç´ççççççççççèèèèèèèèèèé¶ééééééééééê·êêêêêêêêë¸ëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððñ¾ññññññññòòòòòòòòóÀóóóóóóóóôôôôôôôôõÂõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øÅøøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ9 ? BCDEFHJKMNOPR S!!!!!!!!!!!!!!!!!T"""""""""""""""""U###################V$$$$$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%%%%%%%X&&&&&&&&&&&&&&&&&&&&&&&Y'''''''''''''''''''''''''Z((((((((((((((((((((((((([([)))))))))))))))))))))))))))\)\*****************************]*]+++++++++++++++++++++++++++++++++^,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,_,_---------------------------------------`-`................ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââããããããããããããããääääääääääääååååååååååååææææææææææææææççççççççççèèèèèèèèèèèèééééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïïïððððððððððññññññññòòòòòòòòòòóóóóóóóóôôôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------------....................ÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááááââââââââââââââããããããããããããääääääääääääääååååååååååååææææææææææææççççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïððððððððððññññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""""""##################$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''(((((((((((((((((((((((((((())))))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------------........................ÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× × ×××××××××××××××××××××ר Ø ØØØØØØØØØØØØØØØØØØØØÙ Ù ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ Û ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßàààààààààààààààáááááááááááááááââââââââââââââããããããããããããäääääääääääääåååååååååååæææææææææææçççççççççççèèèèèèèèèèèééééééééééêêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïð"ððððððððññññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷)÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿÖ Ù ÛÞßàáâäåæçéêëìí î!!!!!!!!!!!!!!!ï"""""""""""""""""""ð#################ñ$$$$$$$$$$$$$$$$$$$ò$ò%%%%%%%%%%%%%%%%%%%ó%ó&&&&&&&&&&&&&&&&&&&&&ô&ô'''''''''''''''''''''''õ(((((((((((((((((((((((((ö(ö)))))))))))))))))))))))))))÷*******************************ø+++++++++++++++++++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ú,ú---------------------------------------û-û........................ÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×××××××××××××××××××××××ר>ØØØØØØØØØØØØØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßßßàFààààààààààààààáGááááááááááááâHââââââââââââãIããããããããããããäJääääääääääääååååååååååååæLææææææææææçMççççççççççèèèèèèèèèèéOééééééééééêêêêêêêêêêëQëëëëëëëëìRììììììììíSííííííííîTîîîîîîîîïïïïïïïïïïððððððððñWññññññññòòòòòòòòóYóóóóóóóóôôôôôôôôõõõõõõõõö\öööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿš £ ¦ ¨©¯±²³´µ¶·¸¹ º!!!!!!!!!!!!!!!»"""""""""""""""""¼"¼#################½$$$$$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&&&&&&&&&À'''''''''''''''''''''''Á'Á(((((((((((((((((((((((((Â)))))))))))))))))))))))))))Ã)Ã*****************************Ä*Ä+++++++++++++++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Æ,Æ-------------------------------------Ç-Ç-Ç............................ÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×p×××××××××××××××××××××רqØqØØØØØØØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßßßàyààààààààààààààázááááááááááááâ{ââââââââââââã|ããããããããããããä}ääääääääääå~ååååååååååååææææææææææææççççççççççèèèèèèèèèèèé‚ééééééééêƒêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîïˆïïïïïïïïð‰ððððððððññññññññò‹òòòòòòòòóóóóóóóóôôôôôôôôõŽõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÿÿhij q wxyz{}‚ƒ„…† ‡!!!!!!!!!!!!!!!ˆ"""""""""""""""""‰###################Š$$$$$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''''Ž(((((((((((((((((((((((((())))))))))))))))))))))))))*****************************‘*‘+++++++++++++++++++++++++++++++’+’,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,“,“-------------------------------------”-”..................................ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפ×××××××××××××××××××××××ר¥ØØØØØØØØØØØØØØØØØØØØÙ¦Ù¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßßßà­ààààààààààààààá®ááááááááááááâ¯ââââââââââââã°ããããããããããããä±ääääääääääå²ååååååååååæ³ææææææææææç´ççççççççççèµèèèèèèèèèèééééééééééê·êêêêêêêêë¸ëëëëëëëëì¹ììììììììíºííííííííî»îîîîîîîîïïïïïïïïïïððððððððñ¾ññññññññòòòòòòòòóóóóóóóóôÁôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúÇúúúúúúûÈûûûûûûüÉüüüüüüýÊýýýýýýþËþþþþþþÿÿÿÿ78 > @BHJKLMOPQR S!!!!!!!!!!!!!!!T"""""""""""""""""U###################V$$$$$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%%%%%X%X&&&&&&&&&&&&&&&&&&&&&Y'''''''''''''''''''''''Z'Z((((((((((((((((((((((([([)))))))))))))))))))))))))))\*****************************]*]+++++++++++++++++++++++++++++++^+^,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,_,_-------------------------------------`-`......................................ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááââââââââââââââããããããããããããããääääääääääääååååååååååååææææææææææææççççççççççççèèèèèèèèèèééééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîïïïïïïïïïïððððððððððññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""""####################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))))))******************************++++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------------..........................................ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßßààààààààààààààààááááááááááááááââââââââââââââããããããããããããääääääääääääääååååååååååååææææææææææææççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîîîïïïïïïïïððððððððððññññññññòòòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþÿÿÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""""##################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------------..............................................ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××××××××××××××ר Ø ØØØØØØØØØØØØØØØØØØØØÙ Ù ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ Ú ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßßàààààààààààààààáááááááááááááâââââââââââââãããããããããããäääääääääääääååååååååååååææææææææææææççççççççççèèèèèèèèèèèééééééééééêêêêêêêêêëëëëëëëëëìììììììììíííííííííî îîîîîîîîïïïïïïïïð"ððððððððññññññññò$òòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõö(öööööö÷)÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþÿ1ÿÿÖ × ÝÞäçéêëìí î î!!!!!!!!!!!!!!!ï"""""""""""""""""ð#################ñ$$$$$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%%%%%%%ó&&&&&&&&&&&&&&&&&&&&&ô'''''''''''''''''''''''õ'õ(((((((((((((((((((((((ö(ö)))))))))))))))))))))))))÷)÷*****************************ø*ø+++++++++++++++++++++++++++++++ù,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ú,ú-------------------------------------û-û...........................................ü.üÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××××××××××××××ר>ØØØØØØØØØØØØØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßEßßßßßßßßßßßßàFààààààààààààààáGááááááááááááâHââââââââââââããããããããããããäJääääääääääåKååååååååååæLææææææææææçMççççççççççèNèèèèèèèèéOééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîïUïïïïïïïïððððððððñWññññññññòòòòòòòòóóóóóóóóôZôôôôôôõ[õõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ ¤ §«¬­®¯±²´µ¶·¸¹ º!!!!!!!!!!!!!!!!!»"""""""""""""""""¼#################½$$$$$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%%%%%¿%¿&&&&&&&&&&&&&&&&&&&&&À'''''''''''''''''''''''Á(((((((((((((((((((((((((Â)))))))))))))))))))))))))))Ã*****************************Ä*Ä+++++++++++++++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Æ,Æ-------------------------------------Ç-Ç.........................................È.È.È////ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×××××××××××××××××××××רqØqØØØØØØØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßàyààààààààààààààázááááááááááááâ{ââââââââââã|ããããããããããããä}ääääääääääå~ååååååååååæææææææææææç€ççççççççççèèèèèèèèèèé‚ééééééééêƒêêêêêêêêë„ëëëëëëëëì…ììììììììí†ííííííííîîîîîîîîîîïïïïïïïïð‰ððððððððññññññññòòòòòòòòóŒóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ r s uw}€‚ƒ„…† ‡!!!!!!!!!!!!!!!!!ˆ"""""""""""""""‰"‰#################Š$$$$$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''Ž'Ž(((((((((((((((((((((((())))))))))))))))))))))))))***************************‘*‘+++++++++++++++++++++++++++++++’+’,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,“,“-------------------------------------”-”.........................................•.•//////////ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפפ×××××××××××××××××××××ר¥ØØØØØØØØØØØØØØØØØØØØÙ¦Ù¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨Û¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«Þ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßà­ààààààààààààààááááááááááááááââââââââââââã°ããããããããããããä±ääääääääääå²ååååååååååæ³ææææææææææççççççççççèµèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííî»îîîîîîîîïïïïïïïïïïððððððððññññññññò¿òòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ @BDEFGHIJKLMOPQ S!!!!!!!!!!!!!!!!!T"""""""""""""""U#################V#V$$$$$$$$$$$$$$$$$W$W%%%%%%%%%%%%%%%%%%%X&&&&&&&&&&&&&&&&&&&&&Y'''''''''''''''''''''''Z((((((((((((((((((((((((([)))))))))))))))))))))))))\)\*****************************]+++++++++++++++++++++++++++++++^+^,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,_,_-------------------------------------`-`.........................................a.a//////////////ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááááââââââââââââââããããããããããããããääääääääääääååååååååååååææææææææææççççççççççççèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííííîîîîîîîîïïïïïïïïïïððððððððññññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!!!""""""""""""""""##################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))********************************++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------------............................................//////////////////ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááááââââââââââââââããããããããããããääääääääääääååååååååååååææææææææææææççççççççççèèèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííîîîîîîîîîîïïïïïïïïððððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõõõöööööööö÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""""##################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))))******************************++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------------............................................//////////////////////ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× × ×××××××××××××××××××××ר ØØØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßàààààààààààààáááááááááááááâââââââââââââãããããããããããäääääääääääåååååååååååæææææææææææçççççççççèèèèèèèèèèèééééééééééêêêêêêêêêëëëëëëëëëììììììììììííííííííî îîîîîîîîïïïïïïïïð"ððððððððññññññññòòòòòòòòó%óóóóóóô&ôôôôôôõ'õõõõõõõõöööööööö÷÷÷÷÷÷ø*øøøøøøù+ùùùùùùúúúúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿÓÔ Ø Ù Ýßàãäæçèéêëìí î!!!!!!!!!!!!!!!ï"""""""""""""""""ð#################ñ$$$$$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%%%%%ó&&&&&&&&&&&&&&&&&&&&&ô'''''''''''''''''''''''õ(((((((((((((((((((((((ö(ö)))))))))))))))))))))))))÷)÷***************************ø*ø+++++++++++++++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ú,ú-------------------------------------û-û.......................................ü.ü.ü//////////////////////ÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×××××××××××××××××××××ר>Ø>ØØØØØØØØØØØØØØØØØØÙ?Ù?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßàFààààààààààààáGááááááááááááâHââââââââââââãIããããããããããäJääääääääääåKååååååååååæLææææææææææççççççççççèNèèèèèèèèéOééééééééééêêêêêêêêêêëëëëëëëëìRììììììììíSííííííííîîîîîîîîïUïïïïïïïïððððððððññññññññòXòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùú`úúúúúúûûûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿž ¦ §ª­®¯±²³´µ·¸¹ º!!!!!!!!!!!!!!!»"""""""""""""""""¼#################½$$$$$$$$$$$$$$$$$¾$¾%%%%%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&&&&&&&À'''''''''''''''''''''Á'Á(((((((((((((((((((((((Â)))))))))))))))))))))))))Ã)Ã***************************Ä*Ä+++++++++++++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Æ,Æ-----------------------------------Ç-Ç-Ç.......................................È.È////////////////////////////ÏÏÏÏÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×p×××××××××××××××××××××רqØØØØØØØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßàyààààààààààààázááááááááááááâ{ââââââââââââããããããããããããä}ääääääääääå~ååååååååååææææææææææç€ççççççççççèèèèèèèèèèé‚ééééééééêƒêêêêêêêêë„ëëëëëëëëììììììììììííííííííî‡îîîîîîîîïïïïïïïïð‰ððððððñŠññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúû”ûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ uy}~€‚ƒ„…† ‡!!!!!!!!!!!!!!!ˆ"""""""""""""""""‰#################Š$$$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%%%%%Œ%Œ&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''Ž(((((((((((((((((((((((()))))))))))))))))))))))))***************************‘*‘+++++++++++++++++++++++++++++’+’,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,“,“-----------------------------------”-”.........................................•.•////////////////////////////////ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפ×××××××××××××××××××××ר¥ØØØØØØØØØØØØØØØØØØØØÙ¦Ù¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßà­ààààààààààààá®ááááááááááááâ¯ââââââââââã°ããããããããããããääääääääääääååååååååååæ³ææææææææææç´ççççççççèµèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëì¹ììììììììíºííííííííîîîîîîîîï¼ïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôÁôôôôôôõÂõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ6 < = > BDFGHIKMOPQR S!!!!!!!!!!!!!!!T"""""""""""""""""U###############V#V$$$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%%%%%X&&&&&&&&&&&&&&&&&&&&&Y'''''''''''''''''''''Z'Z((((((((((((((((((((((([)))))))))))))))))))))))))\)\***************************]+++++++++++++++++++++++++++++++^,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,_,_-----------------------------------`-`.........................................a.a////////////////////////////////////ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááááââââââââââââããããããããããããääääääääääääååååååååååååææææææææææææççççççççççèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëëëììììììììììííííííííîîîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóóóôôôôôôôôõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""""################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((((((((())))))))))))))))))))))))))******************************++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------------............................................////////////////////////////////////////ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááááââââââââââââããããããããããããääääääääääääååååååååååååææææææææææççççççççççççèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëììììììììììííííííííííîîîîîîîîïïïïïïïïððððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúúúûûûûûûüüüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""##################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))))******************************++++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------------..........................................//////////////////////////////////////////////ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× × ×××××××××××××××××××ר ØØØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ Ú ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßàààààààààààààáááááááááááááâââââââââââãããããããããããäääääääääääåååååååååååæææææææææçççççççççççèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëìììììììììíííííííííîîîîîîîîïïïïïïïïð"ððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷ø*øøøøøøùùùùùùùùúúúúúúúúûûûûûûü.üüüüüüýýýýýýýýþþþþþþþþÿÿÔ ÜÝßáâãäåçèéêëìí î!!!!!!!!!!!!!!!ï"""""""""""""""ð#################ñ$$$$$$$$$$$$$$$$$ò$ò%%%%%%%%%%%%%%%%%ó%ó&&&&&&&&&&&&&&&&&&&ô'''''''''''''''''''''õ'õ(((((((((((((((((((((((ö)))))))))))))))))))))))))÷***************************ø*ø+++++++++++++++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ú,ú-----------------------------------û-û.......................................ü.ü/////////////////////////////////////////////ýÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×××××××××××××××××××ר>Ø>ØØØØØØØØØØØØØØØØØØÙ?Ù?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßàFààààààààààààáGááááááááááááââââââââââââãIããããããããããäJääääääääääåKååååååååååææææææææææçMççççççççèNèèèèèèèèéOééééééééêPêêêêêêêêëQëëëëëëëëììììììììììííííííííîîîîîîîîïUïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøù_ùùùùùùúúúúúúúúûûûûûûûûüüüüüüýýýýýýýýþþþþþþþþÿÿ ª¬¯°²³´µ¶·¸¹ º!!!!!!!!!!!!!!!»"""""""""""""""¼#################½$$$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&&&&&&&À'''''''''''''''''''''Á(((((((((((((((((((((((Â(Â)))))))))))))))))))))))Ã)Ã*************************Ä*Ä+++++++++++++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Æ,Æ-----------------------------------Ç-Ç.......................................È.È///////////////////////////////////////////É/É/É00ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×p×××××××××××××××××××רqØØØØØØØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßàyààààààààààààázááááááááááâ{ââââââââââââã|ããããããããããä}ääääääääääååååååååååæææææææææææççççççççççèèèèèèèèèé‚ééééééééêƒêêêêêêêêëëëëëëëëì…ììììììììí†ííííííî‡îîîîîîîîïïïïïïïïððððððððñŠññññññò‹òòòòòòóŒóóóóóóôôôôôôôõŽõõõõõõöööööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúúúûûûûûûûûüüüüüüýýýýýýýýþþþþþþþþÿÿil p q r s tuxz{~‚ƒ„† ‡!!!!!!!!!!!!!!!ˆ"""""""""""""""‰#################Š$$$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&&&&&&'''''''''''''''''''Ž'Ž(((((((((((((((((((((()))))))))))))))))))))))))***************************‘+++++++++++++++++++++++++++++’+’,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,“,“-----------------------------------”-”.......................................•.•///////////////////////////////////////////–/–00000000ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפ×××××××××××××××××××ר¥Ø¥ØØØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§Ú§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßà­ààààààààààààá®ááááááááááâ¯ââââââââââââããããããããããããääääääääääå²ååååååååååæ³ææææææææç´ççççççççççèèèèèèèèèèééééééééééêêêêêêêêë¸ëëëëëëëëì¹ììììììììííííííííîîîîîîîîï¼ïïïïïïð½ððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõöÃöööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúúúûûûûûûûûüüüüüüýýýýýýýýþþþþþþþþÿÿ; BCEGHIJKLNPQR S!!!!!!!!!!!!!!!T"""""""""""""""U###############V#V$$$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%%%X%X&&&&&&&&&&&&&&&&&&&Y'''''''''''''''''''''Z((((((((((((((((((((((([)))))))))))))))))))))))))\)\*************************]*]+++++++++++++++++++++++++++^+^,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,_,_-----------------------------------`-`.....................................a.a.a/////////////////////////////////////////b/b/b000000000000ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááââââââââââââããããããããããããääääääääääääååååååååååååææææææææææççççççççççèèèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëëëììììììììííííííííîîîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúúúûûûûûûûûüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""################$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))))****************************++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------------........................................//////////////////////////////////////////////000000000000000000ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààààááááááááááááââââââââââââããããããããããããääääääääääääååååååååååææææææææææææççççççççççèèèèèèèèèèééééééééééêêêêêêêêëëëëëëëëëëììììììììííííííííííîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúûûûûûûûûüüüüüüýýýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""""################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))))****************************++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------------........................................//////////////////////////////////////////////0000000000000000000000ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××××××××××××ר Ø ØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ Û ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßàààààààààààààáááááááááááâââââââââââãããããããããããäääääääääääåååååååååæææææææææææççççççççççèèèèèèèèèéééééééééêêêêêêêêëëëëëëëëëìììììììíííííííííîîîîîîîîï!ïïïïïïð"ððððððñ#ññññññò$òòòòòòó%óóóóóóô&ôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷øøøøøøøøùùùùùùùùúúúúúúûûûûûûûûüüüüüüýýýýýýýýþþþþþþþþÿÿÒÕ Ù Ú ÛÜÝàâãåæçèéêëìí î!!!!!!!!!!!!!ï!ï"""""""""""""ð"ð###############ñ$$$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%%%%%ó&&&&&&&&&&&&&&&&&&&ô'''''''''''''''''''''õ(((((((((((((((((((((((ö)))))))))))))))))))))))))÷*************************ø*ø+++++++++++++++++++++++++++++ù,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ú,ú-----------------------------------û-û.....................................ü.ü///////////////////////////////////////////ý/ý0000000000000000000000ÎÎÎÎÏ5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××××××××××××ר>ØØØØØØØØØØØØØØØØØØÙ?Ù?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßàFààààààààààààááááááááááááâHââââââââââãIããããããããããäJääääääääääååååååååååæLææææææææçMççççççççççèèèèèèèèèèééééééééêPêêêêêêêêëQëëëëëëëëììììììììííííííííîTîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôõ[õõõõõõöööööööö÷÷÷÷÷÷ø^øøøøøøùùùùùùùùúúúúúúûûûûûûûûüüüüüüýcýýýýýýþþþþþþþþÿÿ  ¤ ª«­¯°±²´µ¶·¸¹ º!!!!!!!!!!!!!»"""""""""""""""¼#################½$$$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%%%¿%¿&&&&&&&&&&&&&&&&&À&À'''''''''''''''''''Á'Á(((((((((((((((((((((Â(Â)))))))))))))))))))))))Ã)Ã*************************Ä+++++++++++++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Æ,Æ---------------------------------Ç-Ç-Ç.....................................È.È/////////////////////////////////////////É/É/É00000000000000000000000000ÎÎÎÎÎÎÎÎÏhÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×××××××××××××××××××רqØqØØØØØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßàyààààààààààázááááááááááááâ{ââââââââââã|ããããããããããä}ääääääääå~ååååååååååæææææææææç€ççççççççèèèèèèèèèé‚ééééééééêêêêêêêêêêëëëëëëëëì…ììììììí†ííííííííîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôôôõõõõõõööööööö÷÷÷÷÷÷÷÷øøøøøøùùùùùùùùúúúúúúû”ûûûûûûüüüüüüüüýýýýýýþþþþþþþþÿÿ p uy{€‚ƒ„…† ‡!!!!!!!!!!!!!ˆ"""""""""""""""‰#################Š$$$$$$$$$$$$$$$‹$‹%%%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&&&&&'''''''''''''''''''''Ž((((((((((((((((((((((())))))))))))))))))))))))*************************‘*‘+++++++++++++++++++++++++++’+’,,,,,,,,,,,,,,,,,,,,,,,,,,,,,“,“---------------------------------”-”.....................................•.•.•/////////////////////////////////////////–/–00000000000000000000000000000000ÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפפ×××××××××××××××××××ר¥ØØØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÞ«Þ«ÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßà­ààààààààààá®ááááááááááááâ¯ââââââââââã°ããããããããããääääääääääå²ååååååååååææææææææææç´ççççççççèµèèèèèèèèééééééééê·êêêêêêêêë¸ëëëëëëëëììììììììííííííííî»îîîîîîï¼ïïïïïïð½ððððððñ¾ññññññò¿òòòòòòóÀóóóóóóôôôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷÷÷øøøøøøùÆùùùùùùúúúúúúúúûûûûûûüüüüüüüüýýýýýýþþþþþþþþÿÿ; > ? @BCDFHIJKLNOPQR S!!!!!!!!!!!!!T"""""""""""""""U###############V#V$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%%%%%X&&&&&&&&&&&&&&&&&&&Y'''''''''''''''''''Z'Z((((((((((((((((((((([([)))))))))))))))))))))))\*************************]*]+++++++++++++++++++++++++++^+^,,,,,,,,,,,,,,,,,,,,,,,,,,,,,_,_---------------------------------`-`.....................................a.a/////////////////////////////////////////b/b/b000000000000000000000000000000000000ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààááááááááááááááââââââââââââããããããããããääääääääääääååååååååååææææææææææææççççççççççèèèèèèèèééééééééééêêêêêêêêêêëëëëëëëëììììììììííííííííííîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóôôôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúúúûûûûûûüüüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""""################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))))**************************++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------........................................////////////////////////////////////////////000000000000000000000000000000000000000000ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààááááááááááááááââââââââââããããããããããããääääääääääääååååååååååææææææææææççççççççççèèèèèèèèèèééééééééééêêêêêêêêëëëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóóóôôôôôôõõõõõõõõöööööööö÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúúúûûûûûûüüüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""""################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''''(((((((((((((((((((((())))))))))))))))))))))))))**************************++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------........................................////////////////////////////////////////////0000000000000000000000000000000000000000000000ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× × ×××××××××××××××××ר Ø ØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ Ú ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ Û ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßàààààààààààáááááááááááááââââââââââãããããããããããäääääääääääåååååååååæææææææææçççççççççèèèèèèèèèéééééééééêêêêêêêêëëëëëëëëëììììììììííííííííî îîîîîîï!ïïïïïïð"ððððððñ#ññññññòòòòòòòòóóóóóóóóôôôôôôõ'õõõõõõöööööööö÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúúúûûûûûûüüüüüüüüýýýýýýþþþþþþþþÿÿÏÕ ÛÜÝÞßáâãçèéëìí î!!!!!!!!!!!!!ï"""""""""""""""ð###############ñ$$$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%%%ó&&&&&&&&&&&&&&&&&&&ô'''''''''''''''''''õ'õ(((((((((((((((((((((ö)))))))))))))))))))))))÷)÷*************************ø+++++++++++++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ú,ú---------------------------------û-û.....................................ü.ü/////////////////////////////////////////ý/ý000000000000000000000000000000000000000000000þÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×××××××××××××××××××ר>ØØØØØØØØØØØØØØØØØØÙ?Ù?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßàFààààààààààáGááááááááááâHââââââââââãIããããããããããäJääääääääääååååååååååæLææææææææçMççççççççèèèèèèèèèèééééééééêPêêêêêêêêëëëëëëëëìRììììììíSííííííííîîîîîîîîïïïïïïïïððððððððññññññòXòòòòòòóYóóóóóóôôôôôôôôõõõõõõöööööööö÷÷÷÷÷÷ø^øøøøøøùùùùùùú`úúúúúúûûûûûûüüüüüüüüýýýýýýþþþþþþþþÿÿ £ ¦ ¬­¯°±²³´µ¶·¸¹ º!!!!!!!!!!!!!»"""""""""""""""¼###############½$$$$$$$$$$$$$$$¾$¾%%%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&&&À&À'''''''''''''''''''Á(((((((((((((((((((((Â(Â)))))))))))))))))))))))Ã*************************Ä*Ä+++++++++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Æ,Æ---------------------------------Ç-Ç...................................È.È.È///////////////////////////////////////É/É/É000000000000000000000000000000000000000000000Ê0Ê11ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×p×××××××××××××××××רqØqØØØØØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜuÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßàyààààààààààázááááááááááâ{ââââââââââã|ããããããããããä}ääääääääå~ååååååååååææææææææææççççççççèèèèèèèèèé‚ééééééééêêêêêêêêë„ëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòòòóóóóóóôôôôôôôõõõõõõööööööö÷÷÷÷÷÷÷÷øøøøøøùùùùùùùùúúúúúúûûûûûûüüüüüüüüýýýýýýþþþþþþþþÿÿmo r vw{}~€‚ƒ„…† ‡!!!!!!!!!!!!!ˆ"""""""""""""‰"‰#############Š#Š$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%%%Œ%Œ&&&&&&&&&&&&&&&&&'''''''''''''''''''Ž'Ž((((((((((((((((((((())))))))))))))))))))))))***********************‘*‘+++++++++++++++++++++++++++’,,,,,,,,,,,,,,,,,,,,,,,,,,,,,“,“---------------------------------”-”...................................•.•/////////////////////////////////////////–/–000000000000000000000000000000000000000000000—0—0—111111ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפ×××××××××××××××××××ר¥ØØØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§Ú§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜݪݪÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßßßà­ààààààààààá®ááááááááááâ¯ââââââââââã°ããããããããããääääääääääå²ååååååååæ³ææææææææç´ççççççççèµèèèèèèèèééééééééê·êêêêêêêêëëëëëëëëì¹ììììììíºííííííî»îîîîîîï¼ïïïïïïð½ððððððñ¾ññññññòòòòòòòòóóóóóóóóôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷÷÷øøøøøøùùùùùùùùúúúúúúûûûûûûüÉüüüüüüýýýýýýþþþþþþþþÿÿ7 = @ADEFHKMNOPQR S S!!!!!!!!!!!!!T"""""""""""""U###############V$$$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%%%X&&&&&&&&&&&&&&&&&&&Y'''''''''''''''''''Z((((((((((((((((((((([([)))))))))))))))))))))\)\***********************]*]+++++++++++++++++++++++++++^+^,,,,,,,,,,,,,,,,,,,,,,,,,,,_,_---------------------------------`-`...................................a.a///////////////////////////////////////b/b/b0000000000000000000000000000000000000000000c0c0c111111111111ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààááááááááááááââââââââââââããããããããããääääääääääääååååååååååææææææææææççççççççççèèèèèèèèééééééééééêêêêêêêêëëëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïïïððððððððññññññòòòòòòòòóóóóóóóóôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷÷÷øøøøøøùùùùùùùùúúúúúúûûûûûûûûüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((((())))))))))))))))))))))))**************************++++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------......................................//////////////////////////////////////////000000000000000000000000000000000000000000000000111111111111111111ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßßààààààààààààááááááááááááââââââââââââããããããããããääääääääääääååååååååååææææææææææççççççççèèèèèèèèèèééééééééééêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïïïððððððððññññññññòòòòòòóóóóóóóóôôôôôôôôõõõõõõöööööööö÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúûûûûûûûûüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!!!""""""""""""""################$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((((((())))))))))))))))))))))))**************************++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------------......................................//////////////////////////////////////////0000000000000000000000000000000000000000000000001111111111111111111111ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××××××××××××ר ØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßßàààààààààààáááááááááááâââââââââââãããããããããäääääääääääååååååååååææææææææææççççççççèèèèèèèèèéééééééééêêêêêêêêëëëëëëëëìììììììíííííííî îîîîîîï!ïïïïïïð"ððððððññññññññòòòòòòó%óóóóóóôôôôôôôôõõõõõõöööööööö÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúûûûûûûûûüüüüüüýýýýýýþþþþþþþþÿÿÕ × Ù ÜÝÞßàáãåæçèêëìí î!!!!!!!!!!!!!ï!ï"""""""""""""ð###############ñ$$$$$$$$$$$$$$$ò$ò%%%%%%%%%%%%%%%ó%ó&&&&&&&&&&&&&&&&&ô'''''''''''''''''''õ(((((((((((((((((((((ö(ö)))))))))))))))))))))÷)÷***********************ø*ø+++++++++++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,,,,,,,,,ú,ú-------------------------------û-û-û.................................ü.ü.ü/////////////////////////////////////ý/ý/ý0000000000000000000000000000000000000000000þ0þ0þ1111111111111111111111ÍÍÎ4Î4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××××××××××ר>Ø>ØØØØØØØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@Ú@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßßßàFààààààààààáGááááááááááâHââââââââââããããããããããäJääääääääåKååååååååæLææææææææçMççççççççèNèèèèèèèèééééééééêPêêêêêêëQëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïïïððððððñWññññññòòòòòòòòóóóóóóôZôôôôôôõõõõõõö\öööööö÷÷÷÷÷÷øøøøøøøøùùùùùùúúúúúúûaûûûûûûüüüüüüýýýýýýþþþþþþþþÿÿŸ §®¯°²³µ¶·¸¹ º!!!!!!!!!!!!!»"""""""""""""""¼###############½$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&&&À&À'''''''''''''''''''Á(((((((((((((((((((Â(Â)))))))))))))))))))))Ã)Ã***********************Ä*Ä+++++++++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,,,,,,,,,,,,Æ,Æ-------------------------------Ç-Ç...................................È.È///////////////////////////////////////É/É000000000000000000000000000000000000000000000Ê0Ê1111111111111111111111111111ÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×p×××××××××××××××××רqØØØØØØØØØØØØØØØØÙrÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßßßààààààààààààázááááááááááâ{ââââââââã|ããããããããããä}ääääääääå~ååååååååæææææææææç€ççççççççèèèèèèèèé‚ééééééééêêêêêêêêë„ëëëëëëì…ììììììí†ííííííî‡îîîîîîïˆïïïïïïððððððððññññññò‹òòòòòòóóóóóóóóôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷ø‘øøøøøøùùùùùùúúúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþþþÿÿio q s vwxyz}~‚„…† ‡!!!!!!!!!!!!!ˆ"""""""""""""""‰#############Š#Š$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&&&'''''''''''''''''''Ž'Ž((((((((((((((((((()))))))))))))))))))))))***********************‘*‘+++++++++++++++++++++++++’+’,,,,,,,,,,,,,,,,,,,,,,,,,,,“,“-------------------------------”-”...................................•.•///////////////////////////////////////–/–0000000000000000000000000000000000000000000—0—0—11111111111111111111111111111111ÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפ×××××××××××××××××ר¥ØØØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨Û¨ÛÛÛÛÛÛÛÛÛÛÛÛܩܩÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßà­ààààààààààààá®ááááááááááââââââââââã°ããããããããããääääääääääå²ååååååååæ³ææææææææççççççççèµèèèèèèèèééééééééê·êêêêêêêêëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïð½ððððððññññññññòòòòòòóÀóóóóóóôôôôôôõÂõõõõõõöööööö÷÷÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþþþÿÿ9 AGHJKLMNOPQR S!!!!!!!!!!!!!T"""""""""""""U"U#############V$$$$$$$$$$$$$$$W$W%%%%%%%%%%%%%%%X%X&&&&&&&&&&&&&&&&&Y'''''''''''''''''''Z((((((((((((((((((([([)))))))))))))))))))))\)\***********************]+++++++++++++++++++++++++^+^,,,,,,,,,,,,,,,,,,,,,,,,,,,_,_-------------------------------`-`...................................a.a/////////////////////////////////////b/b/b0000000000000000000000000000000000000000000c0c11111111111111111111111111111111111111ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààààááááááááááââââââââââââããããããããããääääääääääääååååååååååææææææææççççççççççèèèèèèèèééééééééééêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïïïððððððññññññññòòòòòòòòóóóóóóôôôôôôôôõõõõõõöööööö÷÷÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""################$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((())))))))))))))))))))))))**************************++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------------......................................////////////////////////////////////////000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááááââââââââââââããããããããããääääääääääååååååååååææææææææææççççççççççèèèèèèèèééééééééêêêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîïïïïïïïïððððððððññññññòòòòòòòòóóóóóóôôôôôôôôõõõõõõöööööööö÷÷÷÷÷÷øøøøøøùùùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""################$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((((())))))))))))))))))))))**************************++++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------....................................//////////////////////////////////////////0000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××××××××××ר ØØØØØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ Ú ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßàààààààààààáááááááááááâââââââââââãããããããããäääääääääåååååååååæææææææææçççççççççèèèèèèèèéééééééêêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîï!ïïïïïïð"ððððððññññññò$òòòòòòóóóóóóô&ôôôôôôõõõõõõö(öööööö÷÷÷÷÷÷øøøøøøùùùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþ0þþþþþþÿÿÑÕ Ø Ú Ýãäåçèêëí î!!!!!!!!!!!!!ï"""""""""""""ð###############ñ$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%ó%ó&&&&&&&&&&&&&&&&&ô'''''''''''''''''''õ(((((((((((((((((((ö(ö)))))))))))))))))))))÷***********************ø*ø+++++++++++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,,,,,,,,,ú,ú-----------------------------û-û.................................ü.ü/////////////////////////////////////ý/ý/ý00000000000000000000000000000000000000000þ0þ0þ11111111111111111111111111111111111111111111111ÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××××××××ר>Ø>ØØØØØØØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÝCÝCÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßàFààààààààààáGááááááááááâHââââââââââãIããããããããäJääääääääåKååååååååæLææææææææççççççççèNèèèèèèèèééééééééêPêêêêêêëQëëëëëëìRììììììíSííííííîTîîîîîîïïïïïïïïððððððñWññññññòòòòòòóYóóóóóóôôôôôôõõõõõõõõöööööö÷÷÷÷÷÷øøøøøøù_ùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýýýþþþþþþÿÿ ¨«¬­®¯±²µ¶·¸¹ º!!!!!!!!!!!!!»"""""""""""""¼###############½$$$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&&&À&À'''''''''''''''''Á'Á(((((((((((((((((((Â)))))))))))))))))))))Ã)Ã*********************Ä*Ä+++++++++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,,,,,,,,,,,,Æ,Æ-----------------------------Ç-Ç.................................È.È/////////////////////////////////////É/É0000000000000000000000000000000000000000000Ê0Ê1111111111111111111111111111111111111111111111111Ë1Ë22ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×××××××××××××××××רqØØØØØØØØØØØØØØØØÙrÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛtÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÞwÞwÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßàyààààààààààázááááááááááâ{ââââââââââããããããããããä}ääääääääå~ååååååååææææææææç€ççççççççèèèèèèèé‚ééééééééêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîïˆïïïïïïððððððððññññññòòòòòòòòóóóóóóôôôôôôõŽõõõõõõöööööö÷÷÷÷÷÷ø‘øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýýýþþþþþþÿÿko r tvw}€‚ƒ„…† ‡!!!!!!!!!!!!!ˆ"""""""""""""‰#############Š#Š$$$$$$$$$$$$$‹$‹%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&&&'''''''''''''''''''Ž(((((((((((((((((((())))))))))))))))))))***********************‘+++++++++++++++++++++++++’+’,,,,,,,,,,,,,,,,,,,,,,,,,,,“,“-----------------------------”-”.................................•.•/////////////////////////////////////–/–00000000000000000000000000000000000000000—0—0—11111111111111111111111111111111111111111111111˜1˜1˜222222ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפפ×××××××××××××××ר¥Ø¥ØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§Ú§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛܩܩÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßà­ààààààààààá®ááááááááááâ¯ââââââââã°ããããããããããääääääääääååååååååæ³ææææææææç´ççççççççèèèèèèèèé¶ééééééê·êêêêêêë¸ëëëëëëì¹ììììììíºííííííîîîîîîîîïïïïïïð½ððððððññññññò¿òòòòòòóóóóóóôÁôôôôôôõõõõõõöööööö÷Ä÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýýýþþþþþþÿÿ8 < ? ADEFGHJLMNOPQR S!!!!!!!!!!!!!T"""""""""""""U#############V$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%X%X&&&&&&&&&&&&&&&Y&Y'''''''''''''''''Z'Z((((((((((((((((([([)))))))))))))))))))))\***********************]*]+++++++++++++++++++++++^+^,,,,,,,,,,,,,,,,,,,,,,,,,,,_,_-----------------------------`-`...............................a.a.a///////////////////////////////////b/b/b00000000000000000000000000000000000000000c0c11111111111111111111111111111111111111111111111d1d1d222222222222ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááááââââââââââããããããããããääääääääääååååååååååææææææææææççççççççèèèèèèèèèèééééééééêêêêêêêêëëëëëëëëììììììììííííííîîîîîîîîïïïïïïïïððððððññññññññòòòòòòóóóóóóóóôôôôôôõõõõõõöööööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""##############$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((())))))))))))))))))))))))************************++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------..................................////////////////////////////////////////000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111222222222222222222ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááááââââââââââããããããããããääääääääääååååååååååææææææææççççççççççèèèèèèèèééééééééêêêêêêêêëëëëëëëëììììììììííííííííîîîîîîîîïïïïïïððððððððññññññòòòòòòòòóóóóóóôôôôôôõõõõõõöööööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!!!""""""""""""""##############$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((())))))))))))))))))))))************************++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,--------------------------------..................................////////////////////////////////////////0000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111222222222222222222222222ÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× × ×××××××××××××××ר Ø ØØØØØØØØØØØØØØÙ Ù ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßàààààààààààáááááááááááâââââââââãããããããããäääääääääåååååååååæææææææçççççççççèèèèèèèèéééééééêêêêêêêëëëëëëëìììììììíííííííîîîîîîîîïïïïïïð"ððððððññññññòòòòòòòòóóóóóóôôôôôôõõõõõõö(öööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûü.üüüüüüýýýýýýþþþþþþÿÿÕ Ù ÛÝßàáâãäæêëìí î!!!!!!!!!!!ï!ï"""""""""""ð"ð#############ñ$$$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%ó&&&&&&&&&&&&&&&&&ô'''''''''''''''''õ'õ(((((((((((((((((ö(ö)))))))))))))))))))÷)÷*********************ø*ø+++++++++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,,,,,,,,,ú,ú---------------------------û-û-û...............................ü.ü///////////////////////////////////ý/ý/ý000000000000000000000000000000000000000þ0þ0þ111111111111111111111111111111111111111111111ÿ1ÿ1ÿ222222222222222222222222ÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×××××××××××××××××ר>ØØØØØØØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@Ú@ÚÚÚÚÚÚÚÚÚÚÚÚÛAÛAÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßàFààààààààààáGááááááááááââââââââââãIããããããããäJääääääääåKååååååååææææææææçMççççççèNèèèèèèèèééééééééêêêêêêêêëëëëëëëëììììììììííííííîTîîîîîîïïïïïïïïððððððññññññòXòòòòòòóóóóóóôôôôôôõ[õõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûaûûûûûûüüüüüüýýýýýýþþþþþþÿÿ¢ ¦ ¨ª®±²³´µ¶·¸¹ º!!!!!!!!!!!»"""""""""""""¼###############½$$$$$$$$$$$$$¾$¾%%%%%%%%%%%%%¿%¿&&&&&&&&&&&&&&&À&À'''''''''''''''''Á(((((((((((((((((((Â)))))))))))))))))))))Ã***********************Ä+++++++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,,,,,,,,,,,,Æ,Æ---------------------------Ç-Ç.................................È.È///////////////////////////////////É/É00000000000000000000000000000000000000000Ê0Ê11111111111111111111111111111111111111111111111Ë1Ë222222222222222222222222222222ÌÌÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×p×××××××××××××××רqØqØØØØØØØØØØØØØØÙrÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßàyààààààààààázááááááááâ{ââââââââââã|ããããããããä}ääääääääååååååååæææææææææççççççççèèèèèèèé‚ééééééêƒêêêêêêë„ëëëëëëì…ììììììí†ííííííîîîîîîïˆïïïïïïððððððñŠññññññòòòòòòóóóóóóôôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøù’ùùùùú“úúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ p tvyz|}~€‚ƒ„…† ‡!!!!!!!!!!!ˆ"""""""""""""‰#############Š#Š$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&&&'''''''''''''''''Ž'Ž(((((((((((((((((())))))))))))))))))))*********************‘*‘+++++++++++++++++++++++’,,,,,,,,,,,,,,,,,,,,,,,,,,,“,“---------------------------”-”...............................•.•.•///////////////////////////////////–/–000000000000000000000000000000000000000—0—0—111111111111111111111111111111111111111111111˜1˜1˜2222222222222222222222222222222222ÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפ×××××××××××××××××ר¥ØØØØØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßà­ààààààààààá®ááááááááâ¯ââââââââââããããããããããääääääääå²ååååååååæ³ææææææç´ççççççççèèèèèèèèé¶ééééééê·êêêêêêë¸ëëëëëëììììììììííííííî»îîîîîîïïïïïïð½ððððððññññññò¿òòòòóÀóóóóóóôôôôôôõõõõõõöööööö÷Ä÷÷÷÷øÅøøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ = CDFGHIKMNOPQR S!!!!!!!!!!!T"""""""""""""U#############V$$$$$$$$$$$$$$$W%%%%%%%%%%%%%%%X&&&&&&&&&&&&&&&Y&Y'''''''''''''''''Z((((((((((((((((((([)))))))))))))))))))\)\*********************]*]+++++++++++++++++++++++^+^,,,,,,,,,,,,,,,,,,,,,,,,,_,_---------------------------`-`...............................a.a///////////////////////////////////b/b/b000000000000000000000000000000000000000c0c111111111111111111111111111111111111111111111d1d1d2222222222222222222222222222222222222222ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááââââââââââããããããããããääääääääääååååååååååææææææææççççççççèèèèèèèèèèééééééééêêêêêêêêëëëëëëììììììììííííííííîîîîîîïïïïïïïïððððððññññññññòòòòòòóóóóóóôôôôôôõõõõõõöööööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""""##############$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''''''(((((((((((((((((((())))))))))))))))))))************************++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------..................................//////////////////////////////////////000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààààááááááááááââââââââââããããããããããääääääääääååååååååææææææææææççççççççèèèèèèèèééééééééêêêêêêêêëëëëëëëëììììììììííííííîîîîîîîîïïïïïïððððððððññññññòòòòòòóóóóóóôôôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""""##############$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&''''''''''''''''''(((((((((((((((((((())))))))))))))))))))))**********************++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------..................................//////////////////////////////////////0000000000000000000000000000000000000000001111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××××××××ר Ø ØØØØØØØØØØØØØØÙ Ù ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÛ Û ÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßàààààààààààáááááááááâââââââââãããããããããäääääääääåååååååæææææææææççççççççèèèèèèèéééééééêêêêêêêëëëëëëëììììììììííííííî îîîîîîïïïïïïð"ððððððññññññòòòòòòóóóóóóô&ôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿÒÓÔÕ ÛÝßáâãäåçéêëìí î!!!!!!!!!!!ï"""""""""""""ð#############ñ$$$$$$$$$$$$$ò%%%%%%%%%%%%%%%ó&&&&&&&&&&&&&&&&&ô'''''''''''''''''õ(((((((((((((((((ö(ö)))))))))))))))))))÷)÷*********************ø+++++++++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,,,,,,,ú,ú---------------------------û-û...............................ü.ü/////////////////////////////////ý/ý/ý000000000000000000000000000000000000000þ0þ111111111111111111111111111111111111111111111ÿ1ÿ222222222222222222222222222222222222222222222222223ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××××××××ר>ØØØØØØØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßßßàFààààààààààáGááááááááâHââââââââãIããããããããäJääääääääååååååååæLææææææçMççççççççèèèèèèèèééééééééêêêêêêêêëëëëëëìRììììììíSííííííîîîîîîïUïïïïïïððððððññññññòXòòòòóYóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿœ¢ £ ¤ ¨ª¬²³´·¸¹ º!!!!!!!!!!!»"""""""""""¼"¼###########½#½$$$$$$$$$$$$$¾%%%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&À&À'''''''''''''''Á'Á(((((((((((((((((Â)))))))))))))))))))Ã)Ã*********************Ä*Ä+++++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,,,,,,,,,,Æ,Æ---------------------------Ç-Ç.............................È.È.È/////////////////////////////////É/É000000000000000000000000000000000000000Ê0Ê0Ê1111111111111111111111111111111111111111111Ë1Ë1Ë2222222222222222222222222222222222222222222222222Ì2Ì2Ì33ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×××××××××××××××רqØqØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßßßàyààààààààààááááááááááâ{ââââââââã|ããããããããä}ääääääå~ååååååååæææææææç€ççççççèèèèèèèé‚ééééééêƒêêêêêêë„ëëëëëëììììììììííííííî‡îîîîîîïïïïïïððððððñŠññññññòòòòòòóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ r s vxz{|}~‚ƒ„…† ‡!!!!!!!!!!!ˆ"""""""""""‰#############Š$$$$$$$$$$$$$$$‹%%%%%%%%%%%%%Œ%Œ&&&&&&&&&&&&&&&'''''''''''''''''Ž(((((((((((((((((()))))))))))))))))))*********************‘*‘+++++++++++++++++++++’+’,,,,,,,,,,,,,,,,,,,,,,,,,“,“---------------------------”-”.............................•.•///////////////////////////////////–/–0000000000000000000000000000000000000—0—0—1111111111111111111111111111111111111111111˜1˜1˜2222222222222222222222222222222222222222222222222™2™2™33333333ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפפ×××××××××××××××ר¥ØØØØØØØØØØØØØØÙ¦Ù¦ÙÙÙÙÙÙÙÙÙÙÙÙÚ§Ú§ÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßà­ààààààààá®ááááááááááâ¯ââââââââã°ããããããããääääääääå²ååååååååææææææææç´ççççççèµèèèèèèé¶ééééééê·êêêêêêëëëëëëì¹ììììììííííííííîîîîîîïïïïïïð½ððððððññññññòòòòòòóóóóóóôôôôôôõÂõõõõöÃöööö÷Ä÷÷÷÷øÅøøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ4 @CEHIJLMNOPQR S!!!!!!!!!!!T"""""""""""U#############V$$$$$$$$$$$$$W$W%%%%%%%%%%%%%X&&&&&&&&&&&&&&&Y&Y'''''''''''''''Z'Z((((((((((((((((([)))))))))))))))))))\)\*******************]*]+++++++++++++++++++++^+^,,,,,,,,,,,,,,,,,,,,,,,,,_,_---------------------------`-`.............................a.a/////////////////////////////////b/b/b0000000000000000000000000000000000000c0c1111111111111111111111111111111111111111111d1d1d2222222222222222222222222222222222222222222222222e2e2e33333333333333ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááááááââââââââââããããããããääääääääääååååååååææææææææææççççççççèèèèèèèèééééééééêêêêêêëëëëëëëëììììììííííííííîîîîîîïïïïïïïïððððððññññññòòòòòòóóóóóóôôôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøùùùùùùúúúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""##############$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''''(((((((((((((((((((())))))))))))))))))))**********************++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,,,------------------------------................................////////////////////////////////////000000000000000000000000000000000000000000111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222233333333333333333333ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááááââââââââââããããããããããääääääääääååååååååææææææææççççççççèèèèèèèèééééééééêêêêêêêêëëëëëëììììììììííííííîîîîîîîîïïïïïïððððððññññññññòòòòòòóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúûûûûûûüüüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""##############$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''''(((((((((((((((((())))))))))))))))))))**********************++++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------..................................////////////////////////////////////0000000000000000000000000000000000000000111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222233333333333333333333333333ËþËþÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××××××××ר ØØØØØØØØØØØØØØÙ Ù ÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßàààààààààáááááááááâââââââââãããããããããäääääääääååååååååæææææææçççççççèèèèèèèéééééééêêêêêêêëëëëëëìììììììííííííî îîîîîîïïïïïïð"ððððñ#ññññññòòòòòòóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúû-ûûûûüüüüüüýýýýýýþþþþþþÿÿÖ × Ø Ù Þàâãäåæçèéêëìí î î!!!!!!!!!!!ï"""""""""""ð#############ñ$$$$$$$$$$$$$ò%%%%%%%%%%%%%ó%ó&&&&&&&&&&&&&&&ô'''''''''''''''õ'õ(((((((((((((((((ö)))))))))))))))))))÷*********************ø+++++++++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,,,,,ú,ú-------------------------û-û.............................ü.ü.ü///////////////////////////////ý/ý/ý0000000000000000000000000000000000000þ0þ1111111111111111111111111111111111111111111ÿ1ÿ22222222222222222222222222222222222222222222222233333333333333333333333333333ËËËËÌ2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××××××ר>Ø>ØØØØØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÚ@Ú@ÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÞDÞDÞÞÞÞÞÞÞÞßEßßßßßßßßßßàFààààààààáGááááááááâHââââââââãIããããããããäJääääääåKååååååååææææææææçMççççççèNèèèèèèééééééééêêêêêêëQëëëëëëììììììíSííííííîîîîîîïUïïïïïïððððððññññññòòòòòòóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûüüüüüüýýýýýýþþþþþþÿÿ ¡ ¦ §¨«­°±²´¶·¸¹ º!!!!!!!!!!!»!»"""""""""""¼###########½#½$$$$$$$$$$$¾$¾%%%%%%%%%%%%%¿&&&&&&&&&&&&&&&À&À'''''''''''''''Á(((((((((((((((((Â(Â)))))))))))))))))Ã)Ã*******************Ä*Ä+++++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,,,,,,,,Æ,Æ-------------------------Ç-Ç.............................È.È/////////////////////////////////É/É0000000000000000000000000000000000000Ê0Ê0Ê11111111111111111111111111111111111111111Ë1Ë1Ë22222222222222222222222222222222222222222222222Ì2Ì2Ì33333333333333333333333333333333ËËËËËËËËËËÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×××××××××××××××רqØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÝvÝvÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞßxßßßßßßßßßßàyààààààààázááááááááâ{ââââââââã|ããããããããääääääääå~ååååååæææææææææççççççççèèèèèèé‚ééééééêƒêêêêêêëëëëëëì…ììììììííííííî‡îîîîîîïïïïïïððððððññññññò‹òòòòóŒóóóóôôôôôõŽõõõõööööö÷÷÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûüüüüüüýýýýýýþþþþþþÿÿl vy{|€‚ƒ„…† ‡!!!!!!!!!!!ˆ"""""""""""""‰###########Š$$$$$$$$$$$$$‹%%%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&'''''''''''''''Ž'Ž(((((((((((((((())))))))))))))))))*******************‘*‘+++++++++++++++++++++’+’,,,,,,,,,,,,,,,,,,,,,,,“,“-------------------------”-”.............................•.•/////////////////////////////////–/–00000000000000000000000000000000000—0—0—11111111111111111111111111111111111111111˜1˜1˜22222222222222222222222222222222222222222222222™2™2™33333333333333333333333333333333333333ËËËËËËËËËËËËËËËË̙̙̙ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפפ×××××××××××××ר¥ØØØØØØØØØØØØØØÙ¦Ù¦ÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÛ¨Û¨ÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßà­ààààààààá®ááááááááâ¯ââââââââã°ããããããä±ääääääääå²ååååååæ³ææææææç´ççççççèµèèèèèèé¶ééééééêêêêêêë¸ëëëëëëììììììíºííííííîîîîîîï¼ïïïïð½ððððñ¾ññññññòòòòòòóóóóóóôôôôôôõõõõõõöööö÷Ä÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûüÉüüüüýýýýýýþþþþþþÿÿ CDFHIJKLMNPQR S!!!!!!!!!!!T"""""""""""U"U###########V$$$$$$$$$$$$$W%%%%%%%%%%%%%X%X&&&&&&&&&&&&&Y&Y'''''''''''''''Z((((((((((((((((([)))))))))))))))))))\*******************]*]+++++++++++++++++++++^+^,,,,,,,,,,,,,,,,,,,,,,,_,_-------------------------`-`.............................a.a///////////////////////////////b/b/b00000000000000000000000000000000000c0c11111111111111111111111111111111111111111d1d1d22222222222222222222222222222222222222222222222e2e2e33333333333333333333333333333333333333333333ËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××ØØØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááááââââââââââããããããããääääääääääååååååååææææææææççççççççèèèèèèèèééééééêêêêêêêêëëëëëëììììììììííííííîîîîîîîîïïïïïïððððððññññññòòòòòòóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷øøøøøøùùùùùùúúúúúúûûûûûûüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""##############$$$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''''(((((((((((((((((())))))))))))))))))))********************++++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------................................//////////////////////////////////000000000000000000000000000000000000000011111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááááââââââââââããããããããääääääääååååååååååææææææææççççççççèèèèèèééééééééêêêêêêêêëëëëëëììììììííííííííîîîîîîïïïïïïððððððññññññòòòòòòóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøùùùùùùúúúúúúûûûûûûüüüüýýýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""##############$$$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''(((((((((((((((((())))))))))))))))))))**********************++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,,,----------------------------..............................////////////////////////////////////0000000000000000000000000000000000000011111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËþËþËþÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× × ×××××××××××××ר ØØØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞßßßßßßßßßßßàààààààààáááááááááâââââââââããããããããäääääääåååååååååææææææææççççççççèèèèèèéééééééêêêêêêêëëëëëëìììììíííííííîîîîîîïïïïïïððððððñ#ññññò$òòòòó%óóóóôôôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøù+ùùùùúúúúúúûûûûûûüüüüýýýýýýþþþþþþÿÿÖ Þßáãäèéêëìí î!!!!!!!!!!!ï"""""""""""ð#############ñ$$$$$$$$$$$ò$ò%%%%%%%%%%%%%ó&&&&&&&&&&&&&ô&ô'''''''''''''''õ(((((((((((((((((ö)))))))))))))))))÷)÷*******************ø*ø+++++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,,,,,ú,ú-------------------------û-û...........................ü.ü///////////////////////////////ý/ý/ý00000000000000000000000000000000000þ0þ11111111111111111111111111111111111111111ÿ1ÿ1ÿ22222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333344ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌ2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×××××××××××××ר>Ø>ØØØØØØØØØØØØÙ?Ù?ÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞßEßßßßßßßßßßàFààààààààáGááááááááâHââââââãIããããããããäJääääääåKååååååæLææææææçMççççççèNèèèèèèéOééééééêêêêêêëQëëëëëëììììììííííííîTîîîîïUïïïïðVððððððññññññòòòòòòóóóóôZôôôôõ[õõõõöööööö÷÷÷÷÷÷øøøøøøùùùùúúúúúúûûûûûûüüüüýýýýýýþþþþþþÿÿš¡ ¬®°±²³´µ¶·¸¹ º!!!!!!!!!!!»"""""""""""¼###########½#½$$$$$$$$$$$¾%%%%%%%%%%%%%¿%¿&&&&&&&&&&&&&À'''''''''''''''Á'Á(((((((((((((((Â(Â)))))))))))))))))Ã*******************Ä*Ä+++++++++++++++++++++Å,,,,,,,,,,,,,,,,,,,,,,,Æ,Æ-------------------------Ç-Ç...........................È.È///////////////////////////////É/É00000000000000000000000000000000000Ê0Ê0Ê111111111111111111111111111111111111111Ë1Ë1Ë222222222222222222222222222222222222222222222Ì2Ì2Ì33333333333333333333333333333333333333333333333333333Í3Í3Í4444ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×p×××××××××××××רqØØØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÚsÚsÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞßxßßßßßßßßßßàyààààààààázááááááááââââââââã|ããããããããääääääääå~ååååååæææææææç€ççççççèèèèèèèèééééééêƒêêêêêêëëëëëëì…ììììí†ííííííîîîîîîïïïïïïððððððññññññòòòòòòóóóóóóôôôôôôõõõõööööö÷÷÷÷÷÷øøøøøøùùùùú“úúúúûûûûûûüüüüý–ýýýýþþþþþþÿÿm r s tuvwz|~€ƒ„…† ‡!!!!!!!!!!!ˆ"""""""""""‰###########Š$$$$$$$$$$$$$‹%%%%%%%%%%%%%Œ&&&&&&&&&&&&&&&'''''''''''''''Ž((((((((((((((((())))))))))))))))))*****************‘*‘+++++++++++++++++++++’+’,,,,,,,,,,,,,,,,,,,,,“,“-------------------------”-”...........................•.•///////////////////////////////–/–00000000000000000000000000000000000—0—111111111111111111111111111111111111111˜1˜1˜222222222222222222222222222222222222222222222™2™2™33333333333333333333333333333333333333333333333333333š3š3š4444444444ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËË̙̙̙ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖפ×××××××××××××ר¥Ø¥ØØØØØØØØØØØØÙ¦Ù¦ÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÛ¨Û¨ÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞ߬ßßßßßßßßßßà­ààààààààá®ááááááâ¯ââââââââã°ããããããä±ääääääääååååååååææææææææççççççèµèèèèèèé¶ééééééêêêêêêë¸ëëëëëëììììììííííííî»îîîîï¼ïïïïð½ððððñ¾ññññò¿òòòòóóóóóóôôôôôôõõõõõõöööö÷Ä÷÷÷÷øøøøøøùùùùùùúúúúûûûûûûüüüüüüýýýýþþþþþþÿÿ < = DEGHILNOPQR S!!!!!!!!!!!T"""""""""""U###########V$$$$$$$$$$$$$W%%%%%%%%%%%%%X&&&&&&&&&&&&&Y&Y'''''''''''''Z'Z((((((((((((((([([)))))))))))))))\)\*******************]+++++++++++++++++++++^+^,,,,,,,,,,,,,,,,,,,,,_,_-------------------------`-`...........................a.a/////////////////////////////b/b/b000000000000000000000000000000000c0c0c1111111111111111111111111111111111111d1d1d222222222222222222222222222222222222222222222e2e2e333333333333333333333333333333333333333333333333333f3f3f3f4444444444444444ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßßßààààààààààááááááááââââââââââããããããããääääääääååååååååææææææææççççççççèèèèèèèèééééééêêêêêêêêëëëëëëììììììííííííííîîîîîîïïïïïïððððððññññññòòòòóóóóóóôôôôôôõõõõõõöööööö÷÷÷÷øøøøøøùùùùùùúúúúûûûûûûüüüüüüýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""############$$$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''''''(((((((((((((((((())))))))))))))))))**********************++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,----------------------------..............................////////////////////////////////000000000000000000000000000000000000001111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333444444444444444444444444ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßààààààààààááááááááââââââââââããããããããääääääääååååååååææææææææççççççççèèèèèèééééééééêêêêêêëëëëëëëëììììììííííííîîîîîîïïïïïïððððððññññññòòòòòòóóóóóóôôôôõõõõõõöööööö÷÷÷÷÷÷øøøøùùùùùùúúúúûûûûûûüüüüüüýýýýþþþþþþÿÿ  !!!!!!!!!!!!""""""""""""############$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&&&''''''''''''''''(((((((((((((((())))))))))))))))))))********************++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,,,--------------------------..............................//////////////////////////////////0000000000000000000000000000000000001111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333444444444444444444444444444444ÊýÊýÊýËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËþËþËþÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××××××ר Ø ØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßàààààààààááááááááâââââââââãããããããäääääääåååååååæææææææçççççççèèèèèèéééééééêêêêêêëëëëëëëììììììííííííîîîîîîïïïïïïððððððññññññòòòòòòóóóóóóôôôôõ'õõõõöööööö÷÷÷÷÷÷øøøøùùùùùùúúúúû-ûûûûüüüüüüýýýýþþþþþþÿÿ Ù Ú ßàãåæçèéëìí î!!!!!!!!!!!ï"""""""""ð"ð#########ñ#ñ$$$$$$$$$$$ò%%%%%%%%%%%%%ó&&&&&&&&&&&&&ô&ô'''''''''''''õ'õ(((((((((((((((ö)))))))))))))))))÷)÷*****************ø*ø+++++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,,,ú,ú-----------------------û-û...........................ü.ü/////////////////////////////ý/ý/ý000000000000000000000000000000000þ0þ111111111111111111111111111111111111111ÿ1ÿ1ÿ22222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333444444444444444444444444444444444ÊÊÊÊÊÊË1Ë1Ë1Ë1ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌ2Ì2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××××××ר>ØØØØØØØØØØØØÙ?Ù?ÙÙÙÙÙÙÙÙÙÙÚ@Ú@ÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞÞÞßEßßßßßßßßàFààààààáGááááááááâHââââââââããããããããäJääääääåKååååååæLææææææççççççèNèèèèèèéOééééêPêêêêêêëëëëëëìRììììíSííííîTîîîîïUïïïïðVððððñWññññòXòòòòóóóóóóôôôôôôõõõõö\öööö÷÷÷÷÷÷øøøøùùùùùùúúúúúúûûûûüüüüüüýýýýþþþþþþÿÿœ¡ ¤ ­®°²³´µ¶·¸¹ º!!!!!!!!!»!»"""""""""¼###########½$$$$$$$$$$$$$¾%%%%%%%%%%%%%¿&&&&&&&&&&&&&À'''''''''''''''Á(((((((((((((((Â(Â)))))))))))))))Ã)Ã*****************Ä*Ä+++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,,,,,,Æ,Æ-----------------------Ç-Ç...........................È.È/////////////////////////////É/É000000000000000000000000000000000Ê0Ê0Ê1111111111111111111111111111111111111Ë1Ë1Ë2222222222222222222222222222222222222222222Ì2Ì2Ì3333333333333333333333333333333333333333333333333Í3Í3Í3Í444444444444444444444444444444444444ÊÊÊÊÊÊÊÊÊÊÊÊÊÊËdËdËdËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×××××××××××××רqØqØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÛtÛtÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞÞÞßxßßßßßßßßàyààààààázááááááááâ{ââââââã|ããããããããääääääääååååååååææææææç€ççççççèèèèèèèééééééêƒêêêêë„ëëëëëëììììììííííííîîîîîîïïïïïïððððððññññññòòòòóŒóóóóôôôôôôõõõõõõöööö÷÷÷÷÷÷øøøøù’ùùùùúúúúúúûûûûüüüüüüýýýýþþþþþþÿÿk p tuvwxyz|~ƒ„…† ‡!!!!!!!!!ˆ"""""""""""‰###########Š$$$$$$$$$$$‹$‹%%%%%%%%%%%Œ%Œ&&&&&&&&&&&&&'''''''''''''Ž'Ž((((((((((((((()))))))))))))))))*******************‘+++++++++++++++++++’+’,,,,,,,,,,,,,,,,,,,,,“,“-----------------------”-”...........................•.•/////////////////////////////–/–000000000000000000000000000000000—0—1111111111111111111111111111111111111˜1˜1˜2222222222222222222222222222222222222222222™2™2™3333333333333333333333333333333333333333333333333š3š3š44444444444444444444444444444444444444444444ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ˘˘˘ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËË̙̙̙ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖפפ×××××××××××××ר¥ØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞÞÞ߬ßßßßßßßßà­ààààààá®ááááááááâ¯ââââââã°ããããããä±ääääääå²ååååååæ³ææææææç´ççççççèèèèèèé¶ééééééêêêêêêëëëëëëì¹ììììíºííííî»îîîîï¼ïïïïð½ððððññññññòòòòòòóóóóôÁôôôôõõõõõõöööö÷Ä÷÷÷÷øøøøøøùùùùúúúúúúûûûûüüüüüüýýýýþþþþþþÿÿ9 ? GHIJKLNOPQR S!!!!!!!!!T"""""""""""U###########V$$$$$$$$$$$W%%%%%%%%%%%%%X&&&&&&&&&&&&&Y&Y'''''''''''''Z((((((((((((((([([)))))))))))))))\)\*****************]*]+++++++++++++++++++^,,,,,,,,,,,,,,,,,,,,,_,_-----------------------`-`.........................a.a.a///////////////////////////b/b/b0000000000000000000000000000000c0c0c11111111111111111111111111111111111d1d1d2222222222222222222222222222222222222222222e2e2e3333333333333333333333333333333333333333333333333f3f3f44444444444444444444444444444444444444444444444444ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßààààààààááááááááááââââââââããããããããääääääääååååååååææææææææççççççèèèèèèèèééééééêêêêêêëëëëëëëëììììììííííííîîîîîîïïïïïïððððññññññòòòòòòóóóóóóôôôôõõõõõõöööööö÷÷÷÷øøøøøøùùùùúúúúúúûûûûüüüüüüýýýýþþþþþþÿÿ  !!!!!!!!!!""""""""""""############$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''''''(((((((((((((((())))))))))))))))))********************++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,--------------------------............................////////////////////////////////000000000000000000000000000000000000111111111111111111111111111111111111111122222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßßßßßààààààààááááááááááââââââââããããããããääääääääååååååååææææææççççççççèèèèèèééééééééêêêêêêëëëëëëììììììííííííîîîîîîïïïïïïððððððññññññòòòòóóóóóóôôôôôôõõõõöööööö÷÷÷÷øøøøøøùùùùúúúúúúûûûûüüüüüüýýýýþþþþþþÿÿ  !!!!!!!!!!""""""""""""############$$$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''''(((((((((((((((((())))))))))))))))********************++++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,--------------------------............................////////////////////////////////0000000000000000000000000000000000001111111111111111111111111111111111111111222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444444444ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊýÊýÊýËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËþËþËþÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××××ר Ø ØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßßààààààààáááááááááâââââââãããããããäääääääåååååååææææææçççççççèèèèèéééééééêêêêêêëëëëëìììììíííííî îîîîï!ïïïïððððððññññññòòòòó%óóóóôôôôôôõõõõö(öööö÷÷÷÷ø*øøøøùùùùú,úúúúûûûûü.üüüüýýýýþþþþþþÿÿ Ø ÛÜâãåçèéêëìí î!!!!!!!!!ï"""""""""""ð#########ñ#ñ$$$$$$$$$$$ò%%%%%%%%%%%ó%ó&&&&&&&&&&&ô&ô'''''''''''''õ(((((((((((((((ö(ö)))))))))))))))÷*****************ø*ø+++++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,ú,ú-----------------------û-û.........................ü.ü///////////////////////////ý/ý/ý0000000000000000000000000000000þ0þ0þ11111111111111111111111111111111111ÿ1ÿ1ÿ22222222222222222222222222222222222222223333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444555ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊË1Ë1Ë1Ë1ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌ2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××××ר>ØØØØØØØØØØØØÙ?Ù?ÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÛAÛAÛÛÛÛÛÛÛÛÜBÜBÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞßEßßßßßßàFààààààààáGááááááááââââââââãIããããããäJääääääååååååæLææææææçMççççççèèèèèèéOééééêPêêêêêêëëëëëëììììììííííííîîîîîîïïïïðVððððñWññññòòòòòòóóóóôZôôôôõõõõõõöööö÷÷÷÷÷÷øøøøùùùùùùúúúúûûûûûûüüüüýýýýþþþþþþÿÿŸ¡ £ ¦ ª«¬­®°±²´µ¶·¸¹ º!!!!!!!!!»"""""""""¼"¼#########½$$$$$$$$$$$¾$¾%%%%%%%%%%%¿&&&&&&&&&&&&&À'''''''''''''Á'Á(((((((((((((Â(Â)))))))))))))))Ã)Ã*****************Ä+++++++++++++++++++Å+Å,,,,,,,,,,,,,,,,,,,Æ,Æ-----------------------Ç-Ç.........................È.È///////////////////////////É/É0000000000000000000000000000000Ê0Ê0Ê11111111111111111111111111111111111Ë1Ë1Ë22222222222222222222222222222222222222222Ì2Ì2Ì33333333333333333333333333333333333333333333333Í3Í3Í444444444444444444444444444444444444444444444444444444444Î4Î4Î4Î555555ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËdËdËdËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×p×××××××××××רqØqØØØØØØØØØØØØÙrÙÙÙÙÙÙÙÙÙÙÚsÚsÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞßxßßßßßßàyààààààààázááááááâ{ââââââââããããããããääääääå~ååååååæææææææççççççèèèèèèèééééééêêêêêêë„ëëëëì…ììììí†ííííî‡îîîîïïïïïïððððððññññò‹òòòòóóóóóóôôôôõõõõõõöööö÷÷÷÷÷÷øøøøùùùùùùúúúúûûûûûûüüüüýýýýþþþþþþÿÿj r uv|}€„…† ‡!!!!!!!!!ˆ"""""""""‰###########Š$$$$$$$$$$$‹%%%%%%%%%%%%%Œ&&&&&&&&&&&&'''''''''''''Ž((((((((((((((()))))))))))))))))*****************‘*‘+++++++++++++++++’+’,,,,,,,,,,,,,,,,,,,“,“-----------------------”-”.......................•.•.•///////////////////////////–/–0000000000000000000000000000000—0—11111111111111111111111111111111111˜1˜1˜22222222222222222222222222222222222222222™2™2™33333333333333333333333333333333333333333333333š3š3š4444444444444444444444444444444444444444444444444444444›4›4›4›55555555555555ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ˘˘˘˘ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËË̙̙̙̙ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖפפ×××××××××××ר¥ØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜݪݪÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞ߬ßßßßßßà­ààààààààá®ááááááâ¯ââââââã°ããããããä±ääääääå²ååååååæ³ææææç´ççççççèµèèèèé¶ééééê·êêêêêêëëëëëëììììììííííííîîîîï¼ïïïïð½ððððññññññòòòòóÀóóóóôôôôõÂõõõõöööö÷Ä÷÷÷÷øøøøùÆùùùùúúúúûûûûûûüüüüýýýýþËþþþþÿÿ @DEFGHJLMNOPQR S!!!!!!!!!T"""""""""U###########V$$$$$$$$$$$W%%%%%%%%%%%X%X&&&&&&&&&&&Y'''''''''''''Z'Z((((((((((((([([)))))))))))))))\)\***************]*]+++++++++++++++++^+^,,,,,,,,,,,,,,,,,,,_,_-----------------------`-`.......................a.a///////////////////////////b/b/b00000000000000000000000000000c0c0c11111111111111111111111111111111111d1d22222222222222222222222222222222222222222e2e2e33333333333333333333333333333333333333333333333f3f3f4444444444444444444444444444444444444444444444444444444g4g4g5555555555555555555555ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààààááááááááââââââââããããããããääääääääååååååååææææææççççççççèèèèèèééééééêêêêêêëëëëëëììììììííííííîîîîîîïïïïïïððððññññññòòòòòòóóóóôôôôôôõõõõöööööö÷÷÷÷øøøøøøùùùùúúúúûûûûûûüüüüýýýýýýþþþþÿÿ  !!!!!!!!!!""""""""""############$$$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''''(((((((((((((((())))))))))))))))))******************++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,--------------------------..........................//////////////////////////////000000000000000000000000000000000011111111111111111111111111111111111111112222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444445555555555555555555555555555ÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààààááááááááââââââââããããããããääääääääååååååææææææææççççççèèèèèèééééééééêêêêêêëëëëëëììììììííííîîîîîîïïïïïïððððððññññòòòòòòóóóóôôôôôôõõõõöööööö÷÷÷÷øøøøøøùùùùúúúúúúûûûûüüüüýýýýýýþþþþÿÿ  !!!!!!!!!!""""""""""############$$$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''''(((((((((((((((())))))))))))))))******************++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,,,------------------------............................//////////////////////////////0000000000000000000000000000000000111111111111111111111111111111111111112222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555ÉÉÉüÉüÉüÉüÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊýÊýÊýÊýËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËþËþËþÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× × ×××××××××××ר ØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÚ Ú ÚÚÚÚÚÚÚÚÛ Û ÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞßßßßßßßàààààààààáááááááâââââââãããããããäääääääååååååæææææææçççççèèèèèéééééééêêêêêêëëëëëëììììììííííî îîîîï!ïïïïððððððññññò$òòòòóóóóô&ôôôôõõõõö(öööö÷÷÷÷ø*øøøøùùùùúúúúúúûûûûüüüüýýýýýýþþþþÿÿ Ù Üßàáâãäæèéêëìí î!!!!!!!!!ï"""""""""ð#########ñ#ñ$$$$$$$$$ò$ò%%%%%%%%%%%ó&&&&&&&&&&&ô&ô'''''''''''õ'õ(((((((((((((ö(ö)))))))))))))))÷*****************ø+++++++++++++++++ù+ù,,,,,,,,,,,,,,,,,,,ú,ú---------------------û-û.........................ü.ü/////////////////////////ý/ý/ý00000000000000000000000000000þ0þ0þ111111111111111111111111111111111ÿ1ÿ1ÿ2222222222222222222222222222222222222233333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555ÉÉÉÉÉÉÉÉÉÉÊ0Ê0Ê0Ê0ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊË1Ë1Ë1ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌ2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<ÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×=×××××××××××ר>Ø>ØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÜBÜBÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞßEßßßßßßàFààààààààáGááááááâHââââââãIããããããäJääääåKååååååæLææææææççççççèèèèèèéOééééêPêêêêëQëëëëìRììììíSííííîîîîîîïïïïðVððððññññññòòòòóYóóóóôôôôõõõõõõöööö÷÷÷÷÷÷øøøøùùùùúúúúúúûûûûüüüüýýýýýýþþþþÿÿž¡ £ §ª±²³µ¶·¸¹ º!!!!!!!»!»"""""""""¼#########½$$$$$$$$$$$¾%%%%%%%%%%%¿%¿&&&&&&&&&&&À'''''''''''''Á(((((((((((((((Â)))))))))))))))Ã)Ã***************Ä*Ä+++++++++++++++++Å,,,,,,,,,,,,,,,,,,,Æ,Æ---------------------Ç-Ç.......................È.È.È/////////////////////////É/É00000000000000000000000000000Ê0Ê0Ê111111111111111111111111111111111Ë1Ë1Ë222222222222222222222222222222222222222Ì2Ì2Ì333333333333333333333333333333333333333333333Í3Í3Í44444444444444444444444444444444444444444444444444444Î4Î4Î4Î555555555555555555555555555555555555555555ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊcÊcÊcÊcÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËdËdËdËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖ×p×p×××××××××××רqØØØØØØØØØØÙrÙrÙÙÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞßxßßßßßßàyààààààààázááááááâ{ââââââã|ããããããääääääå~ååååååæææææç€ççççèèèèèèèééééééêêêêêêëëëëëëììììììííííî‡îîîîïˆïïïïððððñŠññññòòòòòòóóóóôôôôõŽõõõõöööö÷÷÷÷÷øøøøùùùùú“úúúúûûûûüüüüýýýýýýþþþþÿÿh q s uvyz{|}~€‚ƒ„† ‡!!!!!!!ˆ"""""""""""‰#########Š$$$$$$$$$$$‹%%%%%%%%%%%Œ&&&&&&&&&&&&'''''''''''Ž'Ž(((((((((((((())))))))))))))***************‘*‘+++++++++++++++++’+’,,,,,,,,,,,,,,,,,“,“---------------------”-”.......................•.•///////////////////////////–/–00000000000000000000000000000—0—111111111111111111111111111111111˜1˜1˜222222222222222222222222222222222222222™2™2™3333333333333333333333333333333333333333333š3š3š3š444444444444444444444444444444444444444444444444444›4›4›4›55555555555555555555555555555555555555555555555555ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ—Ê—Ê—ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ˘˘˘˘ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËË̙̙̙ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ£ÖÖÖÖÖÖÖÖÖÖÖÖÖÖפ×××××××××××ר¥ØØØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞ߬ßßßßßßà­ààààààààááááááááâ¯ââââââããããããä±ääääääå²ååååååææææææç´ççççèµèèèèé¶ééééê·êêêêë¸ëëëëì¹ììììíºííííîîîîîîïïïïð½ððððññññò¿òòòòóóóóôÁôôôôõõõõöööööö÷÷÷÷øøøøùùùùùùúúúúûûûûüüüüýýýýýýþþþþÿÿ8; CDKLMOPQR S S!!!!!!!T"""""""""U"U#########V$$$$$$$$$W$W%%%%%%%%%%%X&&&&&&&&&&&Y'''''''''''''Z((((((((((((([([)))))))))))))))\***************]*]+++++++++++++++++^+^,,,,,,,,,,,,,,,,,_,_---------------------`-`.......................a.a/////////////////////////b/b/b000000000000000000000000000c0c0c111111111111111111111111111111111d1d222222222222222222222222222222222222222e2e2e3333333333333333333333333333333333333333333f3f3f44444444444444444444444444444444444444444444444444444g4g4g5555555555555555555555555555555555555555555555555555555555ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááááááââââââããããããããääääääääååååååææææææææççççççèèèèèèééééééêêêêêêëëëëëëììììììííííîîîîîîïïïïïïððððññññññòòòòóóóóóóôôôôõõõõöööööö÷÷÷÷øøøøùùùùùùúúúúûûûûüüüüýýýýýýþþþþÿÿ  !!!!!!!!!!""""""""""############$$$$$$$$$$%%%%%%%%%%%%%%&&&&&&&&&&&&''''''''''''''(((((((((((((())))))))))))))))))****************++++++++++++++++++++,,,,,,,,,,,,,,,,,,,,------------------------..........................////////////////////////////000000000000000000000000000000001111111111111111111111111111111111111122222222222222222222222222222222222222222233333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááááââââââââããããããããääääääääååååååææææææççççççèèèèèèèèééééééêêêêëëëëëëììììììííííííîîîîïïïïïïððððððññññòòòòóóóóóóôôôôõõõõõõöööö÷÷÷÷øøøøøøùùùùúúúúûûûûüüüüýýýýýýþþþþÿÿ  !!!!!!!!!!""""""""""############$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''(((((((((((((((())))))))))))))))******************++++++++++++++++++,,,,,,,,,,,,,,,,,,,,------------------------..........................////////////////////////////0000000000000000000000000000000011111111111111111111111111111111111122222222222222222222222222222222222222222233333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555556666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉüÉüÉüÉüÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊýÊýÊýÊýËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËþËþËþËþÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××××ר ØØØØØØØØØØØØÙ ÙÙÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞßßßßßßßàààààààáááááááâââââââãããããããäääääääååååååæææææçççççèèèèèèèééééééêêêêëëëëëìììììíííííîîîîï!ïïïïððððððññññòòòòó%óóóóôôôôõ'õõõõöööö÷÷÷÷øøøøøøùùùùúúúúûûûûüüüüý/ýýýýþþþþÿÿÔ × Ú ÜÞßâãäåçèéêëìí î!!!!!!!!!ï"""""""""ð#########ñ#ñ$$$$$$$$$ò%%%%%%%%%%%ó&&&&&&&&&&&ô&ô'''''''''''õ(((((((((((((ö(ö)))))))))))))÷)÷***************ø*ø+++++++++++++++ù+ù,,,,,,,,,,,,,,,,,ú,ú---------------------û-û.....................ü.ü.ü///////////////////////ý/ý/ý000000000000000000000000000þ0þ0þ1111111111111111111111111111111ÿ1ÿ1ÿ2222222222222222222222222222222222223333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444455555555555555555555555555555555555555555555555555555555555555566666666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ0Ê0Ê0Ê0ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊË1Ë1Ë1ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌ2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖ<ÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××ר>Ø>ØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÝCÝCÝÝÝÝÝÝÞDÞÞÞÞÞÞÞÞßEßßßßßßàFààààààáGááááááâHââââââãIããããããäJääääåKååååååææææææçMççççèNèèèèéOééééêPêêêêëQëëëëììììììííííîTîîîîïïïïðVððððññññòXòòòòóóóóôôôôôôõõõõöööö÷÷÷÷ø^øøøøùùùùúúúúûûûûüüüüüüýýýýþþþþÿÿœ ¤ §©¬­²³µ¶·¸¹ º!!!!!!!!!»"""""""""¼#########½$$$$$$$$$$$¾%%%%%%%%%%%¿&&&&&&&&&&&À'''''''''''''Á(((((((((((((Â)))))))))))))))Ã***************Ä*Ä+++++++++++++++Å+Å,,,,,,,,,,,,,,,,,Æ,Æ---------------------Ç-Ç.....................È.È/////////////////////////É/É00000000000000000000000000000Ê0Ê1111111111111111111111111111111Ë1Ë1Ë2222222222222222222222222222222222222Ì2Ì2Ì33333333333333333333333333333333333333333Í3Í3Í3Í4444444444444444444444444444444444444444444444444Î4Î4Î4Î55555555555555555555555555555555555555555555555555555555555Ï5Ï5Ï5Ï666666666666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊcÊcÊcÊcÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËdËdËdËdËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖ×p×××××××××××רqØØØØØØØØØØÙrÙrÙÙÙÙÙÙÙÙÚsÚsÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÛÛÜuÜuÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÞwÞÞÞÞÞÞÞÞßxßßßßßßàyààààààázááááááâ{ââââââã|ããããããääääääå~ååååæææææææççççççèèèèèèééééééêêêêêêëëëëì…ììììííííííîîîîïˆïïïïððððñŠññññòòòòóóóóôôôôôõõõõöööö÷÷÷÷÷øøøøùùùùúúúúûûûûü•üüüüýýýýþþþþÿÿn r x{|}~‚ƒ„…† ‡!!!!!!!!!ˆ"""""""""‰#########Š$$$$$$$$$‹$‹%%%%%%%%%Œ%Œ&&&&&&&&&&'''''''''''Ž'Ž(((((((((((())))))))))))))*************‘*‘+++++++++++++++’+’,,,,,,,,,,,,,,,,,,,“---------------------”-”.....................•.•/////////////////////////–/–000000000000000000000000000—0—0—1111111111111111111111111111111˜1˜2222222222222222222222222222222222222™2™2™33333333333333333333333333333333333333333š3š3š4444444444444444444444444444444444444444444444444›4›4›4›55555555555555555555555555555555555555555555555555555555555œ5œ5œ5œ66666666666666666666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ—Ê—Ê—ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ˘˘˘ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËË̙̙̙ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖפפ×××××××××ר¥Ø¥ØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÛ¨Û¨ÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜÜÜݪÝÝÝÝÝÝÞ«ÞÞÞÞÞÞÞÞ߬ßßßßßßà­ààààààá®ááááááâ¯ââââââã°ããããä±ääääääå²ååååæ³ææææç´ççççèµèèèèé¶ééééê·êêêêë¸ëëëëììììíºííííî»îîîîïïïïð½ððððññññòòòòóÀóóóóôôôôõõõõöÃöööö÷÷÷÷øøøøùùùùúúúúûûûûûûüüüüýýýýþþþþÿÿ6; ? ACEFIJLMOPQR S!!!!!!!!!T"""""""""U#########V$$$$$$$$$W%%%%%%%%%%%X&&&&&&&&&&&Y'''''''''''''Z((((((((((((([)))))))))))))\)\***************]+++++++++++++++++^,,,,,,,,,,,,,,,,,,,_,_-----------------`-`-`.....................a.a///////////////////////b/b/b0000000000000000000000000c0c0c1111111111111111111111111111111d1d1d22222222222222222222222222222222222e2e2e33333333333333333333333333333333333333333f3f3f4444444444444444444444444444444444444444444444444g4g4g55555555555555555555555555555555555555555555555555555555555h5h5h5h6666666666666666666666666666ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááááââââââââããããããääääääääååååååææææææççççççèèèèèèééééééêêêêêêëëëëììììììííííííîîîîïïïïïïððððññññòòòòòòóóóóôôôôõõõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûûûüüüüýýýýþþþþÿÿ  !!!!!!!!!!""""""""""##########$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&&&''''''''''''''(((((((((((((())))))))))))))******************++++++++++++++++++,,,,,,,,,,,,,,,,,,,,--------------------..........................//////////////////////////000000000000000000000000000000111111111111111111111111111111111111222222222222222222222222222222222222222233333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666ÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááááââââââããããããããääääääååååååååææææææççççççèèèèèèééééêêêêêêëëëëëëììììííííííîîîîîîïïïïððððññññññòòòòóóóóôôôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúúúûûûûüüüüýýýýþþþþÿÿ  !!!!!!!!!!""""""""##########$$$$$$$$$$$$%%%%%%%%%%&&&&&&&&&&&&&&''''''''''''(((((((((((((())))))))))))))))****************++++++++++++++++++,,,,,,,,,,,,,,,,,,,,--------------------........................////////////////////////////0000000000000000000000000000001111111111111111111111111111111111222222222222222222222222222222222222222233333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666ÈÈÈÈÈÈÈÈÈûÈûÈûÈûÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉüÉüÉüÉüÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊýÊýÊýÊýËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËþËþËþÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ× × ×××××××××ר Ø ØØØØØØØØÙ Ù ÙÙÙÙÙÙÙÙÚ Ú ÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßßàààààààáááááááâââââãããããããäääääåååååååææææææççççççèèèèèèééééêêêêêëëëëëììììíííííîîîîîîïïïïððððñ#ññññòòòòóóóóô&ôôôôõõõõöööö÷÷÷÷øøøøùùùùú,úúúúûûûûüüüüýýýýþþþþÿÿÓ Ø ÜÞàãäåæçéêëìí î!!!!!!!!!ï"""""""ð#########ñ$$$$$$$$$$$ò%%%%%%%%%ó&&&&&&&&&&&ô&ô'''''''''''õ(((((((((((ö(ö)))))))))))))÷)÷*************ø*ø+++++++++++++++ù+ù,,,,,,,,,,,,,,,,,ú,ú-----------------û-û.....................ü.ü///////////////////////ý/ý/ý0000000000000000000000000þ0þ0þ11111111111111111111111111111ÿ1ÿ1ÿ22222222222222222222222222222222223333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444455555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ/É/É/É/ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ0Ê0Ê0Ê0ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊË1Ë1Ë1ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌ2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÕÕÖ<ÖÖÖÖÖÖÖÖÖÖÖÖ×=×=×××××××××ר>ØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÝÝÞDÞÞÞÞÞÞßEßßßßßßàFààààààáGááááááâHââââãIããããããäJääääåKååååæLææææçMççççèNèèèèéOééééêPêêêêëëëëìRììììííííîTîîîîïïïïðVððððññññòòòòóYóóóóôôôôõõõõöööö÷÷÷÷ø^øøù_ùùùùúúúúûûûûüüüüýýýýþþþþÿÿ  ¥ ¦ ©«­®±²´µ·¸¹ º!!!!!!!!!»"""""""¼#########½$$$$$$$$$¾$¾%%%%%%%%%¿&&&&&&&&&&&À'''''''''''Á'Á(((((((((((Â)))))))))))))Ã)Ã*************Ä*Ä+++++++++++++++Å+Å,,,,,,,,,,,,,,,,,Æ,Æ-----------------Ç-Ç.....................È.È///////////////////////É/É000000000000000000000000000Ê0Ê11111111111111111111111111111Ë1Ë1Ë22222222222222222222222222222222222Ì2Ì2Ì333333333333333333333333333333333333333Í3Í3Í44444444444444444444444444444444444444444444444Î4Î4Î4Î5555555555555555555555555555555555555555555555555555555Ï5Ï5Ï5Ï6666666666666666666666666666666666666666666666666666ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉbÉbÉbÉbÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊcÊcÊcÊcÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËdËdËdËdËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌeÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕnÕÕÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖÖÖ×p×××××××××רqØqØØØØØØØØÙrÙrÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÛtÛtÛÛÛÛÛÛÜuÜuÜÜÜÜÜÜÝvÝÝÝÝÝÝÝÝÞwÞÞÞÞÞÞßxßßßßßßàyààààààázááááááââââââã|ããããããääääääå~ååååæææææç€ççççèèèèèééééééêêêêë„ëëëëììììí†ííííîîîîïˆïïïïððððññññò‹òòòòóóóóôôôôõõõõöööö÷÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿno twy{|}€‚ƒ„…† ‡!!!!!!!ˆ!ˆ"""""""‰#########Š$$$$$$$$$‹%%%%%%%%%Œ%Œ&&&&&&&&&&'''''''''''Ž(((((((((((()))))))))))))***************‘+++++++++++++++’+’,,,,,,,,,,,,,,,,,“,“-----------------”-”.....................•.•///////////////////////–/–0000000000000000000000000—0—0—11111111111111111111111111111˜1˜22222222222222222222222222222222222™2™2™333333333333333333333333333333333333333š3š3š444444444444444444444444444444444444444444444›4›4›4›5555555555555555555555555555555555555555555555555555555œ5œ5œ5œ666666666666666666666666666666666666666666666666666666666666ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ–É–É–É–É–ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ—Ê—Ê—ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ˘˘˘ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËË̙̙̙ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖפפ×××××××××ר¥ØØØØØØØØØØÙ¦ÙÙÙÙÙÙÙÙÚ§Ú§ÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÛÛÜ©ÜÜÜÜÜÜݪÝÝÝÝÝÝÝÝÞ«ÞÞÞÞÞÞ߬ßßßßßßà­ààààààá®ááááâ¯ââââââã°ããããä±ääääääååååååææææææççççççèèèèé¶ééééê·êêêêëëëëì¹ììììííííî»îîîîïïïïð½ððñ¾ññññòòòòóóóóôôôôõÂõõöÃöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿ < = ADFIJKLMNOPQR S!!!!!!!T"""""""""U#########V$$$$$$$$$W%%%%%%%%%X&&&&&&&&&&&Y'''''''''''Z'Z((((((((((([)))))))))))))\)\*************]*]+++++++++++++^+^,,,,,,,,,,,,,,,,,_,_-----------------`-`...................a.a.a/////////////////////b/b/b0000000000000000000000000c0c11111111111111111111111111111d1d1d222222222222222222222222222222222e2e2e3333333333333333333333333333333333333f3f3f3f444444444444444444444444444444444444444444444g4g4g5555555555555555555555555555555555555555555555555555555h5h5h5h66666666666666666666666666666666666666666666666666666666666666666666ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááââââââââããããããääääääååååååææææææççççççèèèèèèééééééêêêêëëëëëëììììííííííîîîîïïïïïïððððññññòòòòóóóóôôôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿ  !!!!!!!!""""""""""##########$$$$$$$$$$%%%%%%%%%%&&&&&&&&&&&&''''''''''''(((((((((((((())))))))))))))****************++++++++++++++++,,,,,,,,,,,,,,,,,,,,--------------------......................//////////////////////////000000000000000000000000000000111111111111111111111111111111112222222222222222222222222222222222222233333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666666666666666666666666666ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààààááááááââââââââããããããääääääååååååææææææççççççèèèèèèééééêêêêêêëëëëììììììííííîîîîîîïïïïððððññññòòòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿ  !!!!!!!!""""""""""########$$$$$$$$$$%%%%%%%%%%%%&&&&&&&&&&''''''''''''''(((((((((((())))))))))))))****************++++++++++++++++,,,,,,,,,,,,,,,,,,,,--------------------......................//////////////////////////0000000000000000000000000000111111111111111111111111111111112222222222222222222222222222222222222233333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666666667777777777ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈûÈûÈûÈûÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉüÉüÉüÉüÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊýÊýÊýËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËþËþËþÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ× × ×××××××ר Ø ØØØØØØØØÙ Ù ÙÙÙÙÙÙÙÙÚ ÚÚÚÚÚÚÚÚÛ ÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßßàààààààáááááâââââââããããããäääääåååååæææææçççççèèèèèééééêêêêêëëëëìììììííííî îîîîïïïïððððñ#ññò$òòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿ ÛÞßáãäéêëìí î!!!!!!!ï"""""""""ð#######ñ$$$$$$$$$ò%%%%%%%%%ó%ó&&&&&&&&&ô'''''''''''õ'õ(((((((((((ö)))))))))))))÷*************ø*ø+++++++++++++++ù,,,,,,,,,,,,,,,,,ú,ú-----------------û-û...................ü.ü/////////////////////ý/ý/ý00000000000000000000000þ0þ0þ111111111111111111111111111ÿ1ÿ1ÿ22222222222222222222222222222222333333333333333333333333333333333333333444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666677777777777777ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ/É/É/É/ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ0Ê0Ê0Ê0ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊË1Ë1Ë1Ë1ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌ2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕ;ÕÕÕÕÕÕÕÕÕÕÕÕÖ<ÖÖÖÖÖÖÖÖÖÖÖÖ×=×××××××××ר>ØØØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÛAÛAÛÛÛÛÛÛÜBÜÜÜÜÜÜÜÜÝCÝÝÝÝÝÝÞDÞÞÞÞÞÞßEßßßßßßàFààààààááááááâHââââãIããããããäJääääåKååååæLææææççççççèèèèéOééééêêêêëQëëëëììììíSííííîîîîïïïïðVððððññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûûûüüüüýýýýþþþþÿÿ ¨©¬®°±²³´µ¶·¸¹ º!!!!!!!»"""""""¼"¼#######½$$$$$$$$$¾%%%%%%%%%¿&&&&&&&&&&&À'''''''''''Á(((((((((((Â(Â)))))))))))Ã)Ã*************Ä+++++++++++++++Å+Å,,,,,,,,,,,,,,,Æ,Æ-----------------Ç-Ç...................È.È/////////////////////É/É0000000000000000000000000Ê0Ê111111111111111111111111111Ë1Ë1Ë222222222222222222222222222222222Ì2Ì2Ì33333333333333333333333333333333333Í3Í3Í3Í4444444444444444444444444444444444444444444Î4Î4Î4Î555555555555555555555555555555555555555555555555555Ï5Ï5Ï5Ï66666666666666666666666666666666666666666666666666666666666666666Ð6Ð6Ð6Ð6Ð777777777777777777ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉbÉbÉbÉbÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊcÊcÊcÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËdËdËdËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÖoÖoÖÖÖÖÖÖÖÖÖÖ×p×p×××××××רqØqØØØØØØØØÙrÙÙÙÙÙÙÙÙÚsÚsÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÜuÜÜÜÜÜÜÜÜÝvÝÝÝÝÝÝÞwÞÞÞÞÞÞßxßßßßßßàyààààázááááááâ{ââââã|ããããããääääääååååååææææç€ççççèèèèèééééêƒêêêêë„ëëì…ììììííííî‡îîïˆïïïïððððññññòòòòóŒóóôôôõŽõõööö÷÷÷ø‘øøù’ùùúúúúûûûûüüüüýýýýþþþþÿÿlmno p q r wxz|€‚ƒ„…† ‡!!!!!!!ˆ"""""""‰#########Š$$$$$$$$$‹%%%%%%%%%Œ&&&&&&&&&&'''''''''Ž'Ž(((((((((())))))))))))*************‘*‘+++++++++++++’+’,,,,,,,,,,,,,,,“,“-----------------”-”.................•.•.•/////////////////////–/–00000000000000000000000—0—0—111111111111111111111111111˜1˜222222222222222222222222222222222™2™2™33333333333333333333333333333333333š3š3š4444444444444444444444444444444444444444444›4›4›4›555555555555555555555555555555555555555555555555555œ5œ5œ5œ666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777ȕȕȕÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ–É–É–É–É–ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ—Ê—Ê—Ê—ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ˘˘˘ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËË̙̙̙ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖÖÖפ×××××××××ר¥ØØØØØØØØÙ¦Ù¦ÙÙÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛܩܩÜÜÜÜÜÜݪÝÝÝÝÝÝÞ«ÞÞÞÞÞÞ߬ßßßßßßà­ààààá®ááááááâ¯ââââã°ããããä±ääääå²ååååæ³ææææç´ççççèèèèé¶ééééê·êêêêëëëëììììíºííííîîîîïïïïð½ððñ¾ññò¿òòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùúÇúúûÈûûüüüüýýýýþþþþÿÿ7 ? @AEGIJLMNPQR S!!!!!!!T"""""""U#########V$$$$$$$W$W%%%%%%%X%X&&&&&&&&&Y'''''''''''Z((((((((((([)))))))))))))\*************]*]+++++++++++++^+^,,,,,,,,,,,,,,,_,_---------------`-`-`.................a.a/////////////////////b/b/b00000000000000000000000c0c111111111111111111111111111d1d1d22222222222222222222222222222e2e2e2e33333333333333333333333333333333333f3f3f4444444444444444444444444444444444444444444g4g4g55555555555555555555555555555555555555555555555555555h5h5h666666666666666666666666666666666666666666666666666666666666666i6i6i6i6i777777777777777777777777777777777777ÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààááááááááââââââããããããääääääååååååææææææççççèèèèèèééééééêêêêëëëëììììììííííîîîîïïïïïïððððññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûüüüüýýýýþþþþÿÿ  !!!!!!!!""""""""##########$$$$$$$$%%%%%%%%%%&&&&&&&&&&&&''''''''''''(((((((((((())))))))))))))**************++++++++++++++++,,,,,,,,,,,,,,,,,,------------------......................////////////////////////000000000000000000000000000011111111111111111111111111111122222222222222222222222222222222223333333333333333333333333333333333333333334444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààááááááááââââââããããããääääääååååååææææççççççèèèèèèééééêêêêêêëëëëììììííííííîîîîïïïïððððññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûüüüüýýýýþþþþÿÿ  !!!!!!!!""""""""########$$$$$$$$$$%%%%%%%%%%&&&&&&&&&&''''''''''''(((((((((((())))))))))))))**************++++++++++++++++,,,,,,,,,,,,,,,,,,------------------......................////////////////////////0000000000000000000000000011111111111111111111111111111122222222222222222222222222222222223333333333333333333333333333333333333333334444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇúÇúÇúÇúÇúÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈûÈûÈûÈûÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉüÉüÉüÉüÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊýÊýÊýËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËþËþËþÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ× ×××××××××ר ØØØØØØØØÙ Ù ÙÙÙÙÙÙÚ Ú ÚÚÚÚÚÚÛ Û ÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞÞÞßßßßßßßàààààáááááááââââââãããããäääääåååååææææçççççèèèèèééééêêêêêëëëëììììíííííîîîîïïïïððððññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøøøùùùùúúúúûûü.üüýýýýþþþþÿÿ ßàâãäæçèéêëìí î!!!!!!!ï"""""""ð#######ñ$$$$$$$$$ò%%%%%%%%%ó&&&&&&&&&ô'''''''''''õ(((((((((((ö)))))))))))÷)÷***********ø*ø+++++++++++++ù+ù,,,,,,,,,,,,,,,ú,ú---------------û-û...................ü.ü///////////////////ý/ý/ý000000000000000000000þ0þ0þ1111111111111111111111111ÿ1ÿ1ÿ22222222222222222222222222223333333333333333333333333333333333333444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈ.È.È.È.È.ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ/É/É/É/ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ0Ê0Ê0Ê0ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊË1Ë1Ë1Ë1ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌ2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔ:ÔÔÔÔÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖ×=×=×××××××ר>Ø>ØØØØØØØØÙ?ÙÙÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÚÚÛAÛÛÛÛÛÛÜBÜÜÜÜÜÜÝCÝÝÝÝÝÝÞDÞÞÞÞÞÞßEßßßßßßàFààààáGááááâHââââââããããããääääääååååæLææææçMççççèèèèéOééééêêêêëQëëìRììììííííîîîîïUïïðVððñWññòXòòóYóóôZôôõ[õõö\öö÷÷÷÷øøøøùùùùúúúúûûûûüüýýýýþþþþÿÿœ¢ £ ¤ ¥ ¦ §¨©ª­®°±²³´µ¶·¹ º!!!!!!!»"""""""¼#######½$$$$$$$$$¾%%%%%%%¿%¿&&&&&&&&&À'''''''''Á'Á(((((((((Â(Â)))))))))))Ã*************Ä+++++++++++++Å+Å,,,,,,,,,,,,,,,Æ,Æ---------------Ç-Ç.................È.È.È///////////////////É/É00000000000000000000000Ê0Ê111111111111111111111111111Ë1Ë22222222222222222222222222222Ì2Ì2Ì33333333333333333333333333333333333Í3Í3Í44444444444444444444444444444444444444444Î4Î4Î4Î5555555555555555555555555555555555555555555555555Ï5Ï5Ï5Ï66666666666666666666666666666666666666666666666666666666666Ð6Ð6Ð6Ð6Ð77777777777777777777777777777777777777777777777777777777777777ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈaÈaÈaÈaÈaÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉbÉbÉbÉbÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊcÊcÊcÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËdËdËdËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÖoÖÖÖÖÖÖÖÖÖÖ×p×××××××××רqØØØØØØØØÙrÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÚÚÛtÛÛÛÛÛÛÜuÜÜÜÜÜÜÝvÝvÝÝÝÝÞwÞÞÞÞÞÞßxßßßßßßàyààààázááááâ{ââââã|ããããä}ääääå~ååååæææææççççèèèèèé‚ééêƒêêêêëëëëì…ììí†ííî‡îîîîïïïïððððññññòòòòóóóóôôôôõõõõöö÷÷÷øøøøùùùùúúúúûûûûüüýýýýþþþþÿÿn xy|~€‚ƒ„…† ‡!!!!!ˆ!ˆ"""""‰"‰#######Š$$$$$$$‹$‹%%%%%%%Œ&&&&&&&&&&'''''''''Ž((((((((((())))))))))))***********‘*‘+++++++++++++’,,,,,,,,,,,,,,,“,“---------------”-”.................•.•/////////////////////–/–000000000000000000000—0—0—1111111111111111111111111˜1˜1˜222222222222222222222222222™2™2™33333333333333333333333333333333333š3š3š444444444444444444444444444444444444444›4›4›4›5555555555555555555555555555555555555555555555555œ5œ5œ5œ66666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇȕȕȕȕÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ–É–É–É–É–ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ—Ê—Ê—Ê—ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ˘˘˘˘ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËË̙̙̙ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÔÔÕ¢ÕÕÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖפפ×××××××ר¥Ø¥ØØØØØØÙ¦Ù¦ÙÙÙÙÙÙÚ§Ú§ÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛܩܩÜÜÜÜÜÜݪÝÝÝÝÞ«ÞÞÞÞÞÞ߬ßßßßßßà­ààààá®ááááâ¯ââââã°ããããä±ääääå²ååååæ³ææç´ççççèµèèèèééééêêêêë¸ëëëëììììííííîîîîïïïïððððññññòòòòóóóóôôôôõõõõöööö÷÷øÅøøùùùùúúúúûûûûüüýÊýýþþþþÿÿ9 AFGIKMNOPQR S!!!!!T"""""""U#########V$$$$$$$W%%%%%%%%%X&&&&&&&&&Y'''''''''Z'Z((((((((([([)))))))))\)\***********]*]+++++++++++++^+^,,,,,,,,,,,,,_,_---------------`-`.................a.a///////////////////b/b/b000000000000000000000c0c1111111111111111111111111d1d1d222222222222222222222222222e2e2e333333333333333333333333333333333f3f3f3f444444444444444444444444444444444444444g4g4g5555555555555555555555555555555555555555555555555h5h5h5h666666666666666666666666666666666666666666666666666666666i6i6i6i6i7777777777777777777777777777777777777777777777777777777777777777777777777j7j7j7jÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞÞÞßßßßßßßßààààààááááááââââââããããããääääääååååååææææççççççèèèèééééêêêêêêëëëëììììííííîîîîïïïïððððññññòòòòóóóóôôôôõõõõöööö÷÷÷÷øøùùùùúúúúûûûûüüüüýýþþþþÿÿ  !!!!!!""""""""##########$$$$$$$$%%%%%%%%%%&&&&&&&&&&''''''''''(((((((((((())))))))))))**************++++++++++++++++,,,,,,,,,,,,,,,,------------------....................//////////////////////000000000000000000000000001111111111111111111111111111222222222222222222222222222222223333333333333333333333333333333333333344444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777777788888888ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßßßààààààááááááââââââããããããääääääååååææææææççççèèèèèèééééêêêêëëëëëëììììííííîîîîïïïïððððññññòòòòóóóóôôõõõõöööö÷÷÷÷øøøøùùúúúúûûûûüüüüýýþþþþÿÿ  !!!!!!""""""""########$$$$$$$$$$%%%%%%%%&&&&&&&&&&''''''''''''(((((((((())))))))))))))************++++++++++++++++,,,,,,,,,,,,,,,,------------------....................//////////////////////0000000000000000000000001111111111111111111111111111222222222222222222222222222222223333333333333333333333333333333333333344444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777777777777777777777888888888888888888ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇúÇúÇúÇúÇúÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈûÈûÈûÈûÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉüÉüÉüÉüÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊýÊýÊýËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËþËþËþËþÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ× × ×××××××ר ØØØØØØØØÙ Ù ÙÙÙÙÙÙÚ ÚÚÚÚÚÚÛ Û ÛÛÛÛÛÛÜÜÜÜÜÜÜÝÝÝÝÝÝÝÞÞÞÞÞßßßßßßßàààààáááááâââââãããããäääääååååæææææçççèèèèèééééêêêëëëëëììììííííîîîîïïïïððððññññòòòòóóóóôôõ'õõöööö÷÷÷÷øøøøùùú,úúûûûûüüüüýýþþþþÿÿÏ × áâãåçèéëìí î!!!!!ï"""""""ð#######ñ$$$$$$$ò$ò%%%%%%%ó&&&&&&&&&ô'''''''''õ'õ(((((((((ö)))))))))))÷)÷***********ø+++++++++++++ù+ù,,,,,,,,,,,,,ú,ú---------------û-û...............ü.ü.ü/////////////////ý/ý/ý000000000000000000000þ0þ11111111111111111111111ÿ1ÿ1ÿ2222222222222222222222222233333333333333333333333333333333333444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777777777777777788888888888888888888888ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈ.È.È.È.ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ/É/É/É/ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ0Ê0Ê0ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊË1Ë1Ë1Ë1ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌ2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÓÓÔ:ÔÔÔÔÔÔÔÔÔÔÔÔÕ;ÕÕÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖ×=×××××××ר>Ø>ØØØØØØØØÙ?ÙÙÙÙÙÙÚ@Ú@ÚÚÚÚÚÚÛAÛÛÛÛÛÛÜBÜÜÜÜÜÜÝCÝÝÝÝÝÝÞDÞÞÞÞßEßßßßßßàFààààáGááááâHââââãIããããääääåKååååæLææææççççèNèèéOééééêêêêëëëëìRììíSííîTîîïUïïðVððñWññòòòòóóóóôôôôõõö\öö÷÷÷÷øøøøùùùùúúûûûûüüüüýýþþþþÿÿž¢ §¨©ª«¬­°²´µ¶·¸¹ º º!!!!!»"""""""¼#######½$$$$$$$¾%%%%%%%%%¿&&&&&&&&&À'''''''''Á(((((((((Â(Â)))))))))Ã)Ã***********Ä*Ä+++++++++++Å+Å,,,,,,,,,,,,,Æ,Æ---------------Ç-Ç...............È.È///////////////////É/É000000000000000000000Ê0Ê0Ê11111111111111111111111Ë1Ë222222222222222222222222222Ì2Ì2Ì333333333333333333333333333333333Í3Í3Í4444444444444444444444444444444444444Î4Î4Î4Î555555555555555555555555555555555555555555555Ï5Ï5Ï5Ï6666666666666666666666666666666666666666666666666666666Ð6Ð6Ð6Ð77777777777777777777777777777777777777777777777777777777777777777777777Ñ7Ñ7Ñ7Ñ7Ñ8888888888888888888888888888Ç`Ç`ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈaÈaÈaÈaÈaÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉbÉbÉbÉbÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊcÊcÊcÊcÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËdËdËdËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÔmÔmÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÕÕÖoÖÖÖÖÖÖÖÖ×p×p×××××××רqØØØØØØØØÙrÙÙÙÙÙÙÙÙÚsÚÚÚÚÚÚÛtÛÛÛÛÛÛÜuÜÜÜÜÜÜÝvÝÝÝÝÝÝÞwÞÞÞÞßxßßßßßßàyààààázááááâ{ââââã|ããä}ääääå~ååååææææç€ççççèèèèé‚ééêƒêêë„ëëëëììììííííîîîîïïïïððððññò‹òòóŒóóôôôôõõõõöö÷÷÷øøøøùùùùúúûûûûüüüüýýþþþþÿÿn r s {|~€‚ƒ„…† ‡!!!!!!!ˆ"""""""‰#######Š$$$$$$$‹%%%%%%%Œ%Œ&&&&&&&&'''''''Ž'Ž((((((((()))))))))))***********‘*‘+++++++++++’+’,,,,,,,,,,,,,“,“-------------”-”-”...............•.•/////////////////–/–/–0000000000000000000—0—0—11111111111111111111111˜1˜1˜2222222222222222222222222™2™2™3333333333333333333333333333333š3š3š3š44444444444444444444444444444444444›4›4›4›555555555555555555555555555555555555555555555œ5œ5œ5œ666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777ž7ž7ž7ž7ž88888888888888888888888888888888888888ÆÆÆÆÇ”Ç”Ç”Ç”Ç”ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇȕȕȕȕȕÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ–É–É–É–É–ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ—Ê—Ê—Ê—ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ˘˘˘˘ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËË̙̙̙ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖפפ×××××ר¥Ø¥ØØØØØØÙ¦Ù¦ÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÛ¨ÛÛÛÛÛÛÜ©ÜÜÜÜÜÜݪÝÝÝÝÝÝÞ«ÞÞÞÞ߬ßßßßßßààààààá®ááááâ¯ââââããããä±ääääå²ååæ³ææææç´ççèµèèèèééééêêêêë¸ëëì¹ììíºííî»îîï¼ïïððððññññòòòòóóôÁôôõõõõöööö÷÷øÅøøùùùùúúûÈûûüüüüýýþþþþÿÿ = BCDEFIJLNOPQR S!!!!!!!T"""""""U#####V#V$$$$$$$W%%%%%%%X&&&&&&&&&Y'''''''''Z((((((((([([)))))))))\)\*********]*]+++++++++++^+^,,,,,,,,,,,,,_,_-------------`-`.................a.a/////////////////b/b000000000000000000000c0c11111111111111111111111d1d1d2222222222222222222222222e2e2e3333333333333333333333333333333f3f3f4444444444444444444444444444444444444g4g4g555555555555555555555555555555555555555555555h5h5h5h66666666666666666666666666666666666666666666666666666i6i6i6i777777777777777777777777777777777777777777777777777777777777777777777j7j7j7j7j888888888888888888888888888888888888888888888888ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààààááááááââââããããããääääääååååææææææççççèèèèééééêêêêêêëëëëììììííííîîîîïïððððññññòòòòóóóóôôõõõõöööö÷÷÷÷øøùùùùúúúúûûüüüüýýþþþþÿÿ  !!!!!!!!""""""""######$$$$$$$$$$%%%%%%%%&&&&&&&&&&''''''''''(((((((((())))))))))))************++++++++++++++,,,,,,,,,,,,,,,,----------------....................////////////////////000000000000000000000000111111111111111111111111112222222222222222222222222222223333333333333333333333333333333333334444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââââããããããääääååååååææææççççççèèèèééééêêêêëëëëììììííííîîîîïïïïððððññòòòòóóóóôôôôõõöööö÷÷÷÷øøùùùùúúúúûûüüüüýýþþþþÿÿ  !!!!!!!!""""""########$$$$$$$$%%%%%%%%%%&&&&&&&&''''''''''(((((((((((())))))))))**************++++++++++++++,,,,,,,,,,,,,,----------------..................//////////////////////0000000000000000000000111111111111111111111111112222222222222222222222222222223333333333333333333333333333333333334444444444444444444444444444444444444444555555555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888888888ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆùÆùÆùÆùÆùÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇúÇúÇúÇúÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈûÈûÈûÈûÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉüÉüÉüÉüÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊýÊýÊýÊýËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËþËþËþÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ× × ×××××ר Ø ØØØØØØÙ ÙÙÙÙÙÙÚ Ú ÚÚÚÚÚÚÛ ÛÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞßßßßßàààààáááááâââââãããããäääåååååæææçççççèèèèééééêêêëëëìììíííî îîïïïïððððññò$òòó%óóôôôôõõö(öö÷÷÷÷øøù+ùùúúúúûûüüüüýýþ0þþÿÿÑ Ú ßàáâãåæèêëìí î!!!!!!!ï"""""ð#######ñ$$$$$$$ò%%%%%%%ó%ó&&&&&&&ô'''''''''õ(((((((((ö(ö)))))))))÷***********ø*ø+++++++++++ù+ù,,,,,,,,,,,ú,ú-------------û-û...............ü.ü/////////////////ý/ý/ý0000000000000000000þ0þ11111111111111111111111ÿ1ÿ22222222222222222222222233333333333333333333333333333333344444444444444444444444444444444444445555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ-Ç-Ç-Ç-Ç-ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈ.È.È.È.È.ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ/É/É/É/ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ0Ê0Ê0ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊË1Ë1Ë1ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌ2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖÖÖ×=×××××××ר>ØØØØØØÙ?Ù?ÙÙÙÙÙÙÚ@ÚÚÚÚÚÚÛAÛÛÛÛÛÛÜBÜÜÜÜÜÜÝCÝÝÝÝÞDÞÞÞÞßEßßßßàFààààáGááááâHââââãIããããääääåKååååææææçMççèNèèéOééééêêêêëëëëììììííííîîïUïïðVððññññòòòòóóôZôôõõõõöö÷]÷÷øøøøùùúúúúûûüüüüýýýýþþÿÿŸ¢ ¥ ¨©ª°±³´µ¶·¸¹ º!!!!!!!»"""""¼#######½$$$$$$$¾%%%%%%%¿&&&&&&&À&À'''''''Á'Á(((((((Â(Â)))))))))Ã)Ã*********Ä*Ä+++++++++++Å+Å,,,,,,,,,,,Æ,Æ-------------Ç-Ç...............È.È/////////////////É/É0000000000000000000Ê0Ê0Ê111111111111111111111Ë1Ë1Ë22222222222222222222222Ì2Ì2Ì33333333333333333333333333333Í3Í3Í3Í444444444444444444444444444444444Î4Î4Î4Î55555555555555555555555555555555555555555Ï5Ï5Ï5Ï666666666666666666666666666666666666666666666666666Ð6Ð6Ð6Ð77777777777777777777777777777777777777777777777777777777777777777Ñ7Ñ7Ñ7Ñ7Ñ888888888888888888888888888888888888888888888888888888888888888888888888888888ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ`Ç`Ç`Ç`Ç`Ç`ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈaÈaÈaÈaÈaÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉbÉbÉbÉbÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊcÊcÊcÊcÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËdËdËdËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌeÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÔmÔÔÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÖoÖÖÖÖÖÖÖÖ×p×p×××××רqØqØØØØØØÙrÙÙÙÙÙÙÚsÚÚÚÚÚÚÛtÛÛÛÛÛÛÜuÜÜÜÜÜÜÝvÝÝÝÝÞwÞÞÞÞßxßßßßàyààààázááááâ{ââââã|ããä}ääääå~ååæææææççççèèèèé‚ééêƒêêë„ëëì…ììí†ííîîîîïïïïððñŠññòòòòóóóóôôõõõõöööö÷÷øøøøùùúúúúûûü•üüýýýýþþÿÿn q txyz{|}€‚„…† ‡!!!!!ˆ!ˆ"""""‰#######Š$$$$$$$‹%%%%%%%Œ&&&&&&&'''''''''Ž((((((((())))))))))*********‘*‘+++++++++++’+’,,,,,,,,,,,“,“-------------”-”...............•.•///////////////–/–/–00000000000000000—0—0—111111111111111111111˜1˜1˜22222222222222222222222™2™2™33333333333333333333333333333š3š3š44444444444444444444444444444444444›4›4›55555555555555555555555555555555555555555œ5œ5œ5œ66666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777ž7ž7ž7ž7ž888888888888888888888888888888888888888888888888888888888888888888888888888888888Ÿ8Ÿ8Ÿ8ŸÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ”ǔǔǔǔÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇȕȕȕȕÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ–É–É–É–É–ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ—Ê—Ê—Ê—ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ˘˘˘˘ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËË̙̙̙ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÒÒÓ ÓÓÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÔÔÕ¢ÕÕÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖÖÖפ×××××××ר¥ØØØØØØÙ¦Ù¦ÙÙÙÙÚ§Ú§ÚÚÚÚÛ¨Û¨ÛÛÛÛÜ©ÜÜÜÜÜÜݪÝÝÝÝÞ«ÞÞÞÞ߬ßßßßà­ààààá®ááááâ¯ââââã°ããä±ääääååååæ³ææç´ççèµèèèèééééêêêêëëëëììììííî»îîï¼ïïððððññò¿òòóóóóôôõÂõõöööö÷÷øøøøùùúÇúúûûûûüüýýýýþþÿÿ < ? BCJKLMNOPQR S!!!!!T"""""""U#####V#V$$$$$W$W%%%%%X%X&&&&&&&Y'''''''Z'Z((((((([([)))))))))\***********]+++++++++++^+^,,,,,,,,,,,_,_-------------`-`.............a.a.a///////////////b/b0000000000000000000c0c111111111111111111111d1d1d22222222222222222222222e2e2e33333333333333333333333333333f3f3f444444444444444444444444444444444g4g4g4g555555555555555555555555555555555555555h5h5h5h6666666666666666666666666666666666666666666666666i6i6i6i777777777777777777777777777777777777777777777777777777777777777j7j7j7j7j8888888888888888888888888888888888888888888888888888888888888888888888888888888k8k8k8k8k8k99999999ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââââããããääääååååååææææççççèèèèééééêêêêëëëëììììííííîîîîïïððððññññòòóóóóôôôôõõöööö÷÷øøøøùùùùúúûûûûüüýýýýþþÿÿ  !!!!!!""""""""######$$$$$$$$%%%%%%%%&&&&&&&&&&''''''''(((((((((())))))))))))************++++++++++++,,,,,,,,,,,,,,----------------................////////////////////000000000000000000000011111111111111111111111122222222222222222222222222223333333333333333333333333333333333444444444444444444444444444444444444445555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßßßààààààááááááââââããããããääääååååææææææççççèèèèééééêêêêëëëëììììííîîîîïïïïððððññòòòòóóôôôôõõõõöö÷÷÷÷øøùùùùúúûûûûüüýýýýþþÿÿ  !!!!!!""""""""######$$$$$$$$%%%%%%%%&&&&&&&&''''''''''(((((((((())))))))))************++++++++++++,,,,,,,,,,,,,,----------------................////////////////////0000000000000000000011111111111111111111111122222222222222222222222222223333333333333333333333333333333344444444444444444444444444444444444444555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888888888888999999999999999999999999999999ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆùÆùÆùÆùÆùÆùÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇúÇúÇúÇúÇúÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈûÈûÈûÈûÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉüÉüÉüÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊýÊýÊýÊýËËËËËËËËËËËËËËËËËËËËËËËËËËËËËþËþËþÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖ× ×××××ר Ø ØØØØØØÙ ÙÙÙÙÙÙÚ ÚÚÚÚÚÚÛ ÛÛÛÛÛÛÜÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßßßàààààáááááâââãããããäääåååæææææççççèèèèééééêêêêëëëëììììííî îîï!ïïððððññò$òòóóô&ôôõõõõöö÷÷÷÷øøùùùùúúûûûûüüýýýýþþÿÿÐÒÔÖ Ø ÛÞßçèêëìí î!!!!!ï"""""ð"ð#####ñ$$$$$$$ò%%%%%%%ó&&&&&&&ô'''''''õ'õ(((((((ö(ö)))))))÷)÷*********ø*ø+++++++++ù+ù,,,,,,,,,,,ú,ú-------------û-û.............ü.ü///////////////ý/ý/ý00000000000000000þ0þ111111111111111111111ÿ1ÿ2222222222222222222222333333333333333333333333333334444444444444444444444444444444444455555555555555555555555555555555555555555666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888888888888888888999999999999999999999999999999999999Æ,ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ-Ç-Ç-Ç-Ç-ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈ.È.È.È.ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ/É/É/É/ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ0Ê0Ê0Ê0ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊË1Ë1Ë1ËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌ2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÔÔÕ;ÕÕÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖ×=×=×××××ר>ØØØØØØÙ?Ù?ÙÙÙÙÚ@Ú@ÚÚÚÚÛAÛÛÛÛÛÛÜBÜÜÜÜÝCÝÝÝÝÞDÞÞÞÞßEßßßßàFààààáGááááâHââãIããããääääåKååæLææçMççèNèèéOééêPêêëQëëìRììííííîîîîïïðVððññññòòóóóóôôõ[õõöö÷]÷÷øøùùùùúúûûûûüüýýýýþþÿÿ ¦ ©¬­®¯°±²³´µ¶·¸¹ º!!!!!»"""""¼#######½$$$$$¾$¾%%%%%¿%¿&&&&&À&À'''''''Á(((((((((Â)))))))))Ã*********Ä*Ä+++++++++Å+Å,,,,,,,,,,,Æ,Æ-------------Ç-Ç.............È.È///////////////É/É00000000000000000Ê0Ê0Ê1111111111111111111Ë1Ë1Ë222222222222222222222Ì2Ì2Ì333333333333333333333333333Í3Í3Í4444444444444444444444444444444Î4Î4Î4Î5555555555555555555555555555555555555Ï5Ï5Ï5Ï66666666666666666666666666666666666666666666666Ð6Ð6Ð6Ð77777777777777777777777777777777777777777777777777777777777Ñ7Ñ7Ñ7Ñ7Ñ888888888888888888888888888888888888888888888888888888888888888888888888888Ò8Ò8Ò8Ò8Ò8Ò999999999999999999999999999999999999999999ÅÅÆ_Æ_Æ_Æ_Æ_Æ_ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ`Ç`Ç`Ç`Ç`ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈaÈaÈaÈaÈaÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉbÉbÉbÉbÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊcÊcÊcÊcÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËdËdËdËdËËËËËËËËËËËËËËËËËËËËËËËËËËÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÐÐÐÐÐÐÑjÑjÑjÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÓÓÔmÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÕÕÖoÖÖÖÖÖÖÖÖ×p×××××רqØqØØØØØØÙrÙÙÙÙÙÙÚsÚÚÚÚÛtÛtÛÛÛÛÜuÜÜÜÜÝvÝÝÝÝÞwÞÞÞÞßxßßßßàyààààázááááââââã|ããä}ääääååååæææç€ççèèèé‚ééêƒêêëëëëììí†ííî‡îîïïïïððñŠññòòóŒóóôôôôõõöööö÷÷øøù’ùùúúû”ûûüüýýýýþþÿÿ p r uwx{|}~€‚ƒ„…† ‡!!!!!ˆ"""""‰#######Š$$$$$‹%%%%%%%Œ&&&&&&&'''''''Ž'Ž(((((((())))))))*********‘+++++++++++’,,,,,,,,,,,“,“-----------”-”-”...........•.•.•/////////////–/–/–00000000000000000—0—1111111111111111111˜1˜1˜222222222222222222222™2™2™333333333333333333333333333š3š3š4444444444444444444444444444444›4›4›5555555555555555555555555555555555555œ5œ5œ5œ6666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777ž7ž7ž7ž7ž8888888888888888888888888888888888888888888888888888888888888888888888888Ÿ8Ÿ8Ÿ8Ÿ8Ÿ8Ÿ999999999999999999999999999999999999999999999999999999ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ“Æ“Æ“Æ“Æ“Æ“Æ“ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ”Ç”Ç”Ç”Ç”Ç”ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇȕȕȕȕȕÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ–É–É–É–É–ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ—Ê—Ê—Ê—ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ˘˘˘ËËËËËËËËËËËËËËËËËËËËËËËËËË̙̙̙ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖפפ×××××ר¥ØØØØØØÙ¦ÙÙÙÙÙÙÚ§ÚÚÚÚÚÚÛ¨ÛÛÛÛÜ©ÜÜÜÜݪݪÝÝÞ«Þ«ÞÞ߬ßßßßà­ààààá®ááâ¯ââââã°ããä±ääå²ååååææææççççèèèèééééêêë¸ëëì¹ììííííîîï¼ïïððððññò¿òòóóôÁôôõõöÃöö÷÷øøøøùùúúúúûûüüýýýýþþÿÿ8: @BEFMNOPQR S!!!!!T"""""U#####V#V$$$$$W%%%%%%%X&&&&&&&Y'''''''Z((((((([([)))))))\)\*********]*]+++++++++^+^,,,,,,,,,_,_-----------`-`.............a.a///////////////b/b00000000000000000c0c0c11111111111111111d1d1d222222222222222222222e2e2e3333333333333333333333333f3f3f3f44444444444444444444444444444g4g4g4g55555555555555555555555555555555555h5h5h5h666666666666666666666666666666666666666666666i6i6i6i777777777777777777777777777777777777777777777777777777777j7j7j7j7j8888888888888888888888888888888888888888888888888888888888888888888888888k8k8k8k8k999999999999999999999999999999999999999999999999999999999999999999ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞßßßßßßààààààááááââââââããããääääååååææææççççèèèèééééêêêêëëëëììííííîîîîïïððððññññòòóóóóôôõõõõöö÷÷øøøøùùúúúúûûüüýýýýþþÿÿ  !!!!!!""""""######$$$$$$$$%%%%%%%%&&&&&&&&''''''''(((((((())))))))))************++++++++++++,,,,,,,,,,,,--------------................//////////////////000000000000000000001111111111111111111111222222222222222222222222223333333333333333333333333333334444444444444444444444444444444444445555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××××ØØØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞßßßßßßààààààááááââââââããããääääååååææææççççèèèèééééêêêêëëììììííííîîïïïïððññññòòóóóóôôõõõõöö÷÷÷÷øøùùúúúúûûüüýýýýþþÿÿ  !!!!!!""""""######$$$$$$$$%%%%%%&&&&&&&&''''''''(((((((((())))))))))**********++++++++++++,,,,,,,,,,,,--------------................//////////////////0000000000000000001111111111111111111111112222222222222222222222223333333333333333333333333333334444444444444444444444444444444444555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999999999999999ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅøÅøÅøÅøÅøÅøÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆùÆùÆùÆùÆùÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇúÇúÇúÇúÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈûÈûÈûÈûÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉüÉüÉüÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊýÊýÊýËËËËËËËËËËËËËËËËËËËËËËËËËËËþËþËþÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ× × ×××××ר ØØØØØØÙ ÙÙÙÙÙÙÚ ÚÚÚÚÛ ÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÞÞÞßßßßßàààààáááâââââããããäääåååæææçççèèèéééêêêêëëìììííííîîï!ïïððñ#ññòòó%óóôôõ'õõöö÷÷÷÷øøùùúúúúûûüüýýýýþþÿÿÎÑÖ Þàáäåæçèéêëìí î!!!!!ï"""""ð#####ñ$$$$$ò$ò%%%%%ó&&&&&&&ô'''''''õ(((((((ö(ö)))))))÷)÷*******ø*ø+++++++++ù+ù,,,,,,,,,ú,ú-----------û-û.............ü.ü/////////////ý/ý/ý000000000000000þ0þ1111111111111111111ÿ1ÿ1ÿ222222222222222222333333333333333333333333333444444444444444444444444444444455555555555555555555555555555555555556666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ,Æ,Æ,Æ,Æ,Æ,ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ-Ç-Ç-Ç-Ç-Ç-ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈ.È.È.È.È.ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ/É/É/É/ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ0Ê0Ê0Ê0ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊË1Ë1Ë1ËËËËËËËËËËËËËËËËËËËËËËËËËËÌ2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÕÕÖ<Ö<ÖÖÖÖÖÖ×=×××××ר>Ø>ØØØØÙ?Ù?ÙÙÙÙÚ@ÚÚÚÚÛAÛAÛÛÛÛÜBÜÜÜÜÝCÝÝÝÝÞDÞÞßEßßßßàFààààáGááâHââãIããããääääååååææææççççèèèèééêPêêëQëëììíSííîTîîïïðVððññòXòòóóôôôôõõöö÷]÷÷øøùùú`úúûûüüýcýýþþÿÿ  £ ¥ §©«®¯³¶·¸¹ º!!!!!»"""""¼#####½$$$$$¾%%%%%%%¿&&&&&À&À'''''Á'Á(((((((Â)))))))Ã)Ã*********Ä+++++++++Å+Å,,,,,,,,,Æ,Æ-----------Ç-Ç.............È.È/////////////É/É000000000000000Ê0Ê0Ê11111111111111111Ë1Ë1Ë2222222222222222222Ì2Ì2Ì33333333333333333333333Í3Í3Í3Í444444444444444444444444444Î4Î4Î4Î555555555555555555555555555555555Ï5Ï5Ï5Ï66666666666666666666666666666666666666666Ð6Ð6Ð6Ð6Ð77777777777777777777777777777777777777777777777777777Ñ7Ñ7Ñ7Ñ7Ñ888888888888888888888888888888888888888888888888888888888888888888888Ò8Ò8Ò8Ò8Ò999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999Ó9Ó9Ó9ÓÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ_Æ_Æ_Æ_Æ_Æ_ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ`Ç`Ç`Ç`Ç`ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈaÈaÈaÈaÈaÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉbÉbÉbÉbÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊcÊcÊcÊcÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËdËdËdËdËËËËËËËËËËËËËËËËËËËËËËËËÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐiÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÔmÔÔÔÔÔÔÔÔÕnÕnÕÕÕÕÕÕÖoÖÖÖÖÖÖ×p×p×××××רqØØØØØØÙrÙÙÙÙÚsÚÚÚÚÚÚÛtÛÛÛÛÜuÜÜÜÜÝvÝÝÝÝÞwÞÞßxßxßßàyààààááááâ{ââã|ããä}ääå~ååæææç€ççèèèé‚ééêêêêëëì…ììííííîîïïïïððññññòòóóôôôõõöööö÷÷øøùùùùúúûûüüüüýýþþÿÿ s uwyz|}~‚ƒ„…† ‡!!!!!ˆ"""‰"‰###Š#Š$$$$$‹%%%%%Œ%Œ&&&&&'''''''Ž(((((((()))))))*********‘*‘+++++++’+’,,,,,,,,,“,“-----------”-”...........•.•.•///////////–/–/–000000000000000—0—11111111111111111˜1˜1˜2222222222222222222™2™2™33333333333333333333333š3š3š44444444444444444444444444444›4›4›555555555555555555555555555555555œ5œ5œ5œ6666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777ž7ž7ž7ž7ž8888888888888888888888888888888888888888888888888888888888888888888Ÿ8Ÿ8Ÿ8Ÿ8Ÿ8Ÿ99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 9 9 9 9 9 9 ::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ“Æ“Æ“Æ“Æ“Æ“Æ“ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ”Ç”Ç”Ç”Ç”ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇȕȕȕȕÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ–É–É–É–É–ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ—Ê—Ê—Ê—ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ˘˘˘ËËËËËËËËËËËËËËËËËËËËËËËË̙̙̙ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛΛÎÎÎÎÎÎÎÎÎÎÎÎÎÎϜϜÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐўўўÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÔÔÕ¢ÕÕÕÕÕÕÖ£Ö£ÖÖÖÖÖÖפ×××××ר¥Ø¥ØØØØÙ¦ÙÙÙÙÚ§Ú§ÚÚÚÚÛ¨ÛÛÛÛÜ©ÜÜÜÜݪÝÝÝÝÞ«ÞÞÞÞ߬ßßà­ààá®ááááâ¯ââã°ããä±ääå²ååæ³ææç´ççèµèèééê·êêë¸ëëììíºííîîï¼ïïððñ¾ññòòóÀóóôôõõöÃöö÷÷øøùÆùùúúûûüüüüýýþþÿÿ7: = @BDFGJKLMNOPQR S!!!T!T"""U#####V$$$$$W$W%%%%%X&&&&&&&Y'''''Z'Z((((((([)))))))\)\*******]*]+++++++^+^,,,,,,,,,_,_-----------`-`...........a.a/////////////b/b000000000000000c0c0c111111111111111d1d1d2222222222222222222e2e2e33333333333333333333333f3f3f444444444444444444444444444g4g4g4g5555555555555555555555555555555h5h5h5h66666666666666666666666666666666666666666i6i6i6i777777777777777777777777777777777777777777777777777j7j7j7j7j88888888888888888888888888888888888888888888888888888888888888888k8k8k8k8k8k99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999l9l9l9l9l9l::::::::::::::::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××××ØØØØØØÙÙÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßààààááááááââââããããääääååååææææççççèèééééêêêêëëììììííîîîîïïððððññòòòòóóôôõõõõöö÷÷øøøøùùúúûûüüüüýýþþÿÿ  !!!!""""""######$$$$$$%%%%%%%%&&&&&&&&''''''(((((((((())))))))**********++++++++++,,,,,,,,,,,,--------------..............////////////////00000000000000000011111111111111111111222222222222222222222222333333333333333333333333333344444444444444444444444444444444555555555555555555555555555555555555556666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××ØØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÝÝÞÞÞÞÞÞßßßßààààááááááââââããããääääååååææççççèèèèééééêêëëëëììííííîîïïïïððññññòòóóôôôôõõöö÷÷øøøøùùúúûûüüüüýýþþÿÿ  !!!!""""""######$$$$$$%%%%%%%%&&&&&&''''''''(((((((())))))))**********++++++++++++,,,,,,,,,,--------------..............////////////////0000000000000000001111111111111111111122222222222222222222223333333333333333333333333333444444444444444444444444444444555555555555555555555555555555555555556666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::Ä÷ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅøÅøÅøÅøÅøÅøÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆùÆùÆùÆùÆùÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇúÇúÇúÇúÇúÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈûÈûÈûÈûÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉüÉüÉüÉüÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊýÊýÊýËËËËËËËËËËËËËËËËËËËËËËËþËþËþÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖ× × ×××ר ØØØØØØÙ ÙÙÙÙÚ ÚÚÚÚÛ Û ÛÛÜÜÜÜÝÝÝÝÝÞÞÞÞÞßßßàààáááááââââãããäääååååææçççèèèéééêêëëëììíííîîï!ïïððñ#ññòòóóô&ôôõõöö÷÷ø*øøùùúúûûü.üüýýþþÿÿÓ × Ú Üßáâäåèéêëìí î!!!ï"""""ð#####ñ$$$$$ò%%%%%ó%ó&&&&&ô'''''õ'õ(((((ö(ö)))))))÷*********ø+++++++++ù+ù,,,,,,,ú,ú-----------û-û...........ü.ü///////////ý/ý/ý0000000000000þ0þ0þ111111111111111ÿ1ÿ1ÿ22222222222222223333333333333333333333344444444444444444444444444445555555555555555555555555555555556666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999999999999:::::::::::::::::::::::::::::::::::::::::::::::::::::::ÄÄÅ+Å+Å+Å+Å+Å+Å+ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ,Æ,Æ,Æ,Æ,Æ,ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ-Ç-Ç-Ç-Ç-Ç-ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈ.È.È.È.È.ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ/É/É/É/ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ0Ê0Ê0Ê0ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊË1Ë1Ë1Ë1ËËËËËËËËËËËËËËËËËËËËÌ2Ì2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5Ï5ÏÏÏÏÏÏÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÔÔÕ;Õ;ÕÕÕÕÖ<Ö<ÖÖÖÖÖÖ×=×××ר>Ø>ØØØØÙ?ÙÙÙÙÚ@Ú@ÚÚÚÚÛAÛÛÛÛÜBÜÜÝCÝCÝÝÞDÞÞÞÞßEßßàFààáGááâHââââããããääåKååæLææçMççèNèèééêPêêëëìRììííîTîîïïðVððññòòóYóóôôõõöö÷]÷÷øøùùúúûûûûüüýýþþÿÿ §©¬®¯±²³·¸¹ º!!!»"""""¼#####½$$$$$¾%%%%%¿&&&&&À&À'''''Á(((((((Â)))))))Ã)Ã*******Ä*Ä+++++++Å+Å,,,,,,,Æ,Æ-----------Ç-Ç.........È.È.È///////////É/É0000000000000Ê0Ê0Ê111111111111111Ë1Ë1Ë22222222222222222Ì2Ì2Ì333333333333333333333Í3Í3Í4444444444444444444444444Î4Î4Î4Î55555555555555555555555555555Ï5Ï5Ï5Ï6666666666666666666666666666666666666Ð6Ð6Ð6Ð6Ð77777777777777777777777777777777777777777777777Ñ7Ñ7Ñ7Ñ7Ñ8888888888888888888888888888888888888888888888888888888888888Ò8Ò8Ò8Ò8Ò8Ò99999999999999999999999999999999999999999999999999999999999999999999999999999999999Ó9Ó9Ó9Ó9Ó9Ó::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ^Å^Å^Å^Å^Å^Å^ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ_Æ_Æ_Æ_Æ_Æ_ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ`Ç`Ç`Ç`Ç`ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈaÈaÈaÈaÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉbÉbÉbÉbÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊcÊcÊcÊcÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËdËdËdËËËËËËËËËËËËËËËËËËËËËËÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÎÎÎÎÎÎÏhÏhÏÏÏÏÏÏÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÓÓÔmÔÔÔÔÔÔÔÔÕnÕÕÕÕÕÕÖoÖoÖÖÖÖ×p×p×××רqØØØØÙrÙrÙÙÙÙÚsÚÚÚÚÛtÛÛÛÛÜuÜÜÜÜÝvÝÝÞwÞÞÞÞßxßßàyààázááâ{ââã|ããä}ääå~ååæææç€ççèèé‚ééêêë„ëëììí†ííîîïˆïïððññò‹òòóóôôõõööö÷÷øøùùúúû”ûûüüýýþþÿÿm q r uwxz|}€‚ƒ„…† ‡!!!ˆ"""""‰###Š#Š$$$‹$‹%%%%%Œ&&&&&'''''Ž'Ž(((((()))))))*******‘*‘+++++++’+’,,,,,,,“,“---------”-”-”.........•.•///////////–/–/–0000000000000—0—111111111111111˜1˜1˜22222222222222222™2™2™333333333333333333333š3š3š4444444444444444444444444›4›4›55555555555555555555555555555œ5œ5œ5œ666666666666666666666666666666666666666677777777777777777777777777777777777777777777777ž7ž7ž7ž7ž88888888888888888888888888888888888888888888888888888888888Ÿ8Ÿ8Ÿ8Ÿ8Ÿ8Ÿ999999999999999999999999999999999999999999999999999999999999999999999999999999999 9 9 9 9 9 9 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ’Å’Å’Å’Å’Å’Å’Å’ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ“Æ“Æ“Æ“Æ“Æ“Æ“ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ”Ç”Ç”Ç”Ç”ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇȕȕȕȕȕÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ–É–É–É–ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ—Ê—Ê—Ê—ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ˘˘˘ËËËËËËËËËËËËËËËËËËËËËË̙̙̙ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍΛΛÎÎÎÎÎÎÎÎÎÎÎÎϜϜϜÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÔ¡Ô¡ÔÔÔÔÔÔÕ¢Õ¢ÕÕÕÕÕÕÖ£ÖÖÖÖÖÖפ×××ר¥Ø¥ØØØØÙ¦ÙÙÙÙÚ§ÚÚÚÚÛ¨ÛÛÛÛÜ©ÜÜÜÜݪÝÝÞ«ÞÞÞÞ߬ßßà­ààá®ááâ¯ââã°ããä±ääå²ååæ³ææççèµèèééê·êêëëì¹ììííî»îîïïððñ¾ññòòóóôôõÂõõöö÷÷øøùùúÇúúûûüüýýþþÿÿ4: ? BEGIJLMNOPQR S!!!T"""""U###V$$$$$W%%%%%X%X&&&Y&Y'''''Z((((((([)))))))\)\*****]*]+++++++^+^,,,,,,,_,_---------`-`...........a.a///////////b/b0000000000000c0c0c1111111111111d1d1d22222222222222222e2e2e3333333333333333333f3f3f3f44444444444444444444444g4g4g4g555555555555555555555555555h5h5h5h66666666666666666666666666666666666i6i6i6i6i777777777777777777777777777777777777777777777j7j7j7j7j888888888888888888888888888888888888888888888888888888888k8k8k8k8k8k9999999999999999999999999999999999999999999999999999999999999999999999999999999l9l9l9l9l9l9l::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÛÛÜÜÜÜÜÜÝÝÝÝÞÞÞÞÞÞßßßßààààááááââââããããääääååååææççççèèééééêêëëëëììííííîîïïððððññòòóóôôôôõõöö÷÷øøùùùùúúûûüüýýþþÿÿ  !!!!""""""####$$$$$$%%%%%%&&&&&&''''''''(((((((())))))))********++++++++++,,,,,,,,,,------------..............//////////////000000000000000011111111111111111122222222222222222222223333333333333333333333334444444444444444444444444444445555555555555555555555555555555555666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××ØØØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÜÜÜÜÜÜÝÝÝÝÞÞÞÞÞÞßßßßààààááááââââããããääääååææææççèèèèééééêêëëììììííîîïïïïððññòòóóóóôôõõöö÷÷øøøøùùúúûûüüýýþþÿÿ  !!!!!!""""######$$$$$$%%%%%%&&&&&&''''''(((((((())))))))**********++++++++,,,,,,,,,,------------..............//////////////00000000000000001111111111111111112222222222222222222233333333333333333333333344444444444444444444444444445555555555555555555555555555555555666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ÷Ä÷Ä÷Ä÷Ä÷Ä÷Ä÷Ä÷ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅøÅøÅøÅøÅøÅøÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆùÆùÆùÆùÆùÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇúÇúÇúÇúÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈûÈûÈûÈûÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉüÉüÉüÉüÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊýÊýÊýËËËËËËËËËËËËËËËËËËËËËþËþËþÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÖÖÖÖÖÖÖ× ×××ר Ø ØØØØÙ ÙÙÙÙÚ ÚÚÚÚÛ ÛÛÜÜÜÜÜÝÝÝÞÞÞÞÞßßßàààáááâââãããäääååæææçèèèéééêêëìììííî ï!ïïððññò$ó%óóôôõõöö÷÷ø*øøùùúúûûüüýýþþÿÿÐ × Ø ÜÝßàâäæçéêëìí î!!!!!ï"""ð#####ñ$$$$$ò%%%%%ó&&&&&ô'''''õ(((((((ö)))))))÷*******ø*ø+++++ù+ù,,,,,,,ú,ú---------û-û.........ü.ü.ü/////////ý/ý/ý00000000000þ0þ0þ1111111111111ÿ1ÿ1ÿ222222222222223333333333333333333334444444444444444444444444555555555555555555555555555556666666666666666666666666666666666666677777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ+Å+Å+Å+Å+Å+Å+ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ,Æ,Æ,Æ,Æ,Æ,ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ-Ç-Ç-Ç-Ç-ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈ.È.È.È.È.ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ/É/É/É/ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ0Ê0Ê0Ê0ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊË1Ë1Ë1Ë1ËËËËËËËËËËËËËËËËËËÌ2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4ÎÎÎÎÎÎÎÎÎÎÎÎÏ5Ï5ÏÏÏÏÏÏÏÏÏÏÐ6Ð6Ð6ÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÓÓÔ:Ô:ÔÔÔÔÕ;Õ;ÕÕÕÕÖ<Ö<ÖÖÖÖ×=×=×××ר>ØØØØÙ?ÙÙÙÙÚ@ÚÚÚÚÛAÛÛÜBÜBÜÜÝCÝÝÞDÞÞÞÞßEßßàFààáGááâHââãIããääåKååæLææççèNèèééêPêêëëììíSííîîïïðVñWññòòóóôôõõö\÷]÷÷øøùùúúûûüüýýþþÿÿ ¥ ¦ ª­¯°±³´¶·¸¹ º!!!!!»"""¼#####½$$$¾$¾%%%¿%¿&&&À&À'''''Á(((((Â(Â)))))Ã)Ã*****Ä*Ä+++++++Å,,,,,,,,,Æ---------Ç-Ç.........È.È///////////É/É00000000000Ê0Ê0Ê1111111111111Ë1Ë1Ë222222222222222Ì2Ì2Ì3333333333333333333Í3Í3Í444444444444444444444Î4Î4Î4Î5555555555555555555555555Ï5Ï5Ï5Ï666666666666666666666666666666666Ð6Ð6Ð6Ð6Ð77777777777777777777777777777777777777777Ñ7Ñ7Ñ7Ñ7Ñ88888888888888888888888888888888888888888888888888888Ò8Ò8Ò8Ò8Ò8Ò9999999999999999999999999999999999999999999999999999999999999999999999999Ó9Ó9Ó9Ó9Ó9Ó9Ó:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::Ô:Ô:Ô:Ô:Ô:Ô:Ô:Ô;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ^Å^Å^Å^Å^Å^Å^ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ_Æ_Æ_Æ_Æ_Æ_ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ`Ç`Ç`Ç`Ç`Ç`ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈaÈaÈaÈaÈaÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉbÉbÉbÉbÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊcÊcÊcÊcÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËdËdËdËËËËËËËËËËËËËËËËËËÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÎÎÎÎÏhÏhÏhÏÏÏÏÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÓlÓlÓÓÓÓÓÓÔmÔmÔÔÔÔÕnÕnÕÕÕÕÖoÖoÖÖÖÖ×p×××רqØqØØÙrÙrÙÙÚsÚsÚÚÛtÛÛÛÛÜuÜÜÝvÝÝÞwÞwÞÞßxßßàyààázááâ{ââããä}ääå~ååææç€ççèèé‚ééêêë„ì…ììííîîïˆïïððññòòóóôõŽõõöö÷÷øøùùúúûûüüýýþþÿÿkl tuxy{|~€‚ƒ„…† ‡!!!!!ˆ"""‰###Š#Š$$$‹%%%%%Œ&&&&&'''''Ž'Ž(((())))))*****‘*‘+++++++’+’,,,,,,,“,“-------”-”.........•.•/////////–/–/–00000000000—0—1111111111111˜1˜1˜222222222222222™2™2™33333333333333333š3š3š3š444444444444444444444›4›4›5555555555555555555555555œ5œ5œ5œ66666666666666666666666666666666666677777777777777777777777777777777777777777ž7ž7ž7ž7ž888888888888888888888888888888888888888888888888888Ÿ8Ÿ8Ÿ8Ÿ8Ÿ8Ÿ99999999999999999999999999999999999999999999999999999999999999999999999 9 9 9 9 9 9 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::¡:¡:¡:¡:¡:¡:¡:¡;;;;;;;;;;;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ’Å’Å’Å’Å’Å’Å’Å’ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ“Æ“Æ“Æ“Æ“Æ“ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ”Ç”Ç”Ç”Ç”ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇȕȕȕȕÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ–É–É–É–ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ—Ê—Ê—Ê—ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ˘˘˘˘ËËËËËËËËËËËËËËËË̙̙̙̙ÌÌÌÌÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍÍÍÍÍΛΛΛÎÎÎÎÎÎÎÎÎÎϜϜÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÑÑÒŸÒŸÒÒÒÒÒÒÓ Ó ÓÓÓÓÓÓÔ¡ÔÔÔÔÔÔÕ¢ÕÕÕÕÕÕÖ£ÖÖÖÖפפ×××ר¥ØØØØÙ¦ÙÙÙÙÚ§ÚÚÛ¨Û¨ÛÛÜ©ÜÜݪÝÝÝÝÞ«ÞÞ߬ßßà­ààá®ááââã°ããä±ää岿³ææç´èµèèééê·êêëëììíºî»îîïïððññò¿óÀóóôôõõöö÷÷øøùùúúûûüüýýþþÿÿ9:; BCFGIKMNPQR S!!!T!T"""U###V$$$$$W%%%X%X&&&Y&Y'''''Z((((([)))))))\*******]+++++++^+^,,,,,,,_,_-------`-`.........a.a/////////b/b00000000000c0c0c1111111111111d1d222222222222222e2e2e33333333333333333f3f3f444444444444444444444g4g4g4g55555555555555555555555h5h5h5h6666666666666666666666666666666i6i6i6i6i777777777777777777777777777777777777777j7j7j7j7j888888888888888888888888888888888888888888888888888k8k8k8k8k99999999999999999999999999999999999999999999999999999999999999999999999l9l9l9l9l9l:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::m:m:m:m:m:m:m:m;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÝÝÞÞÞÞßßßßààààááââââããããääääååææææççèèééééêêëëììììííîîïïððññññòòóóôôõõöö÷÷øøùùúúûûüüýýþþÿÿ  !!!!""""""####$$$$$$%%%%&&&&&&''''''''(((((())))))))********++++++++,,,,,,,,,,----------............////////////000000000000001111111111111111112222222222222222223333333333333333333333444444444444444444444444445555555555555555555555555555556666666666666666666666666666666666666677777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÙÙÚÚÚÚÚÚÛÛÛÛÜÜÜÜÜÜÝÝÝÝÞÞÞÞßßßßààààááââââããããääååååææççççèèééêêêêëëììííîîîîïïððññòòóóôôõõöö÷÷øøùùúúûûüüýýþþÿÿ  !!!!""""""####$$$$%%%%%%&&&&&&''''''(((((())))))))********++++++++,,,,,,,,,,----------..........//////////////00000000000000111111111111111122222222222222222233333333333333333333334444444444444444444444445555555555555555555555555555556666666666666666666666666666666666666677777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÃÃÃöÃöÃöÃöÃöÃöÃöÃöÃöÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ÷Ä÷Ä÷Ä÷Ä÷Ä÷Ä÷ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅøÅøÅøÅøÅøÅøÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆùÆùÆùÆùÆùÆùÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇúÇúÇúÇúÇúÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈûÈûÈûÈûÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉüÉüÉüÉüÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊýÊýÊýÊýËËËËËËËËËËËËËËËËËþËþËþÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖ× × ×ר Ø ØØÙ Ù ÙÙÚ ÚÚÚÚÛ ÛÛÜÜÜÜÜÝÝÝÞÞÞßßßàààááâââãããäåååæçççèèéêêêëëììíî îîïïððññòòóóôôõõöö÷÷øøùùúúûûüüýýþþÿÿ ÛÜÝáâäåçéêëìí î!!!ï"""ð"ð###ñ$$$ò%%%%%ó&&&&&ô'''''õ(((((ö)))))÷)÷*****ø*ø+++++ù+ù,,,,,,,ú,ú-------û-û.......ü.ü/////////ý/ý/ý000000000þ0þ0þ11111111111ÿ1ÿ1ÿ222222222222333333333333333334444444444444444444444555555555555555555555555566666666666666666666666666666666777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄ*Ä*Ä*Ä*Ä*Ä*Ä*Ä*Ä*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ+Å+Å+Å+Å+Å+Å+Å+ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ,Æ,Æ,Æ,Æ,Æ,ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ-Ç-Ç-Ç-Ç-ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈ.È.È.È.È.ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ/É/É/É/ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ0Ê0Ê0Ê0ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊË1Ë1Ë1ËËËËËËËËËËËËËËËËÌ2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍ3Í3ÍÍÍÍÍÍÍÍÍÍÍÍÎ4Î4Î4ÎÎÎÎÎÎÎÎÏ5Ï5Ï5ÏÏÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÑÑÒ8Ò8ÒÒÒÒÒÒÓ9Ó9ÓÓÓÓÔ:Ô:ÔÔÔÔÕ;Õ;ÕÕÖ<Ö<ÖÖÖÖ×=×××ר>ØØØØÙ?ÙÙÚ@Ú@ÚÚÛAÛÛÜBÜBÜÜÝCÝÝÞDÞÞßEßßàFáGááâHââãIããääåKååææçMèNèèééêPëQìRììííîîïïðVñWòXóYôZõ[ö\÷]ø^ù_ú`ûaüüýýþþÿÿ ª«¬¯°²³´µ¶·¸¹ º!!!»"""¼#####½$$$¾%%%¿%¿&&&À&À'''Á'Á(((Â(Â)))))Ã*****Ä*Ä+++++Å+Å,,,,,,,Æ,Æ-----Ç-Ç-Ç.......È.È/////////É/É00000000000Ê0Ê11111111111Ë1Ë1Ë2222222222222Ì2Ì2Ì333333333333333Í3Í3Í4444444444444444444Î4Î4Î4Î55555555555555555555555Ï5Ï5Ï66666666666666666666666666666Ð6Ð6Ð6Ð7777777777777777777777777777777777777Ñ7Ñ7Ñ7Ñ7Ñ888888888888888888888888888888888888888888888Ò8Ò8Ò8Ò8Ò8Ò999999999999999999999999999999999999999999999999999999999999999Ó9Ó9Ó9Ó9Ó9Ó9Ó:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::Ô:Ô:Ô:Ô:Ô:Ô:Ô:Ô;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄ]Ä]Ä]Ä]Ä]Ä]Ä]Ä]Ä]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ^Å^Å^Å^Å^Å^Å^ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ_Æ_Æ_Æ_Æ_Æ_ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ`Ç`Ç`Ç`Ç`ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈaÈaÈaÈaÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉbÉbÉbÉbÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊcÊcÊcÊcÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËdËdËdËËËËËËËËËËËËËËËËÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÍÍÍÍÍÍÎgÎgÎÎÎÎÎÎÎÎÎÎÏhÏhÏÏÏÏÏÏÏÏÐiÐiÐiÐÐÐÐÐÐÑjÑjÑÑÑÑÑÑÒkÒkÒÒÒÒÒÒÓlÓÓÓÓÓÓÔmÔmÔÔÔÔÕnÕÕÕÕÖoÖoÖÖ×p×p×רqØqØØÙrÙrÙÙÚsÚÚÛtÛtÛÛÜuÜÜÝvÝÝÞwÞÞßxßßàyázááâ{ââã|ä}ääå~æææççèé‚ééêêëëììí†î‡ïˆïïððññòòóóôôõõöö÷÷øøùùúúü•ýýþþÿÿ z{|~ƒ„…† ‡!!!ˆ"""‰###Š#Š$$$‹%%%Œ&&&&&'''''Ž((((())))))***‘*‘+++++’+’,,,,,,,“,“-----”-”.........•.•///////–/–/–000000000—0—0—111111111˜1˜1˜2222222222222™2™2™333333333333333š3š3š4444444444444444444›4›4›55555555555555555555555œ5œ5œ5œ66666666666666666666666666666677777777777777777777777777777777777ž7ž7ž7ž7ž888888888888888888888888888888888888888888888Ÿ8Ÿ8Ÿ8Ÿ8Ÿ999999999999999999999999999999999999999999999999999999999999999 9 9 9 9 9 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::¡:¡:¡:¡:¡:¡:¡:¡;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃđđđđđđđđđÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ’Å’Å’Å’Å’Å’Å’ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ“Æ“Æ“Æ“Æ“Æ“ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ”Ç”Ç”Ç”Ç”Ç”ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇȕȕȕȕȕÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ–É–É–É–ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ—Ê—Ê—ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ˘˘˘˘ËËËËËËËËËËËËËË̙̙̙ÌÌÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍÍÍΛΛΛÎÎÎÎÎÎÎÎϜϜϜÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐўўÑÑÑÑÑÑÒŸÒŸÒÒÒÒÓ Ó ÓÓÓÓÓÓÔ¡ÔÔÔÔÕ¢Õ¢ÕÕÕÕÖ£ÖÖÖÖפ×××ר¥ØØØØÙ¦ÙÙÚ§ÚÚÚÚÛ¨ÛÛÜ©ÜÜݪÝÝÞ«ÞÞ߬ßßà­á®ááâ¯ââããä±ääååæ³ç´ççèèé¶ê·ë¸ì¹ììííîîïïððññòòóóôôõõöö÷÷øøùùúúûûýýþþÿÿ:; < = > ? @ABCDEIJLMNOPR S!!!T"""U###V$$$W$W%%%X&&&Y&Y'''Z'Z((([([)))\)\*****]+++++++^,,,,,,,_,_-----`-`.......a.a.a///////b/b000000000c0c0c11111111111d1d2222222222222e2e2e333333333333333f3f3f44444444444444444g4g4g4g555555555555555555555h5h5h5h6666666666666666666666666i6i6i6i6i777777777777777777777777777777777j7j7j7j7j8888888888888888888888888888888888888888888k8k8k8k8k8k99999999999999999999999999999999999999999999999999999999999l9l9l9l9l9l9l:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::m:m:m:m:m:m:m:m;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØØØÙÙÙÙÚÚÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞßßßßààááááââããããääååååææççèèèèééêêëëììííîîïïððññòòóóôôõõöö÷÷øøùùúúûûýýþþÿÿ  !!!!""""####$$$$%%%%%%&&&&''''''(((((())))))********++++++++,,,,,,,,--------..........////////////0000000000001111111111111111222222222222222233333333333333333333444444444444444444444455555555555555555555555555556666666666666666666666666666666677777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××××ØØØØÙÙÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÜÝÝÝÝÞÞÞÞßßßßààááááââããããääååææææççèèééêêëëëëììííîîïïððññòòóóõõöö÷÷øøùùúúûûüüþþÿÿ  !!!!""""####$$$$%%%%&&&&&&''''''(((())))))))******++++++++,,,,,,,,--------..........////////////000000000000111111111111112222222222222222333333333333333333444444444444444444444455555555555555555555555555556666666666666666666666666666666677777777777777777777777777777777777777778888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃöÃöÃöÃöÃöÃöÃöÃöÃöÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ÷Ä÷Ä÷Ä÷Ä÷Ä÷Ä÷ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅøÅøÅøÅøÅøÅøÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆùÆùÆùÆùÆùÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇúÇúÇúÇúÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈûÈûÈûÈûÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉüÉüÉüÉüÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊýÊýÊýÊýËËËËËËËËËËËËËþËþËþËþÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÑÑÑÑÑÑÑÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÖÖÖÖ× ×××ר ØØÙ Ù ÙÙÚ ÚÚÛ ÛÛÜÜÜÝÝÝÞÞÞßßßàáááâãããääåæææççèéêëëëììííîîïïððññòòóóõ'ö(÷÷øøùùúúûûüüþþÿÿÒ ÛÜÝÞßàáåæèéëìí î!!!ï"""ð###ñ$$$ò%%%ó&&&&&ô'''õ'õ(((ö)))))÷)÷***ø*ø+++++ù+ù,,,,,ú,ú-----û-û.......ü.ü///////ý/ý/ý0000000þ0þ0þ111111111ÿ1ÿ1ÿ222222222233333333333333344444444444444444445555555555555555555555566666666666666666666666666777777777777777777777777777777777778888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;< < < < < < < < < < <<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄ*Ä*Ä*Ä*Ä*Ä*Ä*Ä*Ä*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ+Å+Å+Å+Å+Å+Å+ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ,Æ,Æ,Æ,Æ,Æ,ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ-Ç-Ç-Ç-Ç-Ç-ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈ.È.È.È.È.ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ/É/É/É/ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ0Ê0Ê0Ê0ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊË1Ë1Ë1ËËËËËËËËËËËËËËÌ2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÍ3Í3Í3ÍÍÍÍÍÍÍÍÎ4Î4Î4ÎÎÎÎÎÎÎÎÏ5Ï5ÏÏÏÏÏÏÏÏÐ6Ð6ÐÐÐÐÐÐÑ7Ñ7ÑÑÑÑÒ8Ò8ÒÒÒÒÓ9Ó9ÓÓÓÓÔ:Ô:ÔÔÕ;Õ;ÕÕÕÕÖ<ÖÖ×=×=×ר>Ø>ØØÙ?ÙÙÚ@ÚÚÛAÛÛÜBÜÜÝCÝÝÞDÞÞßEßßààáGááâHãIäJääåKæLçMççèèééêêëQìRíSîTïUððññòòóóôôõõ÷]ø^ùùúúûûüüþþÿÿ ¤ ¥ ¦®¯°±³´µ¶·¸¹ º!!!»"""¼#½#½$$$¾%%%¿&&&À&À'''Á(((Â(Â)))Ã)Ã***Ä*Ä+++++Å+Å,,,,,Æ,Æ-----Ç-Ç.......È.È///////É/É000000000Ê0Ê111111111Ë1Ë1Ë22222222222Ì2Ì2Ì3333333333333Í3Í3Í444444444444444Î4Î4Î4Î5555555555555555555Ï5Ï5Ï5Ï66666666666666666666666Ð6Ð6Ð6Ð7777777777777777777777777777777Ñ7Ñ7Ñ7Ñ7Ñ888888888888888888888888888888888888888Ò8Ò8Ò8Ò8Ò8Ò99999999999999999999999999999999999999999999999999999Ó9Ó9Ó9Ó9Ó9Ó9Ó:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::Ô:Ô:Ô:Ô:Ô:Ô:Ô:Ô;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄ]Ä]Ä]Ä]Ä]Ä]Ä]Ä]Ä]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ^Å^Å^Å^Å^Å^Å^Å^ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ_Æ_Æ_Æ_Æ_Æ_ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ`Ç`Ç`Ç`Ç`ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈaÈaÈaÈaÈaÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉbÉbÉbÉbÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊcÊcÊcÊcÊÊÊÊÊÊÊÊÊÊÊÊÊÊËdËdËdËdËËËËËËËËËËËËÌeÌeÌeÌÌÌÌÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÏhÏhÏhÏÏÏÏÏÏÐiÐiÐÐÐÐÐÐÑjÑjÑÑÑÑÒkÒkÒÒÒÒÓlÓlÓÓÓÓÔmÔmÔÔÕnÕnÕÕÖoÖoÖÖ×p×p×רqØØÙrÙÙÚsÚsÛtÛtÜuÜuÝvÝvÞwÞÞßxàyààázááââã|ä}ääååæç€èé‚êƒêêëëììííîîð‰ñŠò‹óŒôôõõöö÷÷ù’úúûûüüþ—ÿÿj p xyz{|€ƒ„…† ‡!!!ˆ"‰"‰#Š$$$‹$‹%Œ%Œ&&&'''Ž'Ž((()))))*****‘+++++’+’,,,,,“,“-----”-”.....•.•.•/////–/–/–0000000—0—0—111111111˜1˜22222222222™2™2™3333333333333š3š3š444444444444444›4›4›5555555555555555555œ5œ5œ5œ666666666666666666666666677777777777777777777777777777ž7ž7ž7ž7ž8888888888888888888888888888888888888Ÿ8Ÿ8Ÿ8Ÿ8Ÿ8Ÿ999999999999999999999999999999999999999999999999999 9 9 9 9 9 9 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::¡:¡:¡:¡:¡:¡:¡:¡;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;¢;¢;¢;¢;¢;¢;¢;¢;¢;¢<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃđđđđđđđđđÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ’Å’Å’Å’Å’Å’Å’ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ“Æ“Æ“Æ“Æ“Æ“ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ”Ç”Ç”Ç”Ç”Ç”ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇȕȕȕȕȕÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ–É–É–É–ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ—Ê—Ê—ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ˘˘˘ËËËËËËËËËËËË̙̙̙ÌÌÌÌÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍÍÍΛΛÎÎÎÎÎÎÎÎϜϜÏÏÏÏÏÏÐÐÐÐÐÐÐÐўўÑÑÑÑÒŸÒŸÒÒÒÒÓ Ó ÓÓÓÓÔ¡ÔÔÔÔÕ¢Õ¢ÕÕÖ£ÖÖÖÖפ×ר¥Ø¥Ù¦Ù¦ÙÙÚ§ÚÚÛ¨ÛÛÜ©ÜÜݪޫÞÞ߬à­ààá®â¯ââã°ä±å²ååææççèèé¶ê·ë¸ì¹íºîîïïððññòòôÁõõöö÷÷øøúúûûüüýýÿÿ:; @ABCIJKLNOPQR S!T!T"U###V$$$W%%%X&&&Y&Y'''Z((([([)))\)\***]*]+++^+^,,,,,_,_-----`-`.....a.a///////b/b0000000c0c0c111111111d1d1d222222222e2e2e33333333333f3f3f3f4444444444444g4g4g4g55555555555555555h5h5h5h666666666666666666666i6i6i6i77777777777777777777777777777j7j7j7j7j88888888888888888888888888888888888k8k8k8k8k8k9999999999999999999999999999999999999999999999999l9l9l9l9l9l9l:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::m:m:m:m:m:m:m:m;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;n;n;n;n;n;n;n;n;n;n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÕÖÖÖÖÖÖ××××××ØØØØÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÜÝÝÞÞÞÞßßààààááââââããääååææççèèèèééêêëëììîîïïððññòòóóõõöö÷÷øøúúûûüüýýÿÿ  !!""""####$$$$%%%%&&&&''''''(((())))))******++++++,,,,,,,,--------........//////////00000000001111111111111122222222222222333333333333333344444444444444444444555555555555555555555555666666666666666666666666666677777777777777777777777777777777777788888888888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËËËËËËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÒÒÒÒÒÒÒÒÓÓÓÓÓÓÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÖÖÖ××××ØØØØÙÙÙÙÚÚÚÚÛÛÛÛÜÜÜÜÝÝÞÞÞÞßßààààááââããããääååææççèèééêêëëììííîîïïððòòóóôôõõ÷÷øøùùûûüüýýÿÿ  !!""""####$$$$%%%%&&&&''''(((((())))******++++++,,,,,,,,--------........//////////000000000011111111111122222222222222333333333333333344444444444444444455555555555555555555555566666666666666666666666666777777777777777777777777777777777777888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂõÂõÂõÂõÂõÂõÂõÂõÂõÂõÂõÂõÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃöÃöÃöÃöÃöÃöÃöÃöÃöÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ÷Ä÷Ä÷Ä÷Ä÷Ä÷Ä÷Ä÷ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅøÅøÅøÅøÅøÅøÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆùÆùÆùÆùÆùÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇúÇúÇúÇúÇúÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈûÈûÈûÈûÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉüÉüÉüÉüÊÊÊÊÊÊÊÊÊÊÊÊÊýÊýÊýÊýËËËËËËËËËËËþËþËþÌÌÌÌÌÌÌÌÌÌÌÿÌÿÌÿÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÏÏÏÏÏÏÏÏÐÐÐÐÐÐÑÑÑÑÑÑÒÒÒÒÒÒÓÓÓÓÔÔÔÔÕÕÕÕÖÖÖÖ× ×ר ØØÙ Ù Ú Ú Û ÛÛÜÜÜÝÞÞÞßàààáâãããääåæçèéêëìííîîïïððò$óóôôõõ÷)øøùùûûüüýýÿÿÐÔ Ø ÝÞßçèéêëìí î!ï"""ð###ñ$ò$ò%ó%ó&ô&ô'''õ(((ö(ö)))÷***ø*ø+++ù+ù,,,,,ú,ú-----û-û.....ü.ü/////ý/ý/ý00000þ0þ0þ1111111ÿ1ÿ1ÿ22222222333333333333344444444444444455555555555555555556666666666666666666666777777777777777777777777777777888888888888888888888888888888888888899999999999999999999999999999999999999999999999999:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;< < < < < < < < < < < <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃ)Ã)Ã)Ã)Ã)Ã)Ã)Ã)Ã)Ã)Ã)ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄ*Ä*Ä*Ä*Ä*Ä*Ä*Ä*Ä*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ+Å+Å+Å+Å+Å+Å+ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ,Æ,Æ,Æ,Æ,Æ,ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ-Ç-Ç-Ç-Ç-Ç-ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈ.È.È.È.È.ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ/É/É/É/ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ0Ê0Ê0Ê0ÊÊÊÊÊÊÊÊÊÊÊÊË1Ë1Ë1ËËËËËËËËËËÌ2Ì2Ì2ÌÌÌÌÌÌÌÌÌÌÍ3Í3ÍÍÍÍÍÍÍÍÎ4Î4ÎÎÎÎÎÎÏ5Ï5Ï5ÏÏÏÏÐ6Ð6ÐÐÐÐÑ7Ñ7Ñ7ÑÑÒ8Ò8ÒÒÒÒÓ9Ó9ÓÓÔ:Ô:ÔÔÕ;Õ;ÕÕÖ<ÖÖ×=×=Ø>Ø>ØØÙ?ÙÙÚ@ÛAÛAÜBÜÜÝCÞDÞDßEàFààáGâHãIäJääååææççèèééêêëëíSîTïUððññóYôZõõööøøùùûaüüýýÿÿŸ £ §¨¬­®¯°±²³´µ¶·¸¹ º!»"""¼#½#½$¾%%%¿&&&À'''Á'Á(Â(Â)))Ã)Ã***Ä+++++Å,,,,,Æ,Æ---Ç-Ç-Ç...È.È.È/////É/É0000000Ê0Ê1111111Ë1Ë1Ë222222222Ì2Ì2Ì333333333Í3Í3Í3Í44444444444Î4Î4Î4Î555555555555555Ï5Ï5Ï5Ï6666666666666666666Ð6Ð6Ð6Ð7777777777777777777777777Ñ7Ñ7Ñ7Ñ7Ñ8888888888888888888888888888888Ò8Ò8Ò8Ò8Ò8Ò9999999999999999999999999999999999999999999Ó9Ó9Ó9Ó9Ó9Ó9Ó:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::Ô:Ô:Ô:Ô:Ô:Ô:Ô:Ô;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃ\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄ]Ä]Ä]Ä]Ä]Ä]Ä]Ä]Ä]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ^Å^Å^Å^Å^Å^Å^ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ_Æ_Æ_Æ_Æ_Æ_ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ`Ç`Ç`Ç`Ç`ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈaÈaÈaÈaÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉbÉbÉbÉbÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊcÊcÊcÊÊÊÊÊÊÊÊÊÊÊÊËdËdËdËdËËËËËËËËÌeÌeÌeÌeÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÍÍÎgÎgÎgÎÎÎÎÎÎÏhÏhÏÏÏÏÐiÐiÐiÐÐÐÐÑjÑjÑÑÒkÒkÒÒÒÒÓlÓlÓÓÔmÔmÔÔÕnÕÕÖoÖoÖÖ×p×רqØØÙrÙÙÚsÚÚÛtÜuÜuÝvÝÝÞwßxàyààázâ{ã|ä}å~æç€èé‚êƒë„ì…ííîîð‰ñŠòòóóõŽööø‘ùùúúüüýýÿÿo swx}~€‚„…† ‡!ˆ"""‰#Š$$$‹%%%Œ&&&'''Ž((())))***‘*‘+++’+’,,,“,“---”-”.....•.•/////–/–/–00000—0—0—1111111˜1˜222222222™2™2™333333333š3š3š4444444444444›4›4›555555555555555œ5œ5œ5œ66666666666666666666677777777777777777777777ž7ž7ž7ž7ž88888888888888888888888888888Ÿ8Ÿ8Ÿ8Ÿ8Ÿ8Ÿ9999999999999999999999999999999999999999999 9 9 9 9 9 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::¡:¡:¡:¡:¡:¡:¡:¡;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;¢;¢;¢;¢;¢;¢;¢;¢;¢;¢<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃđđđđđđđđđÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ’Å’Å’Å’Å’Å’Å’Å’ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ“Æ“Æ“Æ“Æ“Æ“ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ”Ç”Ç”Ç”Ç”ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇȕȕȕȕȕÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉ–É–É–É–ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊ—Ê—Ê—Ê—ÊÊÊÊÊÊÊÊÊÊÊÊ˘˘˘ËËËËËËËËËË̙̙̙ÌÌÌÌÌÌ͚͚͚ÍÍÍÍÍÍΛΛΛÎÎÎÎϜϜϜÏÏÏÏÐÐÐÐÐÐўўÑÑÒŸÒŸÒÒÒÒÓ Ó ÓÓÔ¡ÔÔÕ¢Õ¢ÕÕÖ£ÖÖפפإإ٦٦ڧÚÚÛ¨ÛÛܩݪÝÝޫ߬à­ààááâ¯ã°ä±å²æ³ç´èµé¶êêëëíºî»ïïððò¿óóôôöö÷÷ùùúúüüýýÿÿ > ABEFGHOPQR S!T"U"U#V$$$W%X%X&Y&Y'Z'Z([([)))\***]*]+++^+^,,,_,_---`-`.....a.a/////b/b0000000c0c1111111d1d1d2222222e2e2e333333333f3f3f44444444444g4g4g4g5555555555555h5h5h5h66666666666666666i6i6i6i77777777777777777777777j7j7j7j7j88888888888888888888888888888k8k8k8k8k99999999999999999999999999999999999999999l9l9l9l9l9l9l:::::::::::::::::::::::::::::::::::::::::::::::::::::::::m:m:m:m:m:m:m:m;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;n;n;n;n;n;n;n;n;n;n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<Ù?Ù?Ú@ÚÚÛAÜBÜÜÝCÞDßEàFáGâHãIäJåKæLçMèNééëQìRííïUððòXóóõ[ööøøú`ûûýýÿÿ›  ¥ ¨«®¯°³´µ¶·¸¹ º!»"¼#½#½$¾%¿%¿&À'''Á(((Â)))Ã***Ä*Ä+Å+Å,,,Æ,Æ---Ç-Ç...È.È/////É/É00000Ê0Ê11111Ë1Ë1Ë2222222Ì2Ì2Ì3333333Í3Í3Í444444444Î4Î4Î4Î55555555555Ï5Ï5Ï5Ï6666666666666Ð6Ð6Ð6Ð6Ð7777777777777777777Ñ7Ñ7Ñ7Ñ7Ñ88888888888888888888888Ò8Ò8Ò8Ò8Ò8Ò99999999999999999999999999999999999Ó9Ó9Ó9Ó9Ó9Ó9Ó:::::::::::::::::::::::::::::::::::::::::::::::::Ô:Ô:Ô:Ô:Ô:Ô:Ô:Ô;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö========================================================================Â[Â[Â[ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃ\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄ]Ä]Ä]Ä]Ä]Ä]Ä]Ä]Ä]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ^Å^Å^Å^Å^Å^Å^ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ_Æ_Æ_Æ_Æ_Æ_ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ`Ç`Ç`Ç`Ç`Ç`ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈaÈaÈaÈaÈaÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉbÉbÉbÉbÉÉÉÉÉÉÉÉÉÉÉÉÊcÊcÊcÊÊÊÊÊÊÊÊËdËdËdËdËËËËËËÌeÌeÌeÌÌÌÌÌÌÍfÍfÍfÍÍÍÍÎgÎgÎgÎÎÏhÏhÏhÏÏÐiÐiÐÐÑjÑjÑjÑÑÒkÒkÓlÓlÓÓÔmÔmÕnÕnÖoÖo×p×pØqØqÙrÚsÚsÛtÜuÜÜÝvÞwßxàyázâ{ã|ä}å~æç€é‚êƒë„í†î‡ð‰ññóŒôôööø‘ùùûûýýÿÿo q tvwyz}~‚ƒ„…† ‡ ‡!ˆ"‰#Š$$$‹%Œ&&&'Ž'Ž(())*‘*‘+’+’,,,“,“---”-”...•.•///–/–/–000—0—0—11111˜1˜2222222™2™2™3333333š3š3š444444444›4›4›55555555555œ5œ5œ5œ66666666666666667777777777777777777ž7ž7ž7ž7ž88888888888888888888888Ÿ8Ÿ8Ÿ8Ÿ8Ÿ999999999999999999999999999999999 9 9 9 9 9 9 :::::::::::::::::::::::::::::::::::::::::::::::¡:¡:¡:¡:¡:¡:¡:¡;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;¢;¢;¢;¢;¢;¢;¢;¢;¢;¢<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<£<£<£<£<£<£<£<£<£<£<£<£<£<£==================================================================================================ÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃđđđđđđđđđÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ’Å’Å’Å’Å’Å’Å’ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ“Æ“Æ“Æ“Æ“Æ“ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ”Ç”Ç”Ç”Ç”ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇȕȕȕȕȕÈÈÈÈÈÈÈÈÈÈÈÈÉ–É–É–É–ÉÉÉÉÉÉÉÉÉÉÊ—Ê—Ê—Ê—ÊÊÊÊÊÊÊÊ˘˘˘ËËËËËË̙̙̙ÌÌÌÌÌÌ͚͚͚ÍÍÍÍΛΛÎÎÎÎϜϜÏÏÐÐÐÐÐўўÑÑÒŸÒŸÓ Ó ÓÓԡԡբբ֣֣פ×ר¥Ù¦Ù¦Ú§Û¨Ü©Ü©ÝªÞ«ß¬à­á®â¯ã°ä±å²ææèµé¶êêì¹ííï¼ñ¾òòôÁöÃ÷÷ùùûûýýÿÿ68 ?ADGHJKLMOPQR S!!!T"U#V$W$W%X&Y&Y'Z([([)\)\*]*]+++^,,,_,_---`-`...a.a///b/b00000c0c11111d1d1d22222e2e2e33333f3f3f3f4444444g4g4g4g555555555h5h5h5h6666666666666i6i6i6i77777777777777777j7j7j7j7j888888888888888888888k8k8k8k8k8k99999999999999999999999999999l9l9l9l9l9l9l:::::::::::::::::::::::::::::::::::::::::::::m:m:m:m:m:m:m:m;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;n;n;n;n;n;n;n;n;n;n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<Ù?Ù?Ú@ÛAÜBÝCÞDßEàFáGâHäJåKæLèNéOëQíSïUððòòôôööøøúúýýÿÿ¢ ¤ ¦¨ª¬­¯±²´µ¶·¹ º!»"¼#½$W$¾%¿&À'Á'Á(Â)Ã)Ã*Ä*Ä+Å+Å,Æ,Æ-Ç-Ç...È.È///É/É000Ê0Ê0Ê111Ë1Ë22222Ì2Ì2Ì33333Í3Í3Í44444Î4Î4Î4Î5555555Ï5Ï5Ï5Ï666666666Ð6Ð6Ð6Ð6Ð7777777777777Ñ7Ñ7Ñ7Ñ7Ñ88888888888888888Ò8Ò8Ò8Ò8Ò9999999999999999999999999Ó9Ó9Ó9Ó9Ó9Ó9Ó:::::::::::::::::::::::::::::::::::::Ô:Ô:Ô:Ô:Ô:Ô:Ô:Ô;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö==============================================================================================================================================================================================================ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂ[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃ\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄ]Ä]Ä]Ä]Ä]Ä]Ä]Ä]Ä]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ^Å^Å^Å^Å^Å^Å^Å^ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ_Æ_Æ_Æ_Æ_Æ_ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ`Ç`Ç`Ç`Ç`ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈaÈaÈaÈaÈÈÈÈÈÈÈÈÈÈÉbÉbÉbÉbÉÉÉÉÉÉÊcÊcÊcÊcÊÊÊÊÊÊËdËdËdËËËËÌeÌeÌeÌÌÍfÍfÍfÍÍÎgÎgÎgÎÎÏhÏhÏÏÐiÐiÑjÑjÑjÒkÒkÓlÓlÔmÔmÕnÖoÖo×pØqØqÙrÚsÛtÜuÝvÞwßxàyázãä}å~ç€èêƒì…î‡ð‰ò‹ôöøøúúý–ÿÿkm tvxz{}€‚ƒ„ì ‡!ˆ"‰#Š$‹%Œ%Œ&'Ž(()*‘*‘+’+’,“,“-”-”...•.•/–/–/–0—0—0—111˜1˜1˜222™2™2™333š3š3š3š44444›4›4›5555555œ5œ5œ5œ6666666666667777777777777ž7ž7ž7ž7ž888888888888888Ÿ8Ÿ8Ÿ8Ÿ8Ÿ8Ÿ99999999999999999999999 9 9 9 9 9 :::::::::::::::::::::::::::::::::::¡:¡:¡:¡:¡:¡:¡:¡;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;¢;¢;¢;¢;¢;¢;¢;¢;¢;¢<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<£<£<£<£<£<£<£<£<£<£<£<£<£===========================================================================================================================================================================================================¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃđđđđđđđđđÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ’Å’Å’Å’Å’Å’Å’ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ“Æ“Æ“Æ“Æ“Æ“ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇ”Ç”Ç”Ç”Ç”Ç”ÇÇÇÇÇÇÇÇÇÇȕȕȕȕȕÈÈÈÈÈÈÈÈÉ–É–É–É–ÉÉÉÉÉÉÊ—Ê—Ê—Ê—ÊÊÊÊ˘˘˘˘ËË̙̙̙ÌÌ͚͚͚ÍÍΛΛΛϜϜϜÐÐÐÐўўҟҟӠӠԡÕnÕ¢Ö£×pפإ٦ڧÛtÜuÝvÞw߬à­á®ã°ä±æ³ç´é¶ë¸íºï¼ñ¾óÀõõøÅúúüüÿÿ < >EGHJLMOP… S!T"U#V$W%X&Y&'Z([)\)\*]+^+^,_,_-`-`.a.a.a/b/b000c0c111d1d1d222e2e2e333f3f3f44444g4g4g4g55555h5h5h5h6666666i6i6i6i6i77777777777j7j7j7j7j8888888888888k8k8k8k8k8k999999999999999999999l9l9l9l9l9l9l:::::::::::::::::::::::::::::::m:m:m:m:m:m:m:m;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;n;n;n;n;n;n;n;n;n;n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÌÌÌÍÍÍÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÐÐÐÐÐÐÑÑÑÑÒÒÒÒÓÓÓÓÔÔÕÕÕÕÖÖ×רØÙÙÙÙÚÚÛÛÜÜÞÞßßààââããååææèèêêììîîððòòõõ÷÷úúüüÿÿ  !!""##$$%%&&''(((())****++,,,,----....//////000000111111222222223333333344444444445555555555556666666666666677777777777777777777888888888888888888888899999999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<========================================================================================================================================================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÊËËËËËËËËÌÌÌÌÌÌÌÌÍÍÍÍÍÍÎÎÎÎÎÎÏÏÏÏÏÏÐÐÐÐÑÑÑÑÒÒÒÒÓÓÔÔÔÔÕÕÖÖÖÖ×רØÙÙÚÚÛÛÜÜÞÞßßààââããååççééëëííïïòòôô÷÷ùùüüÿÿ  !!""##$$%%&&''(())****++,,,,----....//////00001111112222222233333333444444445555555555556666666666666677777777777777777788888888888888888888889999999999999999999999999999::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==========================================================================================================================================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂõÂõÂõÂõÂõÂõÂõÂõÂõÂõÂõÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃöÃöÃöÃöÃöÃöÃöÃöÃöÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ÷Ä÷Ä÷Ä÷Ä÷Ä÷Ä÷Ä÷ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅøÅøÅøÅøÅøÅøÆÆÆÆÆÆÆÆÆÆÆÆÆùÆùÆùÆùÆùÆùÇÇÇÇÇÇÇÇÇúÇúÇúÇúÇúÈÈÈÈÈÈÈûÈûÈûÈûÉÉÉÉÉüÉüÉüÉüÊÊÊýÊýÊýËËËþËþËþÌÌÌÿÌÿÌÿÎÎÎÏÏÏÐÐÑÑÒÒÓÓ9ÔÕÕ;Ö× Ø Ù Ú Û ÜÝCÞDàáGãåçéëíï!ò$ô&÷)ùùüüÿÿÐÓ Ø Ûݬâäæ´¶ë¹ î!ï#½$¾%¿&À'Á(Â(ö)÷*ø*ø+ù,ú,ú-û-û.ü.ü/ý/ý/ý0þ0þ1ÿ1ÿ1ÿ223334444445555555666666666677777777777788888888888888899999999999999999999:::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;< < < < < < < < < < <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<= = = = = = = = = = = = = = ==================================================================================================================================================================> > > > > > > > > > > > > > > > > > > > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Á'Á'Á'Á'Á'Á'Á'Á'ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂ(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃ)Ã)Ã)Ã)Ã)Ã)Ã)Ã)Ã)Ã)Ã)Ã)ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄ*Ä*Ä*Ä*Ä*Ä*Ä*Ä*Ä*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ+Å+Å+Å+Å+Å+Å+ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ,Æ,Æ,Æ,Æ,Æ,ÆÆÆÆÆÆÆÆÆÆÆÆÇ-Ç-Ç-Ç-Ç-ÇÇÇÇÇÇÇÇÈ.È.È.È.ÈÈÈÈÈÈÉ/É/É/É/ÉÉÉÉÊ0Ê0Ê0ÊÊË1Ë1Ë1Ë1Ì2Ì2Ì2Ì2Í3Í3Í3Î4Î4Î4Ï5Ï5Ð6Ð6Ñ7Ñ7Ò8Ò8Ó9Ó Ô:Õ;Ö<×=פإ٦ÛAÜBÝCÞ«àFâHã°å²ç´é¶ìRîTñWóóööùùüüÿÿ¢ ¥¨ª­¯±³µ·R º"U#V$¾%¿&À'Á(Â)Ã*]*Ä+Å,_,Æ-Ç-Ç.È.È/É/É0Ê0Ê0Ê1Ë1Ë222Ì2Ì2Ì3Í3Í3Í444Î4Î4Î4Î555Ï5Ï5Ï5Ï66666Ð6Ð6Ð6Ð6Ð7777777Ñ7Ñ7Ñ7Ñ7Ñ888888888Ò8Ò8Ò8Ò8Ò8Ò999999999999999Ó9Ó9Ó9Ó9Ó9Ó:::::::::::::::::::::::Ô:Ô:Ô:Ô:Ô:Ô:Ô:Ô;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö=====================================================================================================================================================×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂ[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃ\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄ]Ä]Ä]Ä]Ä]Ä]Ä]Ä]Ä]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ^Å^Å^Å^Å^Å^Å^ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆ_Æ_Æ_Æ_Æ_Æ_ÆÆÆÆÆÆÆÆÆÆÇ`Ç`Ç`Ç`Ç`ÇÇÇÇÇÇÈaÈaÈaÈaÈaÈÈÈÈÉbÉbÉbÉbÉÉÊcÊcÊcÊcÊÊËdËdËdËËÌeÌeÌeÍfÍfÍfÎgÎgÏhÏhÐÐiÑÑjÒkÒkÓlÔmÕÖÖo×pØqÚ Û ÜÝvßáâ{ä}æèëí†ð‰óŒöù’ü•ÿÿ p svß{äæèêì ‡!ï#Š$‹%ó&ô'õ(ö)*‘+’+ù,“-”-û.•.ü/–/ý0—0—1˜1˜1˜2™2™2™3š3š3š444›4›4›555œ5œ5œ5œ666666667777777ž7ž7ž7ž7ž8888888Ÿ8Ÿ8Ÿ8Ÿ8Ÿ8Ÿ9999999999999 9 9 9 9 9 9 :::::::::::::::::::¡:¡:¡:¡:¡:¡:¡:¡;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;¢;¢;¢;¢;¢;¢;¢;¢;¢;¢<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<£<£<£<£<£<£<£<£<£<£<£<£<£<£=======================================================================================================================================¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃđđđđđđđđđÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ’Å’Å’Å’Å’Å’Å’Å’ÅÅÅÅÅÅÅÅÅÅÅÅÆ“Æ“Æ“Æ“Æ“Æ“ÆÆÆÆÆÆÆÆÇ”Ç”Ç”Ç”Ç”Ç”ÇÇÇÇȕȕȕȕȕÈÈÉ–É–É–É–ÉÉʗʗʗʗ˘˘˘˘̙̙̙͚͚ÎgΛΛϜϜÐÑjÑžÒkÓlÓ Ô¡ÕnÖo×pØqÙrÚ§Üuݪßxázã|å~ç€é¶ì…ïˆò¿õÂøÅûûÿÿ9 = @CF|Kƒ… S!ˆ#V$‹%Œ'Z([)\*]*‘+’,_-`-”.a/b/b0c0c1d1d1d2e2e2e3f3f3f4g4g4g4g5h5h5h5h666i6i6i6i6i77777j7j7j7j7j8888888k8k8k8k8k99999999999l9l9l9l9l9l9l:::::::::::::::::m:m:m:m:m:m:m:m;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;n;n;n;n;n;n;n;n;n;n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÉÉÊÊÊÊÊÊÊÊËËËËËËÌÌÌÌÌÌÍÍÍÍÎÎÎÎÏÏÏÏÐÐÐÐÑÑÒÒÓÓÓÓÔÔÕÕÖÖ××ÙÙÚÚÜÜÝÝßßááããååèèêêííññôô÷÷ûûÿÿ  !!##$$&&''(())**++,,----..////0000111122222233333344444455555555666666666677777777777777888888888888888899999999999999999999::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<====================================================================================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÉÉÊÊÊÊÊÊËËËËËËÌÌÌÌÌÌÍÍÍÍÎÎÎÎÏÏÐÐÐÐÑÑÒÒÓÓÔÔÕÕÖÖ×רØÚÚÛÛÝÝßßááããææééììïïóó÷÷ûûÿÿ  ""##%%&&(())**++,,----..////00111122222233334444445555555566666666667777777777778888888888888899999999999999999999::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<========================================================================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂõÂõÂõÂõÂõÂõÂõÂõÂõÂõÂõÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃöÃöÃöÃöÃöÃöÃöÃöÃöÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ÷Ä÷Ä÷Ä÷Ä÷Ä÷Ä÷ÅÅÅÅÅÅÅÅÅÅÅøÅøÅøÅøÅøÅøÆÆÆÆÆùÆùÆùÆùÆùÇÇÇúÇúÇúÇúÇúÈÈÈûÈûÈûÈûÉüÉüÉüÊýÊýÊýË1ËþËþÌÿÌÿÎÎÏÏ5ÐÐ6Ñ7Ò8Ó9Ô:Õ;Ö<×=Ù?Ú@ÜBÞDàFâHåKèNëQï!ó%÷)û-ÿÿÖ Úªá±´¶†!»#½$¾&À'Á)Ã*Ä+Å,Æ-Ç-û.È/É/ý0Ê0þ1ÿ1ÿ333Í44555666677777778888888999999999999:::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;< < < < < < < < < < < <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<= = = = = = = = = = = = = ================================================================================================> > > > > > > > > > > > > > > > > > > > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁ'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂ(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃ)Ã)Ã)Ã)Ã)Ã)Ã)Ã)Ã)Ã)Ã)Ã)ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄ*Ä*Ä*Ä*Ä*Ä*Ä*Ä*Ä*ÄÄÄÄÄÄÄÄÄÄÅ+Å+Å+Å+Å+Å+Å+Å+ÅÅÅÅÅÅÆ,Æ,Æ,Æ,Æ,Æ,ÆÆÇ-Ç-Ç-Ç-Ç-Ç-È.È.È.È.È.É/É/É/É–Ê0Ê0Ê0Ë1Ë1˘Ì2Ì™Í3ÍšÎ4ΛÏ5ÏœÐÑžÒŸÓ Ô¡Õ¢× Ø¥Ú§ÜÞà­ã°æ³é¶íºñ¾ö\úúÿÿž £ §EHLOì!T#V%X&ô([)\+^,_-`.a.È/b0c0Ê1d1Ë2e2Ì3f3Í4g4Î4Î5h5Ï5Ï5Ï6Ð6Ð6Ð6Ð777Ñ7Ñ7Ñ7Ñ7Ñ8Ò8Ò8Ò8Ò8Ò8Ò99999Ó9Ó9Ó9Ó9Ó9Ó9Ó:::::::::Ô:Ô:Ô:Ô:Ô:Ô:Ô:Ô;;;;;;;;;;;;;;;;;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö=================================================================================×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>ØÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂ[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃ\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\Ã\ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄ]Ä]Ä]Ä]Ä]Ä]Ä]Ä]Ä]ÄÄÄÄÄÄÄÄÅ^Å^Å^Å^Å^Å^Å^ÅÅÅÅÆ_Æ_Æ_Æ_Æ_Æ_ÆÆÇ`Ç`Ç`Ç`Ç`ÈaÈaÈaÈaÈûÉbÉbÉüÊcÊcÊýËdËþÌeÌÿÍfÎÎgÏÐÑÒÓÔÕÖ£Ø¥Ú ÜÞ«á®ä±èìð"õ'ú“ÿÿl qÜáJNQ î#V%X'Z(ö)÷+^,ú-û.ü/–/ý0þ1˜1ÿ333š44›55œ5œ5œ66667ž7ž7ž7ž7ž8Ÿ8Ÿ8Ÿ8Ÿ8Ÿ999 9 9 9 9 9 9 :::::::¡:¡:¡:¡:¡:¡:¡:¡;;;;;;;;;;;;;¢;¢;¢;¢;¢;¢;¢;¢;¢;¢<<<<<<<<<<<<<<<<<<<<<<<<<<<<<£<£<£<£<£<£<£<£<£<£<£<£<£=====================================================================¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥??????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃđđđđđđđđđÄÄÄÄÅ’Å’Å’Å’Å’Å’Å’ÅÅÆ“ƓƓƓƓƓǔǔǔǔǔȕȕȕÉbÉ–É–ÊcÊ—ËdËdÌeÌeÍfÍfÎgÏhÐiÑ7Ò8ÓlÔmÖ<Ø>Ú@ÜBßEâHæLêPî‡óÀùÆÿÿ rª¯³· º"¼%¿'Á)*Ä+Å-”.•/–0—0—1˜2™2™3š4g4›4›5h5œ6i6i6i67j7j7j7ž8k8k8k8k8k9l9l9l9l9l9l:::::m:m:m:m:m:m:m:m;;;;;;;;;n;n;n;n;n;n;n;n;n;n<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÆÆÇÇÇÇÇÇÇÇÈÈÈÈÈÈÉÉÉÉÉÉÊÊÊÊËËËËÌÌÍÍÎÎÎÎÏÏÑÑÒÒÓÓÕÕ××ÙÙÜÜßßããççììòòøøÿÿ  ##%%((**++--..//0011222233444455556666667777777788888888999999999999::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==================================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÆÆÆÆÆÇÇÇÇÇÇÈÈÈÈÈÈÉÉÉÉÊÊËËËËÌÌÍÍÎÎÏÏÐÐÒÒÔÔÖÖØØÛÛßßããééïï÷÷ÿÿ ##&&))++--..//112222334455556666667777778888889999999999::::::::::::::;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<====================================================================>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿ò¿òÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÀóÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÁôÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂõÂõÂõÂõÂõÂõÂõÂõÂõÂõÂõÃÃÃÃÃöÃöÃöÃöÃöÃöÃöÃöÄ*Ä÷Ä÷Ä÷Ä÷Ä÷Å+ÅøÅøÅøÆ,Æ,ÆùÇ-Ç-ÇúÈ.È.É/ÉbÊ0Ë1ËdÌeÍfÎgϜўӠբإÛÛà­æ³í†ö\ÿÿ £EL#V'')\,_.a/–0—1˜2Ì3Í4›5œ5Ï6Ð6Ð77Ñ7Ñ8Ò8Ò8Ò99Ó9Ó:::::Ô;;;;;;;< < < < < < < < < < <<<<<<= = = = = = = = = = = = = = ==========================> > > > > > > > > > > > > > > > > > > > > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&À&ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁ'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'Á'ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂ(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(Â(ÂÂÂÂÃ)Ã)Ã)Ã)Ã)Ã)Ã)Ã)Ã)Ã)Ã)ÃÄ*Ä*Ä*Ä*Ä*đđđÅ+Å+Å’Å’Æ,ƓƓƓǔǔȕÈûÉ–ÉüÊýËþÌÿÎgÐiÑÑÔÔ××ÜBâHééô&ÿÿ Ù·##'Á++--/–0þ2™3š4›566i7j7j8k8k8k9l9l9Ó9Ó:m:m:Ô:Ô:Ô:Ô;n;n;Õ;Õ;Õ;Õ;Õ;Õ;Õ;Õ<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö<Ö===============×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×=×>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø>Ø????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿ÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀYÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁZÁÁÁÁÁÁÁÁÁÁÁÁÂ[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[Â[ÂõÂõÃ\Ã\Ã\Ã\Ã\Ã\ÃöÃöÃöÄ]Ä÷Ä÷Ä÷Ä÷Å’ÅøÆ“Æ“Ç”Ç”È•É/Ê0Ë1ÌÌÍÍÐiÓ× Ü©ä±ð‰ÿÿvN#V([,“//1133445h6i7j7j8k8k99l:::;;;;;¢;¢< < < < <£<£<£<£<£<£<£<£<£<£=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤=¤>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥>¥????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÁŽÂ[Â[Â[Â[Â[ÂÂÂÂÃ\Ã\Ã\Ã\Ã\Ã\Ä*Ä]Ä]Å+Å+ÅøÆ,ÆùÇÇÈÈÉɢÍfÑÕ¢ÝCêPÿÿ¯"¼**.ü1˜3š5h78899Ó9Ó:Ô:Ô:Ô;¢;¢;¢;¢<£<£<£<£<£<£=p=p=p=p=p=p=p=p=p=p=p=p=p=p>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q>q??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÂÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÄÄÅÅÆÆÇÇÉÉÌÌÒÒßßÿÿ --22667799::::;;;;<<<<<<==============>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾ñ¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$½V½V½V½V½V¼‰¼‰¼‰»»ºíº ¹R··µN°}¦ Y&NµJ±GzF­EDDDDCvCvB©B©B©AÛAÛAÛAÛAÛAÛAÛAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¿%¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$½Š½Š½Š½Š½Š½Š½#½#½#¼‰¼‰¼‰¼‰¼‰¼‰»î»ˆ»ˆºíºíºS¹ì¹R¸¸··¶¶µ³€°I¬¤×—Êg4Z'SSNµLJ}HâG®F­F­E¬EEDDDCvCvCvCvBuBuBuBuBuBuBuAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛ@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¿X¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W½½½½½½½½½½½V½V½V½V½V½V½V½V½V½V½V½V½V½V¼ï¼ï¼U¼U¼U¼U¼U¼U»î»î»î»T»Tºíºíºíº‡¹ì¹†¹†¸…¸…·„·¶µ³³²²°I­à©Ü¤qœi)nÕb•ZUˆQ¸OOMMKKJJI|H{GzGzFyFyFExEEEDDDDCªCªCªCCCB©B©B©B©B©B©B©B©B©B©A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¿Œ¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š¼¼¼¼¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼U»ˆ»ˆ»ˆ»ˆ»ˆ»T»T»Tº‡º‡ºSºSºS¹R¹R¹R¸Q¸Q·P·¶O¶µ´³±ä¯â®®««¨¨¤qžk––‹òs hh`“[[V‰SSQQOMçLKJIãHâH¯G®G®F­F­F­E¬E¬ExExD«D«DwDwDwDwCªCªCvCvCvCvCvCvCvCvBuBuBuBuBuBuBuBuBuBuBuBuBuBuBBBBBBBBBBBBAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»ºººººººººººº¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸······¶¶¶¶µµ´´´´³³²²±±°°®®¬¬ªª§§¤¤ŸŸ™™’’‰‰uullee__[[WWUURRPPOONNMMLLKKJJIIIIHHHHHHGGGGFFFFFFFFEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸······¶¶¶¶¶¶µµµµ´´³³³³²²±±°°¯¯®®¬¬ªª¨¨¦¦££ŸŸ››••‡‡wwppiidd__\\YYVVTTRRQQPPNNMMMMLLKKKKJJIIIIIIHHHHHHGGGGGGFFFFFFFFFFEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»î»î»î»î»î»î»î»î»î»î»î»î»»»»»»»»ºíºíºíºíºíºíºíºíºíºº¹ì¹ì¹ì¹ì¹ì¹ì¹¸ë¸ë¸ë¸ë¸¸·ê·ê··¶é¶¶µèµµ´´³²±J±°®G­F¬EªC¨A¦?£p mœi˜e“,&†¹yr kÒfÍb•^Å[ÂYŒV½T»SºQëP·O¶NèMçLæLæKåJäJäJIãIIHâHHGáGáGGGFàFFFFFFEEEEEEEEDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½#½#½#½#½#½#½#½#½#½#½#½#½#½#½#½#¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼"¼"¼"¼"¼"¼"¼"¼"¼"¼"¼"»»»»»»»»»»»»»»»!»!»!»!»!»!»!»!»!ººººº º º º º º º º ¹¹¹¹¹¹¸¸¸¸¸···¶ƒ¶¶µ‚µ´´´³€²²±~°}¯|®á­à¬y«x©Ü§Ú¥Ø£Ö ÓЙ̕ȑ^‹ò…ìyys¦n;i6e2a.^+\)Y&W$V#T!S Q„PƒO‚NNM€LLK~JäJ}J}IãI|HâHâHâH{GáGáGáGzFàFàFàFàFàEßEßEßEßEßEßEßEEDÞDÞDÞDÞDÞDÞDÞDÞDDDDDDDDCÝCÝCÝCÝCÝCÝCÝCÝCÝCÝCCCCCCCCCCCCCCCCCCCCCCBÜBÜBÜBÜBÜBÜBÜBÜBÜBÜBÜBÜBÜBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@Ú@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½V½V½V½V½V½V½V½V½V½V½V½V½V½V½V½V¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼U¼U¼U¼U¼U¼U¼U¼U¼U¼U¼U¼U»»»»»»»»»»»»»»»»»»»T»T»T»T»T»T»T»T»TºººººººººSºSºSºSºSºSºS¹¹¹¹¹R¹R¹R¹R¹R¹R¸¸¸Q¸Q¸Q¸Q¸Q·P·P·P·P¶é¶O¶OµèµNµN´ç´M³æ³L²å²å±ä±J°ã¯â®á­à¬ß«ÞªÝ©v§t¥Ø£Ö¡nžk›h—Ê“ÆÂн…yàtÛp=k8gšc–`“^+[ŽYŒX%V#U"S†RQPO¶ONM´MLLK²KJ±JI°I°I°H¯H¯H¯H¯G®G®G®G®G®F­F­F­F­F­FFFFE¬E¬E¬E¬E¬E¬EEEEEED«D«D«D«D«D«D«D«DDDDDDDDDDDDCªCªCªCªCªCªCªCªCªCªCªCCCCCCCCCCCCCCCCCCCCCCCCCCB©B©B©B©B©B©B©B©B©B©B©B©B©B©BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBA¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@§@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰»»»»»»»»»»»»»»»»»»»»»»»»»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆººººººººººººº‡º‡º‡º‡º‡º‡º‡¹¹¹¹¹¹¹†¹†¹†¹†¹†¹†¸¸¸…¸…¸…¸…¸…¸…·„·„·„·„·„¶ƒ¶ƒ¶ƒ¶ƒµ‚µ‚µ‚´´´M³€³L²²K±~±J°}°I¯H®G­F¬E«DªC©§@¥>¤ ¢Ÿ8œ5™2–/’+Ž'‰V„„z­u¨q¤lÓiÐeÌbÉ_ù]Ä[ÂYÀWñV½U¼SºR¹Q¸P·PƒO¶NµNM´M€L³LK²K~J±J}J}I°I|I|I|H{H{H{H{HHGzGzGzGzGzFyFyFyFyFyFyFFFFExExExExExExExEEEEEEEEDwDwDwDwDwDwDwDwDDDDDDDDDDDDDDDDDDCvCvCvCvCvCvCvCvCvCvCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBuBuBuBuBuBuBuBuBuBuBuBuBuBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸············¶¶¶¶¶¶¶¶¶¶µµµµµµµµ´´´´´´³³³³²²²²±±±±°°°°¯¯¯¯®®­­¬¬««ªª©©¨¨¦¦¥¥££¡¡ŸŸšš——””ŒŒˆˆ„„{{vvrrnnkkggddbb__]][[ZZXXWWUUTTSSRRQQQQPPOOOONNNNMMMMLLLLKKKKKKJJJJJJIIIIIIIIHHHHHHHHHHHHGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸············¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµ´´´´´´³³³³³³²²²²²²±±±±°°°°¯¯®®®®­­¬¬««ªª©©¨¨§§¦¦¤¤££¡¡ŸŸ››˜˜••’’‹‹‡‡ƒƒ{{wwsspplliiffddbb__]]\\ZZYYWWVVUUTTSSRRRRQQPPPPOONNNNMMMMMMLLLLKKKKKKKKJJJJJJIIIIIIIIIIHHHHHHHHHHHHGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½ð½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»î»î»î»î»î»î»î»î»î»î»î»î»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºíºíºíºíºíºíºíºíºíºººººººººººººººººº¹ì¹ì¹ì¹ì¹ì¹ì¹ì¹¹¹¹¹¹¹¹¹¹¸ë¸ë¸ë¸ë¸ë¸ë¸ë¸¸¸¸¸¸·ê·ê·ê·ê·ê····¶é¶é¶é¶é¶¶µèµèµèµèµè´ç´ç´ç´ç³æ³æ³æ²å²å²å±ä±ä±°ã°¯â¯®á­à­¬«ÞªÝ©Ü¨Û§Ú¦ ¥ £Ö¢ žœš–ý”Ç‘Äô퇇ƒƒ|IxEtAq>nkheÿc0`ú^ø]÷[õZôXòWñVðUïTîSíS RQëQPOéONèNNMMLæLLLKKKJJJJIIIIIIHHHHHHHHHGGGGGGGGGGFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$¾$½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½#½#½#½#½#½#½#½#½#½#½#½#½#½#½#½#½#¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼"¼"¼"¼"¼"¼"¼"¼"¼"¼"¼"»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»!»!»!»!»!»!»!»!»!ººººººººººººººººººººººº º º º º º º ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸·········¶¶¶¶¶¶µµµµµµ´´´´³³³²²±~±±°°¯®{®­z¬y¬«ªw©v¨u§t¦s¥ £p¢o mžkœišg˜e•ü“`]Œó‰ð†íƒƒ||yur oliœgd—b•`“^ø][õZYŒWñVðUïTîT‡S†RìQëQ„PêOéOéNèNèMçMçMçLæLæLæKåKåKåJäJäJäJäIãIãIãIãIIHâHâHâHâHâHHHHGáGáGáGáGáGGGGGGFàFàFàFàFàFFFFFFFFFFEßEßEßEßEßEßEßEEEEEEEEEEEEEEEEDÞDÞDÞDÞDÞDÞDÞDÞDÞDDDDDDDDDDDDDDDDDDDDDDDDDDDDCÝCÝCÝCÝCÝCÝCÝCÝCÝCÝCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBÜBÜBÜBÜBÜBÜBÜBÜBÜBÜBÜBÜBÜBÜBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAÛAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W¾W½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½V½V½V½V½V½V½V½V½V½V½V½V½V½V½V½V¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼U¼U¼U¼U¼U¼U¼U¼U¼U¼U¼U¼U»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»T»T»T»T»T»T»T»T»TºººººººººººººººººººººººººSºSºSºSºSºSºSºS¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹R¹R¹R¹R¹R¹R¸¸¸¸¸¸¸¸¸¸¸Q¸Q¸Q¸Q¸Q·······P·P·P·P·P¶¶¶¶¶O¶O¶O¶OµµµNµNµNµN´´´M´M´M³³³L³L³L²K²K²K±J±J°I°I¯â¯H®á®G­F­F¬E«DªÝªC©B¨A§@¦?¤×£Ö¢; ÓŸ86›4™2—0”Ç’+(Œ%‰"†ƒ||yyuÜrÙoÖm:jÑh5f3d1b/`-^Å]*[ÂZÁY&X%W$V#U¼T»SºS R¹Q¸QP·PO¶ONµNµM´M´M´L³L³L³K²K²K²KKJ±J±J±JJI°I°I°I°IIIIH¯H¯H¯H¯HHHHHHG®G®G®G®G®GGGGGGF­F­F­F­F­F­FFFFFFFFFFFFE¬E¬E¬E¬E¬E¬E¬EEEEEEEEEEEEEEEEEEEED«D«D«D«D«D«D«D«DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCªCªCªCªCªCªCªCªCªCªCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCB©B©B©B©B©B©B©B©B©B©B©B©B©BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBA¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹¾‹½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆººººººººººººººººººººººººººººº‡º‡º‡º‡º‡º‡º‡¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹†¹†¹†¹†¹†¹†¸¸¸¸¸¸¸¸¸¸¸¸¸…¸…¸…¸…¸…·········„·„·„·„¶¶¶¶¶¶¶ƒ¶ƒ¶ƒ¶ƒµµµµµ‚µ‚µ‚´´´´´´³³³€³€³€²²²±~±~±~°}°}¯|¯|®{®{­z­z¬y¬E«xªw©v©B¨A§@¦?¥>£p¢o¡:Ÿlž7œ5š3˜1–/“`‘^Ž[‹‹ˆˆ……‚‚||yyv©s¦p£n¡kžiœgše˜c–a”_Æ^‘\Ã[ÂZYŒX‹WŠV‰U¼T»T‡S†R¹R…Q„Q„PƒPƒO‚O‚NNNM€M€MMLLLK~K~K~KKJ}J}J}J}JJI|I|I|I|IIIIH{H{H{H{H{HHHHHHGzGzGzGzGzGGGGGGGGFyFyFyFyFyFyFFFFFFFFFFFFFFExExExExExExExEEEEEEEEEEEEEEEEEEEEEEDwDwDwDwDwDwDwDwDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCvCvCvCvCvCvCvCvCvCvCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBuBuBuBuBuBuBuBuBuBuBuBuBuBuBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··················¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´³³³³³³³³³³²²²²²²±±±±±±°°°°°°¯¯¯¯®®®®­­­­¬¬¬¬««ªªªª©©¨¨§§¦¦¥¥¤¤££¢¢¡¡ŸŸžžœœšš˜˜––””’’‹‹ˆˆ……‚‚||yywwttqqoolljjhhffddbbaa__^^]][[ZZYYXXWWWWVVUUTTTTSSRRRRQQQQPPPPOOOOOONNNNMMMMMMMMLLLLLLKKKKKKKKKKJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµ´´´´´´´´´´³³³³³³³³²²²²²²²²±±±±±±°°°°°°¯¯¯¯¯¯®®®®­­­­¬¬¬¬««ªªªª©©¨¨¨¨§§¦¦¥¥¤¤££¢¢  ŸŸžžœœ››™™——••““‘‘ŒŒŠŠ‡‡……‚‚}}zzwwuurrppnnkkiiggffddbbaa__^^]]\\[[ZZYYXXWWVVUUUUTTSSSSRRRRQQQQPPPPPPOOOONNNNNNMMMMMMMMLLLLLLLLKKKKKKKKKKJJJJJJJJJJIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»î»î»î»î»î»î»î»î»î»î»î»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºíºíºíºíºíºíºíºíºíºººººººººººººººººººººººººººººººººº¹ì¹ì¹ì¹ì¹ì¹ì¹ì¹ì¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸ë¸ë¸ë¸ë¸ë¸ë¸¸¸¸¸¸¸¸¸¸¸¸¸¸·ê·ê·ê·ê·ê··········¶é¶é¶é¶é¶é¶¶¶¶¶¶µèµèµèµèµèµµµµ´ç´ç´ç´ç´´´´³æ³æ³æ³³²å²å²å²²±ä±ä±ä±±°ã°ã°°¯â¯â®á®á®á­à­à¬ß¬ß«Þ«ÞªÝ©Ü©Ü¨Û§Ú§ ¦ ¥Ø¤×£Ö¢Õ¡ŸÒžÑ›Îš˜Ë–ɔǒÅÃŽÁŒŒ‰¼‡‡„·‚‚}}zzxEuus@q>o¤=£<¢;¡: 9Ÿ8ž7œÏ›4š3˜1—0•.“,‘*(&‹$‰"††„„‚‚}}{{xßvvttqØoÖmÔkÒjÑhÏfÍeÌcÊbÉaÈ`-^Å]Ä\Ã[ÂZÁYÀYÀX¿W¾V½V½U¼T»T»SºSºR¹R¹Q¸Q¸QQP·P·O¶O¶O¶NµNµNµNNM´M´M´MML³L³L³LLK²K²K²K²KKKKJ±J±J±JJJJJJI°I°I°I°IIIIIIIIH¯H¯H¯H¯HHHHHHHHHHHHG®G®G®G®G®GGGGGGGGGGGGGGF­F­F­F­F­F­FFFFFFFFFFFFFFFFFFFFFFE¬E¬E¬E¬E¬E¬EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEED«D«D«D«D«D«D«D«DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCªCªCªCªCªCªCªCªCªCªCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCB©B©B©B©B©B©B©B©B©B©B©B©B©B©BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBA¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨A¨½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š½Š¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆººººººººººººººººººººººººººººººººººººººººººººº‡º‡º‡º‡º‡º‡º‡º‡¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹†¹†¹†¹†¹†¹†¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸…¸…¸…¸…¸…···············„·„·„·„·„¶¶¶¶¶¶¶¶¶¶¶ƒ¶ƒ¶ƒ¶ƒµµµµµµµµµ‚µ‚µ‚µ‚´´´´´´´´³³³³³€³€³€²²²²²²±±±±±~±~°°°}°}°}¯|¯|¯|®{®{­­­z­z¬y¬y«x«xªwªw©v¨u¨u§t¦s¦s¥r¤q£p¢o¡n mŸlžkj›hšg™f—d–c”a’_]ŽŽŒŒŠŠˆˆ††„„‚O}}{{yyv©t§r¥p£n¡lŸkžiœgšf™d—c–b•a”_’^‘]\[ŽZÁZYŒX‹WŠWŠV‰UˆUˆT‡T‡S†S†R…R…Q„Q„Q„PƒPƒPPO‚O‚OONNNNNM€M€MMMMLLLLLLLK~K~K~KKKKJ}J}J}J}JJJJJJI|I|I|I|IIIIIIIIH{H{H{H{H{HHHHHHHHHHHHGzGzGzGzGzGGGGGGGGGGGGGGGGFyFyFyFyFyFyFFFFFFFFFFFFFFFFFFFFFFExExExExExExExEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDwDwDwDwDwDwDwDwDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCvCvCvCvCvCvCvCvCvCvCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBuBuBuBuBuBuBuBuBuBuBuBuBuBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµ´´´´´´´´´´´´³³³³³³³³³³³³²²²²²²²²²²±±±±±±±±°°°°°°¯¯¯¯¯¯®®®®®®­­­­­­¬¬¬¬««««ªªªª©©©©¨¨§§§§¦¦¥¥¥¥¤¤££¢¢¡¡  ŸŸžžœœšš™™˜˜––••““‘‘ŽŽŒŒŠŠˆˆ††„„}}{{yywwuussqqoommlljjhhggeeddccbb``__^^]]\\\\[[ZZYYXXXXWWVVVVUUUUTTTTSSSSRRRRRRQQQQPPPPPPOOOOOOOONNNNNNMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKKJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´³³³³³³³³³³³³²²²²²²²²²²±±±±±±±±°°°°°°°°¯¯¯¯¯¯®®®®®®­­­­­­¬¬¬¬««««ªªªª©©©©¨¨¨¨§§§§¦¦¥¥¤¤¤¤££¢¢¡¡  ŸŸžžœœ››™™˜˜——••””’’‹‹‰‰‡‡……ƒƒ}}{{yywwuussrrppnnllkkiihhffeeddccbb``__^^]]]]\\[[ZZYYYYXXWWWWVVVVUUUUTTTTSSSSRRRRRRQQQQPPPPPPPPOOOOOONNNNNNNNMMMMMMMMMMLLLLLLLLLLKKKKKKKKKKKKKKJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼ï¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»î»î»î»î»î»î»î»î»î»î»î»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºíºíºíºíºíºíºíºíºíºººººººººººººººººººººººººººººººººººººººººººººººººººº¹ì¹ì¹ì¹ì¹ì¹ì¹ì¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸ë¸ë¸ë¸ë¸ë¸ë¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·ê·ê·ê·ê·ê·ê················¶é¶é¶é¶é¶¶¶¶¶¶¶¶¶¶¶¶µèµèµèµèµèµµµµµµµµ´ç´ç´ç´ç´´´´´´³æ³æ³æ³æ³³³³³³²å²å²å²²²²±ä±ä±ä±±°ã°ã°ã°°¯â¯â¯â¯¯®á®á®®­à­à­­¬ß¬ß«Þ«Þ««ªÝªª©Ü©©¨Û§Ú§Ú¦Ù¦Ù¥Ø¤×£Ö£Ö¢Õ¡Ô ÓŸÒžÑМϛΚ͘˗ʖɔǓƑĎÁŒ¿‹‹‰‰‡‡……ƒƒ}}{{yyxEvCtArrppo¥>¤=£<£<¢;¡: 9Ÿ8ž76œ5›4š3™2˜1–/•.”-’+‘*(Œ%ŠŠˆˆ‡ ……ƒƒ}}||zzxxvÝtÛssqØoÖnÕlÓkÒjjhÏgÎfÍeecÊbÉaÈ`Ç_Æ^Å^Å]Ä\Ã[Â[[ZÁYÀYYX¿W¾W¾V½V½U¼U¼T»T»SºSºSSR¹R¹RRQ¸Q¸QQP·P·PPO¶O¶O¶OONµNµNµNNNNM´M´M´MMMML³L³L³LLLLLLK²K²K²KKKKKKKKJ±J±J±JJJJJJJJJJI°I°I°I°IIIIIIIIIIIIH¯H¯H¯H¯H¯HHHHHHHHHHHHHHHHG®G®G®G®G®GGGGGGGGGGGGGGGGGGGGGGF­F­F­F­F­F­FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE¬E¬E¬E¬E¬E¬E¬EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEED«D«D«D«D«D«D«D«DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCªCªCªCªCªCªCªCªCªCªCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCB©B©B©B©B©B©B©B©B©B©B©B©B©B©BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº‡º‡º‡º‡º‡º‡º‡¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹†¹†¹†¹†¹†¹†¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸…¸…¸…¸…¸…¸…·····················„·„·„·„¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ƒ¶ƒ¶ƒ¶ƒµµµµµµµµµµµµµ‚µ‚µ‚µ‚´´´´´´´´´´´´³³³³³³³€³€³€²²²²²²²²²±±±±±~±~±~°°°°°}°}¯¯¯¯¯|¯|®®®{®{®{­­­z­z¬y¬y«««x«xªªªw©©©v¨¨¨u§§§t¦s¦s¥r¤¤¤q£p¢¢¢o¡n mŸlžkjœi›hšg™f˜e—d••”a“`‘‘]ŽŽZ‹‹ŠWˆˆ††…Rƒƒ}°||zzx«wwuus¦rrp£oom lljiœh›gge˜d—c–b•a”`“_’__^‘]\[Ž[ŽZYŒYŒX‹XXWŠWWV‰VVUˆUUT‡T‡S†S†SSR…R…RRQ„Q„QQPƒPƒPPPPO‚O‚OOOONNNNNNNNM€M€MMMMMMLLLLLLLLLK~K~K~KKKKKKKKJ}J}J}J}JJJJJJJJJJI|I|I|I|IIIIIIIIIIIIIIH{H{H{H{HHHHHHHHHHHHHHHHHHGzGzGzGzGzGGGGGGGGGGGGGGGGGGGGGGGGFyFyFyFyFyFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFExExExExExExExEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDwDwDwDwDwDwDwDwDwDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCvCvCvCvCvCvCvCvCvCvCvCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBuBuBuBuBuBuBuBuBuBuBuBuBuBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®­­­­­­­­¬¬¬¬««««««ªªªªªª©©©©¨¨¨¨§§§§¦¦¥¥¥¥¤¤¤¤££¢¢¢¢¡¡  ŸŸžžœœ››šš™™˜˜——––••““’’‘‘ŽŽŒŒ‹‹‰‰ˆˆ††„„ƒƒ~~||zzyywwuuttrrqqoonnllkkjjiiggffeeddccbbaa``____^^]]\\\\[[ZZZZYYXXXXWWWWVVVVUUUUUUTTTTSSSSSSRRRRRRQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLLLKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­­¬¬¬¬¬¬««««ªªªªªª©©©©¨¨¨¨§§§§¦¦¦¦¥¥¥¥¤¤££££¢¢¡¡¡¡  ŸŸžžœœ››šš™™——––••””““‘‘ŒŒŠŠ‰‰‡‡††„„‚‚~~||zzyywwvvttssqqppnnmmllkkiihhggffeeddccbbaa``____^^]]\\\\[[ZZZZYYYYXXXXWWWWVVVVUUUUTTTTTTSSSSSSRRRRRRQQQQQQQQPPPPPPPPOOOOOOOONNNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»î»î»î»î»î»î»î»î»î»î»î»î»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºíºíºíºíºíºíºíºíºíºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹ì¹ì¹ì¹ì¹ì¹ì¹ì¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸ë¸ë¸ë¸ë¸ë¸ë¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·ê·ê·ê·ê·ê······················¶é¶é¶é¶é¶é¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µèµèµèµèµµµµµµµµµµµµ´ç´ç´ç´ç´´´´´´´´´´³æ³æ³æ³æ³³³³³³³³²å²å²å²²²²²²±ä±ä±ä±±±±±±°ã°ã°ã°°°°¯â¯â¯¯¯¯®á®á®®®®­à­à­­¬ß¬ß¬ß¬¬«Þ«ÞªÝªÝªª©Ü©Ü©©¨Û¨¨§Ú§§¦Ù¦¦¥Ø¥¥¤×£Ö££¢Õ¡Ô¡¡ ÓŸÒžÑžžœÏ›ÎšÍ™Ì˜Ë——––”Ǔƒő‘ÂŽÁ‹¾ŠŠˆ»‡‡…¸„„‚‚~~||{HyyxEvvuBssr?ppo¤¤¤=£<£<¢;¡¡¡: 9Ÿ8žžž76œ5›4š3™2˜1—0–/•.”-“,‘‘(Ž'ŒŒ‹‹Š#ˆˆ‡ ……„„‚‚~~||{{yyxxvÝuuttrÙqqppnÕmÔllkkjjhÏgÎfÍeÌdËddccbbaÈ`Ç_Æ__^Å]Ä]]\Ã[Â[[ZÁZZYÀYYX¿XXW¾WWV½V½U¼U¼UUT»T»TTSºSºSSR¹R¹RRQ¸Q¸QQQQP·P·PPPPO¶O¶O¶OOOONµNµNµNNNNNNM´M´MMMMMMMML³L³L³LLLLLLLLK²K²K²KKKKKKKKKKKKJ±J±J±JJJJJJJJJJJJJJI°I°I°I°IIIIIIIIIIIIIIIIH¯H¯H¯H¯H¯HHHHHHHHHHHHHHHHHHHHHHG®G®G®G®G®GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGF­F­F­F­F­FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE¬E¬E¬E¬E¬E¬E¬EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEED«D«D«D«D«D«D«D«DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCªCªCªCªCªCªCªCªCªCªCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰¼‰»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº‡º‡º‡º‡º‡º‡º‡¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹†¹†¹†¹†¹†¹†¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸…¸…¸…¸…¸…¸…···························„·„·„·„·„¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ƒ¶ƒ¶ƒ¶ƒµµµµµµµµµµµµµµµµµ‚µ‚µ‚µ‚´´´´´´´´´´´´´´´³³³³³³³³³³³€³€³€³€²²²²²²²²²²±±±±±±±±±~±~±~°°°°°}°}°}¯¯¯¯¯|¯|®®®®®{®{®{­­­z­z¬¬¬¬¬y¬y«««x«xªªªwªw©©©v¨¨¨u¨u§t§t¦¦¦s¥¥¥r¤q¤q£p¢¢¢o¡n¡n mŸlžžžkjœi›hšš™™˜˜——––••””““’’‘^]ŽŽŒY‹X‰‰ˆˆ††……„Q‚‚~~||{{y¬xxwwu¨ttssq¤p£oonnlŸkžjiœh›gšf™e˜d—c–b•bba”`“_’__^‘]]]\[Ž[ŽZZZYŒYYX‹XXWŠWŠWWV‰VVUˆUˆUUT‡TTTTS†S†SSR…R…RRQ„Q„Q„QQPƒPƒPƒPPPPO‚O‚OOOOOONNNNNNNNM€M€M€MMMMMMMMLLLLLLLLLLLK~K~K~K~KKKKKKKKKKJ}J}J}J}JJJJJJJJJJJJJJI|I|I|I|IIIIIIIIIIIIIIIIIIH{H{H{H{HHHHHHHHHHHHHHHHHHHHHHHHGzGzGzGzGzGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFyFyFyFyFyFyFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFExExExExExExEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDwDwDwDwDwDwDwDwDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCvCvCvCvCvCvCvCvCvCvCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬««««««ªªªªªª©©©©©©¨¨¨¨§§§§¦¦¦¦¦¦¥¥¥¥¤¤££££¢¢¢¢¡¡    ŸŸžžžžœœ››šššš™™˜˜——––••””““’’ŽŽ‹‹ŠŠ‰‰ˆˆ††……ƒƒ‚‚~~||{{zzxxwwvvttssrrqqoonnmmllkkjjiihhggffeeddccbbbbaa``____^^]]]]\\\\[[ZZZZYYYYXXXXXXWWWWVVVVVVUUUUTTTTTTTTSSSSSSRRRRRRRRQQQQQQQQPPPPPPPPOOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬««««««ªªªªªª©©©©©©¨¨¨¨¨¨§§§§¦¦¦¦¥¥¥¥¤¤¤¤££££¢¢¢¢¡¡    ŸŸžžžžœœ››››šš™™˜˜——––••””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰‡‡††……ƒƒ‚‚~~}}{{zzyywwvvuussrrqqppoonnllkkjjiihhggffffeeddccbbbbaa``____^^]]]]\\\\[[[[ZZZZYYYYXXXXWWWWWWVVVVUUUUUUTTTTTTSSSSSSSSRRRRRRRRQQQQQQQQPPPPPPPPPPOOOOOOOOOONNNNNNNNNNNNMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼¼¼¼»î»î»î»î»î»î»î»î»î»î»î»î»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºíºíºíºíºíºíºíºíºíºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹ì¹ì¹ì¹ì¹ì¹ì¹ì¹ì¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸ë¸ë¸ë¸ë¸ë¸ë¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·ê·ê·ê·ê·ê······························¶é¶é¶é¶é¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µèµèµèµèµµµµµµµµµµµµµµµµ´ç´ç´ç´ç´´´´´´´´´´´´´´³æ³æ³æ³æ³³³³³³³³³³²å²å²å²²²²²²²²²²±ä±ä±ä±±±±±±°ã°ã°ã°°°°°°¯â¯â¯â¯¯¯¯¯¯®á®á®®®®­à­à­­­­¬ß¬ß¬¬¬¬«Þ«Þ««ªÝªÝªªªª©Ü©©¨Û¨Û¨¨§Ú§Ú§§¦Ù¦¦¥Ø¥¥¤×¤¤£Ö££¢Õ¢¢¡Ô Ó  ŸÒžÑžžÐœÏœœ››šÍ™Ì˜Ë—Ê——––••””““’’ÃÂŽÁÀŒŒ‹‹ŠŠˆ»‡‡††„·ƒƒ‚‚~~}}{{zzyywwvvuutAs@qqppoonnm:l9k8j7i6h5g4ffeee2d1c0bbaaa.`-___,^+^+]*\\\)[[[(ZZZ'YYY&XXX%X%WWW$VVV#V#UUU"U"TTT!T!SSSSS S RRRRRRQQQQQQPPPPPPPPOOOOOOOOONNNNNNNNNMMMMMMMMMMMLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC¼"¼"»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»!»!»!»!»!»!»!»!»!ººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº º º º º º º ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³²²²²²²²²²²²²²±±±±±±±±±±°°°°°°°°°°¯¯¯¯¯¯¯¯¯®®®®®®­­­­­­¬¬¬¬¬¬«««««ªªªªªª©©©¨¨¨¨¨§§§ § ¦ ¦ ¥¥¥ ¤¤¤ £££ ¢¢¢¡   Ÿžžžœœœ›š™™˜˜——–ý•ü”û“ú’ù‘øŽŽŒŒŠñ‰ðˆˆ‡‡††„„ƒƒ‚‚~~}}{{zzyyxwuuttssr q p ommllkkjjjihgeÿeeddcýbüaûaa`ú_ù__^ø^^]÷\ö\\[õ[[ZôZZYóYYXòXòXXWñWWVðVðVVUïUïUUTîTîTTSíSíSSSSRìRìRRRRQëQëQQQQPêPêPPPPPPOéOéOOOOOOOONèNèNNNNNNNNMçMçMçMMMMMMMMLæLæLæLLLLLLLLLLKåKåKåKåKKKKKKKKKKKKJäJäJäJäJJJJJJJJJJJJJJJJIãIãIãIãIIIIIIIIIIIIIIIIIIIIHâHâHâHâHâHHHHHHHHHHHHHHHHHHHHHHHHHHGáGáGáGáGáGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFàFàFàFàFàFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEßEßEßEßEßEßEßEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDÞDÞDÞDÞDÞDÞDÞDÞDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCÝCÝCÝCÝCÝCÝCÝCÝCÝCÝCÝCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»T»T»T»T»T»T»T»T»TºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººSºSºSºSºSºSºS¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹R¹R¹R¹R¹R¹R¹R¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸Q¸Q¸Q¸Q¸Q·································P·P·P·P·P¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶O¶O¶O¶OµµµµµµµµµµµµµµµµµµµµµNµNµNµN´´´´´´´´´´´´´´´M´M´M´M³³³³³³³³³³³³³L³L³L²²²²²²²²²²²K²K²K±±±±±±±±±J±J±J°°°°°°°I°I°I¯¯¯¯¯¯¯H¯H®®®®®®®G®G­­­­­F­F¬¬¬¬¬E¬E«««««D«DªªªCªC©©©B©B¨¨¨A¨A§§§@¦¦¦?¥¥¥>¥>¤¤¤=£££<¢;¢;¡:   9ŸŸžžž7œœœ5›4šš™™™2˜1—0–/•.””““’’‘‘(Ž'&Œ%ŠŠ‰‰ˆˆ‡‡†„„ƒƒ‚‚~~}}{âzzyyxxwwuÜttssrrqqppoomÔlÓkÒjÑjjiihhggfÍeÌdËddccbÉaÈaa`Ç_Æ__^Å^^]Ä\Ã\Ã[Â[ÂZÁZÁYÀYÀYYX¿XXW¾W¾WWV½VVVVU¼UUUUT»TTTTSºSºSSSSR¹R¹RRRRQ¸Q¸QQQQP·P·P·PPPPO¶O¶O¶OOOOOONµNµNµNNNNNNNNM´M´MMMMMMMMMML³L³L³LLLLLLLLLLLLK²K²K²KKKKKKKKKKKKKKJ±J±J±JJJJJJJJJJJJJJJJJJI°I°I°I°IIIIIIIIIIIIIIIIIIIIIIH¯H¯H¯H¯HHHHHHHHHHHHHHHHHHHHHHHHHHHHG®G®G®G®G®GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGF­F­F­F­F­F­FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE¬E¬E¬E¬E¬E¬EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEED«D«D«D«D«D«D«D«DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCªCªCªCªCªCªCªCªCªCªCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº‡º‡º‡º‡º‡º‡º‡º‡¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹†¹†¹†¹†¹†¹†¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸…¸…¸…¸…¸…···································„·„·„·„¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ƒ¶ƒ¶ƒ¶ƒµµµµµµµµµµµµµµµµµµµµµ‚µ‚µ‚µ‚´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³€³€³€²²²²²²²²²²²²²±±±±±±±±±~±~±~°°°°°°°°°}°}¯¯¯¯¯¯¯¯¯|¯|®®®®®®®{®{­­­­­z­z¬¬¬¬¬y¬y«««««x«xªªªwªw©©©©©v¨¨¨¨¨u§§§t§t¦¦¦s¥¥¥r¤¤¤q¤q£p£p¢o¡¡¡n   mŸŸŸlžkjœi›hšššg™f˜e——––••”””a“`’_‘^]ŽŽŒŒ‹‹ŠŠ‰‰ˆU‡T……„„ƒƒ‚‚€€~~}}||z­yyxxwwvvt§s¦r¥qqppoonnmmllkkjiœh›gšggffe˜d—c–ccb•a”aa`“_’__^‘^^]]]\\\[Ž[[ZZZYŒYYX‹X‹XXWŠWWV‰V‰VVUˆUˆUUT‡T‡TTTTS†S†SSSSR…R…RRRRQ„Q„QQQQQQPƒPƒPPPPPPO‚O‚OOOOOOOONNNNNNNNNNM€M€M€MMMMMMMMMMLLLLLLLLLLLLLLLK~K~K~KKKKKKKKKKKKKKJ}J}J}J}JJJJJJJJJJJJJJJJJJI|I|I|I|IIIIIIIIIIIIIIIIIIIIIIH{H{H{H{HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGzGzGzGzGzGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFyFyFyFyFyFyFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFExExExExExExExEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDwDwDwDwDwDwDwDwDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCvCvCvCvCvCvCvCvCvCvCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸············································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªª©©©©©©©©¨¨¨¨¨¨§§§§¦¦¦¦¦¦¥¥¥¥¤¤¤¤££££¢¢¢¢¡¡¡¡    ŸŸŸŸžžœœ››šššš™™˜˜————––••””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰‡‡††……„„ƒƒ‚‚€€~~}}||{{yyxxwwvvuuttssqqppoonnmmllkkkkjjiihhggffffeeddccccbbaaaa``____^^^^]]]]\\\\[[[[ZZZZYYYYYYXXXXWWWWWWVVVVVVUUUUUUTTTTTTTTSSSSSSSSRRRRRRRRQQQQQQQQQQPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··············································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬««««««««ªªªªªªªª©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¥¥¥¥¥¥¤¤¤¤££££¢¢¢¢¡¡¡¡    ŸŸŸŸžžœœ››››šš™™˜˜˜˜——––••””““““’’‘‘ŽŽŒŒ‹‹‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{yyxxwwvvuuttssrrqqppoonnmmllkkjjiihhhhggffeeeeddccbbbbaaaa``____^^^^]]]]\\\\[[[[ZZZZYYYYYYXXXXXXWWWWWWVVVVVVUUUUUUTTTTTTTTSSSSSSSSRRRRRRRRQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCC»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ºíºíºíºíºíºíºíºíºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹ì¹ì¹ì¹ì¹ì¹ì¹ì¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸ë¸ë¸ë¸ë¸ë¸ë¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·ê·ê·ê·ê·ê····································¶é¶é¶é¶é¶é¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µèµèµèµèµµµµµµµµµµµµµµµµµµµµµµ´ç´ç´ç´´´´´´´´´´´´´´´´´´³æ³æ³æ³³³³³³³³³³³³³³²å²å²å²å²²²²²²²²²²±ä±ä±ä±±±±±±±±±±°ã°ã°ã°°°°°°°°¯â¯â¯¯¯¯¯¯¯¯®á®á®®®®®®­à­à­­­­­­¬ß¬ß¬¬¬¬«Þ«Þ««««ªÝªÝªªªª©Ü©Ü©©¨Û¨Û¨¨§Ú§Ú§§¦Ù¦Ù¦¦¥Ø¥¥¤×¤×¤¤£Ö££¢Õ¢¢¡Ô¡¡ Ó  ŸÒŸŸžÑМϛΛ›šÍ™Ì™™˜˜—Ê–É––••””““’Å‘ÄÃÂŽÁÀŒ¿‹¾Š½‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zGyFwwvvuuttssrrqqppoonnmmlll9k8j7i6hhggg4f3eeddd1c0bbb/aaa.`-___,^^^+]]]*\\\)[[[(ZZZ'Z'YYY&XXXXX%WWWWW$VVVVV#UUUUU"U"TTTTT!T!SSSSS S RRRRRRQQQQQQQQPPPPPPPPPPOOOOOOOOOONNNNNNNNNNNNNMMMMMMMMMMMMMLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»!»!»!»!»!»!»!»!»!ººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº º º º º º º º ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··········································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²±±±±±±±±±±±±±°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬«««««««ªªªªªª©©©©©¨¨¨¨¨§§§§§ ¦¦¦¦¦ ¥¥¥ ¤¤¤¤¤ £££ ¢¢¢¡¡¡   ŸŸŸžœœ›››šš™™˜ÿ—þ——––•ü”û“ú““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒè€€~~}}||{{zzyyxwvut s r q p onmllkkjjiiihggffeÿdþddcýbübbaûaa`ú_ù__^ø^^]÷]]\ö\\[õ[[ZôZôZZYóYYXòXòXXWñWñWWVðVðVVUïUïUUUUTîTîTTTTSíSSSSSSRìRìRRRRQëQëQQQQQQPêPêPêPPPPPPOéOéOOOOOOOONèNèNèNNNNNNNNNNMçMçMçMMMMMMMMMMLæLæLæLLLLLLLLLLLLLLKåKåKåKKKKKKKKKKKKKKKKJäJäJäJäJJJJJJJJJJJJJJJJJJJJIãIãIãIãIIIIIIIIIIIIIIIIIIIIIIIIHâHâHâHâHâHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGáGáGáGáGáGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFàFàFàFàFàFàFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEßEßEßEßEßEßEßEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDÞDÞDÞDÞDÞDÞDÞDÞDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»T»T»T»T»T»T»T»T»TºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººSºSºSºSºSºSºS¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹R¹R¹R¹R¹R¹R¹R¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸Q¸Q¸Q¸Q¸Q¸Q·······································P·P·P·P·P¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶O¶O¶O¶OµµµµµµµµµµµµµµµµµµµµµµµµµNµNµNµN´´´´´´´´´´´´´´´´´´´M´M´M³³³³³³³³³³³³³³³³³L³L³L²²²²²²²²²²²²²²²K²K±±±±±±±±±±±±±J±J°°°°°°°°°°°I°I¯¯¯¯¯¯¯¯¯H¯H¯H®®®®®®®G®G­­­­­­­F­F¬¬¬¬¬¬¬E¬E«««««D«DªªªªªC©©©©©B©B¨¨¨A¨A§§§@§@¦¦¦?¦?¥¥¥>¤¤¤=¤=£££<¢¢¢;¡¡¡:   9ŸŸŸ8ž76œœœ5›4ššš3™2˜˜———0–/••””“““,’+‘*)ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒ€€~~}}||{{zzyyxxwwvvuuttssrrqqppoonnmmllkÒjÑiÐiihhgÎfÍffeedËddccbÉbbaÈaa``_Æ__^Å^^]Ä]]\Ã\\[Â[Â[[ZÁZZYÀYYYYX¿XXXXW¾WWWWV½VVVVU¼U¼UUUUT»TTTTSºSºSSSSSSR¹R¹RRRRQ¸Q¸Q¸QQQQQQP·P·PPPPPPO¶O¶O¶OOOOOOOONµNµNµNNNNNNNNNNM´M´MMMMMMMMMMMML³L³L³LLLLLLLLLLLLLLK²K²K²KKKKKKKKKKKKKKKKKKJ±J±J±JJJJJJJJJJJJJJJJJJJJJJI°I°I°I°IIIIIIIIIIIIIIIIIIIIIIIIIIH¯H¯H¯H¯HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHG®G®G®G®G®GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGF­F­F­F­F­F­FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE¬E¬E¬E¬E¬E¬E¬EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEED«D«D«D«D«D«D«D«DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»»»»»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆ»ˆººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº‡º‡º‡º‡º‡º‡º‡¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹†¹†¹†¹†¹†¹†¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸…¸…¸…¸…¸…·········································„·„·„·„·„¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ƒ¶ƒ¶ƒ¶ƒµµµµµµµµµµµµµµµµµµµµµµµµµ‚µ‚µ‚µ‚´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³€³€³€²²²²²²²²²²²²²²²²²±±±±±±±±±±±~±~±~°°°°°°°°°}°}°}¯¯¯¯¯¯¯¯¯|¯|®®®®®®®®®{®{­­­­­­­z­z¬¬¬¬¬¬¬y¬y«««««x«xªªªªªwªw©©©©©v¨¨¨¨¨u§§§§§t¦¦¦¦¦s¥¥¥¥¥r¤¤¤q£££p£p¢¢¢o¡¡¡n   mŸŸŸlžžjœœœi››šššg™™˜˜˜e—d––•••b”a“`’’‘‘\Ž[ZŒY‹XŠW‰VˆU‡T†S…R„Q‚‚€€~~}}||{{zzyyxxwwvvuuttssrrqqppoon¡m lŸllkkjjiœh›hhggf™e˜eed—c–ccb•bba”`“``_’__^‘^^]]]\\\\\[Ž[[ZZZYŒYŒYYX‹X‹XXWŠWŠWWV‰V‰VVVVUˆUUUUT‡T‡TTTTS†S†SSSSSSR…R…RRRRRRQ„Q„QQQQQQPƒPƒPPPPPPPPO‚O‚OOOOOOOOOONNNNNNNNNNNNM€M€M€MMMMMMMMMMMMLLLLLLLLLLLLLLLLLK~K~K~K~KKKKKKKKKKKKKKKKJ}J}J}J}JJJJJJJJJJJJJJJJJJJJJJI|I|I|I|IIIIIIIIIIIIIIIIIIIIIIIIIIH{H{H{H{H{HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGzGzGzGzGzGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFyFyFyFyFyFyFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFExExExExExExExEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDwDwDwDwDwDwDwDwDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»»»»»»»»»»»»»»»»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··················································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««ªªªªªªªª©©©©©©©©¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤££££¢¢¢¢¢¢¡¡¡¡    ŸŸŸŸžžžžœœœœ››››šš™™™™˜˜——––––••””““’’’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyxxwwvvuuttssrrqqppoooonnmmllkkjjjjiihhggggffeeeeddccccbbbbaa````____^^^^]]]]\\\\\\[[[[ZZZZZZYYYYYYXXXXXXWWWWWWVVVVVVUUUUUUUUTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD»»»»ºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··················································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««ªªªªªªªª©©©©©©©©¨¨¨¨¨¨§§§§§§§§¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££¢¢¢¢¢¢¡¡¡¡    ŸŸŸŸžžžžœœœœ››››šš™™™™˜˜————––••””””““’’‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyxxwwvvuuttssssrrqqppoonnmmllllkkjjiiiihhggffffeeddddccccbbbbaa````____^^^^]]]]]]\\\\[[[[ZZZZZZYYYYYYXXXXXXWWWWWWVVVVVVVVUUUUUUUUTTTTTTTTSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOONNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDºíºíºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹ì¹ì¹ì¹ì¹ì¹ì¹ì¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸ë¸ë¸ë¸ë¸ë¸ë¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·ê·ê·ê·ê·ê·ê··········································¶é¶é¶é¶é¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µèµèµèµèµµµµµµµµµµµµµµµµµµµµµµµµµµ´ç´ç´ç´´´´´´´´´´´´´´´´´´´´´´³æ³æ³æ³³³³³³³³³³³³³³³³³³²å²å²å²²²²²²²²²²²²²²±ä±ä±ä±±±±±±±±±±±±°ã°ã°°°°°°°°°°¯â¯â¯â¯¯¯¯¯¯¯¯®á®á®á®®®®®®­à­à­à­­­­­­¬ß¬ß¬¬¬¬¬¬«Þ«Þ««««ªÝªÝªªªªªª©Ü©©©©¨Û¨Û¨¨¨¨§Ú§§§§¦Ù¦Ù¦¦¥Ø¥¥¥¥¤×¤¤¤¤£Ö££¢Õ¢¢¡Ô¡Ô¡¡ Ó  ŸÒŸŸžÑžžÐœÏœœ›Î››šÍšš™™˜Ë˜˜——–ɕȕ•””“Æ’Å’’‘‘ÂŽÁÀŒŒ‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyxxwwvvvCuBtAssrrqqppoonnn;m:llkkk8j7iihhh5g4fff3e2ddd1ccc0bbaaa.```-___,^^^+]]]]]*\\\)[[[([(ZZZ'Z'YYY&XXXXX%X%WWW$W$VVVVV#V#UUUUU"U"TTTTT!T!SSSSSSS S RRRRRRRRQQQQQQQQQPPPPPPPPPPOOOOOOOOOOOONNNNNNNNNNNNNNNMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº º º º º º º ¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·················································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®­­­­­­­­­­¬¬¬¬¬¬¬¬«««««««ªªªªªªªª©©©©©¨¨¨¨¨¨§§§§§ ¦¦¦¦¦ ¥¥¥¥¥ ¤¤¤ ¤ £££ ¢¢¢¡¡¡¡¡   ŸŸŸžžžœœœ›››ššš˜ÿ˜˜—þ–ý––••”û””““’’‘ø÷ŽŽŒó‹ò‹‹ŠŠ‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{zzyyyxwvvuuttssrrqqppp onnmmlllkkjjiiihhgggffeedþddcýccbbaûaa`ú``_ù__^ø^^]÷]÷]]\ö\\[õ[[[[ZôZZZZYóYYXòXòXXXXWñWWWWVðVðVVVVUïUUUUUUTîTTTTTTSíSíSSSSSSRìRìRRRRRRQëQëQQQQQQQQPêPêPPPPPPPPOéOéOOOOOOOOOONèNèNèNNNNNNNNNNNNMçMçMMMMMMMMMMMMMMLæLæLæLLLLLLLLLLLLLLLLKåKåKåKKKKKKKKKKKKKKKKKKKKJäJäJäJäJJJJJJJJJJJJJJJJJJJJJJJJIãIãIãIãIIIIIIIIIIIIIIIIIIIIIIIIIIIIHâHâHâHâHâHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGáGáGáGáGáGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFàFàFàFàFàFàFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEßEßEßEßEßEßEßEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDÞDÞDÞDÞDÞDÞDÞDÞDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººSºSºSºSºSºSºSºS¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹R¹R¹R¹R¹R¹R¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸Q¸Q¸Q¸Q¸Q·············································P·P·P·P·P¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶O¶O¶O¶OµµµµµµµµµµµµµµµµµµµµµµµµµµµµµNµNµNµN´´´´´´´´´´´´´´´´´´´´´´´M´M´M³³³³³³³³³³³³³³³³³³³L³L³L³L²²²²²²²²²²²²²²²K²K²K±±±±±±±±±±±±±J±J±J°°°°°°°°°°°I°I°I¯¯¯¯¯¯¯¯¯¯¯H¯H®®®®®®®®®G®G­­­­­­­­­F­F¬¬¬¬¬¬¬E¬E«««««««D«DªªªªªCªC©©©©©B©B¨¨¨¨¨A§§§§§@§@¦¦¦?¦?¥¥¥>¥>¤¤¤=£££££<¢¢¢;¡¡¡:¡:   9ŸŸŸ8žžž76œœ›››4ššš3™™˜˜˜1——–––/••”””-“,’’‘‘)ŽŽŒŒ‹‹‹$Š#‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€~~}}||{{záyàyyxxwwvvuuttssrrqØp×ppoonnmÔlÓllkkjÑiÐiihhgÎggfÍeÌeedËddcÊbÉbbaÈaa`Ç``_Æ__^Å^^^^]Ä]]\Ã\\[Â[Â[[ZÁZZZZYÀYYYYX¿XXXXW¾W¾WWWWV½VVVVU¼U¼UUUUT»T»TTTTTTSºSºSSSSSSR¹R¹RRRRRRQ¸Q¸QQQQQQQQP·P·PPPPPPPPO¶O¶O¶OOOOOOOOOONµNµNµNNNNNNNNNNM´M´M´MMMMMMMMMMMMMML³L³L³LLLLLLLLLLLLLLLLK²K²K²K²KKKKKKKKKKKKKKKKKKKKJ±J±J±JJJJJJJJJJJJJJJJJJJJJJJJJJI°I°I°I°IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH¯H¯H¯H¯HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHG®G®G®G®G®GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGF­F­F­F­F­F­FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE¬E¬E¬E¬E¬E¬EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEED«D«D«D«D«D«D«D«DDDDDDDDDDDDDDDDDDDDDDDDººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº‡º‡º‡º‡º‡º‡º‡¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹†¹†¹†¹†¹†¹†¹†¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸…¸…¸…¸…¸…¸…···············································„·„·„·„¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ƒ¶ƒ¶ƒ¶ƒµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ‚µ‚µ‚µ‚´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³€³€³€²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±~±~°°°°°°°°°°°°°}°}¯¯¯¯¯¯¯¯¯¯¯|¯|¯|®®®®®®®®®{®{­­­­­­­­­z­z¬¬¬¬¬¬¬y¬y«««««««x«xªªªªªwªw©©©©©v©v¨¨¨¨¨u¨u§§§§§t¦¦¦¦¦s¥¥¥¥¥r¤¤¤¤¤q£££££p¢¢¢o¡¡¡n     mŸŸŸlžžžkjœœœi››šššg™™™f˜˜———d––•••b””““’’’_‘‘\Ž[ŒŒ‹‹ŠŠ‰‰‰VˆU‡‡††……„„ƒƒ‚‚€€~~}}||{®{{zzyyxxwwvvuutts¦r¥rrqqppoon¡nnmmllkžkkjjiœh›hhgšggffe˜eed—ddccb•bba”aa`“``_’__^‘^^^^]]]\\\\\[Ž[[ZZZZYŒYŒYYX‹X‹XXXXWŠWWWWV‰V‰VVVVUˆUˆUUUUT‡T‡TTTTTTS†SSSSSSSSR…R…RRRRRRQ„Q„QQQQQQQQPƒPƒPPPPPPPPPPO‚O‚OOOOOOOOOOOONNNNNNNNNNNNNNM€M€M€MMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLK~K~K~KKKKKKKKKKKKKKKKKKKKJ}J}J}J}JJJJJJJJJJJJJJJJJJJJJJJJJJI|I|I|I|IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH{H{H{H{H{HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGzGzGzGzGzGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFyFyFyFyFyFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFExExExExExExExEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDwDwDwDwDwDwDwDwDDDDDDDDºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··························································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¡¡¡¡      ŸŸŸŸžžžžœœœœ››››šš™™™™˜˜˜˜——––––••””””““’’‘‘‘‘ŽŽŒŒ‹‹ŠŠ‰‰ˆˆ‡‡‡‡††……„„ƒƒ‚‚€€~~}}||||{{zzyyxxwwvvuuttttssrrqqppoooonnmmllllkkjjjjiihhhhggffffeeeeddccccbbbbaaaa````____^^^^^^]]]]\\\\\\[[[[[[ZZZZZZYYYYYYXXXXXXWWWWWWWWVVVVVVVVUUUUUUUUTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDDDDDDºººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸··························································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££¢¢¢¢¢¢¡¡¡¡      ŸŸŸŸžžžžœœœœ››››šššš™™˜˜˜˜——––––••••””““’’’’‘‘ŽŽŒŒ‹‹‹‹ŠŠ‰‰ˆˆ‡‡††††……„„ƒƒ‚‚€€~~}}}}||{{zzyyxxwwvvvvuuttssrrqqqqppoonnnnmmllkkkkjjiiiihhggggffffeeddddccccbbbbaaaa````____^^^^^^]]]]\\\\\\[[[[[[ZZZZZZYYYYYYXXXXXXXXWWWWWWVVVVVVVVUUUUUUUUUUTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEºººººººººººººººººººººººººººººººººººººººººººººº¹ì¹ì¹ì¹ì¹ì¹ì¹ì¹ì¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸ë¸ë¸ë¸ë¸ë¸ë¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·ê·ê·ê·ê·ê················································¶é¶é¶é¶é¶é¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µèµèµèµèµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´ç´ç´ç´ç´´´´´´´´´´´´´´´´´´´´´´´´³æ³æ³æ³³³³³³³³³³³³³³³³³³³³²å²å²å²²²²²²²²²²²²²²²²±ä±ä±ä±±±±±±±±±±±±±±°ã°ã°ã°°°°°°°°°°°°¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯®á®á®®®®®®®®®®­à­à­­­­­­­­¬ß¬ß¬¬¬¬¬¬«Þ«Þ««««««ªÝªÝªªªªªª©Ü©Ü©©©©¨Û¨Û¨¨¨¨§Ú§Ú§§§§¦Ù¦¦¦¦¥Ø¥Ø¥¥¤×¤×¤¤£Ö£Ö££¢Õ¢¢¢¢¡Ô¡¡ Ó    ŸÒŸŸžÑžžÐœÏœœ›Î››šÍšš™Ì™™˜˜—Ê——––•È••”ǓƓ“’’‘Ä‘‘ŽÁŽŽŒŒ‹‹Š½ŠŠ‰‰ˆˆ‡‡††…¸……„„ƒƒ‚‚€€~~}}}}||{{zzyyxxwwwDvvuuttssrrr?qqppooo¤¤¤¤¤=£££££<¢¢¢¢¢;¡¡¡:     9ŸŸŸ8žžž76œœœ5›››4ššš3™™™2˜˜˜1——–––/••”””-““’’’+‘‘)ŽŽ&ŒŒ‹‹ŠŠ‰‰‰"ˆˆ‡‡††……„„„ƒƒ‚‚€€~~~~}}||{{zzyyxßxxwwvvuutÛttssrrqqp×ppoonÕmÔmmllkÒkkjjiÐiihÏhhggfÍffeÌeedËddcÊccbÉbbaÈaa`Ç``_Æ____^Å^^]Ä]]]]\Ã\\[Â[Â[[ZÁZÁZZZZYÀYYYYX¿XXXXXXW¾WWWWV½V½VVVVVVU¼UUUUUUT»T»TTTTTTSºSºSSSSSSR¹R¹RRRRRRRRQ¸Q¸Q¸QQQQQQQQP·P·PPPPPPPPPPPPO¶O¶OOOOOOOOOOOONµNµNNNNNNNNNNNNNNM´M´M´MMMMMMMMMMMMMMMML³L³L³LLLLLLLLLLLLLLLLLLLLK²K²K²KKKKKKKKKKKKKKKKKKKKKKKKJ±J±J±JJJJJJJJJJJJJJJJJJJJJJJJJJJJI°I°I°I°IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH¯H¯H¯H¯H¯HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHG®G®G®G®G®GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGF­F­F­F­F­F­FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE¬E¬E¬E¬E¬E¬E¬EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEººº‡º‡º‡º‡º‡º‡º‡º‡¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹†¹†¹†¹†¹†¹†¹†¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸…¸…¸…¸…¸…·····················································„·„·„·„·„¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ƒ¶ƒ¶ƒ¶ƒµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ‚µ‚µ‚µ‚´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³€³€³€²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±~±~±~°°°°°°°°°°°°°°°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|®®®®®®®®®®®{®{­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬y«««««««««x«xªªªªªªªwªw©©©©©v©v¨¨¨¨¨¨¨u§§§§§t§t¦¦¦¦¦s¥¥¥¥¥r¥r¤¤¤¤¤q£££££p¢¢¢o¢o¡¡¡n     mŸŸŸlžžžkjœœœœ››››šššš™™™f˜˜˜e———d––•••b””“““`’’‘‘‘^\ŽŽŒŒŒY‹‹ŠŠ‰‰ˆˆˆU‡‡††……„„ƒƒƒƒ‚‚€€~~~~}}||{{zzyyyyxxwwvvu¨uuttssrrq¤qqppo¢oonnmmlŸllkkjjjiœiihhgšggf™ffe˜eeddddccccbbbba”aa`“``_’____^‘^^]]]]]\\\\\[Ž[[[[ZZZZZYŒYYYYX‹X‹XXXXWŠWWWWWWV‰V‰VVVVUˆUˆUUUUUUT‡T‡TTTTTTS†S†SSSSSSR…R…RRRRRRRRRRQ„Q„QQQQQQQQPƒPƒPƒPPPPPPPPPPO‚O‚OOOOOOOOOOOONNNNNNNNNNNNNNNNNM€M€M€MMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLK~K~K~KKKKKKKKKKKKKKKKKKKKKKKKJ}J}J}J}JJJJJJJJJJJJJJJJJJJJJJJJJJJJI|I|I|I|IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH{H{H{H{HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGzGzGzGzGzGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFyFyFyFyFyFyFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFExExExExExExExEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEºº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······························································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸžžžžœœœœœœ››››šššš™™˜˜˜˜————––––••””””““’’’’‘‘ŽŽŽŽŒŒ‹‹‹‹ŠŠ‰‰ˆˆ‡‡‡‡††……„„ƒƒƒƒ‚‚€€~~~~}}||{{zzyyyyxxwwvvvvuuttssrrrrqqppppoonnmmmmllkkkkjjjjiihhhhggggffffeeddddccccbbbbbbaaaa````______^^^^]]]]]]\\\\\\[[[[[[ZZZZZZYYYYYYYYXXXXXXWWWWWWWWWWVVVVVVVVUUUUUUUUUUTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¤¤¤¤¤¤££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸžžžžœœœœ››››šššš™™™™˜˜————––––••••””““““’’‘‘‘‘ŽŽŒŒ‹‹ŠŠŠŠ‰‰ˆˆ‡‡††††……„„ƒƒ‚‚‚‚€€~~~~}}||{{zzzzyyxxwwvvvvuuttssssrrqqqqppoonnnnmmllllkkkkjjiiiihhhhggffffeeeeddddccccbbbbbbaaaa````______^^^^]]]]]]\\\\\\[[[[[[ZZZZZZZZYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVVVUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSRRRRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸ë¸ë¸ë¸ë¸ë¸ë¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·ê·ê·ê·ê·ê························································¶é¶é¶é¶é¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µèµèµèµèµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´ç´ç´ç´ç´´´´´´´´´´´´´´´´´´´´´´´´´´³æ³æ³æ³æ³³³³³³³³³³³³³³³³³³³³³³²å²å²å²²²²²²²²²²²²²²²²²²²²±ä±ä±ä±±±±±±±±±±±±±±±±°ã°ã°ã°°°°°°°°°°°°°°¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯®á®á®®®®®®®®®®®®­à­à­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬«Þ«Þ««««««ªÝªÝªªªªªª©Ü©Ü©©©©©©¨Û¨Û¨¨¨¨¨¨§Ú§§§§§§¦Ù¦¦¦¦¥Ø¥Ø¥¥¥¥¤×¤¤¤¤£Ö££££¢Õ¢¢¢¢¡Ô¡¡¡¡ Ó    ŸÒŸŸžÑžžÐœÏœœ›Î››šÍšš™Ì™™˜Ë˜˜————––•È••”Ç””““’Å’’‘‘ÃŽÁŽŽŒ¿ŒŒ‹‹ŠŠ‰¼‰‰ˆˆ‡‡††††……„„ƒƒ‚‚‚‚€€~~~~}}||{{{HzzyyxxwwwDvvuutttAssrrqqqqppooo¥>¤¤¤¤¤=£££££<¢¢¢¢¢;¡¡¡¡¡:     9ŸŸŸ8žžžžž76œœœ5›››4ššš3™™™2˜˜˜1———0–––/••””””“““,’’‘‘‘‘ŽŽŒŒ‹‹‹$ŠŠ‰‰ˆˆˆˆ‡‡††…………„„ƒƒ‚‚‚‚€€~~~~}}||{{{{zzyyxxxxwwvvuuuuttssrÙrrqqp×ppoonÕnnmmlÓllkÒkkjjiÐiihÏhhgÎggfÍffeÌeedËddcÊccbÉbbaÈaaaa`Ç``_Æ____^Å^^^^]Ä]]\Ã\Ã\\\\[Â[[[[ZÁZZZZYÀYÀYYYYX¿XXXXXXW¾WWWWWWV½V½VVVVVVU¼U¼UUUUUUT»T»TTTTTTSºSºSSSSSSSSR¹R¹RRRRRRRRRRQ¸Q¸QQQQQQQQQQP·P·P·PPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOONµNµNNNNNNNNNNNNNNNNM´M´M´MMMMMMMMMMMMMMMMMML³L³L³LLLLLLLLLLLLLLLLLLLLLLK²K²K²K²KKKKKKKKKKKKKKKKKKKKKKKKKKJ±J±J±JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI°I°I°I°IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH¯H¯H¯H¯H¯HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHG®G®G®G®G®GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGF­F­F­F­F­F­FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE¬E¬E¬E¬E¬E¬E¬EEEEEE¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹†¹†¹†¹†¹†¹†¹†¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸…¸…¸…¸…¸…·····························································„·„·„·„¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ƒ¶ƒ¶ƒ¶ƒµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ‚µ‚µ‚´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³€³€³€²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±~±~±~°°°°°°°°°°°°°°°}°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|®®®®®®®®®®®®®{®{­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««x«xªªªªªªªwªw©©©©©©©v©v¨¨¨¨¨¨¨u§§§§§§§t§t¦¦¦¦¦s¦s¥¥¥¥¥r¤¤¤¤¤q¤q£££££p¢¢¢¢¢o¡¡¡¡¡n     mŸŸŸlžžžžžkjœœœi››››šššš™™™™˜˜˜˜————––––•••b”””a““’’’_‘‘‘^\ŽŽZŒŒ‹‹ŠŠŠŠ‰‰ˆˆˆU‡‡††………R„„ƒƒ‚‚‚‚€€~±~~}}||{®{{zzyyx«xxwwvvu¨uutts¦ssrrq¤qqppo¢oonnm mmllllkkjjjiœiihhhhggggffffeeeeddddc–ccb•bba”aaaa`“``_’____^‘^^^^]]]]]\\\\\[Ž[[[[ZZZZZZZYŒYYYYX‹X‹XXXXWŠWŠWWWWWWV‰VVVVVVVVUˆUUUUUUUUT‡TTTTTTTTS†S†SSSSSSSSR…R…RRRRRRRRRRQ„Q„QQQQQQQQQQQQPƒPƒPPPPPPPPPPPPO‚O‚OOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNM€M€M€MMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLK~K~K~KKKKKKKKKKKKKKKKKKKKKKKKKKJ}J}J}J}JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI|I|I|I|IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH{H{H{H{HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGzGzGzGzGzGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFyFyFyFyFyFyFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFExExEx¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸······································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤££££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸžžžžžžœœœœ››››››šššš™™™™˜˜˜˜————––––••””””““““’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹ŠŠŠŠ‰‰ˆˆ‡‡‡‡††……„„„„ƒƒ‚‚‚‚€€~~}}||||{{zzyyyyxxwwvvvvuuttttssrrrrqqppppoonnnnmmllllkkkkjjjjiihhhhggggffffeeeeddddddccccbbbbaaaaaa````______^^^^^^]]]]]]\\\\\\[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸········································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤££££££££¢¢¢¢¢¢¡¡¡¡¡¡    ŸŸŸŸŸŸžžžžžžœœœœœœ››››šššš™™™™˜˜˜˜————––––••••””””““’’’’‘‘‘‘ŽŽŒŒ‹‹‹‹ŠŠ‰‰‰‰ˆˆ‡‡‡‡††……„„„„ƒƒ‚‚€€~~}}||||{{zzyyyyxxwwwwvvuuttttssrrrrqqppppoooonnmmmmllllkkjjjjiiiihhhhggggffffeeeeddddccccccbbbbaaaaaa````______^^^^^^]]]]]]\\\\\\[[[[[[[[ZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSSSRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸ë¸ë¸ë¸ë¸ë¸ë¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·ê·ê·ê·ê·ê······························································¶é¶é¶é¶é¶é¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µèµèµèµèµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´ç´ç´ç´ç´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³æ³æ³æ³æ³³³³³³³³³³³³³³³³³³³³³³³³³³²å²å²å²²²²²²²²²²²²²²²²²²²²±ä±ä±ä±±±±±±±±±±±±±±±±±±±±°ã°ã°°°°°°°°°°°°°°°°¯â¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯®á®á®á®®®®®®®®®®®®­à­à­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««ªÝªÝªªªªªªªª©Ü©Ü©©©©©©¨Û¨Û¨¨¨¨¨¨§Ú§§§§§§¦Ù¦Ù¦¦¦¦¥Ø¥Ø¥¥¥¥¤×¤×¤¤¤¤£Ö££££¢Õ¢Õ¢¢¢¢¡Ô¡¡¡¡ Ó  ŸÒŸŸŸŸžÑžžžžÐœÏœœœœ›Î››šÍšš™Ì™™˜Ë˜˜—Ê——–É––•È••”Ç””“Æ““’’‘Ä‘‘ÃŽÁŽŽŒŒ‹‹‹‹ŠŠ‰‰‰‰ˆˆ‡‡†¹††……„„„„ƒƒ‚‚€€~~}}||||{{zzyyyyxxwwwwvvuuuBttsss@rrqqq>ppoooonnn;mmllllkkk8jjj7iii6hhh5ggg4fff3eee2ddd1ccccbbbbb/aaaa`````-_____,^^^^^+]]]]]*\\\\\)[[[[[[[(ZZZZZ'Z'YYYYY&Y&XXXXX%X%WWWWWWW$W$VVVVVVV#V#UUUUUUU"U"TTTTTTTTT!T!SSSSSSSSS S RRRRRRRRRRRRQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªª©©©©©©©©¨¨¨¨¨¨¨¨§§§§§§§ ¦¦¦¦¦¦¦ ¥¥¥¥¥¥¥ ¤¤¤¤¤¤¤ £££££ ¢¢¢¢¢¢¡¡¡¡¡   ŸŸŸŸŸžžžžžœœœœœ›››ššš™™™™˜˜˜˜————––––••••””“ú““’ù’’‘‘‘‘öŽŽŽŽŒóŒŒ‹‹ŠñŠŠ‰‰ˆïˆˆ‡‡††††……„„„„ƒƒ‚‚€€~~}}||||{{zzzyyxxxwwvvuuuuttssssrrr qqppp oonnnnmmmlllkkjjjjiiiihhhhggggffffeeeedþddcýccbübbbbaûaa`ú````_ù____^ø^^^^]÷]]]]\ö\\\\[õ[õ[[[[ZôZZZZZZYóYYYYYYXòXXXXXXWñWWWWWWWWVðVVVVVVVVUïUUUUUUUUTîTîTTTTTTTTSíSíSSSSSSSSRìRìRRRRRRRRRRQëQëQëQQQQQQQQQQPêPêPêPPPPPPPPPPPPOéOéOéOOOOOOOOOOOOOONèNèNèNNNNNNNNNNNNNNNNMçMçMçMMMMMMMMMMMMMMMMMMMMLæLæLæLLLLLLLLLLLLLLLLLLLLLLLLKåKåKåKåKKKKKKKKKKKKKKKKKKKKKKKKKKKKJäJäJäJäJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIãIãIãIãIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHâHâHâHâHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGáGáGáGáGáGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFàFàFàFàFàFàFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF¹¹¹¹¹R¹R¹R¹R¹R¹R¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸Q¸Q¸Q¸Q¸Q¸Q·································································P·P·P·P¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶O¶O¶O¶O¶OµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµNµNµNµN´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´M´M´M´M³³³³³³³³³³³³³³³³³³³³³³³³³³³L³L³L²²²²²²²²²²²²²²²²²²²²²²²²²K²K²K±±±±±±±±±±±±±±±±±±±J±J±J°°°°°°°°°°°°°°°°°I°I°I¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯H¯H®®®®®®®®®®®®®G®G®G­­­­­­­­­­­F­F¬¬¬¬¬¬¬¬¬¬¬E¬E«««««««««««DªªªªªªªªªCªC©©©©©©©©©B¨¨¨¨¨¨¨¨¨A§§§§§§§@§@¦¦¦¦¦¦¦?¥¥¥¥¥¥¥>¤¤¤¤¤=¤=£££££<¢¢¢¢¢;¡¡¡¡¡:¡:   9ŸŸŸŸŸ8žžžžž7œœœœœ5›››4šššš™™™™™2˜˜˜1———0–––/•••.””““““’’’’‘‘‘*ŽŽŽ'ŒŒŒ%‹‹ŠŠŠŠ‰‰ˆˆˆˆ‡‡††††……„„„ƒƒ‚‚€€~~}}||||{{zzzzyyxxxxwwvvuÜuuttsÚssrrrrqqp×ppoonÕnnmÔmmllllkkjÑjjiÐiihÏhhgÎggfÍffeÌeeeeddddcÊccbÉbbbbaÈaa`Ç````_Æ____^Å^^^^]Ä]]]]\Ã\\\\\\[Â[[[[ZÁZZZZZZYÀYYYYYYX¿XXXXXXW¾W¾WWWWWWV½V½VVVVVVU¼U¼UUUUUUUUT»TTTTTTTTTTSºSºSSSSSSSSR¹R¹RRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQP·P·PPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOONµNµNNNNNNNNNNNNNNNNNNM´M´M´MMMMMMMMMMMMMMMMMMMML³L³L³LLLLLLLLLLLLLLLLLLLLLLLLLLK²K²K²KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ±J±J±JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI°I°I°I°IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH¯H¯H¯H¯H¯HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHG®G®G®G®G®GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGF­F­F­F­F­F­FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF¹†¹†¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸…¸…¸…¸…¸…···································································„·„·„·„·„¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ƒ¶ƒ¶ƒ¶ƒµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ‚µ‚µ‚´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³€³€³€²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±~±~°°°°°°°°°°°°°°°°°°°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|®®®®®®®®®®®®®{®{­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««x«xªªªªªªªªªw©©©©©©©©©v©v¨¨¨¨¨¨¨u¨u§§§§§§§t¦¦¦¦¦¦¦s¦s¥¥¥¥¥r¥r¤¤¤¤¤q£££££££p¢¢¢¢¢o¡¡¡¡¡n     mŸŸŸŸŸlžžžžžkjœœœi››››šššššg™™™f˜˜˜e———d–––c•••b”””a“““`’’’_‘‘\ŽŽŒŒ‹‹‹‹ŠŠŠW‰‰ˆˆˆU‡‡†††S……„„ƒƒƒƒ‚‚€€~~}}|¯||{{zzzzyyxxxxwwvvvvuut§ttssr¥rrqqqqppo¢oonnnnmmlŸllkžkkjjjiœiih›hhgšggf™ffe˜eed—ddddc–ccb•bbbba”aa`“````_’____^‘^^^^]]]]]\\\\\\[Ž[[[[ZZZZZZYŒYŒYYYYX‹X‹XXXXXXWŠWWWWWWWWV‰VVVVVVVVUˆUUUUUUUUT‡T‡TTTTTTTTTTS†SSSSSSSSSSR…R…RRRRRRRRRRRRQ„Q„QQQQQQQQQQQQPƒPƒPPPPPPPPPPPPPPO‚O‚OOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNM€M€M€MMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK~K~K~KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ}J}J}J}JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI|I|I|I|IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH{H{H{H{HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGzGzGzGzGzGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFyFyFyFyFyFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸············································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««ªªªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœ››››››šššš™™™™˜˜˜˜————––––••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒ‹‹‹‹ŠŠ‰‰‰‰ˆˆ‡‡‡‡††…………„„ƒƒƒƒ‚‚€€~~}}}}||{{zzzzyyxxxxwwvvvvuuuuttssssrrqqqqppppoonnnnmmmmllllkkkkjjjjiiiihhhhggggffffeeeeddddddccccbbbbbbaaaa``````______^^^^^^]]]]]]]]\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸············································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««ªªªªªªªªªªªª©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœ››››››šššš™™™™˜˜˜˜˜˜————––––••••””””““““’’’’‘‘ŽŽŽŽŒŒŒŒ‹‹ŠŠŠŠ‰‰‰‰ˆˆ‡‡‡‡††…………„„ƒƒƒƒ‚‚€€~~}}}}||{{{{zzyyyyxxwwwwvvuuuuttssssrrrrqqppppoooonnnnmmllllkkkkjjjjiiiihhhhggggffffffeeeeddddccccccbbbbbbaaaa``````______^^^^^^]]]]]]]]\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYXXXXXXXXXXWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUUUTTTTTTTTTTTTSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·ê·ê·ê·ê·ê·ê····································································¶é¶é¶é¶é¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µèµèµèµèµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´ç´ç´ç´ç´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³æ³æ³æ³æ³³³³³³³³³³³³³³³³³³³³³³³³³³³³²å²å²å²²²²²²²²²²²²²²²²²²²²²²²²±ä±ä±ä±±±±±±±±±±±±±±±±±±±±°ã°ã°ã°°°°°°°°°°°°°°°°°°¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬«Þ««««««««««ªÝªÝªªªªªªªª©Ü©Ü©©©©©©©©¨Û¨Û¨¨¨¨¨¨§Ú§Ú§§§§§§¦Ù¦Ù¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¤×¤¤¤¤¤¤£Ö££££¢Õ¢Õ¢¢¢¢¡Ô¡¡¡¡ Ó    ŸÒŸŸŸŸžÑžžžžÐœÏœœœœ››››šÍšš™Ì™™™™˜˜˜˜—Ê——–É––•È••”Ç””“Æ““’Å’’‘Ä‘‘ŽÁŽŽÀŒŒŒŒ‹‹ŠŠŠŠ‰‰ˆ»ˆˆ‡‡†¹††…………„„ƒƒƒƒ‚‚€€~~}}}}||{{{{zzyyyyxxwwwwvvuuuutttAssrrrrqqq>ppoooonnnnmmm:lll9kkk8jjj7iii6hhh5ggg4ffffeeeee2ddd1ccccc0bbbbaaaaa.`````-_____,^^^^^+]]]]]]]*\\\\\)[[[[[[[(ZZZZZZZ'YYYYYYY&Y&XXXXXXX%WWWWWWWWW$VVVVVVVVV#V#UUUUUUUUU"U"TTTTTTTTT!T!SSSSSSSSSSS S RRRRRRRRRRRRRRQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFFFFFFFFFFFFF¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸···········································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««ªªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨§§§§§§§§§ ¦¦¦¦¦¦¦ ¦ ¥¥¥¥¥ ¥ ¤¤¤¤¤ ¤ £££££ ¢¢¢¢¢¢¢¡¡¡¡¡     ŸŸŸŸŸžžžžžœœœœœ›››šššš™™™™˜ÿ˜˜—þ————––––••••””””““““’’’’‘‘÷öŽŽŽŽŒŒ‹ò‹‹ŠŠŠŠ‰‰ˆˆˆˆ‡‡††††……„ë„„ƒƒƒƒ‚‚€€~~}}}}||{{{{zzyyyyxxwwwwvvvuuttttsss rrqqqqppp ooonnmmmmllllkkkkjjjjiiiihhhhhgggffeÿeeeedþddcýccccbübbaûaaaa`ú````_ù____^ø^^^^]÷]÷]]]]\ö\\\\[õ[õ[[[[ZôZôZZZZYóYóYYYYYYXòXXXXXXWñWñWWWWWWVðVðVVVVVVVVUïUUUUUUUUUUTîTTTTTTTTTTSíSíSSSSSSSSSSRìRìRRRRRRRRRRRRQëQëQQQQQQQQQQQQQQPêPêPPPPPPPPPPPPPPOéOéOéOOOOOOOOOOOOOOOONèNèNèNNNNNNNNNNNNNNNNNNMçMçMçMMMMMMMMMMMMMMMMMMMMMMLæLæLæLLLLLLLLLLLLLLLLLLLLLLLLLLLLKåKåKåKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJäJäJäJäJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIãIãIãIãIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHâHâHâHâHâHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGáGáGáGáGáGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFàFàFàFàFàFàFFFFFF¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸Q¸Q¸Q¸Q¸Q·······································································P·P·P·P·P¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶O¶O¶O¶O¶OµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµNµNµN´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´M´M´M´M³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³L³L³L²²²²²²²²²²²²²²²²²²²²²²²²²K²K²K±±±±±±±±±±±±±±±±±±±±±±±J±J°°°°°°°°°°°°°°°°°°°°°I°I¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯H¯H¯H®®®®®®®®®®®®®®®G®G­­­­­­­­­­­­­F­F¬¬¬¬¬¬¬¬¬¬¬¬¬E¬E«««««««««««DªªªªªªªªªªªCªC©©©©©©©©©B¨¨¨¨¨¨¨¨¨A¨A§§§§§§§@§@¦¦¦¦¦¦¦?¥¥¥¥¥¥¥>¤¤¤¤¤¤¤=£££££££<¢¢¢¢¢¢¢;¡¡¡¡¡:     9ŸŸŸŸŸ8žžžžž76œœœœœ5›››4ššššš3™™™2˜˜˜˜—————0–––/•••.”””-“““,’’’+‘‘ŽŽŽ'&ŒŒ‹‹‹‹ŠŠŠ#‰‰ˆˆˆˆ‡‡††††……„„„„ƒƒƒ‚‚€€~~}}}}||{{{{zzyyyyxxwÞwwvvvvuutÛttssssrrqØqqppppoooonnmÔmmlÓllkÒkkjÑjjiÐiihÏhhhhggggfÍffeÌeeeeddddcÊccccbbbbaÈaaaa`Ç````_Æ____^Å^^^^^^]Ä]]]]\Ã\\\\\\[Â[[[[[[ZÁZZZZZZYÀYYYYYYX¿X¿XXXXXXW¾WWWWWWWWV½V½VVVVVVU¼U¼UUUUUUUUT»T»TTTTTTTTTTSºSºSSSSSSSSSSR¹R¹RRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQP·P·PPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOONµNµNNNNNNNNNNNNNNNNNNNNM´M´M´MMMMMMMMMMMMMMMMMMMMMML³L³L³LLLLLLLLLLLLLLLLLLLLLLLLLLLLK²K²K²KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ±J±J±JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI°I°I°I°IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH¯H¯H¯H¯HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHG®G®G®G®G®GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGF­F­F­¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸…¸…¸…¸…¸…¸…·········································································„·„·„·„¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ƒ¶ƒ¶ƒ¶ƒµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ‚µ‚µ‚µ‚´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³€³€³€³€²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±~±~±~°°°°°°°°°°°°°°°°°°°}°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|®®®®®®®®®®®®®®®{®{®{­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««x«xªªªªªªªªªwªw©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨u§§§§§§§§§t¦¦¦¦¦¦¦s¦s¥¥¥¥¥¥¥r¤¤¤¤¤¤¤q£££££££p¢¢¢¢¢¢¢o¡¡¡¡¡n     mŸŸŸŸŸlžžžžžkjœœœœœi››››šššššg™™™™˜˜˜˜˜e———d–––c••••””””““““’’’’‘‘‘‘]\ŽŽŒŒŒŒ‹‹‹XŠŠ‰‰‰‰ˆˆˆU‡‡††††……„„„„ƒƒ‚‚‚‚€€~~}}}}||{{{{zzy¬yyxxxxwwv©vvuuuutts¦ssrrrrqqp£ppo¢oon¡nnmmmmllllkkkkjjjjiœiih›hhgšggggffffe˜eed—ddddc–ccb•bbbba”aaaa`“````_’____^‘^^^^^^]]]]]\\\\\\\[Ž[[[[[[ZZZZZZZYŒYYYYYYYYX‹XXXXXXWŠWŠWWWWWWWWV‰VVVVVVVVUˆUˆUUUUUUUUT‡T‡TTTTTTTTTTS†S†SSSSSSSSSSR…R…RRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQPƒPƒPPPPPPPPPPPPPPPPO‚O‚OOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNM€M€M€MMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK~K~K~K~KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ}J}J}J}JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI|I|I|I|IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH{H{H{H{H{HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGzGzGzGzGzGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····················································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««ªªªªªªªªªªªª©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššš™™™™™™˜˜˜˜————––––••••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹ŠŠŠŠ‰‰‰‰ˆˆ‡‡‡‡††††……„„„„ƒƒ‚‚‚‚€€~~}}}}||{{{{zzzzyyxxxxwwwwvvuuuuttttssrrrrqqqqppppoooonnmmmmllllkkkkjjjjjjiiiihhhhggggffffffeeeeddddddccccbbbbbbaaaaaa``````______^^^^^^^^]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZYYYYYYYYYYXXXXXXXXXXWWWWWWWWWWVVVVVVVVVVVVUUUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸····················································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««ªªªªªªªªªªªªªª©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¡¡¡¡¡¡¡¡      ŸŸŸŸŸŸžžžžžžžžœœœœœœ››››››šššš™™™™™™˜˜˜˜——————––––••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒ‹‹‹‹ŠŠŠŠ‰‰ˆˆˆˆ‡‡‡‡††…………„„„„ƒƒ‚‚‚‚€€~~}}}}||||{{zzzzyyxxxxwwwwvvuuuuttttssssrrqqqqppppoooonnnnmmmmllllkkkkjjjjiiiihhhhhhggggffffeeeeeeddddccccccbbbbbbaaaaaa``````______^^^^^^^^]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZZZYYYYYYYYXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVUUUUUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸·ê·ê·ê·ê·ê··········································································¶é¶é¶é¶é¶é¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µèµèµèµèµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´ç´ç´ç´ç´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³æ³æ³æ³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²å²å²å²²²²²²²²²²²²²²²²²²²²²²²²²²²²±ä±ä±±±±±±±±±±±±±±±±±±±±±±±±°ã°ã°°°°°°°°°°°°°°°°°°°°¯â¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®á®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««ªÝªÝªªªªªªªªªª©Ü©Ü©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨§Ú§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¤×¤×¤¤¤¤¤¤£Ö££££££¢Õ¢¢¢¢¡Ô¡¡¡¡¡¡ Ó    ŸÒŸŸŸŸŸŸžžžžžžÐœœœœ›Î››››šÍšššš™™™™˜Ë˜˜˜˜————–É––•È••”Ç””””““““’’’’‘‘‘‘ŽÁŽŽÀŒ¿ŒŒ‹‹‹‹ŠŠ‰¼‰‰ˆˆˆˆ‡‡‡‡††…………„„„„ƒƒ‚‚‚‚€³€€~~}}}}||||{{zzzzyyyFxxwwwwvvvCuuttttssssrrr?qqq>ppoooonnnnmmmmllllkkkkk8jjj7iii6hhhhggggg4fff3eeeee2ddd1ccccc0bbbbb/aaaaa.`````-_____,^^^^^^^+]]]]]*]*\\\\\)\)[[[[[([(ZZZZZZZ'YYYYYYY&Y&XXXXXXX%X%WWWWWWWWW$VVVVVVVVV#V#UUUUUUUUUUU"TTTTTTTTTTTTT!SSSSSSSSSSSSS S RRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG¸¸¸¸¸¸¸¸¸¸···············································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««ªªªªªªªªªªªª©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨§§§§§§§ § ¦¦¦¦¦¦¦ ¦ ¥¥¥¥¥¥¥ ¤¤¤¤¤¤¤ ¤ £££££ £ ¢¢¢¢¢¡¡¡¡¡¡¡     ŸŸŸŸŸŸŸžžžžžœœœœ›››››ššššš™™˜ÿ˜˜˜˜—þ——–ý––––••••””””“ú““’ù’’‘ø‘‘÷öŽŽŽŽŒŒŒŒ‹‹ŠñŠŠ‰‰‰‰ˆˆˆˆ‡‡†í††…………„„ƒêƒƒ‚‚‚‚€€€€~~}}}}||||{{zzzzyyyyxxwwwwvvvvuuuttssssrrrrqqqqppp ooonnnmmmlllkkkkjjjjiiiiihhhggggffffeÿeeeeddddcýccccbübbbbaûaaaa`ú````_ù____^ø^^^^^^]÷]]]]]]\ö\\\\\\[õ[[[[[[ZôZZZZZZYóYYYYYYYYXòXXXXXXXXWñWWWWWWWWVðVðVVVVVVVVUïUïUUUUUUUUTîTîTTTTTTTTTTSíSíSSSSSSSSSSSSRìRìRRRRRRRRRRRRQëQëQëQQQQQQQQQQQQQQPêPêPPPPPPPPPPPPPPPPOéOéOéOOOOOOOOOOOOOOOOOONèNèNèNNNNNNNNNNNNNNNNNNNNMçMçMçMMMMMMMMMMMMMMMMMMMMMMMMMMLæLæLæLLLLLLLLLLLLLLLLLLLLLLLLLLLLKåKåKåKåKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJäJäJäJäJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIãIãIãIãIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHâHâHâHâHâHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGáGáGáGáGáGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG¸Q¸Q···············································································P·P·P·P¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶O¶O¶O¶O¶OµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµNµNµN´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´M´M´M´M³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³L³L³L²²²²²²²²²²²²²²²²²²²²²²²²²²²²²K²K²K±±±±±±±±±±±±±±±±±±±±±±±J±J±J°°°°°°°°°°°°°°°°°°°°°I°I°I¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯H¯H®®®®®®®®®®®®®®®®®G®G­­­­­­­­­­­­­­­F­F¬¬¬¬¬¬¬¬¬¬¬¬¬E¬E«««««««««««««DªªªªªªªªªªªCªC©©©©©©©©©©©B¨¨¨¨¨¨¨¨¨¨¨A§§§§§§§§§@¦¦¦¦¦¦¦¦¦?¥¥¥¥¥¥¥¥¥>¤¤¤¤¤¤¤=£££££££<¢¢¢¢¢¢¢;¡¡¡¡¡¡¡:     9ŸŸŸŸŸŸŸ8žžžžž76œœœœœ5›››4ššššš3™™™™˜˜˜˜˜1————–––––/•••.”””-““““’’’’‘‘‘‘ŽŽŽŽ&ŒŒŒ%‹‹ŠŠŠŠ‰‰‰‰ˆˆˆ!‡‡††††…………„„ƒƒƒƒ‚‚‚‚€€€€~~}}}}||||{{zázzyyyyxxwÞwwvvvvuuuuttsÚssrÙrrqqqqppppoooonnnnmmmmllllkkkkjÑjjiÐiiiihhhhgÎggfÍffffeÌeedËddddcÊccccbÉbbbbaÈaaaa`Ç````_Æ____^Å^Å^^^^]Ä]]]]]]\Ã\\\\\\[Â[[[[[[ZÁZZZZZZYÀYÀYYYYYYX¿X¿XXXXXXW¾W¾WWWWWWWWV½VVVVVVVVVVU¼UUUUUUUUUUT»T»TTTTTTTTTTSºSºSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQP·P·PPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOOOONµNµNNNNNNNNNNNNNNNNNNNNNNM´M´M´MMMMMMMMMMMMMMMMMMMMMMMMMML³L³L³LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK²K²K²KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ±J±J±JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI°I°I°I°IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH¯H¯H¯H¯HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHG®G®G®G®G®GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG·········································································„·„·„·„·„¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ƒ¶ƒ¶ƒ¶ƒµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ‚µ‚µ‚µ‚´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³€³€³€²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±~±~°°°°°°°°°°°°°°°°°°°°°°°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|¯|®®®®®®®®®®®®®®®®®{®{­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««x«xªªªªªªªªªªªw©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨u¨u§§§§§§§t§t¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥r¥r¤¤¤¤¤¤¤q£££££££p¢¢¢¢¢¢¢o¡¡¡¡¡¡¡n     mŸŸŸŸŸŸŸlžžžžžkjœœœœœi››››šššššg™™™™™f˜˜˜˜—————d–––c••••””””“““““`’’’_‘‘‘^]\ŽŽŽ[ŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆ‡‡‡‡††††…………„„ƒƒƒƒ‚‚‚‚€€€€~~}}}}||||{{{{zzyyyyxxxxwwv©vvuuuuttttssssrrq¤qqp£ppo¢oon¡nnm mmlŸllkžkkkkjjjjiiiih›hhhhggggf™ffffeeeed—ddddc–ccccb•bbbba”aaaa`“````_’______^‘^^^^]]]]]]]\\\\\\\[Ž[[[[[[ZZZZZZZZZYŒYYYYYYYYX‹XXXXXXXXWŠWWWWWWWWV‰V‰VVVVVVVVUˆUˆUUUUUUUUUUT‡T‡TTTTTTTTTTS†S†SSSSSSSSSSSSR…R…RRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQPƒPƒPƒPPPPPPPPPPPPPPPPO‚O‚OOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNM€M€M€MMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK~K~K~KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ}J}J}J}JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI|I|I|I|IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH{H{H{H{H{HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGzGzGzGzGzGGGGGGGGGGGGGGGGGGGGGGGGGGGG········································································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««ªªªªªªªªªªªªªª©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššš™™™™™™˜˜˜˜˜˜————––––••••••””””““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆ‡‡‡‡††††…………„„ƒƒƒƒ‚‚‚‚€€€€~~}}}}||||{{{{zzyyyyxxxxwwwwvvuuuuttttssssrrrrqqqqppppoooonnnnmmmmllllkkkkjjjjiiiiiihhhhggggggffffeeeeeeddddddccccccbbbbbbaaaaaa``````________^^^^^^]]]]]]]]\\\\\\\\[[[[[[[[ZZZZZZZZZZYYYYYYYYYYXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVUUUUUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGG······························································¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««ªªªªªªªªªªªªªª©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡      ŸŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššššš™™™™˜˜˜˜˜˜————––––––••••””””““““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††……„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}||||{{{{zzyyyyxxxxwwwwvvvvuuttttssssrrrrqqqqppppoooonnnnmmmmllllllkkkkjjjjiiiihhhhhhggggffffffeeeeeeddddddccccbbbbbbbbaaaaaa``````________^^^^^^]]]]]]]]\\\\\\\\[[[[[[[[[[ZZZZZZZZYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVUUUUUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGG······················································¶é¶é¶é¶é¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µèµèµèµèµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´ç´ç´ç´ç´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³æ³æ³æ³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²å²å²å²å²²²²²²²²²²²²²²²²²²²²²²²²²²²²±ä±ä±ä±±±±±±±±±±±±±±±±±±±±±±±±°ã°ã°ã°°°°°°°°°°°°°°°°°°°°°°¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®®®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««ªÝªÝªªªªªªªªªª©Ü©Ü©©©©©©©©©©¨Û¨¨¨¨¨¨¨¨¨¨§Ú§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤£Ö£Ö££££££¢Õ¢¢¢¢¢¢¡Ô¡¡¡¡¡¡ Ó    ŸÒŸŸŸŸŸŸžÑžžžžÐœÏœœœœ›Î››››šÍšššš™Ì™™™™˜˜˜˜—Ê————––––•È••••””””““““’Å’’‘Ä‘‘ÃÂŽŽŽŽŒ¿ŒŒ‹¾‹‹Š½ŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††…¸……„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}||||{{{{zzzGyyxxxxwwwwvvvvuuuBtttAsss@rrr?qqq>ppp=ooo¤¤¤¤¤¤¤¤¤=£££££££<¢¢¢¢¢¢¢;¢;¡¡¡¡¡:       9ŸŸŸŸŸŸŸ8žžžžž76œœœœœœ››››››ššššš3™™™™™2˜˜˜˜˜1———0–––––/•••.””””“““““,’’’+‘‘‘*ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆ!‡‡‡ ††…………„„„„ƒƒƒƒ‚‚‚€€€€~~~~}}||||{{{{zzzzyyyyxxwÞwwvvvvuuuuttttssssrrrrqqqqppppoooonnnnmÔmmlÓllllkkkkjjjjiÐiiiihhhhgÎggggfÍffffeeeedËddddcÊccccbÉbbbbaÈaaaaaa`Ç````_Æ______^Å^^^^]Ä]Ä]]]]]]\Ã\\\\\\[Â[[[[[[ZÁZÁZZZZZZYÀYYYYYYYYX¿X¿XXXXXXXXW¾WWWWWWWWWWV½VVVVVVVVVVU¼U¼UUUUUUUUUUT»T»TTTTTTTTTTTTSºSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQP·P·P·PPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOOOONµNµNµNNNNNNNNNNNNNNNNNNNNNNNNM´M´M´MMMMMMMMMMMMMMMMMMMMMMMMMMMML³L³L³LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK²K²K²KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ±J±J±JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI°I°I°I°IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH¯H¯H¯H¯HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH···························„·„·„·„¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ƒ¶ƒ¶ƒ¶ƒ¶ƒµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ‚µ‚µ‚µ‚´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³€³€³€²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±~±~±~°°°°°°°°°°°°°°°°°°°°°°°}°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|®®®®®®®®®®®®®®®®®®®{®{­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y«««««««««««««««x«xªªªªªªªªªªªwªw©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤q£££££££p¢¢¢¢¢¢¢o¡¡¡¡¡¡¡n       mŸŸŸŸŸŸŸlžžžžžkœœœœœœœi›››››hšššš™™™™™f˜˜˜˜˜e————–––––c••••”””””a““““’’’’‘‘‘‘]\ŽŽŽ[ZŒŒŒY‹‹‹XŠŠŠW‰‰‰Vˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚€€€€~~~~}}|¯||{{{{zzzzyyyyxxxxwwv©vvu¨uut§tts¦ssr¥rrq¤qqp£ppo¢oon¡nnnnmmmmllllkžkkjjjjjiiiih›hhhhgšggggffffe˜eeeed—ddddc–ccccb•bbbba”aaaaaa`“````_’______^‘^^^^^^]]]]]]]\\\\\\\[Ž[[[[[[[[ZZZZZZZYŒYŒYYYYYYYYX‹XXXXXXXXWŠWŠWWWWWWWWV‰V‰VVVVVVVVVVUˆUUUUUUUUUUUUT‡T‡TTTTTTTTTTS†S†SSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQPƒPƒPPPPPPPPPPPPPPPPPPO‚O‚OOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNM€M€M€MMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK~K~K~K~KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ}J}J}J}JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI|I|I|I|IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH{H{H{H{H{HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH··························¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««ªªªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššššš™™™™˜˜˜˜˜˜——————––––••••••””””““““““’’’’‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚€€€€~~~~}}}}||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqppppoooonnnnmmmmllllllkkkkjjjjiiiiiihhhhhhggggffffffeeeeeeddddddccccccbbbbbbaaaaaaaa``````________^^^^^^^^]]]]]]]]\\\\\\\\[[[[[[[[[[ZZZZZZZZZZYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH················¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««ªªªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžœœœœœœ››››››šššššš™™™™™™˜˜˜˜——————––––––••••””””””““““’’’’‘‘‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒ‚‚‚‚€€€€~~~~}}}}||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqppppoooonnnnnnmmmmllllkkkkkkjjjjiiiiiihhhhggggggffffffeeeeeeddddddccccccbbbbbbaaaaaa````````________^^^^^^^^]]]]]]]]\\\\\\\\[[[[[[[[[[ZZZZZZZZZZYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVVVUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH······¶é¶é¶é¶é¶é¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µèµèµèµèµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´ç´ç´ç´ç´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³æ³æ³æ³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²å²å²å²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±ä±ä±±±±±±±±±±±±±±±±±±±±±±±±±±±±°ã°ã°ã°°°°°°°°°°°°°°°°°°°°°°¯â¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®®®®®®®®®®®®®®®®®®­à­à­à­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««ªÝªÝªªªªªªªªªªªª©Ü©©©©©©©©©©©©¨Û¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤£Ö££££££££¢Õ¢¢¢¢¢¢¡Ô¡¡¡¡¡¡ Ó      ŸÒŸŸŸŸŸŸžÑžžžžÐœÏœœœœ›Î››››šÍšššš™Ì™™™™˜Ë˜˜˜˜————–É––––•È••••””””“Æ““’Å’’’’‘‘‘‘ÃÂŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒ‚‚‚‚€€€€~~~~}}}}|||I{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqppppp=ooo¤¤¤¤¤¤¤¤¤=£££££££<£<¢¢¢¢¢¢¢;¡¡¡¡¡¡¡:       9ŸŸŸŸŸŸŸ8žžžžžž6œœœœœ5››››››šššššš™™™™™™˜˜˜˜˜1—————0––––•••••.”””””-“““,’’’’‘‘‘‘‘*)ŽŽŽŽŒŒŒŒŒ%‹‹‹$ŠŠŠ#‰‰‰"ˆˆˆ!‡‡‡ †††……„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzyàyyxßxxwÞwwvÝvvuÜuutÛttsÚssssrrrrqqqqppppoooonÕnnnnmmmmllllkÒkkkkjjjjiÐiiiihhhhhhggggfÍffffeÌeeeedËddddcÊccccbÉbbbbbbaÈaaaa`Ç``````_Æ______^Å^^^^^^]Ä]]]]]]\Ã\\\\\\\\[Â[[[[[[[[ZÁZZZZZZZZYÀYYYYYYYYX¿X¿XXXXXXXXW¾W¾WWWWWWWWWWV½VVVVVVVVVVU¼U¼UUUUUUUUUUUUT»T»TTTTTTTTTTTTSºSºSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQQQP·P·PPPPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOOOOOONµNµNµNNNNNNNNNNNNNNNNNNNNNNNNNNM´M´M´MMMMMMMMMMMMMMMMMMMMMMMMMMMMMML³L³L³LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK²K²K²K²KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ±J±J±JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI°I°I°I°IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH¯H¯H¯H¯H¯HHHHHHHHHHHHHHHHHHHHHHHHHH¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ƒ¶ƒ¶ƒ¶ƒ¶ƒµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ‚µ‚µ‚µ‚´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³€³€³€²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±~±~±~°°°°°°°°°°°°°°°°°°°°°°°°°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|®®®®®®®®®®®®®®®®®®®®®{®{­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««xªªªªªªªªªªªªªªªw©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨u§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥r¥r¤¤¤¤¤¤¤q¤q£££££££p¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡n       mŸŸŸŸŸŸŸlžžžžžžžkjœœœœœœ›››››››hšššššg™™™™™f˜˜˜˜——————–––––c••••”””””a““““’’’’’_‘‘‘‘\ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqp£ppo¢oooonnnnmmmmlŸllllkkkkjjjjjiiiih›hhhhgšggggf™ffffe˜eeeed—ddddc–ccccb•bbbbbba”aaaa`“``````_’______^‘^^^^^^]]]]]]]\\\\\\\\[Ž[[[[[[[[ZZZZZZZZZYŒYYYYYYYYYYX‹XXXXXXXXXXWŠWWWWWWWWWWV‰V‰VVVVVVVVVVUˆUˆUUUUUUUUUUUUT‡TTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQPƒPƒPPPPPPPPPPPPPPPPPPPPO‚O‚OOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM€M€MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK~K~K~KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ}J}J}J}JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI|I|I|I|IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH{H{H{H{HHHHHHHHHHHHHHHHHH¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««ªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››šššššš™™™™™™˜˜˜˜˜˜——————––––••••••””””““““““’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssrrrrqqqqqqppppoooonnnnmmmmmmllllkkkkkkjjjjiiiiiihhhhhhggggggffffffeeeeeeddddddccccccbbbbbbbbaaaaaa````````________^^^^^^^^]]]]]]]]]]\\\\\\\\[[[[[[[[[[ZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHHHHHHHHHHHH¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««ªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››šššššš™™™™™™˜˜˜˜˜˜——————––––––••••””””””““““’’’’’’‘‘‘‘ŽŽŽŽŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuuttttssssssrrrrqqqqppppoooooonnnnmmmmllllllkkkkjjjjjjiiiiiihhhhhhggggffffffeeeeeeddddddddccccccbbbbbbbbaaaaaa````````________^^^^^^^^]]]]]]]]]]\\\\\\\\[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHHHHHH¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µèµèµèµèµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´ç´ç´ç´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³æ³æ³æ³æ³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²å²å²å²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±ä±ä±ä±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°ã°ã°°°°°°°°°°°°°°°°°°°°°°°°°°¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®á®®®®®®®®®®®®®®®®®®­à­à­à­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««ªÝªÝªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©¨Û¨¨¨¨¨¨¨¨¨¨¨¨§Ú§§§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤£Ö££££££££¢Õ¢¢¢¢¢¢¡Ô¡Ô¡¡¡¡¡¡ Ó      ŸÒŸŸŸŸŸŸžÑžžžžžžÐœÏœœœœœœ›Î››››šÍšššš™Ì™™™™˜Ë˜˜˜˜—Ê————–É––––•È••••””””“Æ““““’’’’‘Ä‘‘‘‘ÂŽŽŽŽŒŒŒŒ‹¾‹‹Š½ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvuuuutttttAssssrrrrqqqqppppp=oooonnnnmmmmm:llllkkkkk8jjjjj7iiiihhhhhhggggg4fffff3eeeee2ddddddd1ccccc0bbbbbbaaaaaaa.```````-_______,^^^^^^^+]]]]]]]]]*\\\\\\\)\)[[[[[[[([(ZZZZZZZZZ'YYYYYYYYYYY&XXXXXXXXXXX%WWWWWWWWWWW$W$VVVVVVVVVVV#V#UUUUUUUUUUUUU"U"TTTTTTTTTTTTTTT!SSSSSSSSSSSSSSSSS S RRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««ªªªªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§ ¦¦¦¦¦¦¦¦¦¦¦ ¥¥¥¥¥¥¥¥¥ ¥ ¤¤¤¤¤¤¤¤¤ £££££££££ ¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡       ŸŸŸŸŸŸŸžžžžžžžœœœœœœœ›››››šššššš™™™™™™˜˜˜˜˜˜——————––––•ü••••”û””””““““’ù’’’’‘‘‘‘÷ŽõŽŽôŒŒŒŒ‹‹‹‹ŠŠŠŠ‰ð‰‰ˆïˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwwwwvvvvvuuuttttssssrrrrqqqqq ppppoooonnnnnmmmmlllllkkkkkjjjjiiiiihhhhhgggggffffeÿeeeedþddddddccccccbübbbbaûaaaaaa`ú``````_ù______^ø^^^^^^]÷]]]]]]]]\ö\\\\\\\\[õ[[[[[[[[ZôZZZZZZZZYóYóYYYYYYYYXòXXXXXXXXXXWñWñWWWWWWWWWWVðVVVVVVVVVVVVUïUïUUUUUUUUUUUUTîTîTTTTTTTTTTTTSíSíSSSSSSSSSSSSSSSSRìRìRRRRRRRRRRRRRRRRQëQëQQQQQQQQQQQQQQQQQQPêPêPêPPPPPPPPPPPPPPPPPPPPOéOéOéOOOOOOOOOOOOOOOOOOOOOOOONèNèNNNNNNNNNNNNNNNNNNNNNNNNNNNNMçMçMçMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLæLæLæLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKåKåKåKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJäJäJäJäJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIãIãIãIãIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶O¶O¶O¶OµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµNµNµNµN´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´M´M´M³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³L³L³L²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²K²K²K±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±J±J±J°°°°°°°°°°°°°°°°°°°°°°°°°°°I°I¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯H¯H®®®®®®®®®®®®®®®®®®®®®G®G­­­­­­­­­­­­­­­­­­­F­F¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬E¬E«««««««««««««««D«DªªªªªªªªªªªªªªªCªC©©©©©©©©©©©B©B¨¨¨¨¨¨¨¨¨¨¨¨¨A§§§§§§§§§§§@§@¦¦¦¦¦¦¦¦¦?¦?¥¥¥¥¥¥¥¥¥>¤¤¤¤¤¤¤¤¤=¤=£££££££<£<¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡:       9ŸŸŸŸŸŸŸ8žžžžžžž7œœœœœœœ5››››››ššššššš3™™™™™2˜˜˜˜˜1—————0––––••••••”””””-““““’’’’’+‘‘‘‘)ŽŽŽŽ&ŒŒŒŒ‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆˆ!‡‡‡‡††††…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyxxxxwÞwwvÝvvvvuuuuttttssssrrrrqØqqqqppppoooonÕnnnnmmmmlÓllllkkkkkkjjjjiÐiiiihÏhhhhgÎggggfÍffffeÌeeeedËddddcÊccccccbÉbbbbaÈaaaaaa`Ç``````_Æ______^Å^^^^^^]Ä]Ä]]]]]]\Ã\\\\\\\\[Â[[[[[[[[ZÁZZZZZZZZZZYÀYYYYYYYYX¿X¿XXXXXXXXXXW¾WWWWWWWWWWV½V½VVVVVVVVVVVVU¼UUUUUUUUUUUUUUT»TTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQQQQQP·P·PPPPPPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOOOOOOOONµNµNµNNNNNNNNNNNNNNNNNNNNNNNNNNNNM´M´M´MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMML³L³L³LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK²K²K²KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ±J±J±JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI°I°I°I°IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ƒ¶ƒ¶ƒ¶ƒ¶ƒµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ‚µ‚µ‚µ‚´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³€³€³€²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±~±~°°°°°°°°°°°°°°°°°°°°°°°°°°°}°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|¯|®®®®®®®®®®®®®®®®®®®®®{®{­­­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««xªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©v¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤q£££££££££p¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡n       mŸŸŸŸŸŸŸlžžžžžžžkjœœœœœi›››››››hšššššg™™™™™f˜˜˜˜˜e—————d–––––c•••••b””””“““““`’’’’‘‘‘‘‘^\ŽŽŽŽŒŒŒŒŒY‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡‡T†††S…………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyx«xxxxwwwwvvvvuuuutttts¦ssr¥rrrrqqqqppppo¢oooonnnnm mmmmllllkžkkkkjjjjjiiiiiihhhhhhggggggffffffeeeeeed—ddddc–ccccccbbbbbba”aaaaaa`“``````_’______^‘^^^^^^^^]]]]]]]\\\\\\\\\[Ž[[[[[[[[ZZZZZZZZZZYŒYYYYYYYYYYX‹XXXXXXXXXXWŠWŠWWWWWWWWWWV‰V‰VVVVVVVVVVUˆUˆUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQQQPƒPƒPPPPPPPPPPPPPPPPPPPPPPO‚O‚OOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM€M€MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK~K~K~KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ}J}J}J}JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI|I|I|I|IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««ªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœ››››››››šššššš™™™™™™˜˜˜˜˜˜——————––––––••••••””””””““““’’’’’’‘‘‘‘ŽŽŽŽŽŽŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††………………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{zzzzyyyyyyxxxxwwwwvvvvuuuuttttttssssrrrrqqqqppppppoooonnnnnnmmmmllllllkkkkkkjjjjiiiiiihhhhhhggggggffffffeeeeeeeeddddddccccccbbbbbbbbaaaaaaaa````````________^^^^^^^^^^]]]]]]]]\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII¶¶¶¶¶¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««ªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡        ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœ››››››››šššššš™™™™™™™™˜˜˜˜˜˜——————––––––••••””””””““““““’’’’‘‘‘‘‘‘ŽŽŽŽŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{{{zzzzyyyyxxxxwwwwvvvvuuuuuuttttssssrrrrqqqqqqppppoooooonnnnmmmmmmllllkkkkkkjjjjjjiiiiiihhhhhhggggggffffffeeeeeeddddddddccccccbbbbbbbbaaaaaaaa````````________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIµèµèµèµèµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´ç´ç´ç´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³æ³æ³æ³æ³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²å²å²å²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±ä±ä±ä±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°ã°ã°ã°°°°°°°°°°°°°°°°°°°°°°°°°°¯â¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®®®®®®®®®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ««««««««««««««««ªÝªÝªªªªªªªªªªªªªª©Ü©©©©©©©©©©©©©©¨Û¨¨¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¦¦¥Ø¥Ø¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤£Ö££££££££¢Õ¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡ Ó Ó      ŸÒŸŸŸŸŸŸžÑžžžžžžÐœÏœœœœœœ››››››šÍšššššš™™™™™™˜Ë˜˜˜˜—Ê————–É––––•È••••””””””““““’Å’’’’‘‘‘‘‘‘ÂŽŽŽŽŒ¿ŒŒŒŒ‹‹‹‹ŠŠŠŠ‰¼‰‰‰‰ˆˆˆˆ‡‡‡‡††††…………„„„„ƒ¶ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||{{{{{{zzzzyyyyxxxxwwwwvvvvvCuuuuttttssssrrrrr?qqqqppppp=oooonnnnn;mmmmlllll9kkkkk8jjjjj7iiiihhhhhhh5ggggg4fffff3eeeee2ddddddd1ccccc0bbbbbbb/aaaaaaa.```````-_______,^^^^^^^^^+]]]]]]]]]*\\\\\\\\\)[[[[[[[[[(ZZZZZZZZZZZ'YYYYYYYYYYY&XXXXXXXXXXX%X%WWWWWWWWWWW$W$VVVVVVVVVVVVV#UUUUUUUUUUUUUUU"U"TTTTTTTTTTTTTTT!T!SSSSSSSSSSSSSSSSS S RRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««ªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§ § ¦¦¦¦¦¦¦¦¦¦¦ ¥¥¥¥¥¥¥¥¥¥¥ ¤¤¤¤¤¤¤¤¤ ¤ £££££££££ ¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡         ŸŸŸŸŸŸŸžžžžžžžœœœœœœœ›››››ššššššš™™™™˜ÿ˜˜˜˜—þ————–ý––––•ü••••”û””””“ú““““’’’’’’‘‘‘‘÷ŽõŽŽŽŽŒŒŒŒ‹ò‹‹‹‹ŠŠŠŠ‰‰‰‰ˆïˆˆˆˆ‡‡‡‡††††…………„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€~~~~}}}}|||||{{{{zzzzyyyyxxxxwwwwwvvvvuuuuttttsssss rrrrqqqqq ppppooooonnnnmmmmmlllllkkkkjjjjjjiiiiihhhhhhggggggffffffeÿeeeedþddddddccccccbübbbbbbaûaaaaaa`ú``````_ù______^ø^^^^^^^^]÷]]]]]]]]\ö\\\\\\\\[õ[[[[[[[[ZôZZZZZZZZZZYóYYYYYYYYYYXòXXXXXXXXXXXXWñWWWWWWWWWWWWVðVVVVVVVVVVVVUïUïUUUUUUUUUUUUUUTîTTTTTTTTTTTTTTTTSíSíSSSSSSSSSSSSSSSSRìRìRRRRRRRRRRRRRRRRRRQëQëQQQQQQQQQQQQQQQQQQQQPêPêPPPPPPPPPPPPPPPPPPPPPPOéOéOéOOOOOOOOOOOOOOOOOOOOOOOOOONèNèNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMçMçMçMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLæLæLæLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKåKåKåKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJäJäJäJäJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIãIãIãIãIIIIIIIIIIIIIIIIIIIIIIIIIIµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµNµNµNµN´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´M´M´M´M³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³L³L³L²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²K²K²K±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±J±J±J°°°°°°°°°°°°°°°°°°°°°°°°°°°I°I°I¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯H¯H®®®®®®®®®®®®®®®®®®®®®®®G®G­­­­­­­­­­­­­­­­­­­­­F­F¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬E¬E«««««««««««««««D«DªªªªªªªªªªªªªªªCªC©©©©©©©©©©©©©B©B¨¨¨¨¨¨¨¨¨¨¨¨¨A§§§§§§§§§§§§§@¦¦¦¦¦¦¦¦¦¦¦?¦?¥¥¥¥¥¥¥¥¥>¥>¤¤¤¤¤¤¤¤¤=£££££££££££<¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡:         9ŸŸŸŸŸŸŸ8žžžžžžž76œœœœœœœ5››››››ššššššš3™™™™™2˜˜˜˜˜˜——————––––––••••••””””””“““““,’’’’’+‘‘‘‘)ŽŽŽŽŽ'ŒŒŒŒ‹‹‹‹‹$ŠŠŠŠ‰‰‰‰ˆˆˆˆˆ!‡‡‡‡††††…………„„„„ƒƒƒƒƒ‚‚‚‚€€€€~~~~}}}}||||||{{{{zzzzyyyyxxxxwÞwwwwvvvvuuuuttttsÚssssrrrrqØqqqqppppoooooonnnnmÔmmmmllllllkkkkjÑjjjjiÐiiiihÏhhhhgÎggggfÍffffffeeeeeedËddddcÊccccccbÉbbbbbbaÈaaaaaa`Ç``````_Æ______^Å^^^^^^^^]Ä]]]]]]]]\Ã\\\\\\\\[Â[[[[[[[[ZÁZÁZZZZZZZZYÀYÀYYYYYYYYX¿X¿XXXXXXXXXXW¾W¾WWWWWWWWWWV½V½VVVVVVVVVVVVU¼U¼UUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTSºSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQQQQQP·P·PPPPPPPPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOOOOOOOOOONµNµNµNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM´M´MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMML³L³L³LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK²K²K²K²KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ±J±J±JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI°I°I°I°IIIIIIIIIIIIIIIIIIµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ‚µ‚µ‚µ‚´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³€³€³€²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±~±~±~°°°°°°°°°°°°°°°°°°°°°°°°°°°°°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|®®®®®®®®®®®®®®®®®®®®®®®{®{­­­­­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««xªªªªªªªªªªªªªªªªªw©©©©©©©©©©©©©©©v¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤q£££££££££p£p¢¢¢¢¢¢¢o¢o¡¡¡¡¡¡¡n         mŸŸŸŸŸŸŸlžžžžžžžkjœœœœœœœi›››››››hšššššg™™™™™™˜˜˜˜˜˜˜e—————d–––––c•••••b”””””a““““’’’’’’‘‘‘‘‘^\ŽŽŽŽZŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡‡T††††…………„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€~~~~}}}}|¯||||{{{{zzzzyyyyxxxxxxwwwwvvvvuuuut§ttttssssrrrrrrqqqqppppo¢oooonnnnnnmmmmlŸllllkžkkkkjjjjjjiiiiiihhhhhhggggggf™ffffe˜eeeeeeddddddc–ccccccb•bbbbbba”aaaaaa`“``````_’______^‘^^^^^^^^]]]]]]]]]\\\\\\\\\[Ž[[[[[[[[[[ZZZZZZZZZZZYŒYYYYYYYYYYX‹XXXXXXXXXXXXWŠWWWWWWWWWWWWV‰VVVVVVVVVVVVVVUˆUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQQQPƒPƒPPPPPPPPPPPPPPPPPPPPPPPPO‚O‚O‚OOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM€M€M€MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK~K~K~KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ}J}J}J}JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI|I|I|I|IIIIIIIIIIµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››››šššššš™™™™™™™™˜˜˜˜˜˜——————––––––••••••””””””““““““’’’’’’‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡‡‡††††††…………„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€~~~~}}}}}}||||{{{{zzzzyyyyxxxxxxwwwwvvvvuuuuuuttttssssrrrrrrqqqqppppppoooonnnnnnmmmmmmllllllkkkkjjjjjjiiiiiihhhhhhggggggggffffffeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa````````________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››››šššššššš™™™™™™˜˜˜˜˜˜——————––––––––••••••””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆ‡‡‡‡††††††…………„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€~~~~}}}}}}||||{{{{zzzzyyyyyyxxxxwwwwvvvvvvuuuuttttssssssrrrrqqqqqqppppoooooonnnnnnmmmmllllllkkkkkkjjjjjjiiiiiihhhhhhggggggffffffffeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa````````________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´ç´ç´ç´ç´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³æ³æ³æ³æ³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²å²å²å²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±ä±ä±ä±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°ã°ã°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®á®®®®®®®®®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««ªÝªÝªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©¨Û¨¨¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¦¦¥Ø¥Ø¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤£Ö£Ö££££££££¢Õ¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡ Ó        ŸÒŸŸŸŸŸŸžÑžžžžžžžžœœœœœœ›Î››››››šÍšššššš™Ì™™™™˜Ë˜˜˜˜˜˜——————––––––•È••••”Ç””””““““““’’’’’’‘‘‘‘ÃŽŽŽŽÀŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰ˆ»ˆˆˆˆ‡‡‡‡††††…¸…………„„„„ƒƒƒƒ‚‚‚‚´€€€€~~~~}}}}}}||||{{{{zzzzyyyyyyxxxxwwwwvvvvvvuuuutttttAssssrrrrr?qqqqppppp=oooonnnnnnmmmmm:lllll9kkkkk8jjjjj7iiiii6hhhhh5ggggg4ffffffeeeeeee2ddddddd1ccccccbbbbbbbbaaaaaaaaa.```````-_______,_,^^^^^^^+]]]]]]]]]*\\\\\\\\\\\)[[[[[[[[[([(ZZZZZZZZZ'Z'YYYYYYYYYYY&XXXXXXXXXXXXX%WWWWWWWWWWWWW$W$VVVVVVVVVVVVV#V#UUUUUUUUUUUUUUU"TTTTTTTTTTTTTTTTT!T!SSSSSSSSSSSSSSSSSSS S RRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««ªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§ § ¦¦¦¦¦¦¦¦¦¦¦ ¥¥¥¥¥¥¥¥¥¥¥ ¥ ¤¤¤¤¤¤¤¤¤ £££££££££££ ¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡         ŸŸŸŸŸŸŸžžžžžžžžžœœœœœœ›››››››ššššššš™™™™™™˜˜˜˜˜˜—þ————–ý––––•ü••••”û””””“ú““““’ù’’’’‘ø‘‘‘‘ŽõŽŽŽŽŒóŒŒŒŒ‹‹‹‹ŠñŠŠŠŠ‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡††††………………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}}}}}}||||{{{{zzzzzyyyyxxxxwwwwwvvvvuuuuttttttssssrrrrrrqqqqq ppppooooonnnnnmmmmllllllkkkkkkjjjjjjiiiiiihhhhhhgggggggffffeÿeeeeeedþddddddccccccbübbbbbbaûaaaaaaaa`ú``````_ù________^ø^^^^^^]÷]]]]]]]]\ö\ö\\\\\\\\[õ[[[[[[[[[[ZôZZZZZZZZZZYóYYYYYYYYYYXòXXXXXXXXXXXXWñWñWWWWWWWWWWWWVðVVVVVVVVVVVVVVUïUUUUUUUUUUUUUUTîTîTTTTTTTTTTTTTTTTSíSíSSSSSSSSSSSSSSSSSSRìRRRRRRRRRRRRRRRRRRRRQëQëQQQQQQQQQQQQQQQQQQQQQQPêPêPPPPPPPPPPPPPPPPPPPPPPPPOéOéOéOOOOOOOOOOOOOOOOOOOOOOOOOONèNèNèNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMçMçMçMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLæLæLæLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKåKåKåKåKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJäJäJäJäJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJµµµµµµµµµµµµµµµµµµµNµNµNµN´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´M´M´M´M³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³L³L³L²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²K²K²K±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±J±J±J°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°I°I°I¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯H¯H®®®®®®®®®®®®®®®®®®®®®®®G®G®G­­­­­­­­­­­­­­­­­­­­­F­F¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬E¬E«««««««««««««««««D«DªªªªªªªªªªªªªªªªªC©©©©©©©©©©©©©©©B©B¨¨¨¨¨¨¨¨¨¨¨¨¨A¨A§§§§§§§§§§§§§@¦¦¦¦¦¦¦¦¦¦¦¦¦?¥¥¥¥¥¥¥¥¥¥¥>¤¤¤¤¤¤¤¤¤¤¤=£££££££££££<¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡:         9ŸŸŸŸŸŸŸ8žžžžžžžžž76œœœœœœœ5››››››ššššššš3™™™™™™™2˜˜˜˜˜1——————––––––••••••””””””““““““’’’’’’‘‘‘‘‘*)ŽŽŽŽŽ'ŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆˆ!‡‡‡‡††††……………„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~}ä}}}}||||{{{{zzzzzzyyyyxxxxwwwwwwvvvvuuuutÛttttssssrÙrrrrqqqqqqppppoÖoooonnnnnnmmmmlÓllllkÒkkkkjÑjjjjiÐiiiihÏhhhhgÎggggggffffffeÌeeeeeedËddddcÊccccccbÉbbbbbbaÈaaaaaaaa`Ç``````_Æ________^Å^^^^^^]Ä]Ä]]]]]]]]\Ã\\\\\\\\[Â[[[[[[[[[[ZÁZZZZZZZZZZYÀYYYYYYYYYYX¿X¿XXXXXXXXXXXXW¾WWWWWWWWWWWWV½V½VVVVVVVVVVVVU¼U¼UUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQQQQQQQP·P·PPPPPPPPPPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOOOOOOOOOOOONµNµNµNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM´M´MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMML³L³L³LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK²K²K²KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ±J±J±JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJµµµµµµµµµµµ‚µ‚µ‚µ‚´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³€³€³€²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±~±~°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|¯|®®®®®®®®®®®®®®®®®®®®®®®{®{­­­­­­­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««xªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u§§§§§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦¦¦s¦s¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤q£££££££££p£p¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡n         mŸŸŸŸŸŸŸlžžžžžžžžžkjœœœœœœœi›››››››hšššššš™™™™™™™f˜˜˜˜˜˜———————d–––––c•••••b”””””a“““““`’’’’’_‘‘‘‘\ŽŽŽŽŒŒŒŒŒY‹‹‹‹ŠŠŠŠŠW‰‰‰‰ˆˆˆˆ‡‡‡‡‡‡††††…………„„„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~~~}}}}||||{{{{z­zzzzyyyyxxxxwªwwwwvvvvu¨uuuutttts¦ssssrrrrq¤qqqqppppppoooon¡nnnnmmmmmmllllllkkkkkkjjjjjjiiiiiih›hhhhgšggggf™ffffffe˜eeeeeeddddddc–ccccccb•bbbbbba”aaaaaaaa````````_’________^‘^^^^^^^^]]]]]]]]]\\\\\\\\\[Ž[[[[[[[[[[ZZZZZZZZZZZYŒYŒYYYYYYYYYYX‹XXXXXXXXXXXXWŠWŠWWWWWWWWWWWWV‰VVVVVVVVVVVVVVUˆUˆUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQQQQQPƒPƒPƒPPPPPPPPPPPPPPPPPPPPPPPPO‚O‚O‚OOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM€M€M€MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK~K~K~KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ}J}J}J}JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJµµµµµµµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœ››››››››šššššššš™™™™™™˜˜˜˜˜˜˜˜——————––––––••••••””””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡‡††††…………„„„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~~~}}}}||||{{{{{{zzzzyyyyxxxxxxwwwwvvvvvvuuuuttttttssssrrrrrrqqqqppppppoooooonnnnmmmmmmllllllkkkkkkjjjjjjiiiiiiiihhhhhhggggggffffffffeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa``````````__________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJµµµµ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœ››››››››šššššššš™™™™™™˜˜˜˜˜˜˜˜——————––––––––••••••””””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡††††††…………„„„„„„ƒƒƒƒ‚‚‚‚€€€€~~~~~~}}}}||||{{{{{{zzzzyyyyxxxxxxwwwwvvvvvvuuuuttttttssssrrrrrrqqqqqqppppoooooonnnnnnmmmmmmllllllkkkkkkjjjjjjiiiiiihhhhhhggggggggffffffeeeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa``````````__________^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ´ç´ç´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³æ³æ³æ³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²å²å²å²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±ä±ä±ä±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°ã°ã°ã°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®®®®®®®®®®®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««ªÝªÝªªªªªªªªªªªªªªªª©Ü©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§§§§§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¦¦¥Ø¥Ø¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤£Ö££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡ Ó        ŸÒŸŸŸŸŸŸžÑžžžžžžžžÐœÏœœœœœœ›Î››››››šÍšššššš™Ì™™™™™™˜˜˜˜˜˜—Ê——————––––––•È••••”Ç””””“Æ““““’Å’’’’‘Ä‘‘‘‘ÃŽŽŽŽÀŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡††††††…………„„„„ƒ¶ƒƒƒƒ‚‚‚‚€€€€~~~~~~}}}}||||{{{{{{zzzzyyyyyFxxxxwwwwwDvvvvuuuuuBttttsssss@rrrrqqqqqqppppp=ooooo¥>¤¤¤¤¤¤¤¤¤¤¤=£££££££££££<¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡:         9ŸŸŸŸŸŸŸ8žžžžžžžžž76œœœœœœœœ››››››››šššššššš™™™™™™™2˜˜˜˜˜˜˜1—————0––––––•••••••.”””””-“““““,’’’’’+‘‘‘‘‘*ŽŽŽŽŽŽ&ŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆ!‡‡‡‡††††………………„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€~~~~~~}}}}||||||{{{{zzzzyyyyyyxxxxwwwwwwvvvvuÜuuuuttttsÚssssrrrrrrqqqqp×ppppoÖoooonnnnnnmmmmmmllllllkkkkkkjjjjjjiÐiiiihÏhhhhhhggggggfÍffffffeÌeeeeeeddddddddccccccccbbbbbbbbaÈaaaaaa`Ç````````_Æ________^Å^^^^^^^^]Ä]]]]]]]]\Ã\\\\\\\\\\[Â[[[[[[[[[[ZÁZZZZZZZZZZZZYÀYYYYYYYYYYYYX¿XXXXXXXXXXXXW¾WWWWWWWWWWWWWWV½V½VVVVVVVVVVVVVVU¼UUUUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQQQQQQQP·P·P·PPPPPPPPPPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOOOOOOOOOOOOOONµNµNµNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM´M´MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMML³L³L³LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK²K²K²KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ±J±J±JJJJJJJJJJJJJJ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³€³€³€³€²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±~±~±~°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°}°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|®®®®®®®®®®®®®®®®®®®®®®®®®{®{®{­­­­­­­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««xªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦¦¦s¦s¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££p¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡n         mŸŸŸŸŸŸŸŸžžžžžžžžžkœœœœœœœœœi›››››››hšššššššg™™™™™™˜˜˜˜˜˜˜e——————–––––––c•••••b””””””““““““’’’’’’‘‘‘‘‘‘\ŽŽŽŽŽ[ŒŒŒŒŒŒ‹‹‹‹‹XŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡‡††††………………„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€€€~~~~~~}}}}||||||{{{{zzzzy¬yyyyxxxxwªwwwwvvvvvvuuuuttttttssssr¥rrrrqqqqqqppppppoooon¡nnnnm mmmmlŸllllkžkkkkjjjjjjjiiiiiih›hhhhgšggggggf™ffffffeeeeeed—ddddddc–ccccccb•bbbbbbbba”aaaaaa`“````````_’________^‘^^^^^^^^]]]]]]]]]\\\\\\\\\\[Ž[Ž[[[[[[[[ZZZZZZZZZZZZYŒYYYYYYYYYYYYX‹XXXXXXXXXXXXWŠWŠWWWWWWWWWWWWWWV‰VVVVVVVVVVVVVVUˆUˆUUUUUUUUUUUUUUUUT‡TTTTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQQQQQQQPƒPƒPPPPPPPPPPPPPPPPPPPPPPPPPPO‚O‚O‚OOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM€M€M€MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK~K~K~K~KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ}J}J}J}JJJJJJ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««ªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››››šššššššš™™™™™™™™˜˜˜˜˜˜————————––––––••••••””””””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡‡††††………………„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€€€~~~~~~}}}}||||||{{{{zzzzzzyyyyxxxxxxwwwwvvvvvvuuuuttttttssssssrrrrqqqqqqppppppoooooonnnnnnmmmmmmllllllkkkkkkjjjjjjiiiiiiiihhhhhhggggggggffffffeeeeeeeeddddddddccccccccbbbbbbbbbbaaaaaaaa``````````__________^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJJJJ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸŸŸžžžžžžžžœœœœœœœœ››››››››šššššššš™™™™™™™™˜˜˜˜˜˜————————––––––••••••••””””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡††††††………………„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}||||||{{{{zzzzzzyyyyxxxxxxwwwwvvvvvvuuuuuuttttssssssrrrrrrqqqqqqppppoooooonnnnnnmmmmmmllllllkkkkkkkkjjjjjjiiiiiihhhhhhhhggggggffffffffeeeeeeeeddddddddccccccccbbbbbbbbbbaaaaaaaa``````````__________^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK´´´´´´´´´´´´´´´´´´´´´´´´´´´´³æ³æ³æ³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²å²å²å²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±ä±ä±ä±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°ã°ã°ã°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯â¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®®®®®®®®®®®®®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««ªÝªÝªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¤×¤×¤¤¤¤¤¤¤¤¤¤£Ö££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡ Ó Ó        ŸÒŸŸŸŸŸŸŸŸžÑžžžžžžÐœÏœœœœœœ›Î››››››šÍšššššš™Ì™™™™™™˜Ë˜˜˜˜˜˜——————–É––––––••••••”Ç””””“Æ““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒ¿ŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰¼‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡††††††…………„·„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}||||||{{{{zzzzzzyyyyxxxxxxwwwwwDvvvvuuuuuutttttAssssrrrrrrqqqqqqppppp=ooooo¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££<¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡:           9ŸŸŸŸŸŸŸŸŸ8žžžžžžž76œœœœœœœ5››››››››šššššššš™™™™™™™™˜˜˜˜˜˜˜1———————0––––––•••••••.”””””-““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒ%‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆ‡‡‡‡‡‡††††††…………„„„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}|ã||||{{{{{{zzzzyyyyyyxxxxwwwwwwvvvvvvuuuuttttttssssssrrrrqØqqqqp×ppppoÖoooonÕnnnnmÔmmmmlÓllllkÒkkkkkkjjjjjjiÐiiiiiihhhhhhgÎggggggffffffffeeeeeeeeddddddddccccccccbÉbbbbbbaÈaaaaaaaa`Ç````````_Æ________^Å^^^^^^^^]Ä]Ä]]]]]]]]\Ã\\\\\\\\\\[Â[[[[[[[[[[[[ZÁZZZZZZZZZZYÀYÀYYYYYYYYYYYYX¿XXXXXXXXXXXXW¾W¾WWWWWWWWWWWWWWV½VVVVVVVVVVVVVVVVU¼U¼UUUUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTTTSºSSSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQQQQQQQQQQQP·P·PPPPPPPPPPPPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONµNµNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM´M´M´MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMML³L³L³LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK²K²K²KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK´´´´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³€³€³€²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±~±~±~°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|®®®®®®®®®®®®®®®®®®®®®®®®®®®®®{®{­­­­­­­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦¦¦s¦s¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤q¤q£££££££££££p¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡n           mŸŸŸŸŸŸŸŸŸlžžžžžžžžjœœœœœœœœ›››››››››hšššššššg™™™™™™™f˜˜˜˜˜˜———————d–––––––c•••••b””””””“““““““`’’’’’_‘‘‘‘‘^]\ŽŽŽŽŽ[ZŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰Vˆˆˆˆ‡‡‡‡‡‡†††††S…………„„„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||{{{{{{zzzzyyyyyyxxxxwªwwwwvvvvvvuuuut§ttttssssssrrrrrrqqqqqqppppppoooooonnnnnnmmmmmmllllllkžkkkkjjjjjjjiiiiiih›hhhhhhggggggf™ffffffe˜eeeeeed—ddddddc–ccccccccb•bbbbbba”aaaaaaaa`“````````_’________^‘^^^^^^^^^^]]]]]]]]]\\\\\\\\\\\[Ž[Ž[[[[[[[[[[ZZZZZZZZZZZZZYŒYYYYYYYYYYYYX‹XXXXXXXXXXXXXXWŠWWWWWWWWWWWWWWV‰V‰VVVVVVVVVVVVVVVVUˆUUUUUUUUUUUUUUUUUUT‡TTTTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQQQQQQQQQPƒPƒPPPPPPPPPPPPPPPPPPPPPPPPPPPPO‚O‚O‚OOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM€M€M€MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK~K~K~KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK´´´´´´´´³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœœœ››››››››šššššššš™™™™™™™™˜˜˜˜˜˜˜˜——————––––––––••••••””””””””““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††………………„„„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||{{{{{{zzzzyyyyyyxxxxxxwwwwvvvvvvuuuuuuttttssssssrrrrrrqqqqqqppppppoooooonnnnnnmmmmmmllllllllkkkkkkjjjjjjiiiiiiiihhhhhhggggggggffffffffeeeeeeeeddddddddccccccccccbbbbbbbbaaaaaaaaaa``````````__________^^^^^^^^^^^^]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœœœ››››››››šššššššš™™™™™™™™˜˜˜˜˜˜˜˜————————––––––••••••••””””””““““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††………………„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||{{{{{{zzzzyyyyyyxxxxxxwwwwwwvvvvuuuuuuttttttssssssrrrrrrqqqqppppppoooooonnnnnnnnmmmmmmllllllkkkkkkjjjjjjjjiiiiiihhhhhhhhggggggggffffffffeeeeeeeeddddddddccccccccbbbbbbbbbbaaaaaaaaaa``````````__________^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²å²å²å²å²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±ä±ä±ä±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°ã°ã°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®á®®®®®®®®®®®®®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««««ªÝªÝªªªªªªªªªªªªªªªªªª©Ü©©©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡ Ó          ŸÒŸŸŸŸŸŸŸŸžÑžžžžžžžžÐœÏœœœœœœœœ›Î››››››šÍšššššš™Ì™™™™™™˜Ë˜˜˜˜˜˜—Ê——————–É––––––••••••”Ç””””””““““““’Å’’’’‘Ä‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹Š½ŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡†¹††††………………„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||{{{{{{zzzzzGyyyyxxxxxxwwwwwwvvvvuuuuuuttttttssssssrrrrrrqqqqq>ppppp=ooooo¥>¤¤¤¤¤¤¤¤¤¤¤=¤=£££££££££££<¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡:           9ŸŸŸŸŸŸŸŸŸ8žžžžžžžžž76œœœœœœœ5››››››››ššššššššš3™™™™™™™2˜˜˜˜˜˜˜1——————––––––––•••••••.””””””“““““““,’’’’’+‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰"ˆˆˆˆ‡‡‡‡‡‡††††††……………„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~å~~~~}}}}}}||||{â{{{{zzzzzzyyyyxßxxxxwwwwwwvvvvvvuuuuuuttttsÚssssrÙrrrrqØqqqqp×ppppoÖoooonÕnnnnnnmmmmmmllllllkÒkkkkkkjjjjjjiÐiiiiiihhhhhhgÎggggggfÍffffffeÌeeeeeedËddddddddcÊccccccbÉbbbbbbbbaÈaaaaaaaa`Ç````````_Æ________^Å^^^^^^^^^^]Ä]]]]]]]]]]\Ã\\\\\\\\\\[Â[[[[[[[[[[[[ZÁZZZZZZZZZZZZYÀYYYYYYYYYYYYYYX¿XXXXXXXXXXXXXXW¾WWWWWWWWWWWWWWWWV½VVVVVVVVVVVVVVVVU¼U¼UUUUUUUUUUUUUUUUUUT»TTTTTTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQQQQQQQQQQQP·P·PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONµNµNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM´M´M´MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMML³L³L³LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK²K²K²KKKKKKKKKK³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³€³€³€²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±~±~°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°}°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|¯|®®®®®®®®®®®®®®®®®®®®®®®®®®®®®{®{­­­­­­­­­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©©©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u§§§§§§§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££p¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡n         m mŸŸŸŸŸŸŸŸŸlžžžžžžžžžkjœœœœœœœi›››››››››hšššššššg™™™™™™™f˜˜˜˜˜˜˜e———————d–––––––c••••••”””””””a““““““’’’’’’‘‘‘‘‘‘‘^]ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠW‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††…………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚O€€€€€€~~~~}}}}}}||||||{{{{zzzzzzyyyyyyxxxxwªwwwwvvvvvvuuuuuuttttttssssssrrrrrrqqqqqqppppppoooooonnnnnnmmmmmmlŸllllllkkkkkkjjjjjjjiiiiiih›hhhhhhgšggggggf™ffffffe˜eeeeeed—ddddddddccccccccb•bbbbbbbba”aaaaaaaa`“````````_’________^‘^^^^^^^^^^]]]]]]]]]]]\\\\\\\\\\\[Ž[Ž[[[[[[[[[[ZZZZZZZZZZZZZYŒYŒYYYYYYYYYYYYX‹X‹XXXXXXXXXXXXWŠWŠWWWWWWWWWWWWWWV‰V‰VVVVVVVVVVVVVVVVUˆUˆUUUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQQQQQQQQQPƒPƒPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO‚O‚O‚OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM€M€M€MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK~K~K~KKKK³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœ››››››››››šššššššš™™™™™™™™˜˜˜˜˜˜˜˜————————––––––––••••••••””””””““““““““’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††…………„„„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€€€~~~~}}}}}}||||||{{{{zzzzzzyyyyyyxxxxxxwwwwvvvvvvuuuuuuttttttssssssrrrrrrqqqqqqppppppoooooonnnnnnmmmmmmmmllllllkkkkkkkkjjjjjjiiiiiiiihhhhhhhhggggggggffffffffeeeeeeeeddddddddccccccccccbbbbbbbbbbaaaaaaaaaa``````````__________^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKK³³³³³³³³³³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœœœ››››››››šššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜————————––––––••••••••””””””””““““““’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€€€~~~~}}}}}}||||||{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvuuuuuuttttttssssssrrrrrrqqqqqqppppppoooooooonnnnnnmmmmmmllllllllkkkkkkjjjjjjjjiiiiiiiihhhhhhggggggggffffffffeeeeeeeeeeddddddddccccccccccbbbbbbbbbbaaaaaaaaaa``````````__________^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL³³³³³³³³³³³³³³³³³³³³³³³³²å²å²å²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±ä±ä±ä±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°ã°ã°ã°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯â¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®®®®®®®®®®®®®®®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««««ªÝªÝªªªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§§§§§§§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¤×¤×¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££¢Õ¢Õ¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡ Ó        ŸÒŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžÐœÏœœœœœœœœ›Î››››››šÍšššššššš™™™™™™™™˜Ë˜˜˜˜˜˜—Ê——————–É––––––••••••”Ç””””””“Æ““““““’’’’’’‘‘‘‘‘‘ÃŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡†¹††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€€€~~~~}}}}}}||||||{{{{{HzzzzyyyyyyxxxxxxwwwwwwvvvvvCuuuuuBtttttAsssss@rrrrr?qqqqq>ppppp=oooooonnnnnnmmmmmmm:llllllkkkkkkk8jjjjjjiiiiiiiihhhhhhh5ggggggg4fffffff3eeeeeeeee2ddddddd1ccccccccc0bbbbbbbbaaaaaaaaaaa.`````````-_________,^^^^^^^^^^^+]]]]]]]]]]]*\\\\\\\\\\\\\)[[[[[[[[[[[[[(ZZZZZZZZZZZZZ'YYYYYYYYYYYYYYY&XXXXXXXXXXXXXXX%X%WWWWWWWWWWWWWWW$W$VVVVVVVVVVVVVVVVV#V#UUUUUUUUUUUUUUUUUUU"U"TTTTTTTTTTTTTTTTTTT!T!SSSSSSSSSSSSSSSSSSSSSSS S RRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL³³³³³³³³³³³³³³³³³³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§ § ¦¦¦¦¦¦¦¦¦¦¦¦¦ ¦ ¥¥¥¥¥¥¥¥¥¥¥¥¥ ¤¤¤¤¤¤¤¤¤¤¤¤¤ ¤ £££££££££££ ¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡         ŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžœœœœœœœœœ››››››››ššššššššš™™™™™™˜ÿ˜˜˜˜˜˜—þ——————–ý––––––•ü••••••””””””“ú““““““’ù’’’’‘ø‘‘‘‘‘‘öŽõŽŽŽŽôŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆ‡î‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚€€€€€€~~~~}}}}}}||||||{{{{{{zzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuuttttttssssssrrrrrrqqqqqqppppppooooooonnnnnmmmmmmlllllllkkkkkkjjjjjjjiiiiiiihhhhhhhgggggggffffffeÿeeeeeeeeddddddddcýccccccccbbbbbbbbaûaaaaaaaaaa``````````_ù________^ø^^^^^^^^^^]÷]]]]]]]]]]\ö\ö\\\\\\\\\\[õ[[[[[[[[[[[[ZôZZZZZZZZZZZZYóYóYYYYYYYYYYYYXòXòXXXXXXXXXXXXXXWñWWWWWWWWWWWWWWWWVðVðVVVVVVVVVVVVVVVVUïUïUUUUUUUUUUUUUUUUUUTîTTTTTTTTTTTTTTTTTTTTSíSíSSSSSSSSSSSSSSSSSSSSSSRìRìRRRRRRRRRRRRRRRRRRRRRRRRQëQëQQQQQQQQQQQQQQQQQQQQQQQQQQQQPêPêPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOéOéOéOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONèNèNèNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMçMçMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLæLæLæLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL³³³³³³³³³³³L³L³L³L²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²K²K±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±J±J±J°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°I°I°I¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯H¯H®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®G®G­­­­­­­­­­­­­­­­­­­­­­­­­­­F­F¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬E¬E«««««««««««««««««««««D«DªªªªªªªªªªªªªªªªªªªªªC©©©©©©©©©©©©©©©©©©©B©B¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨A§§§§§§§§§§§§§§§§§@¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦?¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥>¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££<¢¢¢¢¢¢¢¢¢¢¢;¢;¡¡¡¡¡¡¡¡¡¡¡:         9ŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžž76œœœœœœœœœ5›››››››››4ššššššš3™™™™™™™2˜˜˜˜˜˜˜˜————————––––––––•••••••.””””””““““““““’’’’’’‘‘‘‘‘‘‘*ŽŽŽŽŽŽ&ŒŒŒŒŒ%‹‹‹‹‹$ŠŠŠŠŠ#‰‰‰‰‰"ˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒ‚‚‚‚€€€€€€~~~~}}}}}}||||||{{{{{{zzzzyàyyyyxxxxxxwwwwwwvvvvvvuuuuuuttttttssssssrrrrrrqqqqqqppppppoÖoooooonnnnnnmmmmmmlÓllllllkkkkkkjÑjjjjjjiÐiiiiiihhhhhhhhggggggggffffffffeÌeeeeeedËddddddddcÊccccccbÉbbbbbbbbaÈaaaaaaaa`Ç``````````_Æ________^Å^Å^^^^^^^^]Ä]]]]]]]]]]]]\Ã\\\\\\\\\\[Â[[[[[[[[[[[[ZÁZÁZZZZZZZZZZZZYÀYYYYYYYYYYYYYYX¿XXXXXXXXXXXXXXW¾W¾WWWWWWWWWWWWWWWWV½VVVVVVVVVVVVVVVVVVU¼UUUUUUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQQQQQQQQQQQQQP·P·PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONµNµNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM´M´M´MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMML³L³L³LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL³³³³³€³€³€²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±~±~±~°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®{®{­­­­­­­­­­­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥r¥r¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££p¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡n         mŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžkjœœœœœœœœœi›››››››››hšššššššg™™™™™™™™˜˜˜˜˜˜˜˜˜e———————d–––––––c••••••”””””””a“““““““`’’’’’_‘‘‘‘‘‘]ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~}}}}}}||||||{{{{{{zzzzzzyyyyx«xxxxwªwwwwvvvvvvuuuuuuttttttssssssr¥rrrrq¤qqqqp£ppppppoooooonnnnnnm mmmmmmllllllkžkkkkkkjjjjjjjjiiiiiih›hhhhhhgšggggggf™ffffffffeeeeeeeed—ddddddddccccccccb•bbbbbbbba”aaaaaaaa`“``````````_’__________^‘^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\[Ž[Ž[[[[[[[[[[[[ZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYX‹X‹XXXXXXXXXXXXXXWŠWWWWWWWWWWWWWWWWV‰V‰VVVVVVVVVVVVVVVVUˆUˆUUUUUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRRRRRQ„Q„Q„QQQQQQQQQQQQQQQQQQQQQQQQQQPƒPƒPƒPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO‚O‚O‚OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM€M€M€MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL³³³³²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡          ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœœœ››››››››››šššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜————————––––––––••••••••””””””““““““““’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwvvvvvvuuuuuuttttttssssssssrrrrrrqqqqqqppppppoooooonnnnnnnnmmmmmmllllllllkkkkkkjjjjjjjjiiiiiiiihhhhhhhhggggggggffffffffeeeeeeeeeeddddddddccccccccccbbbbbbbbbbaaaaaaaaaa````````````____________^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœ››››››››››šššššššššš™™™™™™™™˜˜˜˜˜˜˜˜————————––––––––••••••••””””””””““““““’’’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuuttttttssssssrrrrrrqqqqqqppppppppoooooonnnnnnmmmmmmmmllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhggggggggffffffffeeeeeeeeeeddddddddccccccccccbbbbbbbbbbaaaaaaaaaa````````````____________^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLL²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±ä±ä±ä±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°ã°ã°ã°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­à­à­à­­­­­­­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««««««ªÝªÝªªªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤£Ö£Ö££££££££££¢Õ¢Õ¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡ Ó          ŸÒŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžÐœÏœœœœœœœœ››››››››šÍšššššššš™Ì™™™™™™˜Ë˜˜˜˜˜˜˜˜————————––––––––••••••••””””””“Æ““““““’’’’’’’’‘‘‘‘‘‘ÂŽŽŽŽŽŽŒ¿ŒŒŒŒ‹¾‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††…………„·„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~K}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuuttttttssssssrrrrrrqqqqqqq>ppppppoooooonnnnnnn;mmmmmmlllllll9kkkkkkk8jjjjjjiiiiiiiihhhhhhhhggggggggg4fffffff3eeeeeeeeddddddddd1ccccccccc0bbbbbbbbb/aaaaaaaaa.```````````-___________,^^^^^^^^^^^+]]]]]]]]]]]*\\\\\\\\\\\\\)[[[[[[[[[[[[[(ZZZZZZZZZZZZZZZ'YYYYYYYYYYYYYYY&XXXXXXXXXXXXXXXXX%WWWWWWWWWWWWWWWWW$W$VVVVVVVVVVVVVVVVVVV#UUUUUUUUUUUUUUUUUUUUU"TTTTTTTTTTTTTTTTTTTTTTT!T!SSSSSSSSSSSSSSSSSSSSSSS S RRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLL²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§ ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ ¤¤¤¤¤¤¤¤¤¤¤¤¤ £££££££££££££ ¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡           ŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžœœœœœœœœœ››››››››ššššššššš™™™™™™™™˜˜˜˜˜˜˜˜—þ——————–ý––––––•ü••••••”û””””””““““““’ù’’’’’’‘ø‘‘‘‘‘‘ŽõŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠñŠŠŠŠ‰ð‰‰‰‰ˆïˆˆˆˆ‡î‡‡‡‡†í††††…ì…………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuuttttttsssssss rrrrr qqqqqqppppppooooooonnnnnnmmmmmmmllllllkkkkkkkkjjjjjjjiiiiiiihhhhhhhggggggggffffffffeÿeeeeeedþddddddddcýccccccccbübbbbbbbbaûaaaaaaaa`ú``````````_ù__________^ø^^^^^^^^^^]÷]]]]]]]]]]\ö\\\\\\\\\\\\[õ[[[[[[[[[[[[ZôZôZZZZZZZZZZZZYóYYYYYYYYYYYYYYXòXòXXXXXXXXXXXXXXWñWñWWWWWWWWWWWWWWWWVðVVVVVVVVVVVVVVVVVVUïUïUUUUUUUUUUUUUUUUUUTîTîTTTTTTTTTTTTTTTTTTTTTTSíSSSSSSSSSSSSSSSSSSSSSSSSRìRìRRRRRRRRRRRRRRRRRRRRRRRRRRQëQëQQQQQQQQQQQQQQQQQQQQQQQQQQQQPêPêPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOéOéOéOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONèNèNèNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMçMçMçMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLæLæLæLLLLLLLLLLLLLL²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²K²K²K±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±J±J°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°I°I¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯H¯H®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®G®G­­­­­­­­­­­­­­­­­­­­­­­­­­­­­F­F¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬E¬E«««««««««««««««««««««««D«DªªªªªªªªªªªªªªªªªªªªªCªC©©©©©©©©©©©©©©©©©©©B©B¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨A¨A§§§§§§§§§§§§§§§@§@¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦?¦?¥¥¥¥¥¥¥¥¥¥¥¥¥>¥>¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡:           9ŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžž76œœœœœœœœœ5›››››››››4ššššššš3™™™™™™™™™2˜˜˜˜˜˜˜1———————0–––––––/•••••••.”””””””-““““““’’’’’’’’‘‘‘‘‘‘‘*ŽŽŽŽŽŽŽ'ŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}|ã||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuutÛttttsÚssssssrrrrrrqqqqqqppppppoÖoooooonnnnnnmÔmmmmmmllllllkÒkkkkkkjÑjjjjjjiÐiiiiiihÏhhhhhhgÎggggggfÍffffffffeeeeeeeedËddddddddcÊccccccccbÉbbbbbbbbaÈaaaaaaaa`Ç``````````_Æ__________^Å^^^^^^^^^^]Ä]]]]]]]]]]\Ã\Ã\\\\\\\\\\[Â[Â[[[[[[[[[[[[ZÁZZZZZZZZZZZZYÀYÀYYYYYYYYYYYYYYX¿XXXXXXXXXXXXXXXXW¾WWWWWWWWWWWWWWWWV½V½VVVVVVVVVVVVVVVVVVU¼UUUUUUUUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQQQQQQQQQQQQQP·P·P·PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONµNµNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM´M´M´MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMML³L³L³LLLLLLLL²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±~±~±~°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°}°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|¯|®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®{®{­­­­­­­­­­­­­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u§§§§§§§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡n           mŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžkjœœœœœœœœœi›››››››››hšššššššš™™™™™™™™™f˜˜˜˜˜˜˜˜————————––––––––••••••••””””””””“““““““`’’’’’’’_‘‘‘‘‘‘]ŽŽŽŽŽŽZŒŒŒŒŒY‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||{®{{{{z­zzzzyyyyyyxxxxxxwªwwwwv©vvvvu¨uuuuuuttttttssssssrrrrrrqqqqqqp£ppppppoooooon¡nnnnnnmmmmmmlŸllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhggggggggf™ffffffe˜eeeeeeeed—ddddddddccccccccccbbbbbbbbbba”aaaaaaaa`“``````````_’__________^‘^^^^^^^^^^]]]]]]]]]]]]]\\\\\\\\\\\\\[Ž[[[[[[[[[[[[ZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYX‹X‹XXXXXXXXXXXXXXWŠWŠWWWWWWWWWWWWWWWWV‰V‰VVVVVVVVVVVVVVVVUˆUˆUUUUUUUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPƒPƒPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO‚O‚O‚OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM€M€M€MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLL²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————––––––––••••••••””””””””““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzyyyyyyxxxxxxxxwwwwwwvvvvvvuuuuuuttttttssssssrrrrrrqqqqqqqqppppppoooooooonnnnnnmmmmmmmmllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhggggggggggffffffffeeeeeeeeeeddddddddccccccccccbbbbbbbbbbbbaaaaaaaaaa````````````____________^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLL²²²²²²²²²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————––––––––••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuuttttttssssssssrrrrrrqqqqqqppppppppoooooonnnnnnnnmmmmmmllllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhggggggggffffffffffeeeeeeeeddddddddddccccccccccbbbbbbbbbbbbaaaaaaaaaa````````````____________^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM²²²²²²²²²²²²²²²²²²²²±ä±ä±ä±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°ã°ã°ã°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯â¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««««««««ªÝªÝªªªªªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤×¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¡Ô¡Ô¡¡¡¡¡¡¡¡¡¡ Ó          ŸÒŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžÐœÏœœœœœœœœ›Î››››››››šÍšššššššš™Ì™™™™™™™™˜˜˜˜˜˜˜˜—Ê——————–É––––––––••••••••””””””””““““““’Å’’’’’’‘Ä‘‘‘‘‘‘ÂŽŽŽŽŽŽÀŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰¼‰‰‰‰ˆ»ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuutttttttAssssssrrrrrrqqqqqqq>ppppppoooooonnnnnnnnmmmmmmm:lllllll9kkkkkkjjjjjjjjiiiiiiiihhhhhhhhh5ggggggg4fffffffff3eeeeeee2ddddddddd1ccccccccc0bbbbbbbbbbaaaaaaaaaaa.```````````-___________,^^^^^^^^^^^+]]]]]]]]]]]]]*\\\\\\\\\\\\\)[[[[[[[[[[[[[([(ZZZZZZZZZZZZZ'Z'YYYYYYYYYYYYYYY&XXXXXXXXXXXXXXXXX%X%WWWWWWWWWWWWWWWWW$W$VVVVVVVVVVVVVVVVVVV#UUUUUUUUUUUUUUUUUUUUU"U"TTTTTTTTTTTTTTTTTTTTTTT!T!SSSSSSSSSSSSSSSSSSSSSSSSS S RRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM²²²²²²²²²²²²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§ ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ £££££££££££££ £ ¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡           ŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžœœœœœœœœœœ››››››››››ššššššššš™™™™™™™™˜ÿ˜˜˜˜˜˜˜˜————————––––––––•ü••••••”û””””””“ú““““““’’’’’’’’‘‘‘‘‘‘÷ŽõŽŽŽŽŽŽŒóŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡î‡‡‡‡†í††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvvvuuuuuuuttttttssssssrrrrrrr qqqqqqppppppooooooonnnnnnnmmmmmmllllllllkkkkkkkjjjjjjjiiiiiiihhhhhhhhgggggggggffffffffeeeeeeeedþddddddddcýccccccccbübbbbbbbbaûaaaaaaaaaa`ú``````````_ù__________^ø^^^^^^^^^^]÷]]]]]]]]]]]]\ö\\\\\\\\\\\\[õ[[[[[[[[[[[[[[ZôZZZZZZZZZZZZZZYóYYYYYYYYYYYYYYXòXòXXXXXXXXXXXXXXXXWñWWWWWWWWWWWWWWWWWWVðVVVVVVVVVVVVVVVVVVUïUïUUUUUUUUUUUUUUUUUUUUTîTîTTTTTTTTTTTTTTTTTTTTTTSíSíSSSSSSSSSSSSSSSSSSSSSSSSRìRìRRRRRRRRRRRRRRRRRRRRRRRRRRQëQëQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPêPêPêPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOéOéOéOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONèNèNèNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMçMçMçMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM²²²²²²²²²²²K²K²K±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±J±J±J°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°I°I°I¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯H¯H®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®G®G­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­F­F¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬E¬E«««««««««««««««««««««««D«DªªªªªªªªªªªªªªªªªªªªªªªC©©©©©©©©©©©©©©©©©©©©©B©B¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨A¨A§§§§§§§§§§§§§§§§§@§@¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦?¦?¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥>¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡:           9ŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžž76œœœœœœœœœœœ5›››››››››4šššššššš™™™™™™™™™2˜˜˜˜˜˜˜˜˜1———————0–––––––/••••••••”””””””-“““““““,’’’’’’’+‘‘‘‘‘‘)ŽŽŽŽŽŽŽ'ŒŒŒŒŒŒŒ%‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡†††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwvvvvvvuÜuuuuuuttttttssssssrrrrrrrrqqqqqqppppppoÖoooooonnnnnnnnmmmmmmlÓllllllkÒkkkkkkjÑjjjjjjiÐiiiiiihÏhhhhhhgÎggggggggffffffffeÌeeeeeeeedËddddddddcÊccccccccbÉbbbbbbbbaÈaaaaaaaaaa`Ç``````````_Æ__________^Å^^^^^^^^^^]Ä]]]]]]]]]]]]\Ã\\\\\\\\\\\\[Â[Â[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZYÀYÀYYYYYYYYYYYYYYX¿XXXXXXXXXXXXXXXXW¾W¾WWWWWWWWWWWWWWWWV½V½VVVVVVVVVVVVVVVVVVU¼U¼UUUUUUUUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQP·P·PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONµNµNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM´M´M´MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM²²²²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±~±~±~°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®{®{­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u§§§§§§§§§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¥r¤¤¤¤¤¤¤¤¤¤¤¤¤q¤q£££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡n           mŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžkœœœœœœœœœœœi›››››››››hšššššššššg™™™™™™™™˜˜˜˜˜˜˜˜˜e————————––––––––•••••••••b””””””““““““““’’’’’’’’‘‘‘‘‘‘‘^ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹‹XŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††…………………R„„„„„Qƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwv©vvvvvvuuuuuuttttttssssssr¥rrrrrrqqqqqqp£ppppppoooooon¡nnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhgšggggggf™ffffffffe˜eeeeeeeed—ddddddddc–ccccccccb•bbbbbbbba”aaaaaaaaaa`“``````````_’__________^‘^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYX‹X‹XXXXXXXXXXXXXXXXWŠWWWWWWWWWWWWWWWWWWV‰VVVVVVVVVVVVVVVVVVVVUˆUUUUUUUUUUUUUUUUUUUUUUT‡TTTTTTTTTTTTTTTTTTTTTTTTS†SSSSSSSSSSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRRRRRRRQ„Q„Q„QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPƒPƒPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO‚O‚O‚OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM€M€M€MMMMMMMMMMMMMMMMMMMMMMMMMMMM²²²²±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜——————————––––––––••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwwwvvvvvvuuuuuuttttttssssssssrrrrrrqqqqqqqqppppppoooooooonnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhhhggggggggffffffffffeeeeeeeeeeddddddddddccccccccccbbbbbbbbbbaaaaaaaaaaaa````````````____________^^^^^^^^^^^^^^]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMM±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡            ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜——————————––––––––••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyxxxxxxxxwwwwwwvvvvvvuuuuuuttttttttssssssrrrrrrrrqqqqqqppppppppoooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhggggggggggffffffffffeeeeeeeeddddddddddccccccccccccbbbbbbbbbbaaaaaaaaaaaa````````````____________^^^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMM±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°ã°ã°ã°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««««««««ªÝªÝªªªªªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§§§§§§§§§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡ Ó          ŸÒŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžÐœÏœœœœœœœœ›Î››››››››šÍšššššššš™Ì™™™™™™™™˜Ë˜˜˜˜˜˜˜˜————————–É––––––––••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘ÃÂŽŽŽŽŽŽÀŒŒŒŒŒŒ‹¾‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆ»ˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zzzzzzyyyyyyyFxxxxxxwwwwwwvvvvvvuuuuuuuBttttttssssssrrrrrrrrqqqqqqppppppppooooooo¥>¤¤¤¤¤¤¤¤¤¤¤¤¤=¤=£££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡:           9ŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžž76œœœœœœœœœœ›››››››››››4ššššššššš3™™™™™™™™˜˜˜˜˜˜˜˜˜1—————————0–––––––/••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘)ŽŽŽŽŽŽŽŽ&ŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠŠ#‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡ ††††††………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{zázzzzzzyyyyyyxxxxxxwwwwwwvÝvvvvvvuuuuuuttttttsÚssssssrrrrrrqØqqqqqqppppppoÖoooooonÕnnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjiÐiiiiiihÏhhhhhhhhggggggggfÍffffffffeÌeeeeeeeedËddddddddcÊccccccccbÉbbbbbbbbbbaÈaaaaaaaaaa`Ç``````````_Æ__________^Å^^^^^^^^^^^^]Ä]]]]]]]]]]]]\Ã\\\\\\\\\\\\[Â[Â[[[[[[[[[[[[ZÁZÁZZZZZZZZZZZZZZYÀYYYYYYYYYYYYYYYYX¿XXXXXXXXXXXXXXXXXXW¾WWWWWWWWWWWWWWWWWWV½V½VVVVVVVVVVVVVVVVVVU¼U¼UUUUUUUUUUUUUUUUUUUUUUT»TTTTTTTTTTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQP·P·PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONµNµNµNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM´M´M´MMMMMM±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±~±~±~°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°}°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®{®{­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­z­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢o¢o¡¡¡¡¡¡¡¡¡¡¡n¡n           mŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžkjœœœœœœœœœœœi›››››››››hšššššššššg™™™™™™™™™f˜˜˜˜˜˜˜˜—————————d––––––––•••••••••b”””””””a“““““““`’’’’’’’_‘‘‘‘‘‘‘^ŽŽŽŽŽŽŽ[ŒŒŒŒŒŒŒY‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡†††††††S………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwwwvvvvvvuuuuuut§ttttttssssssrrrrrrrrqqqqqqp£ppppppoooooooonnnnnnm mmmmmmlŸllllllkžkkkkkkjjjjjjjjjiiiiiiiihhhhhhhhgšggggggggf™ffffffffeeeeeeeeeeddddddddddc–ccccccccb•bbbbbbbbbba”aaaaaaaaaa`“``````````_’__________^‘^^^^^^^^^^^^]]]]]]]]]]]]]\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZYŒYŒYYYYYYYYYYYYYYX‹X‹XXXXXXXXXXXXXXXXWŠWŠWWWWWWWWWWWWWWWWWWV‰VVVVVVVVVVVVVVVVVVVVUˆUˆUUUUUUUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPƒPƒPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO‚O‚O‚OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM€M€M€±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————––––––––––••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡††††††……………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||{{{{{{{{zzzzzzyyyyyyxxxxxxwwwwwwwwvvvvvvuuuuuuuuttttttssssssrrrrrrrrqqqqqqqqppppppoooooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjiiiiiiiihhhhhhhhhhggggggggggffffffffeeeeeeeeeeddddddddddddccccccccccbbbbbbbbbbbbaaaaaaaaaaaa````````````____________^^^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––••••••••””””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††……………………„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€~~~~~~}}}}}}||||||||{{{{{{zzzzzzyyyyyyxxxxxxxxwwwwwwvvvvvvuuuuuuuuttttttssssssssrrrrrrqqqqqqqqppppppppoooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjjjiiiiiiiihhhhhhhhhhggggggggffffffffffeeeeeeeeeeddddddddddccccccccccccbbbbbbbbbbbbaaaaaaaaaaaa````````````____________^^^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN±±±±±±±±±±±±±±±±±±±±°ã°ã°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯â¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®á®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««««««««««ªÝªªªªªªªªªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡ Ó            ŸÒŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžÐœÏœœœœœœœœœœ›Î››››››››šÍšššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜—Ê————————–É––––––––••••••••””””””””“Æ““““““’Å’’’’’’‘Ä‘‘‘‘‘‘ÃŽŽŽŽŽŽŽŽŒ¿ŒŒŒŒŒŒ‹‹‹‹‹‹Š½ŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††………………„·„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€³€€€€€€~~~~~~}}}}}}||||||||{{{{{{zzzzzzyyyyyyyFxxxxxxwwwwwwvvvvvvvCuuuuuutttttttAssssssrrrrrrr?qqqqqqppppppppooooooo¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=¤=£££££££££££££<£<¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡:             9ŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžž76œœœœœœœœœ5›››››››››››4ššššššššš3™™™™™™™™™2˜˜˜˜˜˜˜˜˜1————————–––––––––/••••••••”””””””””-“““““““,’’’’’’’+‘‘‘‘‘‘‘*)ŽŽŽŽŽŽŽŽ&ŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~}}}}}}|ã||||||{{{{{{zzzzzzyyyyyyyyxxxxxxwwwwwwvÝvvvvvvuuuuuutÛttttttssssssrÙrrrrrrqqqqqqqqppppppoÖoooooonÕnnnnnnmÔmmmmmmlÓllllllkÒkkkkkkkkjjjjjjjjiÐiiiiiihÏhhhhhhhhgÎggggggggffffffffffeeeeeeeeeedËddddddddcÊccccccccccbbbbbbbbbbaÈaaaaaaaaaa`Ç````````````_Æ__________^Å^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZYÀYYYYYYYYYYYYYYYYX¿XXXXXXXXXXXXXXXXXXW¾W¾WWWWWWWWWWWWWWWWWWV½V½VVVVVVVVVVVVVVVVVVVVU¼UUUUUUUUUUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRRRRRRRRRRRQ¸Q¸Q¸QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQP·P·PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONµNµNµNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN±±±±±~±~°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|¯|®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®{®{®{­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªªªªªw©©©©©©©©©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u§§§§§§§§§§§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡n             mŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžkjœœœœœœœœœœ›››››››››››hšššššššššg™™™™™™™™™f˜˜˜˜˜˜˜˜˜e—————————d––––––––•••••••••b”””””””a““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽ[ŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹XŠŠŠŠŠŠ‰‰‰‰‰‰‰Vˆˆˆˆˆˆ‡‡‡‡‡‡‡T††††††………………„„„„„„„Qƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~}}}}}}}}||||||{{{{{{zzzzzzy¬yyyyyyxxxxxxwwwwwwwwvvvvvvuuuuuuuuttttttssssssssrrrrrrq¤qqqqqqppppppppoooooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjjiiiiiiiih›hhhhhhhhggggggggf™ffffffffe˜eeeeeeeeeeddddddddddc–ccccccccb•bbbbbbbbbba”aaaaaaaaaa`“````````````_’__________^‘^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYYYX‹X‹XXXXXXXXXXXXXXXXXXWŠWWWWWWWWWWWWWWWWWWWWV‰VVVVVVVVVVVVVVVVVVVVUˆUˆUUUUUUUUUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPƒPƒPƒPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO‚O‚O‚OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNN±±±±°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››šššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••””””””””““““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††††………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~}}}}}}}}||||||{{{{{{zzzzzzzzyyyyyyxxxxxxwwwwwwwwvvvvvvuuuuuuuuttttttssssssssrrrrrrrrqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkkkjjjjjjjjiiiiiiiiiihhhhhhhhggggggggggffffffffffeeeeeeeeeeddddddddddddccccccccccbbbbbbbbbbbbaaaaaaaaaaaa``````````````____________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNN°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››šššššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————––––––––––••••••••••””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††††………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~}}}}}}}}||||||{{{{{{zzzzzzzzyyyyyyxxxxxxxxwwwwwwvvvvvvvvuuuuuuttttttttssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkjjjjjjjjjjiiiiiiiihhhhhhhhhhggggggggggffffffffffeeeeeeeeeeddddddddddddccccccccccbbbbbbbbbbbbaaaaaaaaaaaa``````````````____________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNN°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««««««««««ªÝªªªªªªªªªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§§§§§§§§§§§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡ Ó            ŸÒŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžÐœÏœœœœœœœœœœ›Î››››››››šÍšššššššššš™Ì™™™™™™™™˜Ë˜˜˜˜˜˜˜˜—Ê————————––––––––•È••••••••”Ç””””””“Æ““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒ¿ŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰¼‰‰‰‰‰‰ˆˆˆˆˆˆ‡º‡‡‡‡‡‡††††††…¸………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~}}}}}}}}||||||{{{{{{{Hzzzzzzyyyyyyxxxxxxxxwwwwwwvvvvvvvvuuuuuuttttttttsssssss@rrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmllllllllkkkkkkkkk8jjjjjjjjiiiiiiiii6hhhhhhhhh5ggggggggg4fffffffff3eeeeeeeee2ddddddddddccccccccccc0bbbbbbbbbbb/aaaaaaaaaaa.`````````````-___________,_,^^^^^^^^^^^^^+]]]]]]]]]]]]]*\\\\\\\\\\\\\\\)[[[[[[[[[[[[[[[[[(ZZZZZZZZZZZZZZZZZ'YYYYYYYYYYYYYYYYY&Y&XXXXXXXXXXXXXXXXXXX%WWWWWWWWWWWWWWWWWWWWW$VVVVVVVVVVVVVVVVVVVVVVV#UUUUUUUUUUUUUUUUUUUUUUUUU"U"TTTTTTTTTTTTTTTTTTTTTTTTT!T!SSSSSSSSSSSSSSSSSSSSSSSSSSSSS S RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNN°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§ ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ ¥ ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ ¤ £££££££££££££££ ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡             ŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžœœœœœœœœœœœ››››››››››ššššššššššš™™™™™™™™˜ÿ˜˜˜˜˜˜˜˜—þ————————–ý––––––––••••••••”û””””””””““““““““’ù’’’’’’‘ø‘‘‘‘‘‘‘‘ŽõŽŽŽŽŽŽôŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††……………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~}}}}}}}}||||||{{{{{{{{zzzzzzyyyyyyyxxxxxxwwwwwwwvvvvvvuuuuuuuttttttssssssssrrrrrrr qqqqqqq ppppppp ooooooonnnnnnnmmmmmmmlllllllkkkkkkkkjjjjjjjjjiiiiiiiiihhhhhhhhggggggggggffffffffffeeeeeeeeeedþddddddddcýccccccccccbübbbbbbbbbbaûaaaaaaaaaa`ú````````````_ù____________^ø^^^^^^^^^^^^]÷]]]]]]]]]]]]\ö\\\\\\\\\\\\\\[õ[õ[[[[[[[[[[[[[[ZôZZZZZZZZZZZZZZZZYóYYYYYYYYYYYYYYYYYYXòXXXXXXXXXXXXXXXXXXWñWñWWWWWWWWWWWWWWWWWWVðVðVVVVVVVVVVVVVVVVVVVVUïUïUUUUUUUUUUUUUUUUUUUUUUUUTîTTTTTTTTTTTTTTTTTTTTTTTTTTSíSíSSSSSSSSSSSSSSSSSSSSSSSSSSSSRìRìRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQëQëQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPêPêPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOéOéOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONèNèNNNNNNNNNNNN°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°I°I°I¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯H¯H®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®G®G­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­F­F¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬E¬E«««««««««««««««««««««««««««D«DªªªªªªªªªªªªªªªªªªªªªªªªªCªC©©©©©©©©©©©©©©©©©©©©©©©B¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨A¨A§§§§§§§§§§§§§§§§§§§@§@¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦?¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥>¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££<£<¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:             9ŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžž76œœœœœœœœœœœ5›››››››››››4ššššššššš3™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————–––––––––/••••••••”””””””””-““““““““’’’’’’’’‘‘‘‘‘‘‘‘‘*)ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹$ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††……………………„„„„„„ƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~}}}}}}}}||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxwwwwwwwwvvvvvvuuuuuuuuttttttsÚssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmllllllllkÒkkkkkkjÑjjjjjjjjiiiiiiiiiihhhhhhhhgÎggggggggfÍffffffffeÌeeeeeeeeeeddddddddddcÊccccccccccbÉbbbbbbbbbbaÈaaaaaaaaaa`Ç````````````_Æ____________^Å^^^^^^^^^^^^]Ä]]]]]]]]]]]]\Ã\Ã\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZYÀYÀYYYYYYYYYYYYYYYYX¿XXXXXXXXXXXXXXXXXXXXW¾WWWWWWWWWWWWWWWWWWWWV½VVVVVVVVVVVVVVVVVVVVVVU¼U¼UUUUUUUUUUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSSSSSSSSSSSSSR¹RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQP·P·P·PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONµNµNµNNNNNN°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®{®{®{­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u§§§§§§§§§§§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n             mŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžkjœœœœœœœœœœœi›››››››››››hšššššššššš™™™™™™™™™™™f˜˜˜˜˜˜˜˜˜e—————————d––––––––•••••••••b””””””””“““““““““`’’’’’’’_‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽZŒŒŒŒŒŒŒY‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰Vˆˆˆˆˆˆ‡‡‡‡‡‡‡T††††††…………………R„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~}°}}}}}}||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxwwwwwwwwvvvvvvu¨uuuuuuttttttttssssssr¥rrrrrrq¤qqqqqqppppppppoooooooonnnnnnnnm mmmmmmlŸllllllllkkkkkkkkjjjjjjjiœiiiiiiiih›hhhhhhhhgšggggggggf™ffffffffe˜eeeeeeeed—ddddddddddc–ccccccccccb•bbbbbbbbbba”aaaaaaaaaa`“````````````_’____________^‘^^^^^^^^^^^^]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYYYX‹X‹XXXXXXXXXXXXXXXXXXWŠWŠWWWWWWWWWWWWWWWWWWV‰V‰VVVVVVVVVVVVVVVVVVVVVVUˆUUUUUUUUUUUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTTTTTTTTTTTTTS†SSSSSSSSSSSSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPƒPƒPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO‚O‚O‚OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNN°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••””””””””””““““““““’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††††………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxwwwwwwwwvvvvvvvvuuuuuuttttttttssssssssrrrrrrrrqqqqqqppppppppoooooooonnnnnnnnnnmmmmmmmmllllllllkkkkkkkkkkjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggffffffffffeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONN°°°°°°°°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡              ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››šššššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••••””””””””““““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††††………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxxxwwwwwwvvvvvvvvuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmllllllllllkkkkkkkkjjjjjjjjjjiiiiiiiihhhhhhhhhhggggggggggffffffffffffeeeeeeeeeeddddddddddddccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO°°°°°°°°°°°°°°°°°°°°¯â¯â¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««««««««««««ªÝªªªªªªªªªªªªªªªªªªªªªªªªªª©Ü©©©©©©©©©©©©©©©©©©©©©©©©¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§§§§§§§§§§§§§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö£Ö££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó            ŸÒŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžÐœÏœœœœœœœœœœ›Î››››››››šÍšššššššššš™Ì™™™™™™™™˜Ë˜˜˜˜˜˜˜˜˜˜——————————––––––––•È••••••••”Ç””””””””““““““““’Å’’’’’’‘Ä‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹Š½ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡º‡‡‡‡‡‡††††††††………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}|||||||I{{{{{{zzzzzzzGyyyyyyxxxxxxxxwwwwwwvvvvvvvvuuuuuuuBtttttttAssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmm:llllllllkkkkkkkkk8jjjjjjjjiiiiiiiii6hhhhhhhhh5ggggggggg4ffffffffffeeeeeeeeeee2ddddddddddccccccccccc0bbbbbbbbbbbbaaaaaaaaaaaaa.`````````````-_____________,^^^^^^^^^^^^^+]]]]]]]]]]]]]]]*\\\\\\\\\\\\\\\)[[[[[[[[[[[[[[[[[(ZZZZZZZZZZZZZZZZZ'Z'YYYYYYYYYYYYYYYYY&Y&XXXXXXXXXXXXXXXXXXX%X%WWWWWWWWWWWWWWWWWWWWW$VVVVVVVVVVVVVVVVVVVVVVV#V#UUUUUUUUUUUUUUUUUUUUUUUUU"TTTTTTTTTTTTTTTTTTTTTTTTTTT!T!SSSSSSSSSSSSSSSSSSSSSSSSSSSSS S RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO°°°°°°°°°°°°°°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§ ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ £££££££££££££££££ ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡             ŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžœœœœœœœœœœœ››››››››››ššššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜—þ————————–ý––––––––••••••••••””””””””“ú““““““““’’’’’’’’‘‘‘‘‘‘‘‘÷öŽŽŽŽŽŽŽŽŒóŒŒŒŒŒŒ‹ò‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††…ì………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||||{{{{{{zzzzzzzzyyyyyyxxxxxxxxwwwwwwwvvvvvvuuuuuuuuttttttttsssssss rrrrrrr qqqqqqq ppppppp ooooooonnnnnnnmmmmmmmmlllllllllkkkkkkkkjjjjjjjjjiiiiiiiiihhhhhhhhhgggggggggffffffffeÿeeeeeeeeeedþddddddddcýccccccccccbübbbbbbbbbbaûaaaaaaaaaaaa`ú````````````_ù____________^ø^^^^^^^^^^^^]÷]]]]]]]]]]]]]]\ö\\\\\\\\\\\\\\[õ[õ[[[[[[[[[[[[[[ZôZôZZZZZZZZZZZZZZZZYóYYYYYYYYYYYYYYYYYYXòXXXXXXXXXXXXXXXXXXXXWñWWWWWWWWWWWWWWWWWWWWVðVðVVVVVVVVVVVVVVVVVVVVVVUïUUUUUUUUUUUUUUUUUUUUUUUUTîTîTTTTTTTTTTTTTTTTTTTTTTTTTTSíSíSSSSSSSSSSSSSSSSSSSSSSSSSSSSRìRìRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQëQëQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPêPêPêPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOéOéOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO°°°°°°°°°°°I°I¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯H¯H¯H®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®G®G­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­F­F¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬E¬E«««««««««««««««««««««««««««««D«DªªªªªªªªªªªªªªªªªªªªªªªªªCªC©©©©©©©©©©©©©©©©©©©©©©©©©B¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨A§§§§§§§§§§§§§§§§§§§§§@§@¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦?¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥>¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:             9ŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžž6œœœœœœœœœœœ5›››››››››››4šššššššššš™™™™™™™™™™™2˜˜˜˜˜˜˜˜˜1—————————0–––––––––/•••••••••.””””””””“““““““““,’’’’’’’’‘‘‘‘‘‘‘‘(ŽŽŽŽŽŽŽ'ŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰"ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††……………………„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||||{{{{{{zzzzzzzzyyyyyyxßxxxxxxwwwwwwwwvvvvvvuÜuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmlÓllllllllkkkkkkkkjÑjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggffffffffffeÌeeeeeeeeeeddddddddddcÊccccccccccbÉbbbbbbbbbbaÈaaaaaaaaaaaa`Ç````````````_Æ____________^Å^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZYÀYYYYYYYYYYYYYYYYYYX¿X¿XXXXXXXXXXXXXXXXXXW¾W¾WWWWWWWWWWWWWWWWWWWWV½VVVVVVVVVVVVVVVVVVVVVVU¼U¼UUUUUUUUUUUUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQ¸Q¸Q¸QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQP·P·PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO°°°°°}°}°}¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®{®{­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªªªªªªªw©©©©©©©©©©©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££p£p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡n¡n             mŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžkjœœœœœœœœœœœi›››››››››››hšššššššššššg™™™™™™™™™f˜˜˜˜˜˜˜˜˜˜——————————––––––––––•••••••••b”””””””””a““““““““’’’’’’’’’_‘‘‘‘‘‘‘^ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠW‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††……………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||||{{{{{{zzzzzzzzyyyyyyyyxxxxxxwwwwwwwwvvvvvvvvuuuuuut§ttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooon¡nnnnnnm mmmmmmmmllllllllkžkkkkkkkkjjjjjjjjiœiiiiiiiih›hhhhhhhhgšggggggggf™ffffffffffe˜eeeeeeeed—ddddddddddc–ccccccccccb•bbbbbbbbbba”aaaaaaaaaaaa`“````````````_’____________^‘^^^^^^^^^^^^]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZYŒYŒYYYYYYYYYYYYYYYYYYX‹XXXXXXXXXXXXXXXXXXXXWŠWWWWWWWWWWWWWWWWWWWWV‰V‰VVVVVVVVVVVVVVVVVVVVVVUˆUˆUUUUUUUUUUUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPƒPƒPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO‚O‚O‚OOOOOOOOOOOOOOOOOOOOOOOOOO°°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••””””””””””““““““““““’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††……………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||||{{{{{{zzzzzzzzyyyyyyyyxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooooonnnnnnnnmmmmmmmmllllllllllkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggffffffffffffeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbaaaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOO¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••••””””””””””““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††††……………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxxxwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnmmmmmmmmmmllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggffffffffffeeeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbaaaaaaaaaaaaaa``````````````______________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOO¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««««««««««««««ªÝªªªªªªªªªªªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©©©©©©©©©©©¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§§§§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó              ŸÒŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžÐœÏœœœœœœœœœœœœ››››››››››››šššššššššš™Ì™™™™™™™™™™˜Ë˜˜˜˜˜˜˜˜—Ê————————–É––––––––•È••••••••”Ç””””””””“Æ““““““““’’’’’’’’‘Ä‘‘‘‘‘‘ÃŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡º‡‡‡‡‡‡††††††††……………………„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxxxwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooonnnnnnnnn;mmmmmmmmlllllllll9kkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggg4fffffffff3eeeeeeeeeee2ddddddddddd1ccccccccccc0bbbbbbbbbbb/aaaaaaaaaaaaa.`````````````-_____________,^^^^^^^^^^^^^^^+]]]]]]]]]]]]]]]*\\\\\\\\\\\\\\\)[[[[[[[[[[[[[[[[[([(ZZZZZZZZZZZZZZZZZ'YYYYYYYYYYYYYYYYYYY&Y&XXXXXXXXXXXXXXXXXXX%X%WWWWWWWWWWWWWWWWWWWWW$W$VVVVVVVVVVVVVVVVVVVVVVV#V#UUUUUUUUUUUUUUUUUUUUUUUUU"U"TTTTTTTTTTTTTTTTTTTTTTTTTTTTT!SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS S RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOO¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§ § ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ¦ ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ ¥ ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ £££££££££££££££££ ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡               ŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžœœœœœœœœœœœœœ›››››››››››šššššššššš™™™™™™™™™™˜ÿ˜˜˜˜˜˜˜˜—þ——————————––––––––––••••••••••””””””””“ú““““““““’ù’’’’’’’’‘‘‘‘‘‘‘‘öŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆïˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††………………„ë„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}||||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxxxwwwwwwwvvvvvvvuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppp ooooooonnnnnnnnmmmmmmmmmllllllllkkkkkkkkkjjjjjjjjjiiiiiiiiihhhhhhhhhggggggggggffffffffffeÿeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbaûaaaaaaaaaaaa`ú````````````_ù____________^ø^^^^^^^^^^^^^^]÷]]]]]]]]]]]]]]\ö\\\\\\\\\\\\\\[õ[õ[[[[[[[[[[[[[[[[ZôZZZZZZZZZZZZZZZZYóYóYYYYYYYYYYYYYYYYYYXòXXXXXXXXXXXXXXXXXXXXWñWWWWWWWWWWWWWWWWWWWWWWVðVðVVVVVVVVVVVVVVVVVVVVVVUïUïUUUUUUUUUUUUUUUUUUUUUUUUTîTîTTTTTTTTTTTTTTTTTTTTTTTTTTSíSíSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRìRìRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQëQëQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPêPêPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOéOéOOOOOOOOOOOO¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯H¯H®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®G®G­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­F­F¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬E¬E«««««««««««««««««««««««««««««D«DªªªªªªªªªªªªªªªªªªªªªªªªªªªCªC©©©©©©©©©©©©©©©©©©©©©©©©©B¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨A¨A§§§§§§§§§§§§§§§§§§§§§@¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦?¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥>¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:               9ŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžž7œœœœœœœœœœœœœ5›››››››››››4ššššššššššš3™™™™™™™™™2˜˜˜˜˜˜˜˜˜˜———————————0–––––––––/•••••••••.””””””””““““““““““’’’’’’’’’+‘‘‘‘‘‘‘‘(ŽŽŽŽŽŽŽ'&ŒŒŒŒŒŒŒ%‹‹‹‹‹‹‹$ŠŠŠŠŠŠŠ#‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}|ã||||||{{{{{{{{zzzzzzyàyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuutÛttttttsÚssssssrÙrrrrrrqØqqqqqqp×ppppppppoooooooonnnnnnnnmÔmmmmmmmmllllllllkÒkkkkkkkkjÑjjjjjjjjiiiiiiiiiihhhhhhhhhhgÎggggggggfÍffffffffffeeeeeeeeeedËddddddddddcÊccccccccccbÉbbbbbbbbbbbbaÈaaaaaaaaaaaa`Ç````````````_Æ____________^Å^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZZZYÀYYYYYYYYYYYYYYYYYYX¿X¿XXXXXXXXXXXXXXXXXXW¾W¾WWWWWWWWWWWWWWWWWWWWWWV½VVVVVVVVVVVVVVVVVVVVVVVVU¼UUUUUUUUUUUUUUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQP·P·PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO¶O¶OOOOOOOO¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯|®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®{®{­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u§§§§§§§§§§§§§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q¤q£££££££££££££££p£p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n               mŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžkjœœœœœœœœœœœi›››››››››››hšššššššššššg™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜e—————————d––––––––––•••••••••b”””””””””a“““““““““`’’’’’’’’‘‘‘‘‘‘‘‘‘^]ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡†††††††S………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||{{{{{{{{zzzzzzzzyyyyyyx«xxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooon¡nnnnnnnnmmmmmmmmlŸllllllllkkkkkkkkkkjjjjjjjjiœiiiiiiiih›hhhhhhhhhhggggggggggf™ffffffffe˜eeeeeeeeeed—ddddddddddc–ccccccccccb•bbbbbbbbbbbba”aaaaaaaaaaaa``````````````_’____________^‘^^^^^^^^^^^^^^]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYYYYYYYX‹XXXXXXXXXXXXXXXXXXXXWŠWWWWWWWWWWWWWWWWWWWWWWV‰V‰VVVVVVVVVVVVVVVVVVVVVVUˆUˆUUUUUUUUUUUUUUUUUUUUUUUUUUT‡TTTTTTTTTTTTTTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPƒPƒPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO‚O‚O‚OO¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜——————————––––––––––––••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppoooooooooonnnnnnnnmmmmmmmmmmllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggggffffffffffeeeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaa````````````````______________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜————————————––––––––––••••••••••””””””””””““““““““““’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqqqppppppppoooooooonnnnnnnnnnmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggffffffffffffeeeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaa````````````````______________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®á®á®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­à­à­à­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««««««««««««««ªÝªªªªªªªªªªªªªªªªªªªªªªªªªªªª©Ü©©©©©©©©©©©©©©©©©©©©©©©©©©¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§§§§§§§§§§§§§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó              ŸÒŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžÐœÏœœœœœœœœœœ›Î››››››››››››šššššššššš™Ì™™™™™™™™™™˜Ë˜˜˜˜˜˜˜˜˜˜——————————–É––––––––•È••••••••”Ç””””””””“Æ““““““““’Å’’’’’’’’‘‘‘‘‘‘‘‘ÃŽŽŽŽŽŽŽŽÀŒ¿ŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆ»ˆˆˆˆˆˆ‡º‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}|||||||I{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwDvvvvvvvCuuuuuutttttttttAsssssss@rrrrrrr?qqqqqqqqppppppppooooooooo¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=¤=£££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:               9ŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžž76œœœœœœœœœœœœœ5›››››››››››4ššššššššššš3™™™™™™™™™™™2˜˜˜˜˜˜˜˜˜1——————————–––––––––––/•••••••••.”””””””””-““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘*(ŽŽŽŽŽŽŽ'ŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{zázzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqp×ppppppppoooooooonÕnnnnnnnnmmmmmmmmlÓllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihÏhhhhhhhhgÎggggggggggffffffffffeÌeeeeeeeeeedËddddddddddcÊccccccccccccbÉbbbbbbbbbbaÈaaaaaaaaaaaa`Ç``````````````_Æ____________^Å^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[[[ZÁZÁZZZZZZZZZZZZZZZZYÀYÀYYYYYYYYYYYYYYYYYYX¿X¿XXXXXXXXXXXXXXXXXXXXW¾WWWWWWWWWWWWWWWWWWWWWWV½V½VVVVVVVVVVVVVVVVVVVVVVVVU¼U¼UUUUUUUUUUUUUUUUUUUUUUUUUUT»TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQP·P·PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP¯¯¯¯¯¯¯|¯|®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®{®{­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­z­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªªªªªªªªªw©©©©©©©©©©©©©©©©©©©©©©©©©©©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§§§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n               mŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžkjœœœœœœœœœœœœœi›››››››››››hšššššššššššg™™™™™™™™™™™f˜˜˜˜˜˜˜˜˜˜———————————d–––––––––c••••••••••””””””””””“““““““““`’’’’’’’’’_‘‘‘‘‘‘‘‘]ŽŽŽŽŽŽŽŽZŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††…………………R„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssr¥rrrrrrq¤qqqqqqqqppppppppoooooooooonnnnnnnnm mmmmmmmmllllllllkžkkkkkkkkjjjjjjjjjiœiiiiiiiiiihhhhhhhhhhgšggggggggf™ffffffffffe˜eeeeeeeeeed—ddddddddddc–ccccccccccccbbbbbbbbbbbba”aaaaaaaaaaaa`“``````````````_’____________^‘^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYYYYYYYX‹XXXXXXXXXXXXXXXXXXXXWŠWŠWWWWWWWWWWWWWWWWWWWWWWV‰V‰VVVVVVVVVVVVVVVVVVVVVVVVUˆUUUUUUUUUUUUUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTS†SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPƒPƒPƒPPPPPPPPPPPPPPPPPPPPPPPPPP¯¯¯¯¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————––––––––––••••••••••••””””””””””““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssssrrrrrrrrqqqqqqqqppppppppoooooooooonnnnnnnnnnmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggffffffffffffeeeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````______________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPP¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqppppppppppoooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkjjjjjjjjjjjjiiiiiiiiiihhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeddddddddddddccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````______________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPP®á®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««««««««««««««ªÝªÝªªªªªªªªªªªªªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©©©©©©©©©©©©©¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§§§§§§§§§§§§§§§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó              ŸÒŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžžžœœœœœœœœœœœœ›Î››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜—Ê——————————–É––––––––•È••••••••”Ç””””””””””““““““““’Å’’’’’’’’‘Ä‘‘‘‘‘‘‘‘ÂŽŽŽŽŽŽŽŽÀŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰¼‰‰‰‰‰‰ˆ»ˆˆˆˆˆˆ‡º‡‡‡‡‡‡†¹††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxEwwwwwwwDvvvvvvvCuuuuuuuuttttttttssssssssrrrrrrrrqqqqqqqqq>ppppppppooooooooo¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:¡:               9ŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžžžž76œœœœœœœœœœœœ›››››››››››››4ššššššššššš3™™™™™™™™™™™2˜˜˜˜˜˜˜˜˜˜˜1——————————–––––––––––/•••••••••.”””””””””-“““““““““,’’’’’’’’’+‘‘‘‘‘‘‘‘(ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒ%‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttsÚssssssssrrrrrrrrqqqqqqqqp×ppppppppoooooooonÕnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihÏhhhhhhhhhhggggggggggfÍffffffffffeÌeeeeeeeeeedËddddddddddcÊccccccccccccbÉbbbbbbbbbbbbaÈaaaaaaaaaaaa`Ç``````````````_Æ____________^Å^Å^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZZZYÀYYYYYYYYYYYYYYYYYYYYX¿X¿XXXXXXXXXXXXXXXXXXXXW¾W¾WWWWWWWWWWWWWWWWWWWWWWV½V½VVVVVVVVVVVVVVVVVVVVVVVVU¼U¼UUUUUUUUUUUUUUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQP·P·PPPPPPPPPP®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®{®{­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y«««««««««««««««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©©©©©©©©©©©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§§§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n                 mŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžžžkjœœœœœœœœœœœœœi›››››››››››hšššššššššššg™™™™™™™™™™™f˜˜˜˜˜˜˜˜˜˜˜e———————————d–––––––––c••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘]ŽŽŽŽŽŽŽŽŽ[ŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹XŠŠŠŠŠŠŠW‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuut§ttttttttssssssssrrrrrrrrq¤qqqqqqqqppppppppo¢oooooooonnnnnnnnm mmmmmmmmlŸllllllllkžkkkkkkkkjjjjjjjjjiœiiiiiiiiiihhhhhhhhhhgšggggggggggf™ffffffffffe˜eeeeeeeeeed—ddddddddddc–ccccccccccccb•bbbbbbbbbbbba”aaaaaaaaaaaa`“``````````````_’______________^‘^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZYŒYŒYYYYYYYYYYYYYYYYYYYYX‹XXXXXXXXXXXXXXXXXXXXXXWŠWWWWWWWWWWWWWWWWWWWWWWWWV‰VVVVVVVVVVVVVVVVVVVVVVVVVVUˆUˆUUUUUUUUUUUUUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPƒPƒPƒPPPP®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››šššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––••••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttssssssssrrrrrrrrrrqqqqqqqqppppppppppoooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeddddddddddddccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````________________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPP®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››šššššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————––––––––––––••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssssrrrrrrrrqqqqqqqqppppppppppoooooooooonnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggffffffffffffeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````________________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ®®®®®®®®®®®®®®®®®®®®®®­à­à­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««««««««««««««ªÝªÝªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©Ü©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§§§§§§§§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö£Ö££££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó                ŸÒŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžžžÐœÏœœœœœœœœœœœœ›Î››››››››››››šššššššššššš™Ì™™™™™™™™™™˜Ë˜˜˜˜˜˜˜˜˜˜—Ê——————————––––––––––•È••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ÂŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹¾‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡º‡‡‡‡‡‡†¹††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyyFxxxxxxxEwwwwwwwwvvvvvvvvuuuuuuuuttttttttssssssssssrrrrrrrrqqqqqqqqq>ppppppppoooooooooonnnnnnnnn;mmmmmmmmm:lllllllll9kkkkkkkkk8jjjjjjjjjjiiiiiiiiiii6hhhhhhhhhhggggggggggg4fffffffffff3eeeeeeeeeee2ddddddddddddd1ccccccccccccbbbbbbbbbbbbbbb/aaaaaaaaaaaaa.```````````````-_______________,^^^^^^^^^^^^^^^+]]]]]]]]]]]]]]]]]*\\\\\\\\\\\\\\\\\)\)[[[[[[[[[[[[[[[[[([(ZZZZZZZZZZZZZZZZZZZ'Z'YYYYYYYYYYYYYYYYYYYYY&XXXXXXXXXXXXXXXXXXXXXXX%WWWWWWWWWWWWWWWWWWWWWWWWW$W$VVVVVVVVVVVVVVVVVVVVVVVVV#V#UUUUUUUUUUUUUUUUUUUUUUUUUUUUU"TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT!SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS S RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§ ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ £££££££££££££££££££ ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                 ŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžœœœœœœœœœœœœœ›››››››››››››ššššššššššš™™™™™™™™™™˜ÿ˜˜˜˜˜˜˜˜˜˜—þ——————————–ý––––––––––••••••••••”û””””””””“ú““““““““’ù’’’’’’’’‘ø‘‘‘‘‘‘‘‘÷ŽŽŽŽŽŽŽŽôŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠñŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††…ì………………„ë„„„„„„ƒêƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~}}}}}}}|||||||{{{{{{{zzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuttttttttt ssssssssrrrrrrrrr qqqqqqqqppppppppp oooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhgggggggggggffffffffffeÿeeeeeeeeeedþddddddddddddcýccccccccccbübbbbbbbbbbbbbbaaaaaaaaaaaaaa`ú``````````````_ù______________^ø^^^^^^^^^^^^^^]÷]]]]]]]]]]]]]]]]\ö\\\\\\\\\\\\\\\\\\[õ[[[[[[[[[[[[[[[[[[ZôZZZZZZZZZZZZZZZZZZZZYóYYYYYYYYYYYYYYYYYYYYXòXXXXXXXXXXXXXXXXXXXXXXWñWñWWWWWWWWWWWWWWWWWWWWWWWWVðVVVVVVVVVVVVVVVVVVVVVVVVVVUïUïUUUUUUUUUUUUUUUUUUUUUUUUUUTîTîTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSíSíSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRìRìRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQëQëQëQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ®®®®®®®®®®®®®G®G­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­F­F¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬E¬E«««««««««««««««««««««««««««««««««D«DªªªªªªªªªªªªªªªªªªªªªªªªªªªªªCªC©©©©©©©©©©©©©©©©©©©©©©©©©©©B©B¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨A¨A§§§§§§§§§§§§§§§§§§§§§§§@§@¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦?¦?¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥>¥>¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:                 9ŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžžžž76œœœœœœœœœœœœœ5›››››››››››››4ššššššššššš3™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜———————————0–––––––––––/•••••••••.””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘(ŽŽŽŽŽŽŽŽ&ŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠ#‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuutÛttttttttssssssssrrrrrrrrrrqqqqqqqqp×ppppppppoooooooonÕnnnnnnnnmÔmmmmmmmmlÓllllllllkÒkkkkkkkkjÑjjjjjjjjjjiiiiiiiiiihÏhhhhhhhhhhgÎggggggggggffffffffffffeeeeeeeeeeeedËddddddddddddccccccccccccbÉbbbbbbbbbbbbaÈaaaaaaaaaaaaaa`Ç``````````````_Æ______________^Å^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZZZZZYÀYYYYYYYYYYYYYYYYYYYYX¿X¿XXXXXXXXXXXXXXXXXXXXXXW¾WWWWWWWWWWWWWWWWWWWWWWWWV½V½VVVVVVVVVVVVVVVVVVVVVVVVVVU¼UUUUUUUUUUUUUUUUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ®®®®®®®®®{®{­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªw©©©©©©©©©©©©©©©©©©©©©©©©©©©©©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u§§§§§§§§§§§§§§§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n               m mŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžkjœœœœœœœœœœœœœi›››››››››››››hšššššššššššš™™™™™™™™™™™™™f˜˜˜˜˜˜˜˜˜˜˜e——————————–––––––––––c••••••••••”””””””””””a“““““““““`’’’’’’’’’_‘‘‘‘‘‘‘‘‘^]ŽŽŽŽŽŽŽŽŽ[ŒŒŒŒŒŒŒŒŒY‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰Vˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvu¨uuuuuuuuttttttttssssssssr¥rrrrrrrrqqqqqqqqqqppppppppo¢oooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjiœiiiiiiiiiihhhhhhhhhhhhggggggggggf™ffffffffffe˜eeeeeeeeeeeed—ddddddddddc–ccccccccccccb•bbbbbbbbbbbba”aaaaaaaaaaaaaa`“``````````````_’______________^‘^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZYŒYŒYYYYYYYYYYYYYYYYYYYYX‹XXXXXXXXXXXXXXXXXXXXXXWŠWŠWWWWWWWWWWWWWWWWWWWWWWWWV‰VVVVVVVVVVVVVVVVVVVVVVVVVVUˆUˆUUUUUUUUUUUUUUUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQ„Q„QQQQQQQQQQQQQQQQQQQQQQQQQQQQ®®®®®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––••••••••••••””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvvvuuuuuuuuttttttttssssssssssrrrrrrrrqqqqqqqqqqppppppppppoooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeeeddddddddddddccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````________________^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQ®®®®­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››šššššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––••••••••••””””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuttttttttttssssssssrrrrrrrrrrqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQ­à­à­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««««««««««««««««ªÝªÝªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§§§§§§§§§§§§§§§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö£Ö££££££££££££££££¢Õ¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó              ŸÒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžÐœÏœœœœœœœœœœœœ›Î››››››››››››šššššššššššš™Ì™™™™™™™™™™˜Ë˜˜˜˜˜˜˜˜˜˜˜˜——————————–É––––––––––•È••••••••••””””””””””“Æ““““““““’Å’’’’’’’’‘Ä‘‘‘‘‘‘‘‘ÃÂŽŽŽŽŽŽŽŽŽŽŒ¿ŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹Š½ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡º‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€²~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxxEwwwwwwwwvvvvvvvvuuuuuuuuuBttttttttssssssssrrrrrrrrrrqqqqqqqqq>ppppppppoooooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkk8jjjjjjjjjjiiiiiiiiiii6hhhhhhhhhhh5ggggggggggg4fffffffffff3eeeeeeeeeee2ddddddddddddd1ccccccccccccc0bbbbbbbbbbbbb/aaaaaaaaaaaaaaa.```````````````-_______________,^^^^^^^^^^^^^^^^^+]]]]]]]]]]]]]]]]]*\\\\\\\\\\\\\\\\\\\)[[[[[[[[[[[[[[[[[[[(ZZZZZZZZZZZZZZZZZZZZZ'YYYYYYYYYYYYYYYYYYYYYYY&XXXXXXXXXXXXXXXXXXXXXXX%X%WWWWWWWWWWWWWWWWWWWWWWWWW$VVVVVVVVVVVVVVVVVVVVVVVVVVVVV#UUUUUUUUUUUUUUUUUUUUUUUUUUUUU"U"TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT!T!SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS S RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§ § ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ ¥ ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ £££££££££££££££££££ ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡               ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžœœœœœœœœœœœœœ›››››››››››››ššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜—þ——————————––––––––––––••••••••••”û””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽôŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰ð‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡†í††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttsssssssss rrrrrrrrqqqqqqqqqqppppppppp ooooooooonnnnnnnnnmmmmmmmmmlllllllllkkkkkkkkkkjjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeedþddddddddddddcýccccccccccccbübbbbbbbbbbbbaûaaaaaaaaaaaaaa`ú``````````````_ù______________^ø^^^^^^^^^^^^^^^^]÷]]]]]]]]]]]]]]]]\ö\\\\\\\\\\\\\\\\\\[õ[[[[[[[[[[[[[[[[[[ZôZZZZZZZZZZZZZZZZZZZZYóYóYYYYYYYYYYYYYYYYYYYYXòXXXXXXXXXXXXXXXXXXXXXXXXWñWWWWWWWWWWWWWWWWWWWWWWWWVðVðVVVVVVVVVVVVVVVVVVVVVVVVVVUïUïUUUUUUUUUUUUUUUUUUUUUUUUUUUUTîTîTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSíSíSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRìRìRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQëQëQQQQQQQQQQQQQQQQ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­F­F¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬E¬E«««««««««««««««««««««««««««««««««««D«DªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªC©©©©©©©©©©©©©©©©©©©©©©©©©©©©©B©B¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨A§§§§§§§§§§§§§§§§§§§§§§§§§@¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦?¦?¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥>¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:               9ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžž76œœœœœœœœœœœœœ5›››››››››››››4šššššššššššš™™™™™™™™™™™™™2˜˜˜˜˜˜˜˜˜˜˜1———————————0–––––––––––/••••••••••”””””””””””-“““““““““,’’’’’’’’’+‘‘‘‘‘‘‘‘‘*)(ŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒ%‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡†††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwvvvvvvvvuÜuuuuuuuuttttttttsÚssssssssrrrrrrrrqØqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjÑjjjjjjjjjjiiiiiiiiiihÏhhhhhhhhhhgÎggggggggggfÍffffffffffeÌeeeeeeeeeeeedËddddddddddddccccccccccccccbbbbbbbbbbbbbbaÈaaaaaaaaaaaaaa````````````````_Æ______________^Å^^^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[[[[[ZÁZÁZZZZZZZZZZZZZZZZZZZZYÀYYYYYYYYYYYYYYYYYYYYX¿X¿XXXXXXXXXXXXXXXXXXXXXXW¾W¾WWWWWWWWWWWWWWWWWWWWWWWWV½V½VVVVVVVVVVVVVVVVVVVVVVVVVVU¼U¼UUUUUUUUUUUUUUUUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSºSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQ¸Q¸QQQQQQQQQQQQ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©©©©©©©©©©©©©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§§§§§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n               mŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžžjœœœœœœœœœœœœœi›››››››››››››hšššššššššššššg™™™™™™™™™™™f˜˜˜˜˜˜˜˜˜˜˜˜————————————–––––––––––c•••••••••••b”””””””””a““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽZŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹XŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰Vˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzy¬yyyyyyyyxxxxxxxxwwwwwwwwv©vvvvvvvvuuuuuuuuttttttttttssssssssrrrrrrrrrrqqqqqqqqp£ppppppppo¢oooooooon¡nnnnnnnnm mmmmmmmmlŸllllllllkžkkkkkkkkkkjjjjjjjjjjiœiiiiiiiiiih›hhhhhhhhhhgšggggggggggf™ffffffffffe˜eeeeeeeeeeeeddddddddddddc–ccccccccccccb•bbbbbbbbbbbbbba”aaaaaaaaaaaa`“````````````````_’______________^‘^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYYYYYYYYYX‹XXXXXXXXXXXXXXXXXXXXXXXXWŠWWWWWWWWWWWWWWWWWWWWWWWWWWV‰VVVVVVVVVVVVVVVVVVVVVVVVVVVVUˆUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQ„Q„QQQQQQQQ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––••••••••••••””””””””””““““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{zzzzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuttttttttttssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaa``````````````````________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQ­­­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––••••••••••””””””””””””““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttssssssssssrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffffeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaa````````````````__________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQ­­­­­­­­­­­­­­­­­­­­­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ««««««««««««««««««««««««««««««««««ªÝªÝªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©Ü©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§§§§§§§§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££££££¢Õ¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó              ŸÒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžžžÐœÏœœœœœœœœœœœœœœ››››››››››››››šššššššššššš™Ì™™™™™™™™™™™™˜Ë˜˜˜˜˜˜˜˜˜˜—Ê——————————–É––––––––––•È••••••••••””””””””””“Æ““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ÃÂŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹¾‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰¼‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxxEwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttssssssssssrrrrrrrrr?qqqqqqqqq>ppppppppoooooooooonnnnnnnnnnmmmmmmmmmmm:lllllllll9kkkkkkkkkkjjjjjjjjjjj7iiiiiiiiiii6hhhhhhhhhhh5ggggggggggg4ffffffffffffeeeeeeeeeeeee2ddddddddddddd1ccccccccccccc0bbbbbbbbbbbbbbb/aaaaaaaaaaaaa.```````````````-_________________,^^^^^^^^^^^^^^^^^+]]]]]]]]]]]]]]]]]]]*\\\\\\\\\\\\\\\\\\\)[[[[[[[[[[[[[[[[[[[([(ZZZZZZZZZZZZZZZZZZZZZ'YYYYYYYYYYYYYYYYYYYYYYY&XXXXXXXXXXXXXXXXXXXXXXXXX%WWWWWWWWWWWWWWWWWWWWWWWWWWW$VVVVVVVVVVVVVVVVVVVVVVVVVVVVV#V#UUUUUUUUUUUUUUUUUUUUUUUUUUUUU"U"TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT!T!SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS S RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§ § ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ £££££££££££££££££££ ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡               ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœ›››››››››››››šššššššššššš™™™™™™™™™™™™˜ÿ˜˜˜˜˜˜˜˜˜˜—þ————————————––––––––––•ü••••••••••”û””””””””””““““““““““’ù’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒóŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡†í††††††††……………………„„„„„„„„ƒêƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyxxxxxxxxxxwwwwwwwwvvvvvvvvvuuuuuuuuttttttttt ssssssssrrrrrrrrrrqqqqqqqqqqppppppppp ooooooooonnnnnnnnnmmmmmmmmmmlllllllllllkkkkkkkkkjjjjjjjjjjjiiiiiiiiiihhhhhhhhhhhhhgggggggggggffffffffffeÿeeeeeeeeeeeedþddddddddddddcýccccccccccccbübbbbbbbbbbbbbbaaaaaaaaaaaaaa`ú``````````````_ù________________^ø^^^^^^^^^^^^^^^^]÷]]]]]]]]]]]]]]]]]]\ö\\\\\\\\\\\\\\\\\\[õ[[[[[[[[[[[[[[[[[[[[ZôZZZZZZZZZZZZZZZZZZZZYóYYYYYYYYYYYYYYYYYYYYYYXòXòXXXXXXXXXXXXXXXXXXXXXXWñWñWWWWWWWWWWWWWWWWWWWWWWWWVðVðVVVVVVVVVVVVVVVVVVVVVVVVVVVVUïUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTîTîTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSíSíSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRìRìRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR­­­­­­­­­­­­­­­­­F­F¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬E¬E«««««««««««««««««««««««««««««««««««D«DªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªCªC©©©©©©©©©©©©©©©©©©©©©©©©©©©©©B©B¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨A§§§§§§§§§§§§§§§§§§§§§§§§§§§@¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦?¦?¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥>¥>¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:                 9ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžžžž7œœœœœœœœœœœœœœœ5›››››››››››››4ššššššššššššš3™™™™™™™™™™™2˜˜˜˜˜˜˜˜˜˜˜˜—————————————0––––––––––••••••••••••”””””””””””-““““““““““’’’’’’’’’’’+‘‘‘‘‘‘‘‘‘*)(ŽŽŽŽŽŽŽŽŽ'ŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹$ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰"ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||{â{{{{{{{{zzzzzzzzyyyyyyyyxßxxxxxxxxwwwwwwwwvvvvvvvvvvuuuuuuuuttttttttttssssssssrÙrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmlÓllllllllllkkkkkkkkkkjÑjjjjjjjjjjiiiiiiiiiihÏhhhhhhhhhhhhggggggggggggffffffffffffeÌeeeeeeeeeeeedËddddddddddddcÊccccccccccccbÉbbbbbbbbbbbbaÈaaaaaaaaaaaaaa`Ç``````````````_Æ________________^Å^^^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZZZZZYÀYÀYYYYYYYYYYYYYYYYYYYYYYX¿XXXXXXXXXXXXXXXXXXXXXXXXW¾WWWWWWWWWWWWWWWWWWWWWWWWWWV½VVVVVVVVVVVVVVVVVVVVVVVVVVVVU¼U¼UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR­­­­­­­­­­­­­z­z¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§§§§§§§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q¤q£££££££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n                 mŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžžžkjœœœœœœœœœœœœœi›››››››››››››hšššššššššššššg™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜e———————————d–––––––––––c•••••••••••b””””””””””“““““““““““`’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒY‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||||{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwv©vvvvvvvvuuuuuuuut§ttttttttssssssssssrrrrrrrrq¤qqqqqqqqp£ppppppppo¢oooooooon¡nnnnnnnnm mmmmmmmmmmllllllllllkžkkkkkkkkkkjjjjjjjjjjiœiiiiiiiiiih›hhhhhhhhhhgšggggggggggf™ffffffffffffe˜eeeeeeeeeeeeddddddddddddddccccccccccccccb•bbbbbbbbbbbba”aaaaaaaaaaaaaa`“``````````````_’________________^‘^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYYYYYYYYYX‹XXXXXXXXXXXXXXXXXXXXXXXXWŠWŠWWWWWWWWWWWWWWWWWWWWWWWWV‰V‰VVVVVVVVVVVVVVVVVVVVVVVVVVVVUˆUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUT‡TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRRRRRRRRRRRRRRRRRRRRRR­­­­­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––••••••••••••””””””””””””““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||||{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmllllllllllllkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffffeeeeeeeeeeeeddddddddddddddccccccccccccccccbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````__________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––••••••••••””””””””””””““““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||||{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttttssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````__________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRR­­­­¬ß¬ß¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««««««««««««««««««ªÝªÝªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§§§§§§§§§§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó                ŸÒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžžžÐœÏœœœœœœœœœœœœ›Î››››››››››››››šššššššššššššš™™™™™™™™™™™™˜Ë˜˜˜˜˜˜˜˜˜˜˜˜————————————–É––––––––––•È••••••••••””””””””””””““““““““““’Å’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹Š½ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}||||||||||{{{{{{{{zzzzzzzzzGyyyyyyyyxxxxxxxxxEwwwwwwwwvvvvvvvvvCuuuuuuuuttttttttttsssssssss@rrrrrrrrr?qqqqqqqqppppppppppooooooooooo¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=¤=£££££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:                 9ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžžžž76œœœœœœœœœœœœœœœ5›››››››››››››4ššššššššššššš3™™™™™™™™™™™™™2˜˜˜˜˜˜˜˜˜˜˜1————————————––––––––––––••••••••••••””””””””””””“““““““““““,’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘)(ŽŽŽŽŽŽŽŽŽ'&ŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡ ††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}}}||||||||{{{{{{{{zzzzzzzzzzyyyyyyyyxxxxxxxxxxwwwwwwwwvÝvvvvvvvvuuuuuuuuuuttttttttsÚssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnmÔmmmmmmmmmmllllllllllkÒkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggfÍffffffffffffeÌeeeeeeeeeeeeddddddddddddddcÊccccccccccccbÉbbbbbbbbbbbbbbaÈaaaaaaaaaaaaaa`Ç``````````````_Æ________________^Å^^^^^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZZZZZZZYÀYYYYYYYYYYYYYYYYYYYYYYYYX¿XXXXXXXXXXXXXXXXXXXXXXXXW¾W¾WWWWWWWWWWWWWWWWWWWWWWWWWWV½VVVVVVVVVVVVVVVVVVVVVVVVVVVVU¼U¼UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUT»TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSR¹R¹RRRRRRRRRRRRRR¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u§§§§§§§§§§§§§§§§§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n                 mŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžžžkjœœœœœœœœœœœœœœœi›››››››››››››hšššššššššššššg™™™™™™™™™™™™™f˜˜˜˜˜˜˜˜˜˜˜˜—————————————d–––––––––––c•••••••••••b”””””””””””a““““““““““’’’’’’’’’’’_‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠW‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}}}||||||||{{{{{{{{z­zzzzzzzzyyyyyyyyx«xxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttttssssssssr¥rrrrrrrrq¤qqqqqqqqp£ppppppppo¢oooooooon¡nnnnnnnnnnmmmmmmmmmmlŸllllllllllkkkkkkkkkkjjjjjjjjjjjiœiiiiiiiiiih›hhhhhhhhhhgšggggggggggggf™ffffffffffffeeeeeeeeeeeed—ddddddddddddddccccccccccccccb•bbbbbbbbbbbbbba”aaaaaaaaaaaaaa`“``````````````_’________________^‘^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZYŒYŒYYYYYYYYYYYYYYYYYYYYYYX‹XXXXXXXXXXXXXXXXXXXXXXXXXXWŠWWWWWWWWWWWWWWWWWWWWWWWWWWV‰V‰VVVVVVVVVVVVVVVVVVVVVVVVVVVVUˆUˆUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSR…R…RRRRRRRRRR¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````__________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRR¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššš™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––––••••••••••••””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnnnmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhggggggggggggffffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa````````````````__________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRR¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««««««««««««««««««««ªÝªÝªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§§§§§§§§§§§§§§§§§§§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó                ŸÒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžžžÐœœœœœœœœœœœœœœ›Î››››››››››››››šÍšššššššššššš™Ì™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜—Ê————————————––––––––––––•È••••••••••”Ç””””””””””““““““““““““’’’’’’’’’’‘Ä‘‘‘‘‘‘‘‘‘‘ŽÁŽŽŽŽŽŽŽŽÀŒ¿ŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††…¸……………………„„„„„„„„ƒ¶ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚´€€€€€€€€~~~~~~~~}}}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxxEwwwwwwwwvvvvvvvvvvuuuuuuuuuBttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppp=ooooooooo¥>¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:                 9ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžžžžžž76œœœœœœœœœœœœœœ›››››››››››››››4ššššššššššššš3™™™™™™™™™™™™™2˜˜˜˜˜˜˜˜˜˜˜˜˜1———————————0––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’’+‘‘‘‘‘‘‘‘‘‘(ŽŽŽŽŽŽŽŽŽ'ŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹$ŠŠŠŠŠŠŠŠŠ#‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡ ††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzyàyyyyyyyyxxxxxxxxxxwwwwwwwwvÝvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooonÕnnnnnnnnnnmmmmmmmmmmlÓllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhgÎggggggggggggffffffffffffeÌeeeeeeeeeeeeeeddddddddddddddcÊccccccccccccbÉbbbbbbbbbbbbbbaÈaaaaaaaaaaaaaaaa`Ç``````````````_Æ__________________^Å^^^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]]]\Ã\Ã\\\\\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZZZZZZZYÀYYYYYYYYYYYYYYYYYYYYYYYYX¿XXXXXXXXXXXXXXXXXXXXXXXXXXW¾WWWWWWWWWWWWWWWWWWWWWWWWWWWWV½VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVU¼UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSºSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬y¬y«««««««««««««««««««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§§§§§§§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n                 mŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžžžžžkjœœœœœœœœœœœœœœœi›››››››››››››hšššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜e————————————–––––––––––––c•••••••••••b”””””””””””a“““““““““““`’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘^ŽŽŽŽŽŽŽŽŽŽZŒŒŒŒŒŒŒŒŒY‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}}}||||||||{®{{{{{{{{zzzzzzzzzzyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvu¨uuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqp£ppppppppo¢oooooooooonnnnnnnnnnm mmmmmmmmmmllllllllllkžkkkkkkkkkkjjjjjjjjjjjiœiiiiiiiiiih›hhhhhhhhhhhhggggggggggggf™ffffffffffffe˜eeeeeeeeeeeed—ddddddddddddddccccccccccccccb•bbbbbbbbbbbbbba”aaaaaaaaaaaaaaaa`“``````````````_’__________________^‘^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\[Ž[Ž[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYYYYYYYYYYYX‹XXXXXXXXXXXXXXXXXXXXXXXXXXWŠWŠWWWWWWWWWWWWWWWWWWWWWWWWWWV‰V‰VVVVVVVVVVVVVVVVVVVVVVVVVVVVUˆUˆUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{zzzzzzzzzzyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqqqppppppppppoooooooooonnnnnnnnnnnnmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````____________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                  ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}||||||||||{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppoooooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````____________________^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS¬¬¬¬¬¬¬¬«Þ«Þ««««««««««««««««««««««««««««««««««««ªÝªÝªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§§§§§§§§§§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö£Ö££££££££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó Ó                ŸÒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžžžžžÐœÏœœœœœœœœœœœœœœ›Î››››››››››››››šÍšššššššššššš™Ì™™™™™™™™™™™™˜Ë˜˜˜˜˜˜˜˜˜˜˜˜—Ê————————————––––––––––––•È••••••••••”Ç””””””””””“Æ““““““““““’Å’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘ÃŽÁŽŽŽŽŽŽŽŽÀŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰ˆ»ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}||||||||||{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppp=oooooooooonnnnnnnnnnmmmmmmmmmmmmlllllllllll9kkkkkkkkkkk8jjjjjjjjjjj7iiiiiiiiiiiihhhhhhhhhhhhh5ggggggggggggffffffffffffffeeeeeeeeeeeeeee2ddddddddddddd1ccccccccccccccc0bbbbbbbbbbbbbbb/aaaaaaaaaaaaaaaaa.```````````````-___________________,^^^^^^^^^^^^^^^^^+^+]]]]]]]]]]]]]]]]]]]*\\\\\\\\\\\\\\\\\\\\\)[[[[[[[[[[[[[[[[[[[[[([(ZZZZZZZZZZZZZZZZZZZZZZZ'YYYYYYYYYYYYYYYYYYYYYYYYY&XXXXXXXXXXXXXXXXXXXXXXXXXXX%X%WWWWWWWWWWWWWWWWWWWWWWWWWWW$W$VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV#UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT!T!SSSSSSSSSSSSSSSSSSSSSSSSSS¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§ § ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ¦ ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ £££££££££££££££££££££££ ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                   ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœ›››››››››››››››ššššššššššššš™™™™™™™™™™™™˜ÿ˜˜˜˜˜˜˜˜˜˜˜˜—þ————————————–ý––––––––––•ü••••••••••••””””””””””””““““““““““““’’’’’’’’’’‘ø‘‘‘‘‘‘‘‘‘‘öŽŽŽŽŽŽŽŽŽŽŒóŒŒŒŒŒŒŒŒ‹ò‹‹‹‹‹‹‹‹ŠñŠŠŠŠŠŠŠŠ‰ð‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††…ì……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}||||||||||{{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxxwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqq ppppppppppoooooooooonnnnnnnnnnnmmmmmmmmmmmllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjiiiiiiiiiiihhhhhhhhhhhhgggggggggggggffffffffffffeÿeeeeeeeeeeeeeeddddddddddddddcýccccccccccccccbübbbbbbbbbbbbbbaûaaaaaaaaaaaaaaaa````````````````_ù__________________^ø^^^^^^^^^^^^^^^^^^]÷]]]]]]]]]]]]]]]]]]\ö\\\\\\\\\\\\\\\\\\\\[õ[[[[[[[[[[[[[[[[[[[[[[ZôZZZZZZZZZZZZZZZZZZZZZZYóYYYYYYYYYYYYYYYYYYYYYYYYXòXòXXXXXXXXXXXXXXXXXXXXXXXXXXWñWWWWWWWWWWWWWWWWWWWWWWWWWWWWVðVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUïUïUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTîTîTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSíSíSSSSSSSSSSSSSSSSSSSSSS¬E¬E«««««««««««««««««««««««««««««««««««««««DªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªC©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©B©B¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨A¨A§§§§§§§§§§§§§§§§§§§§§§§§§§§@¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦?¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥>¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££££££££<£<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:                   9ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžžžžžž76œœœœœœœœœœœœœœœ5›››››››››››››››4šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜—————————————0––––––––––––•••••••••••••.”””””””””””-“““““““““““,’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘*(ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwvÝvvvvvvvvuÜuuuuuuuutÛttttttttsÚssssssssrÙrrrrrrrrqØqqqqqqqqqqppppppppppoooooooooonÕnnnnnnnnnnmmmmmmmmmmmmllllllllllkÒkkkkkkkkkkjÑjjjjjjjjjjjjiiiiiiiiiiiihÏhhhhhhhhhhgÎggggggggggggfÍffffffffffffeÌeeeeeeeeeeeedËddddddddddddddcÊccccccccccccccbÉbbbbbbbbbbbbbbaÈaaaaaaaaaaaaaa`Ç````````````````_Æ__________________^Å^^^^^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZZZZZZZYÀYÀYYYYYYYYYYYYYYYYYYYYYYYYX¿XXXXXXXXXXXXXXXXXXXXXXXXXXW¾W¾WWWWWWWWWWWWWWWWWWWWWWWWWWV½V½VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVU¼U¼UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSºSºSSSSSSSSSSSSSSSSSS«««««««««««««««««««««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§§§§§§§§§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n                   mŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžžžžžkœœœœœœœœœœœœœœœœ›››››››››››››››hšššššššššššššššg™™™™™™™™™™™™™f˜˜˜˜˜˜˜˜˜˜˜˜˜e————————————–––––––––––––c•••••••••••b””””””””””””“““““““““““`’’’’’’’’’’’_‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽ[ŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡T††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppo¢oooooooooonnnnnnnnnnm mmmmmmmmmmlŸllllllllllkžkkkkkkkkkkjjjjjjjjjjjiœiiiiiiiiiiiihhhhhhhhhhhhgšggggggggggggf™ffffffffffffe˜eeeeeeeeeeeed—ddddddddddddddc–ccccccccccccccbbbbbbbbbbbbbbbba”aaaaaaaaaaaaaa`“````````````````_’__________________^‘^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\[Ž[Ž[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYYYYYYYYYYYX‹X‹XXXXXXXXXXXXXXXXXXXXXXXXXXWŠWWWWWWWWWWWWWWWWWWWWWWWWWWWWV‰V‰VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUˆUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTS†S†SSSSSSSSSSSSSS««««««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––••••••••••••””””””””””””””““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppppoooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeddddddddddddddddccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSS««««««««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqqqppppppppppoooooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSS««««««««««««««««««««««««««««««ªÝªÝªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó                  ŸÒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžžžžžÐœÏœœœœœœœœœœœœœœ›Î››››››››››››››šÍšššššššššššš™Ì™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————–É––––––––––––•È••••••••••”Ç””””””””””“Æ““““““““““’Å’’’’’’’’’’‘Ä‘‘‘‘‘‘‘‘‘‘ÃŽÁŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„ƒ¶ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyFxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttsssssssssss@rrrrrrrrr?qqqqqqqqqqppppppppppp=oooooooooonnnnnnnnnnn;mmmmmmmmmmm:lllllllllll9kkkkkkkkkkk8jjjjjjjjjjj7iiiiiiiiiiiihhhhhhhhhhhhh5ggggggggggggg4fffffffffffff3eeeeeeeeeeeeeee2ddddddddddddd1ccccccccccccccc0bbbbbbbbbbbbbbbbb/aaaaaaaaaaaaaaa.`````````````````-___________________,^^^^^^^^^^^^^^^^^^^+]]]]]]]]]]]]]]]]]]]]]*\\\\\\\\\\\\\\\\\\\\\)[[[[[[[[[[[[[[[[[[[[[[[(ZZZZZZZZZZZZZZZZZZZZZZZ'Z'YYYYYYYYYYYYYYYYYYYYYYYYY&XXXXXXXXXXXXXXXXXXXXXXXXXXXXX%WWWWWWWWWWWWWWWWWWWWWWWWWWWWW$W$VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV#V#UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"U"TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT!T!SSSSSSSS««««««««««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ § ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ¦ ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ £££££££££££££££££££££££ ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                   ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœ›››››››››››››››šššššššššššššš™™™™™™™™™™™™™™˜ÿ˜˜˜˜˜˜˜˜˜˜˜˜—þ————————————––––––––––––•ü••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘öŽŽŽŽŽŽŽŽŽŽôŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxwwwwwwwwwvvvvvvvvvuuuuuuuuuttttttttt ssssssssssrrrrrrrrrrqqqqqqqqqqq ppppppppppooooooooooonnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjiiiiiiiiiiihhhhhhhhhhhhhgggggggggggggffffffffffffeÿeeeeeeeeeeeeeeddddddddddddddcýccccccccccccccbübbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa`ú````````````````_ù__________________^ø^^^^^^^^^^^^^^^^^^]÷]]]]]]]]]]]]]]]]]]]]\ö\\\\\\\\\\\\\\\\\\\\[õ[[[[[[[[[[[[[[[[[[[[[[ZôZZZZZZZZZZZZZZZZZZZZZZZZYóYYYYYYYYYYYYYYYYYYYYYYYYXòXòXXXXXXXXXXXXXXXXXXXXXXXXXXWñWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVðVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUïUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTîTîTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSíSíSSSS«««««««««««««««««««««««««DªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªCªC©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©B¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨A¨A§§§§§§§§§§§§§§§§§§§§§§§§§§§§§@¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦?¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥>¥>¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££££££££<£<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:                   9ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžžžžžž76œœœœœœœœœœœœœœœ5›››››››››››››››4ššššššššššššššš3™™™™™™™™™™™™™2˜˜˜˜˜˜˜˜˜˜˜˜˜1—————————————0––––––––––––•••••••••••••.”””””””””””-“““““““““““,’’’’’’’’’’’+‘‘‘‘‘‘‘‘‘‘‘*(ŽŽŽŽŽŽŽŽŽŽ&ŒŒŒŒŒŒŒŒŒ%‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††………………………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrqØqqqqqqqqqqppppppppppoooooooooooonnnnnnnnnnmÔmmmmmmmmmmlÓllllllllllkÒkkkkkkkkkkjÑjjjjjjjjjjjjiiiiiiiiiiiihÏhhhhhhhhhhhhggggggggggggggffffffffffffffeÌeeeeeeeeeeeedËddddddddddddddcÊccccccccccccccbÉbbbbbbbbbbbbbbaÈaaaaaaaaaaaaaaaa`Ç````````````````_Æ__________________^Å^^^^^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[[[[[[[[[ZÁZÁZZZZZZZZZZZZZZZZZZZZZZYÀYYYYYYYYYYYYYYYYYYYYYYYYYYX¿XXXXXXXXXXXXXXXXXXXXXXXXXXW¾W¾WWWWWWWWWWWWWWWWWWWWWWWWWWWWV½V½VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVU¼U¼UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUT»T»TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSºSº«««««««««««««««««««««x«xªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u§§§§§§§§§§§§§§§§§§§§§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q¤q£££££££££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n                   mŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžžžžžkjœœœœœœœœœœœœœœœi›››››››››››››››hšššššššššššššššg™™™™™™™™™™™™™f˜˜˜˜˜˜˜˜˜˜˜˜˜˜—————————————d–––––––––––––c••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘]ŽŽŽŽŽŽŽŽŽŽŽ[ŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹XŠŠŠŠŠŠŠŠŠW‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡T†††††††††S……………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||{®{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssr¥rrrrrrrrrrqqqqqqqqqqppppppppppo¢oooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiœiiiiiiiiiiiihhhhhhhhhhhhgšggggggggggggf™ffffffffffffffeeeeeeeeeeeeeed—ddddddddddddddc–ccccccccccccccb•bbbbbbbbbbbbbba”aaaaaaaaaaaaaaaa`“````````````````_’__________________^‘^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\[Ž[Ž[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZYŒYŒYYYYYYYYYYYYYYYYYYYYYYYYX‹X‹XXXXXXXXXXXXXXXXXXXXXXXXXXWŠWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWV‰VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUˆUˆUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUT‡TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT««««««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————––––––––––––––••••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrqqqqqqqqqqppppppppppppoooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT««««««««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––••••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttttssssssssssrrrrrrrrrrqqqqqqqqqqqqppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT««««««««««««ªÝªÝªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó                  ŸÒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžžžžžžžÐœÏœœœœœœœœœœœœœœœœ›Î››››››››››››››šÍšššššššššššššš™™™™™™™™™™™™™™˜Ë˜˜˜˜˜˜˜˜˜˜˜˜—Ê————————————–É––––––––––––••••••••••••”Ç””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽÁŽŽŽŽŽŽŽŽŽŽŒ¿ŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€³€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{HzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvCuuuuuuuuuBttttttttttssssssssssrrrrrrrrrrr?qqqqqqqqqqppppppppppp=oooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjj7iiiiiiiiiiiii6hhhhhhhhhhhhggggggggggggggfffffffffffffff3eeeeeeeeeeeeeeddddddddddddddd1ccccccccccccccccbbbbbbbbbbbbbbbbb/aaaaaaaaaaaaaaaaa.`````````````````-___________________,^^^^^^^^^^^^^^^^^^^+^+]]]]]]]]]]]]]]]]]]]*\\\\\\\\\\\\\\\\\\\\\\\)[[[[[[[[[[[[[[[[[[[[[[[(ZZZZZZZZZZZZZZZZZZZZZZZZZ'YYYYYYYYYYYYYYYYYYYYYYYYYYY&XXXXXXXXXXXXXXXXXXXXXXXXXXXXX%WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW$W$VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV#V#UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"U"TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT««««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ¦ ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ £££££££££££££££££££££££ ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                   ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœ›››››››››››››››ššššššššššššššš™™™™™™™™™™™™˜ÿ˜˜˜˜˜˜˜˜˜˜˜˜—þ————————————–ý––––––––––––•ü••••••••••••””””””””””””“ú““““““““““’ù’’’’’’’’’’‘ø‘‘‘‘‘‘‘‘‘‘÷öŽŽŽŽŽŽŽŽŽŽôŒŒŒŒŒŒŒŒŒŒ‹ò‹‹‹‹‹‹‹‹ŠñŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzyyyyyyyyyxxxxxxxxxwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttsssssssssss rrrrrrrrrrqqqqqqqqqqppppppppppppooooooooooonnnnnnnnnnnmmmmmmmmmmmlllllllllllkkkkkkkkkkkjjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhhgggggggggggggffffffffffffffeÿeeeeeeeeeeeedþddddddddddddddcýccccccccccccccbübbbbbbbbbbbbbbbbaûaaaaaaaaaaaaaaaa`ú````````````````_ù__________________^ø^^^^^^^^^^^^^^^^^^^^]÷]]]]]]]]]]]]]]]]]]\ö\ö\\\\\\\\\\\\\\\\\\\\[õ[[[[[[[[[[[[[[[[[[[[[[ZôZôZZZZZZZZZZZZZZZZZZZZZZYóYóYYYYYYYYYYYYYYYYYYYYYYYYXòXòXXXXXXXXXXXXXXXXXXXXXXXXXXWñWñWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVðVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUïUïUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTîTîTTTTTTTTTTTTTTTTTTTTTTTTTT«««««««DªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªCªC©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©B¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨A§§§§§§§§§§§§§§§§§§§§§§§§§§§§§@§@¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦?¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥>¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:                   9ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžžžžžž76œœœœœœœœœœœœœœœ5›››››››››››››››4ššššššššššššššš3™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––•••••••••••••.””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘(ŽŽŽŽŽŽŽŽŽŽ&ŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠ#‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttsÚssssssssssrrrrrrrrrrqqqqqqqqqqp×ppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjÑjjjjjjjjjjjjiiiiiiiiiiiihÏhhhhhhhhhhhhgÎggggggggggggfÍffffffffffffffeeeeeeeeeeeeeedËddddddddddddddcÊccccccccccccccbÉbbbbbbbbbbbbbbbbaÈaaaaaaaaaaaaaaaa`Ç````````````````_Æ__________________^Å^^^^^^^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\\\\\[Â[Â[[[[[[[[[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZZZZZZZZZYÀYYYYYYYYYYYYYYYYYYYYYYYYYYX¿XXXXXXXXXXXXXXXXXXXXXXXXXXXXW¾WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWV½V½VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVU¼UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUT»TTTTTTTTTTTTTTTTTTTTTTTT«««x«xªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªw©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§§§§§§§§§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q¤q£££££££££££££££££££££p£p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n                   mŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžžžžžkjœœœœœœœœœœœœœœœi›››››››››››››››hšššššššššššššššg™™™™™™™™™™™™™™™f˜˜˜˜˜˜˜˜˜˜˜˜˜e—————————————d–––––––––––––c••••••••••••”””””””””””””a“““““““““““`’’’’’’’’’’’_‘‘‘‘‘‘‘‘‘‘‘^]ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰Vˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚O€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuut§ttttttttttssssssssssrrrrrrrrrrq¤qqqqqqqqqqppppppppppo¢oooooooooon¡nnnnnnnnnnm mmmmmmmmmmlŸllllllllllkžkkkkkkkkkkkkjjjjjjjjjjjjiœiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggf™ffffffffffffe˜eeeeeeeeeeeeeed—ddddddddddddddc–ccccccccccccccb•bbbbbbbbbbbbbbbba”aaaaaaaaaaaaaaaa`“````````````````_’__________________^‘^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYYYYYYYYYYYYYX‹X‹XXXXXXXXXXXXXXXXXXXXXXXXXXWŠWŠWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWV‰VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUˆUˆUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUT‡T‡TTTTTTTTTTTTTTTTTTTT««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••••””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuuttttttttttssssssssssrrrrrrrrrrrrqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                    ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––••••••••••••••””””””””””””””““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrqqqqqqqqqqqqppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffffeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa``````````````````____________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó Ó                  ŸÒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžžžžžÐœÏœœœœœœœœœœœœœœœœ››››››››››››››››šÍšššššššššššššš™Ì™™™™™™™™™™™™˜Ë˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————–É––––––––––––••••••••••••”Ç””””””””””””“Æ““““““““““’Å’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ÂŽÁŽŽŽŽŽŽŽŽŽŽŒ¿ŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹Š½ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„·„„„„„„„„ƒ¶ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwDvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrqqqqqqqqqqqqppppppppppp=ooooooooooo¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=¤=£££££££££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:                     9ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžžžžžž76œœœœœœœœœœœœœœœœœ5›››››››››››››››4ššššššššššššššš3™™™™™™™™™™™™™™™2˜˜˜˜˜˜˜˜˜˜˜˜˜1——————————————––––––––––––––•••••••••••••.””””””””””””“““““““““““““,’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘(ŽŽŽŽŽŽŽŽŽŽŽ'ŒŒŒŒŒŒŒŒŒŒŒ%‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰"ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxßxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuutÛttttttttttssssssssssrrrrrrrrrrrrqqqqqqqqqqp×ppppppppppoÖoooooooooonnnnnnnnnnnnmmmmmmmmmmmmlÓllllllllllkÒkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiihÏhhhhhhhhhhhhgÎggggggggggggggffffffffffffffeÌeeeeeeeeeeeeeedËddddddddddddddcÊccccccccccccccccbbbbbbbbbbbbbbbbaÈaaaaaaaaaaaaaaaaaa`Ç````````````````_Æ__________________^Å^^^^^^^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]]]]]\Ã\Ã\\\\\\\\\\\\\\\\\\\\[Â[Â[[[[[[[[[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZZZZZZZZZZZYÀYYYYYYYYYYYYYYYYYYYYYYYYYYX¿XXXXXXXXXXXXXXXXXXXXXXXXXXXXW¾W¾WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWV½V½VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVU¼U¼UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUT»TTTTTTªªªªªªªªªªªªªªªªªªªªªªªªªwªw©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££££££££££p£p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n                     mŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžžžžžkjœœœœœœœœœœœœœœœœœi›››››››››››››››hšššššššššššššššg™™™™™™™™™™™™™™™f˜˜˜˜˜˜˜˜˜˜˜˜˜˜———————————————d–––––––––––––c••••••••••••”””””””””””””a““““““““““““’’’’’’’’’’’’’_‘‘‘‘‘‘‘‘‘‘‘^]ŽŽŽŽŽŽŽŽŽŽŽŽZŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹XŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆU‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{z­zzzzzzzzy¬yyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvu¨uuuuuuuuuuttttttttttssssssssssr¥rrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooon¡nnnnnnnnnnm mmmmmmmmmmmmllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjiœiiiiiiiiiiiih›hhhhhhhhhhhhgšggggggggggggf™ffffffffffffffe˜eeeeeeeeeeeeeed—ddddddddddddddc–ccccccccccccccb•bbbbbbbbbbbbbbbba”aaaaaaaaaaaaaaaaaa`“````````````````_’__________________^‘^‘^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYYYYYYYYYYYYYX‹X‹XXXXXXXXXXXXXXXXXXXXXXXXXXXXWŠWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWV‰VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUˆUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUT‡T‡TTªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••••””””””””””””““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa``````````````````______________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••••””””””””””””””““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuttttttttttttssssssssssrrrrrrrrrrrrqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUªªªªªªªªªªªªªªªªªª©Ü©Ü©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨Û¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó                    ŸÒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžžžžžÐœœœœœœœœœœœœœœœœ›Î››››››››››››››››šÍšššššššššššššš™Ì™™™™™™™™™™™™™™˜Ë˜˜˜˜˜˜˜˜˜˜˜˜—Ê——————————————––––––––––––––••••••••••••••””””””””””””“Æ““““““““““““’’’’’’’’’’’’‘Ä‘‘‘‘‘‘‘‘‘‘ÃÂŽÁŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹¾‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰¼‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡†¹††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}J||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwDvvvvvvvvvvuuuuuuuuuuttttttttttttssssssssssrrrrrrrrrrrrqqqqqqqqqqq>ppppppppppp=ooooooooooo¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:                     9ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžžžžžžž6œœœœœœœœœœœœœœœœœ5›››››››››››››››4ššššššššššššššš3™™™™™™™™™™™™™™™2˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜1—————————————0––––––––––––––•••••••••••••.”””””””””””””-““““““““““““’’’’’’’’’’’’’+‘‘‘‘‘‘‘‘‘‘‘*)(ŽŽŽŽŽŽŽŽŽŽŽ'ŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹$ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰"ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††……………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}ä}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrqØqqqqqqqqqqp×ppppppppppoÖoooooooooonÕnnnnnnnnnnmÔmmmmmmmmmmmmllllllllllllkÒkkkkkkkkkkkkjjjjjjjjjjjjiÐiiiiiiiiiiiihÏhhhhhhhhhhhhhhggggggggggggggfÍffffffffffffffeÌeeeeeeeeeeeeeedËddddddddddddddcÊccccccccccccccccbÉbbbbbbbbbbbbbbbbaÈaaaaaaaaaaaaaaaa`Ç``````````````````_Æ____________________^Å^^^^^^^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\\\\\\\[Â[Â[[[[[[[[[[[[[[[[[[[[[[ZÁZÁZZZZZZZZZZZZZZZZZZZZZZZZYÀYÀYYYYYYYYYYYYYYYYYYYYYYYYYYX¿XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXW¾WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWV½VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVU¼U¼UUUUUUUUUUUUUUUUUUUUUUUUUUUUªªªªªªªªªw©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n                     mŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžžžžžžžkjœœœœœœœœœœœœœœœœœi›››››››››››››››hšššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜e——————————————–––––––––––––––c••••••••••••””””””””””””””“““““““““““““`’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒY‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆU‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyx«xxxxxxxxxxwwwwwwwwwwvvvvvvvvvvu¨uuuuuuuuuutttttttttts¦ssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmlŸllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjiœiiiiiiiiiiiih›hhhhhhhhhhhhgšggggggggggggggf™ffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddc–ccccccccccccccccb•bbbbbbbbbbbbbbbba”aaaaaaaaaaaaaaaa`“``````````````````_’____________________^‘^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYYYYYYYYYYYYYX‹X‹XXXXXXXXXXXXXXXXXXXXXXXXXXXXWŠWŠWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWV‰V‰VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUˆUˆUUUUUUUUUUUUUUUUUUUUUUUUªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––••••••••••••••””””””””””””””““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuttttttttttttssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggggffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUU©Ü©Ü©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö£Ö££££££££££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó                    ŸÒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžžžžžžžÐœÏœœœœœœœœœœœœœœœœ›Î››››››››››››››››šÍšššššššššššššš™Ì™™™™™™™™™™™™™™˜Ë˜˜˜˜˜˜˜˜˜˜˜˜˜˜—Ê————————————–É––––––––––––––••••••••••••••””””””””””””””““““““““““““’Å’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ÂŽÁŽŽŽŽŽŽŽŽŽŽÀŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹Š½ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡†¹††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zzzzzzzzzzzGyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuBttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqq>ppppppppppp=ooooooooooo¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:                     9ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžžžžžžžž76œœœœœœœœœœœœœœœœœœ›››››››››››››››››4šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜———————————————0–––––––––––––/••••••••••••••”””””””””””””-“““““““““““““,’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘*)ŽŽŽŽŽŽŽŽŽŽŽŽ&ŒŒŒŒŒŒŒŒŒŒŒ%‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡†††††††††††…………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{zázzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvuÜuuuuuuuuuuttttttttttttssssssssssrÙrrrrrrrrrrqØqqqqqqqqqqp×ppppppppppoÖoooooooooonÕnnnnnnnnnnnnmmmmmmmmmmmmlÓllllllllllllkkkkkkkkkkkkjÑjjjjjjjjjjjjiÐiiiiiiiiiiiiiihhhhhhhhhhhhhhgÎggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeedËddddddddddddddcÊccccccccccccccccbÉbbbbbbbbbbbbbbbbaÈaaaaaaaaaaaaaaaaaa`Ç``````````````````_Æ____________________^Å^^^^^^^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\\\\\\\[Â[Â[[[[[[[[[[[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZZZZZZZZZZZYÀYYYYYYYYYYYYYYYYYYYYYYYYYYYYX¿XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXW¾W¾WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWV½VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVU¼UUUUUUUUUUUU©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n                     mŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžžžžžžžkœœœœœœœœœœœœœœœœœœœi›››››››››››››››hšššššššššššššššššg™™™™™™™™™™™™™™™f˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜e—————————————d––––––––––––––•••••••••••••••b””””””””””””““““““““““““““’’’’’’’’’’’’’_‘‘‘‘‘‘‘‘‘‘‘‘\ŽŽŽŽŽŽŽŽŽŽŽ[ŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠW‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆU‡‡‡‡‡‡‡‡‡‡††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuut§ttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnm mmmmmmmmmmmmllllllllllllkžkkkkkkkkkkkkjjjjjjjjjjjjjiœiiiiiiiiiiiih›hhhhhhhhhhhhhhggggggggggggggf™ffffffffffffffe˜eeeeeeeeeeeeeeeeddddddddddddddddc–ccccccccccccccccb•bbbbbbbbbbbbbbbba”aaaaaaaaaaaaaaaaaa`“``````````````````_’____________________^‘^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZYŒYŒYYYYYYYYYYYYYYYYYYYYYYYYYYX‹X‹XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWŠWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWV‰V‰VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUˆUˆUUUUUUUU©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––––••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUU©©©©©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUU©©©©©©©©©©©©©©©©©©©©©©©©¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó                      ŸÒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžžžžžžžÐœÏœœœœœœœœœœœœœœœœ›Î››››››››››››››››šÍšššššššššššššš™Ì™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————–É––––––––––––––••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’‘Ä‘‘‘‘‘‘‘‘‘‘‘‘ÂŽÁŽŽŽŽŽŽŽŽŽŽÀŒ¿ŒŒŒŒŒŒŒŒŒŒ‹¾‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆ»ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††…………………………„·„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}|||||||||||I{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuuttttttttttttsssssssssss@rrrrrrrrrrr?qqqqqqqqqqq>ppppppppppp=oooooooooooonnnnnnnnnnnnn;mmmmmmmmmmmmlllllllllllll9kkkkkkkkkkkkk8jjjjjjjjjjjjj7iiiiiiiiiiiii6hhhhhhhhhhhhhhh5ggggggggggggggfffffffffffffffff3eeeeeeeeeeeeeee2ddddddddddddddddd1ccccccccccccccccc0bbbbbbbbbbbbbbbbb/aaaaaaaaaaaaaaaaaaa.```````````````````-_____________________,^^^^^^^^^^^^^^^^^^^^^+]]]]]]]]]]]]]]]]]]]]]]]*]*\\\\\\\\\\\\\\\\\\\\\\\)[[[[[[[[[[[[[[[[[[[[[[[[[[[(ZZZZZZZZZZZZZZZZZZZZZZZZZZZ'YYYYYYYYYYYYYYYYYYYYYYYYYYYYY&Y&XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW$W$VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV#UU©©©©©©©©©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ £££££££££££££££££££££££££ ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                       ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœ›››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜ÿ˜˜˜˜˜˜˜˜˜˜˜˜˜˜—þ——————————————––––––––––––––•ü••••••••••••”û””””””””””””“ú““““““““““““’ù’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘÷ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡†í††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚耀€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppooooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiihhhhhhhhhhhhhhgggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeedþddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbaûaaaaaaaaaaaaaaaaaa`ú``````````````````_ù____________________^ø^^^^^^^^^^^^^^^^^^^^]÷]÷]]]]]]]]]]]]]]]]]]]]]]\ö\\\\\\\\\\\\\\\\\\\\\\[õ[õ[[[[[[[[[[[[[[[[[[[[[[[[ZôZZZZZZZZZZZZZZZZZZZZZZZZZZYóYóYYYYYYYYYYYYYYYYYYYYYYYYYYYYXòXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWñWñWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVðVðVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUï©©©©©©©©©©©©©©©©©©©B¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨A¨A§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§@§@¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦?¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥>¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:                     9 9ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžžžžžžžž76œœœœœœœœœœœœœœœœœ5›››››››››››››››››4ššššššššššššššššš3™™™™™™™™™™™™™™™2˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜1———————————————0–––––––––––––/••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’’+‘‘‘‘‘‘‘‘‘‘‘‘)ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠ#‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzyàyyyyyyyyyyxxxxxxxxxxwÞwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuutÛttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoÖoooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllkÒkkkkkkkkkkkkjÑjjjjjjjjjjjjiÐiiiiiiiiiiiiiihhhhhhhhhhhhhhgÎggggggggggggggfÍffffffffffffffeÌeeeeeeeeeeeeeeeeddddddddddddddddcÊccccccccccccccccbÉbbbbbbbbbbbbbbbbbbaÈaaaaaaaaaaaaaaaaaa`Ç``````````````````_Æ____________________^Å^^^^^^^^^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZZZZZZZZZZZZZYÀYYYYYYYYYYYYYYYYYYYYYYYYYYYYX¿X¿XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXW¾WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWV½VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV©©©©©©©©©©©©©©©v©v¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q¤q£££££££££££££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n                     mŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžžžžžžžkjœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššššg™™™™™™™™™™™™™™™f˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜———————————————d––––––––––––––•••••••••••••••b”””””””””””””a“““““““““““““`’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘^\ŽŽŽŽŽŽŽŽŽŽŽ[ZŒŒŒŒŒŒŒŒŒŒŒY‹‹‹‹‹‹‹‹‹‹‹XŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆU‡‡‡‡‡‡‡‡‡‡††††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuutttttttttts¦ssssssssssr¥rrrrrrrrrrq¤qqqqqqqqqqp£ppppppppppppoooooooooooonnnnnnnnnnnnm mmmmmmmmmmmmlŸllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiœiiiiiiiiiiiih›hhhhhhhhhhhhhhgšggggggggggggggf™ffffffffffffffe˜eeeeeeeeeeeeeed—ddddddddddddddddc–ccccccccccccccccb•bbbbbbbbbbbbbbbbbba”aaaaaaaaaaaaaaaaaa`“``````````````````_’____________________^‘^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYX‹XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWŠWŠWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWV‰V‰VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV©©©©©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————––––––––––––––––••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV©©©©©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––••••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoooooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVV©©©©©©©©¨Û¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££££££££££££¢Õ¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó                    ŸÒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžžžžžžžžžœÏœœœœœœœœœœœœœœœœœœ›Î››››››››››››››››šÍšššššššššššššššš™™™™™™™™™™™™™™™™˜Ë˜˜˜˜˜˜˜˜˜˜˜˜˜˜—Ê——————————————–É––––––––––––––••••••••••••••”Ç””””””””””””“Æ““““““““““““’Å’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽÁŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰¼‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}J||||||||||{{{{{{{{{{{HzzzzzzzzzzyyyyyyyyyyyFxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvCuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqq>ppppppppppp=oooooooooooonnnnnnnnnnnnn;mmmmmmmmmmmmm:llllllllllllkkkkkkkkkkkkkkk8jjjjjjjjjjjjj7iiiiiiiiiiiiiihhhhhhhhhhhhhhh5ggggggggggggggg4fffffffffffffff3eeeeeeeeeeeeeeeee2ddddddddddddddddd1ccccccccccccccccc0bbbbbbbbbbbbbbbbbbb/aaaaaaaaaaaaaaaaaaa.```````````````````-_____________________,^^^^^^^^^^^^^^^^^^^^^^^+]]]]]]]]]]]]]]]]]]]]]]]*\\\\\\\\\\\\\\\\\\\\\\\\\)[[[[[[[[[[[[[[[[[[[[[[[[[[[(ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'YYYYYYYYYYYYYYYYYYYYYYYYYYYYY&Y&XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%X%WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW$W$VVVVVVVVVVVVVVVVVVVVVVVV©©©©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ ¥ ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ £££££££££££££££££££££££££ ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                     ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœ›››››››››››››››››ššššššššššššššššš™™™™™™™™™™™™™™˜ÿ˜˜˜˜˜˜˜˜˜˜˜˜˜˜—þ——————————————–ý––––––––––––––•ü••••••••••••”û””””””””””””””““““““““““““““’’’’’’’’’’’’‘ø‘‘‘‘‘‘‘‘‘‘‘‘÷ŽŽŽŽŽŽŽŽŽŽŽŽôŒóŒŒŒŒŒŒŒŒŒŒ‹ò‹‹‹‹‹‹‹‹‹‹ŠñŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡†í††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuttttttttttt sssssssssss rrrrrrrrrrr qqqqqqqqqqqqppppppppppppooooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmlllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiihhhhhhhhhhhhhhhgggggggggggggggffffffffffffffeÿeeeeeeeeeeeeeeeedþddddddddddddddddccccccccccccccccccbübbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa`ú``````````````````_ù____________________^ø^^^^^^^^^^^^^^^^^^^^^^]÷]]]]]]]]]]]]]]]]]]]]]]\ö\\\\\\\\\\\\\\\\\\\\\\\\[õ[õ[[[[[[[[[[[[[[[[[[[[[[[[ZôZôZZZZZZZZZZZZZZZZZZZZZZZZZZYóYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXòXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWñWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVðVVVVVVVVVVVVVVVVVVVVVV©B©B¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨A§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§@§@¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦?¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥>¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=¤=£££££££££££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:                     9ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžžžžžžžžžž76œœœœœœœœœœœœœœœœœ5›››››››››››››››››4ššššššššššššššššš3™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————–––––––––––––––/••••••••••••••”””””””””””””””-“““““““““““““,’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘)ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwÞwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoÖoooooooooooonnnnnnnnnnnnmÔmmmmmmmmmmmmlÓllllllllllllkÒkkkkkkkkkkkkjÑjjjjjjjjjjjjiÐiiiiiiiiiiiiiihÏhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeÌeeeeeeeeeeeeeeeeddddddddddddddddcÊccccccccccccccccccbÉbbbbbbbbbbbbbbbbaÈaaaaaaaaaaaaaaaaaaaa`Ç``````````````````_Æ____________________^Å^^^^^^^^^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]]]]]]]\Ã\Ã\\\\\\\\\\\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZZZZZZZZZZZYÀYÀYYYYYYYYYYYYYYYYYYYYYYYYYYYYX¿X¿XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXW¾W¾WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWV½V½VVVVVVVVVVVVVVVVVV¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n                     mŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžžžžžžžžžkjœœœœœœœœœœœœœœœœœi››››››››››››››››››šššššššššššššššššg™™™™™™™™™™™™™™™™™f˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜e———————————————d––––––––––––––•••••••••••••••b”””””””””””””a““““““““““““““’’’’’’’’’’’’’_‘‘‘‘‘‘‘‘‘‘‘‘‘^\ŽŽŽŽŽŽŽŽŽŽŽ[ŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆU‡‡‡‡‡‡‡‡‡‡††††††††††††……………………………R„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwv©vvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqp£ppppppppppppoooooooooooon¡nnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiœiiiiiiiiiiiiiihhhhhhhhhhhhhhgšggggggggggggggf™ffffffffffffffffeeeeeeeeeeeeeeeed—ddddddddddddddddc–ccccccccccccccccccbbbbbbbbbbbbbbbbbba”aaaaaaaaaaaaaaaaaaaa````````````````````_’____________________^‘^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYX‹XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWŠWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWV‰V‰VVVVVVVVVVVVVV¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››››šššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••””””””””””””””““““““““““““““““’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqqqppppppppppppoooooooooooooonnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa``````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVV¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                      ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa``````````````````````______________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVV¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££££££££££££¢Õ¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó                    ŸÒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžžžžžžžžžÐœÏœœœœœœœœœœœœœœœœœœ›Î››››››››››››››››šÍšššššššššššššššš™Ì™™™™™™™™™™™™™™˜Ë˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••”Ç””””””””””””“Æ““““““““““““““’’’’’’’’’’’’‘Ä‘‘‘‘‘‘‘‘‘‘‘‘ÃŽÁŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹Š½ŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††…¸…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjj7iiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggfffffffffffffffff3eeeeeeeeeeeeeeeee2ddddddddddddddddd1ccccccccccccccccc0bbbbbbbbbbbbbbbbbbb/aaaaaaaaaaaaaaaaaaa.`````````````````````-_____________________,_,^^^^^^^^^^^^^^^^^^^^^+]]]]]]]]]]]]]]]]]]]]]]]]]*\\\\\\\\\\\\\\\\\\\\\\\\\)[[[[[[[[[[[[[[[[[[[[[[[[[[[([(ZZZZZZZZZZZZZZZZZZZZZZZZZZZ'Z'YYYYYYYYYYYYYYYYYYYYYYYYYYYYY&Y&XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW$W$VVVVVVVV¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ § ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ¦ ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ ¤ £££££££££££££££££££££££££ ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                     ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœ›››››››››››››››››ššššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜—þ——————————————–ý––––––––––––––•ü••••••••••••”û””””””””””””””““““““““““““““’ù’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘öŽŽŽŽŽŽŽŽŽŽŽŽôŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}|||||||||||{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrr qqqqqqqqqqq ppppppppppppooooooooooooonnnnnnnnnnnnnmmmmmmmmmmmmmlllllllllllllkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiihhhhhhhhhhhhhhhgggggggggggggggffffffffffffffffeÿeeeeeeeeeeeeeeeeddddddddddddddddddcýccccccccccccccccbübbbbbbbbbbbbbbbbbbaûaaaaaaaaaaaaaaaaaa`ú````````````````````_ù______________________^ø^^^^^^^^^^^^^^^^^^^^]÷]÷]]]]]]]]]]]]]]]]]]]]]]\ö\\\\\\\\\\\\\\\\\\\\\\\\[õ[õ[[[[[[[[[[[[[[[[[[[[[[[[[[ZôZZZZZZZZZZZZZZZZZZZZZZZZZZZZYóYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXòXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWñWñWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVðVVVVVV¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨A§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§@¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦?¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥>¥>¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:                     9ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžžžžžžžžžž76œœœœœœœœœœœœœœœœœœœ5›››››››››››››››››4ššššššššššššššššš3™™™™™™™™™™™™™™™™™2˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜1———————————————0–––––––––––––––/••••••••••••••”””””””””””””””-“““““““““““““,’’’’’’’’’’’’’+‘‘‘‘‘‘‘‘‘‘‘‘‘*ŽŽŽŽŽŽŽŽŽŽŽŽ&ŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡ ††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxwÞwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrÙrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppoÖoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjiÐiiiiiiiiiiiiiihÏhhhhhhhhhhhhhhgÎggggggggggggggfÍffffffffffffffffeeeeeeeeeeeeeeeedËddddddddddddddddddccccccccccccccccccbÉbbbbbbbbbbbbbbbbbbaÈaaaaaaaaaaaaaaaaaa`Ç````````````````````_Æ______________________^Å^^^^^^^^^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZZZZZZZZZZZZZYÀYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYX¿X¿XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXW¾WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWV½V½VV¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨u¨u§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n¡n                     mŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžkjœœœœœœœœœœœœœœœœœœœi››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™™f˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––•••••••••••••••b””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘\ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒŒY‹‹‹‹‹‹‹‹‹‹‹XŠŠŠŠŠŠŠŠŠŠŠW‰‰‰‰‰‰‰‰‰‰‰VˆˆˆˆˆˆˆˆˆˆˆU‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„„Qƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚N€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwv©vvvvvvvvvvu¨uuuuuuuuuut§tttttttttts¦ssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqp£ppppppppppppoooooooooooon¡nnnnnnnnnnnnm mmmmmmmmmmmmlŸllllllllllllkžkkkkkkkkkkkkjjjjjjjjjjjjjjjiœiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggf™ffffffffffffffe˜eeeeeeeeeeeeeeeed—ddddddddddddddddc–ccccccccccccccccccb•bbbbbbbbbbbbbbbbbba”aaaaaaaaaaaaaaaaaa`“````````````````````_’______________________^‘^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYŒYŒYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYX‹XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWŠWŠWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWV‰¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••””””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||||{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqqqppppppppppppoooooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœ››››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••••””””””””””””””““““““““““““““’’’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssrrrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW¨¨¨¨¨¨¨¨¨¨¨¨¨¨§Ú§Ú§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö££££££££££££££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó                      ŸÒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžžžžžžžÐœÏœœœœœœœœœœœœœœœœœœ››››››››››››››››››šÍšššššššššššššššš™Ì™™™™™™™™™™™™™™™™˜Ë˜˜˜˜˜˜˜˜˜˜˜˜˜˜—Ê————————————————––––––––––––––•È••••••••••••••”Ç””””””””””””””““““““““““““““’’’’’’’’’’’’’’‘Ä‘‘‘‘‘‘‘‘‘‘‘‘ŽÁŽŽŽŽŽŽŽŽŽŽŽŽŒ¿ŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††…………………………„·„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~}}}}}}}}}}}}||||||||||||{{{{{{{{{{{{zzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttsssssssssssss@rrrrrrrrrrrrqqqqqqqqqqqqppppppppppppppooooooooooooo¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:                       9ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžžžžžžžžž6œœœœœœœœœœœœœœœœœœœ5›››››››››››››››››4šššššššššššššššššš™™™™™™™™™™™™™™™™™2˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜1———————————————0–––––––––––––––/•••••••••••••••.””””””””””””””““““““““““““““’’’’’’’’’’’’’’’+‘‘‘‘‘‘‘‘‘‘‘‘‘*ŽŽŽŽŽŽŽŽŽŽŽŽŽ'ŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹$ŠŠŠŠŠŠŠŠŠŠŠ#‰‰‰‰‰‰‰‰‰‰‰"ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡ †††††††††††…………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyxßxxxxxxxxxxwÞwwwwwwwwwwvÝvvvvvvvvvvuÜuuuuuuuuuutÛttttttttttttssssssssssssrrrrrrrrrrrrqØqqqqqqqqqqqqppppppppppppoÖoooooooooooonÕnnnnnnnnnnnnmmmmmmmmmmmmmmlÓllllllllllllkÒkkkkkkkkkkkkkkjjjjjjjjjjjjjjiÐiiiiiiiiiiiiiihÏhhhhhhhhhhhhhhgÎggggggggggggggggffffffffffffffffeÌeeeeeeeeeeeeeeeedËddddddddddddddddddccccccccccccccccccbÉbbbbbbbbbbbbbbbbbbaÈaaaaaaaaaaaaaaaaaaaa`Ç````````````````````_Æ______________________^Å^^^^^^^^^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[[[[[[[[[[[[[ZÁZÁZZZZZZZZZZZZZZZZZZZZZZZZZZZZYÀYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYX¿X¿XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXW¾W¾WWWWWWWWWWWWWWWWWWWWWWWW¨¨¨¨¨¨¨u§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§t§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n                       mŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžžžžžžžžžkjœœœœœœœœœœœœœœœœœœœi››››››››››››››››››šššššššššššššššššššg™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜e————————————————––––––––––––––––•••••••••••••••b”””””””””””””””a“““““““““““““`’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘]\ŽŽŽŽŽŽŽŽŽŽŽŽZŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆˆU‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssr¥rrrrrrrrrrrrqqqqqqqqqqqqp£ppppppppppppoooooooooooooonnnnnnnnnnnnm mmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjjiœiiiiiiiiiiiiiihhhhhhhhhhhhhhhhgšggggggggggggggf™ffffffffffffffffe˜eeeeeeeeeeeeeeeed—ddddddddddddddddc–ccccccccccccccccccb•bbbbbbbbbbbbbbbbbba”aaaaaaaaaaaaaaaaaaaa`“````````````````````_’______________________^‘^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYX‹XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWŠWWWWWWWWWWWWWWWWWWWWWW¨¨¨¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜——————————————————––––––––––––––––••••••••••••••””””””””””””””””““““““““““““““’’’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqqqppppppppppppoooooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhggggggggggggggggffffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWW¨¨§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––••••••••••••••••””””””””””””””““““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}||||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttttssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqqqppppppppppppppoooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggggffffffffffffffffffeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWW§Ú§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦Ù¦Ù¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥Ø¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤×¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£Ö£Ö££££££££££££££££££££££££££¢Õ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡Ô¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ Ó                      ŸÒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžÑžžžžžžžžžžžžžžžžžžžžÐœÏœœœœœœœœœœœœœœœœœœ›Î››››››››››››››››››šÍšššššššššššššššš™Ì™™™™™™™™™™™™™™™™˜Ë˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜—Ê——————————————–É––––––––––––––•È••••••••••••••”Ç””””””””””””””““““““““““““““’Å’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽÁŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹Š½ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}}J||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuuBttttttttttttssssssssssssrrrrrrrrrrrrr?qqqqqqqqqqqqppppppppppppppooooooooooooo¥>¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤=£££££££££££££££££££££££££££<¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡:                       9ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ8žžžžžžžžžžžžžžžžžžžžž7œœœœœœœœœœœœœœœœœœœœœ5›››››››››››››››››4ššššššššššššššššššš3™™™™™™™™™™™™™™™™™2˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜—————————————————0–––––––––––––––/•••••••••••••••.””””””””””””””“““““““““““““““,’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŽ'ŒŒŒŒŒŒŒŒŒŒŒŒŒ%‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰"ˆˆˆˆˆˆˆˆˆˆˆ!‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}}}||||||||||{â{{{{{{{{{{zázzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwÞwwwwwwwwwwvÝvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttssssssssssssssrrrrrrrrrrrrqqqqqqqqqqqqqqppppppppppppoÖoooooooooooonÕnnnnnnnnnnnnmÔmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjiÐiiiiiiiiiiiiiihÏhhhhhhhhhhhhhhhhggggggggggggggggfÍffffffffffffffffeÌeeeeeeeeeeeeeeeedËddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbaÈaaaaaaaaaaaaaaaaaaaa`Ç````````````````````_Æ______________________^Å^^^^^^^^^^^^^^^^^^^^^^^^]Ä]]]]]]]]]]]]]]]]]]]]]]]]\Ã\\\\\\\\\\\\\\\\\\\\\\\\\\[Â[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZÁZZZZZZZZZZZZZZZZZZZZZZZZZZZZYÀYÀYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYX¿X¿XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXW¾WWWWWWWWWW§§§§§§§§§§§§§§§§§§§§§§§§§§§§§t¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦s¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥r¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤q£££££££££££££££££££££££££££p¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢o¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡n                       mŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸlžžžžžžžžžžžžžžžžžžžžžkjœœœœœœœœœœœœœœœœœœœi››››››››››››››››››šššššššššššššššššššg™™™™™™™™™™™™™™™™™f˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜e———————————————d––––––––––––––––••••••••••••••••”””””””””””””””a““““““““““““““’’’’’’’’’’’’’’’_‘‘‘‘‘‘‘‘‘‘‘‘‘^]\ŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡T†††††††††††S……………………………R„„„„„„„„„„„Qƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}}}||||||||||||{{{{{{{{{{{{zzzzzzzzzzy¬yyyyyyyyyyx«xxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuutttttttttttts¦ssssssssssssrrrrrrrrrrrrq¤qqqqqqqqqqqqppppppppppppppoooooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmlŸllllllllllllkžkkkkkkkkkkkkkkjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiih›hhhhhhhhhhhhhhgšggggggggggggggggf™ffffffffffffffffeeeeeeeeeeeeeeeeeed—ddddddddddddddddc–ccccccccccccccccccb•bbbbbbbbbbbbbbbbbbbba”aaaaaaaaaaaaaaaaaaaa`“````````````````````_’______________________^‘^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\[Ž[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYŒYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYX‹XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWŠWŠWWWWWW§§§§§§§§§§§§§§§§§§§§§§§§§§§§¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££££££££££££££££££££££££££££¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡                        ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžžžžžžžžžžžžžžžžžžžžžœœœœœœœœœœœœœœœœœœœœ››››››››››››››››››››šššššššššššššššššš™™™™™™™™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜————————————————––––––––––––––––––••••••••••••••••””””””””””””””““““““““““““““““’’’’’’’’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††………………………………„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€~~~~~~~~~~~~}}}}}}}}}}}}||||||||||||{{{{{{{{{{{{zzzzzzzzzzzzyyyyyyyyyyyyxxxxxxxxxxxxwwwwwwwwwwwwvvvvvvvvvvvvuuuuuuuuuuuuttttttttttttttssssssssssssrrrrrrrrrrrrrrqqqqqqqqqqqqppppppppppppppoooooooooooooonnnnnnnnnnnnnnmmmmmmmmmmmmmmmmllllllllllllllkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhggggggggggggggggggffffffffffffffffeeeeeeeeeeeeeeeeeeeeddddddddddddddddddccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaa``````````````````````________________________^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWmlt-0.9.0/src/tests/common.pri000066400000000000000000000004531215300731300162460ustar00rootroot00000000000000QT += testlib QT -= gui CONFIG += console CONFIG -= app_bundle CONFIG += testcase TEMPLATE = app DEFINES += SRCDIR=\\\"$$PWD/\\\" win32 { INCLUDEPATH += include/mlt++ include/mlt LIBS += -Llib -lmlt++ -lmlt } else { CONFIG += link_pkgconfig PKGCONFIG += mlt++ } mlt-0.9.0/src/tests/setenv000066400000000000000000000003071215300731300154670ustar00rootroot00000000000000export MLT_REPOSITORY=`pwd`/../modules export LD_LIBRARY_PATH=`pwd`/../framework:\ `pwd`/../modules/bluefish:\ `pwd`/../../../bluefish/lib:\ `pwd`/../../../mpeg_sdk_demo/bin:\ `pwd`/../../../dv_sdk mlt-0.9.0/src/tests/test_properties/000077500000000000000000000000001215300731300174735ustar00rootroot00000000000000mlt-0.9.0/src/tests/test_properties/test_properties.cpp000066400000000000000000000713771215300731300234510ustar00rootroot00000000000000/* * Copyright (C) 2013 Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 consumer library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include using namespace Mlt; extern "C" { #define __DARWIN__ #include #include } #include class TestProperties: public QObject { Q_OBJECT locale_t locale; public: TestProperties() { #if defined(__linux__) || defined(__DARWIN__) locale = newlocale( LC_NUMERIC_MASK, "POSIX", NULL ); #endif } ~TestProperties() { #if defined(__linux__) || defined(__DARWIN__) freelocale(locale); #endif } private Q_SLOTS: void InstantiationIsAReference() { Properties p; QCOMPARE(p.ref_count(), 1); } void CopyAddsReference() { Properties p; Properties q = p; QCOMPARE(p.ref_count(), 2); } void DestructionRemovesReference() { Properties p; Properties* q = new Properties(p); QCOMPARE(p.ref_count(), 2); delete q; QCOMPARE(p.ref_count(), 1); } void SetAndGetString() { Properties p; p.set("key", "value"); QVERIFY(p.get("key")); QVERIFY(QString(p.get("key")) != QString("")); QCOMPARE(p.get("key"), "value"); } void SetAndGetInt() { Properties p; int i = 1; p.set("key", i); QCOMPARE(p.get_int("key"), i); } void SetAndGetDouble() { Properties p; double d = 1.0; p.set("key", d); QCOMPARE(p.get_double("key"), d); } void SetAndGetInt64() { Properties p; int64_t i = 1LL << 32; p.set("key", i); QCOMPARE(p.get_int64("key"), i); } void SetAndGetData() { Properties p; const char *value = "value"; char* const s = strdup(value); p.set("key", s, strlen(s), free); int size = 0; QCOMPARE((char*) p.get_data("key", size), value); QCOMPARE(size, int(strlen(value))); } void IntFromString() { Properties p; const char *s = "-1"; int i = -1; p.set("key", i); QCOMPARE(p.get("key"), s); p.set("key", s); QCOMPARE(p.get_int("key"), i); } void Int64FromString() { Properties p; const char *s = "-1"; int64_t i = -1; p.set("key", i); QCOMPARE(p.get("key"), s); p.set("key", s); QCOMPARE(p.get_int64("key"), i); } void DoubleFromString() { Properties p; const char *s = "-1.23456"; double d = -1.23456; p.set("key", d); QCOMPARE(p.get("key"), s); p.set("key", s); QCOMPARE(p.get_double("key"), d); } void SetNullRemovesProperty() { Properties p; const char *s = NULL; p.set("key", "value"); p.set("key", s); QCOMPARE(p.get("key"), s); } void SetAndGetHexColor() { Properties p; const char *hexColorString = "0xaabbccdd"; int hexColorInt = 0xaabbccdd; p.set("key", hexColorString); QCOMPARE(p.get_int("key"), hexColorInt); } void SetAndGetCssColor() { Properties p; const char *cssColorString = "#aabbcc"; int cssColorInt = 0xaabbccff; p.set("key", cssColorString); QCOMPARE(p.get_int("key"), cssColorInt); const char *cssColorAlphaString = "#00aabbcc"; int cssColorAlphaInt = 0xaabbcc00; p.set("key", cssColorAlphaString); QCOMPARE(p.get_int("key"), cssColorAlphaInt); } void SetAndGetTimeCode() { Profile profile; Properties p; p.set("_profile", profile.get_profile(), 0); const char *timeString = "11:22:33:04"; p.set("key", timeString); QCOMPARE(p.get_int("key"), 1023829); p.set("key", 1023829); QCOMPARE(p.get_time("key", mlt_time_smpte), timeString); } void SetAndGetTimeClock() { Profile profile; Properties p; p.set("_profile", profile.get_profile(), 0); const char *timeString = "11:22:33.400"; p.set("key", timeString); QCOMPARE(p.get_int("key"), 1023835); p.set("key", 1023835); QCOMPARE(p.get_time("key", mlt_time_clock), timeString); } void SetSimpleMathExpression() { Properties p; p.set("key", "@16.0/9.0 *2 +3 -1"); QCOMPARE(p.get_int("key"), 5); QCOMPARE(p.get_double("key"), 16.0/9.0 *2 +3 -1); } void PassOneProperty() { Properties p[2]; const char *s = "value"; p[0].set("key", s); QCOMPARE(p[1].get("key"), (void*) 0); p[1].pass_property(p[0], "key"); QCOMPARE(p[1].get("key"), s); } void PassMultipleByPrefix() { Properties p[2]; const char *s = "value"; p[0].set("key.one", s); p[0].set("key.two", s); QCOMPARE(p[1].get("key.one"), (void*) 0); QCOMPARE(p[1].get("key.two"), (void*) 0); p[1].pass_values(p[0], "key."); QCOMPARE(p[1].get("one"), s); QCOMPARE(p[1].get("two"), s); } void PassMultipleByList() { Properties p[2]; const char *s = "value"; p[0].set("key.one", s); p[0].set("key.two", s); QCOMPARE(p[1].get("key.one"), (void*) 0); QCOMPARE(p[1].get("key.two"), (void*) 0); p[1].pass_list(p[0], "key.one key.two"); QCOMPARE(p[1].get("key.one"), s); QCOMPARE(p[1].get("key.two"), s); } void MirrorProperties() { Properties p[2]; p[0].mirror(p[1]); p[0].set("key", "value"); QCOMPARE(p[1].get("key"), "value"); } void InheritProperties() { Properties p[2]; p[0].set("key", "value"); QVERIFY(p[1].get("key") == 0); p[1].inherit(p[0]); QCOMPARE(p[1].get("key"), "value"); } void ParseString() { Properties p; QCOMPARE(p.get("key"), (void*) 0); p.parse("key=value"); QCOMPARE(p.get("key"), "value"); p.parse("key=\"new value\""); QCOMPARE(p.get("key"), "new value"); } void RenameProperty() { Properties p; p.set("key", "value"); QVERIFY(p.get("new key") == 0); p.rename("key", "new key"); QCOMPARE(p.get("new key"), "value"); } void SequenceDetected() { Properties p; p.set("1", 1); p.set("2", 2); p.set("3", 3); QVERIFY(p.is_sequence()); p.set("four", 4); QVERIFY(!p.is_sequence()); } void SerializesToYamlTiny() { Properties p[2]; p[0].set("key1", "value1"); p[0].set("key2", "value2"); p[1].set("1", "value3"); p[1].set("2", "value4"); p[0].set("seq", p[1].get_properties(), 0); char* serializedYaml = p[0].serialise_yaml(); QCOMPARE(serializedYaml, "---\n" "key1: value1\n" "key2: value2\n" "seq:\n" " - value3\n" " - value4\n" "...\n"); free(serializedYaml); } void RadixRespondsToLocale() { Properties p; p.set_lcnumeric("en_US"); p.set("key", "0.125"); QCOMPARE(p.get_double("key"), double(1) / double(8)); p.set_lcnumeric("de_DE"); p.set("key", "0,125"); QCOMPARE(p.get_double("key"), double(1) / double(8)); } void DoubleAnimation() { double fps = 25.0; mlt_animation a = mlt_animation_new(); struct mlt_animation_item_s item; mlt_animation_parse(a, "50=1; 60=60; 100=0", 100, fps, locale); mlt_animation_remove(a, 60); char *a_serialized = mlt_animation_serialize(a); QCOMPARE(a_serialized, "50=1;100=0"); if (a_serialized) free(a_serialized); item.property = mlt_property_init(); mlt_animation_get_item(a, &item, 10); QCOMPARE(mlt_property_get_double(item.property, fps, locale), 1.0); QCOMPARE(item.is_key, 0); mlt_animation_get_item(a, &item, 50); QCOMPARE(mlt_property_get_double(item.property, fps, locale), 1.0); QCOMPARE(item.is_key, 1); mlt_animation_get_item(a, &item, 75); QCOMPARE(mlt_property_get_double(item.property, fps, locale), 0.5); QCOMPARE(item.is_key, 0); mlt_animation_get_item(a, &item, 100); QCOMPARE(mlt_property_get_double(item.property, fps, locale), 0.0); QCOMPARE(item.is_key, 1); mlt_animation_get_item(a, &item, 110); QCOMPARE(mlt_property_get_double(item.property, fps, locale), 0.0); QCOMPARE(item.is_key, 0); mlt_property_close(item.property); mlt_animation_close(a); } void IntAnimation() { double fps = 25.0; mlt_animation a = mlt_animation_new(); struct mlt_animation_item_s item; mlt_animation_parse(a, "50=100; 60=60; 100=0", 100, fps, locale); mlt_animation_remove(a, 60); char *a_serialized = mlt_animation_serialize(a); QCOMPARE(a_serialized, "50=100;100=0"); if (a_serialized) free(a_serialized); item.property = mlt_property_init(); mlt_animation_get_item(a, &item, 10); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 100); QCOMPARE(item.is_key, 0); mlt_animation_get_item(a, &item, 50); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 100); QCOMPARE(item.is_key, 1); mlt_animation_get_item(a, &item, 75); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 50); QCOMPARE(item.is_key, 0); mlt_animation_get_item(a, &item, 100); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 0); QCOMPARE(item.is_key, 1); mlt_animation_get_item(a, &item, 110); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 0); QCOMPARE(item.is_key, 0); mlt_property_close(item.property); mlt_animation_close(a); } void AnimationWithTimeValueKeyframes() { double fps = 25.0; mlt_animation a = mlt_animation_new(); struct mlt_animation_item_s item; mlt_animation_parse(a, ":2.0=1; :4.0=0", 100, fps, locale); char *a_serialized = mlt_animation_serialize(a); // Time serializes to frame units :-\. QCOMPARE(a_serialized, "50=1;100=0"); if (a_serialized) free(a_serialized); item.property = mlt_property_init(); mlt_animation_get_item(a, &item, 10); QCOMPARE(mlt_property_get_double(item.property, fps, locale), 1.0); QCOMPARE(item.is_key, 0); mlt_animation_get_item(a, &item, 50); QCOMPARE(mlt_property_get_double(item.property, fps, locale), 1.0); QCOMPARE(item.is_key, 1); mlt_animation_get_item(a, &item, 75); QCOMPARE(mlt_property_get_double(item.property, fps, locale), 0.5); QCOMPARE(item.is_key, 0); mlt_animation_get_item(a, &item, 100); QCOMPARE(mlt_property_get_double(item.property, fps, locale), 0.0); QCOMPARE(item.is_key, 1); mlt_animation_get_item(a, &item, 110); QCOMPARE(mlt_property_get_double(item.property, fps, locale), 0.0); QCOMPARE(item.is_key, 0); mlt_property_close(item.property); mlt_animation_close(a); } void DiscreteIntAnimation() { double fps = 25.0; mlt_animation a = mlt_animation_new(); struct mlt_animation_item_s item; mlt_animation_parse(a, "50|=100; 60|=60; 100|=0", 100, fps, locale); char *a_serialized = mlt_animation_serialize(a); QCOMPARE(a_serialized, "50|=100;60|=60;100|=0"); if (a_serialized) free(a_serialized); item.property = mlt_property_init(); mlt_animation_get_item(a, &item, 10); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 100); QCOMPARE(item.is_key, 0); mlt_animation_get_item(a, &item, 50); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 100); QCOMPARE(item.is_key, 1); mlt_animation_get_item(a, &item, 55); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 100); QCOMPARE(item.is_key, 0); mlt_animation_get_item(a, &item, 60); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 60); QCOMPARE(item.is_key, 1); mlt_animation_get_item(a, &item, 75); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 60); QCOMPARE(item.is_key, 0); mlt_animation_get_item(a, &item, 100); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 0); QCOMPARE(item.is_key, 1); mlt_animation_get_item(a, &item, 110); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 0); QCOMPARE(item.is_key, 0); mlt_property_close(item.property); mlt_animation_close(a); } void StringAnimation() { double fps = 25.0; mlt_animation a = mlt_animation_new(); struct mlt_animation_item_s item; mlt_animation_parse(a, "50=hello world; 60=\"good night\"; 100=bar", 100, fps, locale); char *a_serialized = mlt_animation_serialize(a); QCOMPARE(a_serialized, "50=hello world;60=\"good night\";100=bar"); if (a_serialized) free(a_serialized); item.property = mlt_property_init(); mlt_animation_get_item(a, &item, 10); QCOMPARE(mlt_property_get_string(item.property), "hello world"); QCOMPARE(item.is_key, 0); mlt_animation_get_item(a, &item, 50); QCOMPARE(mlt_property_get_string(item.property), "hello world"); QCOMPARE(item.is_key, 1); mlt_animation_get_item(a, &item, 75); QCOMPARE(mlt_property_get_string(item.property), "\"good night\""); QCOMPARE(item.is_key, 0); mlt_animation_get_item(a, &item, 100); QCOMPARE(mlt_property_get_string(item.property), "bar"); QCOMPARE(item.is_key, 1); mlt_animation_get_item(a, &item, 110); QCOMPARE(mlt_property_get_string(item.property), "bar"); QCOMPARE(item.is_key, 0); mlt_property_close(item.property); mlt_animation_close(a); } void test_property_anim_get_double() { double fps = 25.0; int len = 0; mlt_property p = mlt_property_init(); mlt_property_set_string(p, "10=100; 20=200"); QCOMPARE(mlt_property_get_double(p, fps, locale), 10.0); QCOMPARE(mlt_property_anim_get_double(p, fps, locale, 0, len), 100.0); QCOMPARE(mlt_property_anim_get_double(p, fps, locale, 15, len), 150.0); QCOMPARE(mlt_property_anim_get_double(p, fps, locale, 20, len), 200.0); mlt_property_set_string(p, "1.5"); QCOMPARE(mlt_property_get_double(p, fps, locale), 1.5); QCOMPARE(mlt_property_anim_get_double(p, fps, locale, 10, 100), 1.5); mlt_property_close(p); } void test_property_anim_get_int() { double fps = 25.0; int len = 100; mlt_property p = mlt_property_init(); mlt_property_set_string(p, "10=100; 20=200"); QCOMPARE(mlt_property_get_int(p, fps, locale), 10); QCOMPARE(mlt_property_anim_get_int(p, fps, locale, 0, len), 100); QCOMPARE(mlt_property_anim_get_int(p, fps, locale, 15, len), 150); QCOMPARE(mlt_property_anim_get_int(p, fps, locale, 20, len), 200); mlt_property_set_string(p, "1.5"); QCOMPARE(mlt_property_get_int(p, fps, locale), 1); QCOMPARE(mlt_property_anim_get_int(p, fps, locale, 10, 100), 1); mlt_property_close(p); } void SmoothIntAnimation() { double fps = 25.0; mlt_animation a = mlt_animation_new(); struct mlt_animation_item_s item; mlt_animation_parse(a, "0=80;10~=80; 20~=30; 30~=40; 40~=28; 50=90; 60=0; 70=60; 80=20", 100, fps, locale); item.property = mlt_property_init(); char *a_serialized = mlt_animation_serialize(a); QCOMPARE(a_serialized, "0=80;10~=80;20~=30;30~=40;40~=28;50=90;60=0;70=60;80=20"); if (a_serialized) free(a_serialized); mlt_animation_get_item(a, &item, 10); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 80); QCOMPARE(item.is_key, 1); mlt_animation_get_item(a, &item, 50); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 90); QCOMPARE(item.is_key, 1); mlt_animation_get_item(a, &item, 55); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 45); QCOMPARE(item.is_key, 0); mlt_animation_get_item(a, &item, 60); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 0); QCOMPARE(item.is_key, 1); mlt_animation_get_item(a, &item, 75); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 40); QCOMPARE(item.is_key, 0); mlt_animation_get_item(a, &item, 100); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 20); QCOMPARE(item.is_key, 0); mlt_animation_get_item(a, &item, 110); QCOMPARE(mlt_property_get_int(item.property, fps, locale), 20); QCOMPARE(item.is_key, 0); mlt_property_close(item.property); mlt_animation_close(a); } void test_property_anim_set_double() { double fps = 25.0; int len = 100; mlt_property p = mlt_property_init(); mlt_property_set_string(p, "10=100; 20=200"); mlt_property_anim_set_double(p, 1.5, fps, locale, 30, len, mlt_keyframe_linear); QCOMPARE(mlt_property_get_double(p, fps, locale), 10.0); QCOMPARE(mlt_property_anim_get_double(p, fps, locale, 0, len), 100.0); QCOMPARE(mlt_property_anim_get_double(p, fps, locale, 15, len), 150.0); QCOMPARE(mlt_property_anim_get_double(p, fps, locale, 20, len), 200.0); QCOMPARE(mlt_property_anim_get_double(p, fps, locale, 25, len), 100.75); QCOMPARE(mlt_property_anim_get_double(p, fps, locale, 30, len), 1.5); mlt_property_close(p); } void test_property_anim_set_int() { double fps = 25.0; int len = 0; mlt_property p = mlt_property_init(); mlt_property_set_string(p, "10=100; 20=200"); mlt_property_anim_set_int(p, 300, fps, locale, 30, len, mlt_keyframe_linear); QCOMPARE(mlt_property_get_int(p, fps, locale), 10); QCOMPARE(mlt_property_anim_get_int(p, fps, locale, 0, len), 100); QCOMPARE(mlt_property_anim_get_int(p, fps, locale, 15, len), 150); QCOMPARE(mlt_property_anim_get_int(p, fps, locale, 20, len), 200); QCOMPARE(mlt_property_anim_get_int(p, fps, locale, 25, len), 250); QCOMPARE(mlt_property_anim_get_int(p, fps, locale, 30, len), 300); mlt_property_close(p); } void PercentAsRatio() { Properties p; p.set("foo", "12.3%"); QCOMPARE(p.get_double("foo"), 0.123); p.set("foo", "456 %"); QCOMPARE(p.get_double("foo"), 456.0); } void PropertiesAnimInt() { Properties p; p.set_lcnumeric("POSIX"); // Construct animation from scratch p.anim_set("foo", 0, 0); p.anim_set("foo", 100, 50, -1, mlt_keyframe_smooth); QCOMPARE(p.anim_get_int("foo", 0), 0); QCOMPARE(p.anim_get_int("foo", 25), 50); QCOMPARE(p.anim_get_int("foo", 50), 100); QCOMPARE(p.get("foo"), "0=0;50~=100"); // Animation from string value p.set("foo", "10=100;20=200"); QCOMPARE(p.anim_get_int("foo", 0), 100); QCOMPARE(p.anim_get_int("foo", 15), 150); QCOMPARE(p.anim_get_int("foo", 20), 200); // Animation from string using time clock values // Need to set a profile so fps can be used to convert time to frames. Profile profile("dv_pal"); p.set("_profile", profile.get_profile(), 0); p.set("foo", ":0.0=100; :2.0=200"); QCOMPARE(p.anim_get_int("foo", 0), 100); QCOMPARE(p.anim_get_int("foo", 25), 150); QCOMPARE(p.anim_get_int("foo", 50), 200); } void PropertiesAnimDouble() { Properties p; p.set_lcnumeric("POSIX"); // Construct animation from scratch p.anim_set("foo", 0.0, 0); p.anim_set("foo", 100.0, 50, -1, mlt_keyframe_smooth); QCOMPARE(p.anim_get_double("foo", 0), 0.0); QCOMPARE(p.anim_get_double("foo", 25), 50.0); QCOMPARE(p.anim_get_double("foo", 50), 100.0); QCOMPARE(p.get("foo"), "0=0;50~=100"); // Animation from string value p.set("foo", "10=100.2;20=200.8"); QCOMPARE(p.anim_get_double("foo", 0), 100.2); QCOMPARE(p.anim_get_double("foo", 15), 150.5); QCOMPARE(p.anim_get_double("foo", 20), 200.8); // Animation from string using time clock values // Need to set a profile so fps can be used to convert time to frames. Profile profile("dv_pal"); p.set("_profile", profile.get_profile(), 0); p.set("foo", ":0.0=100; :2.0=200"); QCOMPARE(p.anim_get_double("foo", 0), 100.0); QCOMPARE(p.anim_get_double("foo", 25), 150.0); QCOMPARE(p.anim_get_double("foo", 50), 200.0); } void PropertiesStringAnimation() { Properties p; p.anim_set("key", "foo", 10); p.anim_set("key", "bar", 30); QCOMPARE(p.get("key"), "10|=foo;30|=bar"); p.set("key", "0=; 10=foo bar; 30=hello world"); QCOMPARE(p.anim_get("key", 1), ""); QCOMPARE(p.anim_get("key", 15), "foo bar"); QCOMPARE(p.anim_get("key", 45), "hello world"); } void test_mlt_rect() { mlt_property p = mlt_property_init(); mlt_rect r = { 1, 2, 3, 4, 5 }; mlt_property_set_rect( p, r ); QCOMPARE(mlt_property_get_string(p), "1 2 3 4 5"); r.o = DBL_MIN; mlt_property_set_rect( p, r ); QCOMPARE(mlt_property_get_string(p), "1 2 3 4"); r.w = DBL_MIN; r.h = DBL_MIN; mlt_property_set_rect( p, r ); QCOMPARE(mlt_property_get_string(p), "1 2"); mlt_property_set_string(p, "1.1/2.2:3.3x4.4:5.5"); r = mlt_property_get_rect(p, locale); QCOMPARE(r.x, 1.1); QCOMPARE(r.y, 2.2); QCOMPARE(r.w, 3.3); QCOMPARE(r.h, 4.4); QCOMPARE(r.o, 5.5); mlt_property_set_string(p, "1.1 2.2"); r = mlt_property_get_rect(p, locale); QCOMPARE(r.x, 1.1); QCOMPARE(r.y, 2.2); QCOMPARE(r.w, DBL_MIN); mlt_property_set_int64(p, UINT_MAX); r = mlt_property_get_rect(p, locale); QCOMPARE(r.x, double(UINT_MAX)); mlt_property_close(p); } void SetAndGetRect() { Properties p; mlt_rect r; r.x = 1.1; r.y = 2.2; r.w = 3.3; r.h = 4.4; r.o = 5.5; p.set("key", r); mlt_rect q = p.get_rect("key"); QCOMPARE(q.x, 1.1); QCOMPARE(q.y, 2.2); QCOMPARE(q.w, 3.3); QCOMPARE(q.h, 4.4); QCOMPARE(q.o, 5.5); p.set("key", 10, 20, 30, 40); q = p.get_rect("key"); QCOMPARE(q.x, 10.0); QCOMPARE(q.y, 20.0); QCOMPARE(q.w, 30.0); QCOMPARE(q.h, 40.0); } void RectFromString() { Properties p; p.set_lcnumeric("POSIX"); const char *s = "1.1 2.2 3.3 4.4 5.5"; mlt_rect r = { 1.1, 2.2, 3.3, 4.4, 5.5 }; p.set("key", r); QCOMPARE(p.get("key"), s); p.set("key", s); r = p.get_rect("key"); QCOMPARE(r.x, 1.1); QCOMPARE(r.y, 2.2); QCOMPARE(r.w, 3.3); QCOMPARE(r.h, 4.4); QCOMPARE(r.o, 5.5); } void RectAnimation() { mlt_rect r1 = { 0, 0, 200, 200, 0 }; mlt_rect r2 = { 100, 100, 400, 400, 1.0 }; Properties p; p.set_lcnumeric("POSIX"); // Construct animation from scratch p.anim_set("key", r1, 0); p.anim_set("key", r2, 50); QCOMPARE(p.anim_get_rect("key", 0).x, 0.0); QCOMPARE(p.anim_get_rect("key", 25).x, 50.0); QCOMPARE(p.anim_get_rect("key", 25).y, 50.0); QCOMPARE(p.anim_get_rect("key", 25).w, 300.0); QCOMPARE(p.anim_get_rect("key", 25).h, 300.0); QCOMPARE(p.anim_get_rect("key", 25).o, 0.5); QCOMPARE(p.anim_get_rect("key", 50).x, 100.0); QCOMPARE(p.get("key"), "0=0 0 200 200 0;50=100 100 400 400 1"); // Animation from string value QCOMPARE(p.anim_get_rect("key", 0).x, 0.0); QCOMPARE(p.anim_get_rect("key", 0).y, 0.0); QCOMPARE(p.anim_get_rect("key", 0).w, 200.0); QCOMPARE(p.anim_get_rect("key", 0).h, 200.0); QCOMPARE(p.anim_get_rect("key", 0).o, 0.0); QCOMPARE(p.anim_get_rect("key", 50).x, 100.0); QCOMPARE(p.anim_get_rect("key", 50).y, 100.0); QCOMPARE(p.anim_get_rect("key", 50).w, 400.0); QCOMPARE(p.anim_get_rect("key", 50).h, 400.0); QCOMPARE(p.anim_get_rect("key", 50).o, 1.0); QCOMPARE(p.anim_get_rect("key", 15).x, 30.0); QCOMPARE(p.anim_get_rect("key", 15).y, 30.0); QCOMPARE(p.anim_get_rect("key", 15).w, 260.0); QCOMPARE(p.anim_get_rect("key", 15).h, 260.0); QCOMPARE(p.anim_get_rect("key", 15).o, 0.3); // Smooth animation p.set("key", "0~=0/0:200x200:0; 50=100/100:400x400:1"); QCOMPARE(p.anim_get_rect("key", 0).x, 0.0); QCOMPARE(p.anim_get_rect("key", 0).y, 0.0); QCOMPARE(p.anim_get_rect("key", 0).w, 200.0); QCOMPARE(p.anim_get_rect("key", 0).h, 200.0); QCOMPARE(p.anim_get_rect("key", 0).o, 0.0); QCOMPARE(p.anim_get_rect("key", 50).x, 100.0); QCOMPARE(p.anim_get_rect("key", 50).y, 100.0); QCOMPARE(p.anim_get_rect("key", 50).w, 400.0); QCOMPARE(p.anim_get_rect("key", 50).h, 400.0); QCOMPARE(p.anim_get_rect("key", 50).o, 1.0); QCOMPARE(p.anim_get_rect("key", 15).x, 25.8); QCOMPARE(p.anim_get_rect("key", 15).y, 25.8); QCOMPARE(p.anim_get_rect("key", 15).w, 251.6); QCOMPARE(p.anim_get_rect("key", 15).h, 251.6); QCOMPARE(p.anim_get_rect("key", 15).o, 0.258); // Using percentages p.set("key", "0=0 0; 50=100% 200%"); QCOMPARE(p.anim_get_rect("key", 25).x, 0.5); QCOMPARE(p.anim_get_rect("key", 25).y, 1.0); } void ColorFromInt() { Properties p; p.set_lcnumeric("POSIX"); p.set("key", (int) 0xaabbccdd); mlt_color color = p.get_color("key"); QCOMPARE(color.r, quint8(0xaa)); QCOMPARE(color.g, quint8(0xbb)); QCOMPARE(color.b, quint8(0xcc)); QCOMPARE(color.a, quint8(0xdd)); p.set("key", color); QCOMPARE(p.get_int("key"), int(0xaabbccdd)); } void ColorFromString() { Properties p; p.set_lcnumeric("POSIX"); p.set("key", "red"); mlt_color color = p.get_color("key"); QCOMPARE(color.r, quint8(0xff)); QCOMPARE(color.g, quint8(0x00)); QCOMPARE(color.b, quint8(0x00)); QCOMPARE(color.a, quint8(0xff)); p.set("key", "#deadd00d"); color = p.get_color("key"); QCOMPARE(color.r, quint8(0xad)); QCOMPARE(color.g, quint8(0xd0)); QCOMPARE(color.b, quint8(0x0d)); QCOMPARE(color.a, quint8(0xde)); } void SetIntAndGetAnim() { Properties p; p.set_lcnumeric("POSIX"); p.set("key", 123); QCOMPARE(p.anim_get_int("key", 10, 50), 123); p.set("key", "123"); QCOMPARE(p.anim_get_int("key", 10, 50), 123); } void SetDoubleAndGetAnim() { Properties p; p.set_lcnumeric("POSIX"); p.set("key", 123.0); QCOMPARE(p.anim_get_double("key", 10, 50), 123.0); p.set("key", "123"); QCOMPARE(p.anim_get_double("key", 10, 50), 123.0); } void AnimNegativeTimevalue() { Properties p; Profile profile("dv_pal"); p.set("_profile", profile.get_profile(), 0); p.set_lcnumeric("POSIX"); p.set("key", "0=100; -1=200"); QCOMPARE(p.anim_get_int("key", 75, 100), 175); p.set("key", "0=100; -1:=200"); QCOMPARE(p.anim_get_int("key", 75, 125), 175); } }; QTEST_APPLESS_MAIN(TestProperties) #include "test_properties.moc" mlt-0.9.0/src/tests/test_properties/test_properties.pro000066400000000000000000000001221215300731300234430ustar00rootroot00000000000000include (../common.pri) TARGET = test_properties SOURCES = test_properties.cpp mlt-0.9.0/src/tests/test_repository/000077500000000000000000000000001215300731300175165ustar00rootroot00000000000000mlt-0.9.0/src/tests/test_repository/test_repository.cpp000066400000000000000000000031261215300731300235020ustar00rootroot00000000000000/* * Copyright (C) 2013 Dan Dennedy * * This library 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 (at your option) any later version. * * This library 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 consumer library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include using namespace Mlt; class TestRepository : public QObject { Q_OBJECT public: TestRepository() {} private Q_SLOTS: void ThereAreProducers() { Repository* r = Factory::init(); Properties* producers = r->producers(); QVERIFY(producers->is_valid()); if (producers->is_valid()) QVERIFY(producers->count() > 0); delete producers; } void ThereAreConsumers() { Repository* r = Factory::init(); Properties* consumers = r->consumers(); QVERIFY(consumers->is_valid()); if (consumers->is_valid()) QVERIFY(consumers->count() > 0); delete consumers; } }; QTEST_APPLESS_MAIN(TestRepository) #include "test_repository.moc" mlt-0.9.0/src/tests/test_repository/test_repository.pro000066400000000000000000000001201215300731300235070ustar00rootroot00000000000000include(../common.pri) TARGET = test_repository SOURCES += test_repository.cpp mlt-0.9.0/src/tests/tests.pro000066400000000000000000000001031215300731300161160ustar00rootroot00000000000000TEMPLATE = subdirs SUBDIRS = test_properties \ test_repository mlt-0.9.0/src/win32/000077500000000000000000000000001215300731300140405ustar00rootroot00000000000000mlt-0.9.0/src/win32/fnmatch.c000066400000000000000000000134301215300731300156250ustar00rootroot00000000000000/* * Copyright (c) 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Guido van Rossum. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University 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 REGENTS 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 THE REGENTS 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. * * From FreeBSD fnmatch.c 1.11 * $Id$ */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94"; #endif /* LIBC_SCCS and not lint */ /* * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. * Compares a filename or pathname to a pattern. */ #include #include #include #include "fnmatch.h" #define EOS '\0' static const char *rangematch(const char *, char, int); int fnmatch(const char *pattern, const char *string, int flags) { const char *stringstart; char c, test; for (stringstart = string;;) switch (c = *pattern++) { case EOS: if ((flags & FNM_LEADING_DIR) && *string == '/') return (0); return (*string == EOS ? 0 : FNM_NOMATCH); case '?': if (*string == EOS) return (FNM_NOMATCH); if (*string == '/' && (flags & FNM_PATHNAME)) return (FNM_NOMATCH); if (*string == '.' && (flags & FNM_PERIOD) && (string == stringstart || ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) return (FNM_NOMATCH); ++string; break; case '*': c = *pattern; /* Collapse multiple stars. */ while (c == '*') c = *++pattern; if (*string == '.' && (flags & FNM_PERIOD) && (string == stringstart || ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) return (FNM_NOMATCH); /* Optimize for pattern with * at end or before /. */ if (c == EOS) if (flags & FNM_PATHNAME) return ((flags & FNM_LEADING_DIR) || strchr(string, '/') == NULL ? 0 : FNM_NOMATCH); else return (0); else if (c == '/' && flags & FNM_PATHNAME) { if ((string = strchr(string, '/')) == NULL) return (FNM_NOMATCH); break; } /* General case, use recursion. */ while ((test = *string) != EOS) { if (!fnmatch(pattern, string, flags & ~FNM_PERIOD)) return (0); if (test == '/' && flags & FNM_PATHNAME) break; ++string; } return (FNM_NOMATCH); case '[': if (*string == EOS) return (FNM_NOMATCH); if (*string == '/' && flags & FNM_PATHNAME) return (FNM_NOMATCH); if ((pattern = rangematch(pattern, *string, flags)) == NULL) return (FNM_NOMATCH); ++string; break; case '\\': if (!(flags & FNM_NOESCAPE)) { if ((c = *pattern++) == EOS) { c = '\\'; --pattern; } } /* FALLTHROUGH */ default: if (c == *string) ; else if ((flags & FNM_CASEFOLD) && (tolower((unsigned char)c) == tolower((unsigned char)*string))) ; else if ((flags & FNM_PREFIX_DIRS) && *string == EOS && ((c == '/' && string != stringstart) || (string == stringstart+1 && *stringstart == '/')) ) return (0); else return (FNM_NOMATCH); string++; break; } /* NOTREACHED */ } static const char * rangematch(const char *pattern, char test, int flags) { int negate, ok; char c, c2; /* * A bracket expression starting with an unquoted circumflex * character produces unspecified results (IEEE 1003.2-1992, * 3.13.2). This implementation treats it like '!', for * consistency with the regular expression syntax. * J.T. Conklin (conklin@ngai.kaleida.com) */ if ( (negate = (*pattern == '!' || *pattern == '^')) ) ++pattern; if (flags & FNM_CASEFOLD) test = tolower((unsigned char)test); for (ok = 0; (c = *pattern++) != ']';) { if (c == '\\' && !(flags & FNM_NOESCAPE)) c = *pattern++; if (c == EOS) return (NULL); if (flags & FNM_CASEFOLD) c = tolower((unsigned char)c); if (*pattern == '-' && (c2 = *(pattern+1)) != EOS && c2 != ']') { pattern += 2; if (c2 == '\\' && !(flags & FNM_NOESCAPE)) c2 = *pattern++; if (c2 == EOS) return (NULL); if (flags & FNM_CASEFOLD) c2 = tolower((unsigned char)c2); if ((unsigned char)c <= (unsigned char)test && (unsigned char)test <= (unsigned char)c2) ok = 1; } else if (c == test) ok = 1; } return (ok == negate ? NULL : pattern); } mlt-0.9.0/src/win32/fnmatch.h000066400000000000000000000046571215300731300156450ustar00rootroot00000000000000/*- * Copyright (c) 1992, 1993 * The Regents of the University of California. 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University 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 REGENTS 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 THE REGENTS 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. * * @(#)fnmatch.h 8.1 (Berkeley) 6/2/93 * * From FreeBSD fnmatch.h 1.7 * $Id$ */ #ifndef _FNMATCH_H_ #define _FNMATCH_H_ #define FNM_NOMATCH 1 /* Match failed. */ #define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */ #define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */ #define FNM_PERIOD 0x04 /* Period must be matched by period. */ #define FNM_LEADING_DIR 0x08 /* Ignore / after Imatch. */ #define FNM_CASEFOLD 0x10 /* Case insensitive search. */ #define FNM_PREFIX_DIRS 0x20 /* Directory prefixes of pattern match too. */ int fnmatch(const char *pattern, const char *string, int flags); #endif /* !_FNMATCH_H_ */ mlt-0.9.0/src/win32/win32.c000066400000000000000000000015511215300731300151500ustar00rootroot00000000000000 #include #include #include #include int usleep(unsigned int useconds) { HANDLE timer; LARGE_INTEGER due; due.QuadPart = -(10 * (__int64)useconds); timer = CreateWaitableTimer(NULL, TRUE, NULL); SetWaitableTimer(timer, &due, 0, NULL, NULL, 0); WaitForSingleObject(timer, INFINITE); CloseHandle(timer); return 0; } int nanosleep( const struct timespec * rqtp, struct timespec * rmtp ) { if (rqtp->tv_nsec > 999999999) { /* The time interval specified 1,000,000 or more microseconds. */ errno = EINVAL; return -1; } return usleep( rqtp->tv_sec * 1000000 + rqtp->tv_nsec / 1000 ); } int setenv(const char *name, const char *value, int overwrite) { int result = 1; if (overwrite == 0 && getenv (name)) { result = 0; } else { result = SetEnvironmentVariable (name,value); } return result; }